8136421: JEP 243: Java-Level JVM Compiler Interface
Reviewed-by: ihse, alanb, roland, coleenp, iveresov, kvn, kbarrett
This commit is contained in:
parent
f5b4bb46f5
commit
16526e000e
@ -28,4 +28,7 @@ TYPE=COMPILER1
|
||||
|
||||
VM_SUBDIR = client
|
||||
|
||||
# We don't support the JVMCI in a client VM.
|
||||
INCLUDE_JVMCI := false
|
||||
|
||||
CFLAGS += -DCOMPILER1
|
||||
|
@ -149,6 +149,7 @@ ifeq ($(USE_CLANG), true)
|
||||
PCH_FLAG/sharedRuntimeTrig.o = $(PCH_FLAG/NO_PCH)
|
||||
PCH_FLAG/sharedRuntimeTrans.o = $(PCH_FLAG/NO_PCH)
|
||||
PCH_FLAG/unsafe.o = $(PCH_FLAG/NO_PCH)
|
||||
PCH_FLAG/jvmciCompilerToVM.o = $(PCH_FLAG/NO_PCH)
|
||||
|
||||
endif
|
||||
else # ($(USE_CLANG), true)
|
||||
|
@ -38,6 +38,7 @@ INCLUDE_ALL_GCS := false
|
||||
INCLUDE_NMT := false
|
||||
INCLUDE_TRACE := false
|
||||
INCLUDE_CDS := false
|
||||
INCLUDE_JVMCI := false
|
||||
|
||||
CXXFLAGS += -DMINIMAL_JVM -DCOMPILER1 -DVMTYPE=\"Minimal\"
|
||||
CFLAGS += -DMINIMAL_JVM -DCOMPILER1 -DVMTYPE=\"Minimal\"
|
||||
|
@ -106,6 +106,25 @@ ifeq ($(INCLUDE_NMT), false)
|
||||
memTracker.cpp nmtDCmd.cpp mallocSiteTable.cpp
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring $(Platform_arch_model), x86_64, sparc))
|
||||
# JVMCI is supported only on x86_64 and SPARC.
|
||||
else
|
||||
INCLUDE_JVMCI := false
|
||||
endif
|
||||
|
||||
ifeq ($(INCLUDE_JVMCI), false)
|
||||
CXXFLAGS += -DINCLUDE_JVMCI=0
|
||||
CFLAGS += -DINCLUDE_JVMCI=0
|
||||
|
||||
jvmci_dir := $(HS_COMMON_SRC)/share/vm/jvmci
|
||||
jvmci_dir_alt := $(HS_ALT_SRC)/share/vm/jvmci
|
||||
jvmci_exclude := $(notdir $(wildcard $(jvmci_dir)/*.cpp)) \
|
||||
$(notdir $(wildcard $(jvmci_dir_alt)/*.cpp))
|
||||
Src_Files_EXCLUDE += $(jvmci_exclude) \
|
||||
jvmciCodeInstaller_aarch64.cpp jvmciCodeInstaller_ppc.cpp jvmciCodeInstaller_sparc.cpp \
|
||||
jvmciCodeInstaller_x86.cpp
|
||||
endif
|
||||
|
||||
-include $(HS_ALT_MAKE)/excludeSrc.make
|
||||
|
||||
.PHONY: $(HS_ALT_MAKE)/excludeSrc.make
|
||||
|
121
hotspot/make/gensrc/Gensrc-jdk.vm.ci.gmk
Normal file
121
hotspot/make/gensrc/Gensrc-jdk.vm.ci.gmk
Normal file
@ -0,0 +1,121 @@
|
||||
#
|
||||
# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
default: all
|
||||
|
||||
include $(SPEC)
|
||||
include MakeBase.gmk
|
||||
include JavaCompilation.gmk
|
||||
include SetupJavaCompilers.gmk
|
||||
|
||||
GENSRC_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/jdk.vm.ci
|
||||
SRC_DIR := $(HOTSPOT_TOPDIR)/src/jdk.vm.ci/share/classes
|
||||
|
||||
################################################################################
|
||||
# Compile the annotation processor
|
||||
|
||||
$(eval $(call SetupJavaCompilation, BUILD_JVMCI_OPTIONS, \
|
||||
SETUP := GENERATE_OLDBYTECODE, \
|
||||
SRC := $(SRC_DIR)/jdk.vm.ci.options/src \
|
||||
$(SRC_DIR)/jdk.vm.ci.options.processor/src \
|
||||
$(SRC_DIR)/jdk.vm.ci.inittimer/src, \
|
||||
BIN := $(BUILDTOOLS_OUTPUTDIR)/jvmci_options, \
|
||||
JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.ci.options.jar, \
|
||||
))
|
||||
|
||||
$(eval $(call SetupJavaCompilation, BUILD_JVMCI_SERVICE, \
|
||||
SETUP := GENERATE_OLDBYTECODE, \
|
||||
SRC := $(SRC_DIR)/jdk.vm.ci.service/src \
|
||||
$(SRC_DIR)/jdk.vm.ci.service.processor/src, \
|
||||
BIN := $(BUILDTOOLS_OUTPUTDIR)/jvmci_service, \
|
||||
JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.ci.service.jar, \
|
||||
))
|
||||
|
||||
################################################################################
|
||||
|
||||
PROC_SRC_SUBDIRS := \
|
||||
jdk.vm.ci.compiler \
|
||||
jdk.vm.ci.hotspot \
|
||||
jdk.vm.ci.hotspot.amd64 \
|
||||
jdk.vm.ci.hotspot.sparc \
|
||||
#
|
||||
|
||||
PROC_SRC_DIRS := $(patsubst %, $(SRC_DIR)/%/src, $(PROC_SRC_SUBDIRS))
|
||||
|
||||
PROC_SRCS := $(filter %.java, $(call CacheFind, $(PROC_SRC_DIRS)))
|
||||
|
||||
ALL_SRC_DIRS := $(wildcard $(SRC_DIR)/*/src)
|
||||
SOURCEPATH := $(call PathList, $(ALL_SRC_DIRS))
|
||||
PROCESSOR_PATH := $(call PathList, \
|
||||
$(BUILDTOOLS_OUTPUTDIR)/jdk.vm.ci.options.jar \
|
||||
$(BUILDTOOLS_OUTPUTDIR)/jdk.vm.ci.service.jar)
|
||||
|
||||
$(GENSRC_DIR)/_gensrc_proc_done: $(PROC_SRCS) \
|
||||
$(BUILD_JVMCI_OPTIONS) $(BUILD_JVMCI_SERVICE)
|
||||
$(MKDIR) -p $(@D)
|
||||
$(eval $(call ListPathsSafely,PROC_SRCS,$(@D)/_gensrc_proc_files))
|
||||
$(JAVA_SMALL) $(NEW_JAVAC) \
|
||||
-sourcepath $(SOURCEPATH) \
|
||||
-implicit:none \
|
||||
-proc:only \
|
||||
-processorpath $(PROCESSOR_PATH) \
|
||||
-d $(GENSRC_DIR) \
|
||||
-s $(GENSRC_DIR) \
|
||||
@$(@D)/_gensrc_proc_files
|
||||
$(TOUCH) $@
|
||||
|
||||
TARGETS += $(GENSRC_DIR)/_gensrc_proc_done
|
||||
|
||||
################################################################################
|
||||
|
||||
$(GENSRC_DIR)/META-INF/services/jdk.vm.ci.options.OptionDescriptors: \
|
||||
$(GENSRC_DIR)/_gensrc_proc_done
|
||||
$(MKDIR) -p $(@D)
|
||||
($(CD) $(GENSRC_DIR)/META-INF/jvmci.options && \
|
||||
$(RM) -f $@; \
|
||||
for i in $$(ls); do \
|
||||
echo $${i}_OptionDescriptors >> $@; \
|
||||
done)
|
||||
|
||||
TARGETS += $(GENSRC_DIR)/META-INF/services/jdk.vm.ci.options.OptionDescriptors
|
||||
|
||||
################################################################################
|
||||
|
||||
$(GENSRC_DIR)/_providers_converted: $(GENSRC_DIR)/_gensrc_proc_done
|
||||
$(MKDIR) -p $(GENSRC_DIR)/META-INF/services
|
||||
($(CD) $(GENSRC_DIR)/META-INF/jvmci.providers && \
|
||||
for i in $$($(LS)); do \
|
||||
c=$$($(CAT) $$i | $(TR) -d '\n\r'); \
|
||||
$(ECHO) $$i >> $(GENSRC_DIR)/META-INF/services/$$c; \
|
||||
done)
|
||||
$(TOUCH) $@
|
||||
|
||||
TARGETS += $(GENSRC_DIR)/_providers_converted
|
||||
|
||||
################################################################################
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
.PHONY: default all
|
@ -28,4 +28,7 @@ TYPE=COMPILER1
|
||||
|
||||
VM_SUBDIR = client
|
||||
|
||||
# We don't support the JVMCI in a client VM.
|
||||
INCLUDE_JVMCI := false
|
||||
|
||||
CFLAGS += -DCOMPILER1
|
||||
|
@ -38,6 +38,7 @@ INCLUDE_ALL_GCS := false
|
||||
INCLUDE_NMT := false
|
||||
INCLUDE_TRACE := false
|
||||
INCLUDE_CDS := false
|
||||
INCLUDE_JVMCI := false
|
||||
|
||||
CXXFLAGS += -DMINIMAL_JVM -DCOMPILER1 -DVMTYPE=\"Minimal\"
|
||||
CFLAGS += -DMINIMAL_JVM -DCOMPILER1 -DVMTYPE=\"Minimal\"
|
||||
|
@ -28,4 +28,7 @@ TYPE=COMPILER1
|
||||
|
||||
VM_SUBDIR = client
|
||||
|
||||
# We don't support the JVMCI in a client VM.
|
||||
INCLUDE_JVMCI := false
|
||||
|
||||
CFLAGS += -DCOMPILER1
|
||||
|
@ -52,6 +52,7 @@ UNIQ="$MKS_HOME/uniq.exe"
|
||||
CAT="$MKS_HOME/cat.exe"
|
||||
RM="$MKS_HOME/rm.exe"
|
||||
DUMPBIN="link.exe /dump"
|
||||
export VS_UNICODE_OUTPUT=
|
||||
|
||||
if [ "$1" = "-nosa" ]; then
|
||||
echo EXPORTS > vm.def
|
||||
|
@ -111,6 +111,7 @@ esac
|
||||
|
||||
COMPILER2_SPECIFIC_FILES="opto libadt bcEscapeAnalyzer.cpp c2_* runtime_*"
|
||||
COMPILER1_SPECIFIC_FILES="c1_*"
|
||||
JVMCI_SPECIFIC_FILES="*jvmci* *JVMCI*"
|
||||
SHARK_SPECIFIC_FILES="shark"
|
||||
ZERO_SPECIFIC_FILES="zero"
|
||||
|
||||
@ -119,11 +120,11 @@ Src_Files_EXCLUDE="jsig.c jvmtiEnvRecommended.cpp jvmtiEnvStub.cpp"
|
||||
|
||||
# Exclude per type.
|
||||
case "${TYPE}" in
|
||||
"compiler1") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER2_SPECIFIC_FILES} ${ZERO_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES} ciTypeFlow.cpp" ;;
|
||||
"compiler1") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER2_SPECIFIC_FILES} ${JVMCI_SPECIFIC_FILES} ${ZERO_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES} ciTypeFlow.cpp" ;;
|
||||
"compiler2") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER1_SPECIFIC_FILES} ${ZERO_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES}" ;;
|
||||
"tiered") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${ZERO_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES}" ;;
|
||||
"zero") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER1_SPECIFIC_FILES} ${COMPILER2_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES} ciTypeFlow.cpp" ;;
|
||||
"shark") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER1_SPECIFIC_FILES} ${COMPILER2_SPECIFIC_FILES} ${ZERO_SPECIFIC_FILES}" ;;
|
||||
"zero") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER1_SPECIFIC_FILES} ${COMPILER2_SPECIFIC_FILES} ${JVMCI_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES} ciTypeFlow.cpp" ;;
|
||||
"shark") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER1_SPECIFIC_FILES} ${COMPILER2_SPECIFIC_FILES} ${JVMCI_SPECIFIC_FILES} ${ZERO_SPECIFIC_FILES}" ;;
|
||||
esac
|
||||
|
||||
# Special handling of arch model.
|
||||
|
@ -145,6 +145,10 @@ ProjectCreatorIDEOptionsIgnoreCompiler1=\
|
||||
-ignorePath_TARGET tiered \
|
||||
-ignorePath_TARGET c1_
|
||||
|
||||
ProjectCreatorIDEOptionsIgnoreJVMCI=\
|
||||
-ignorePath_TARGET src/share/vm/jvmci \
|
||||
-ignorePath_TARGET vm/jvmci
|
||||
|
||||
ProjectCreatorIDEOptionsIgnoreCompiler2=\
|
||||
-ignorePath_TARGET compiler2 \
|
||||
-ignorePath_TARGET tiered \
|
||||
@ -165,6 +169,8 @@ ProjectCreatorIDEOptionsIgnoreCompiler2=\
|
||||
##################################################
|
||||
ProjectCreatorIDEOptions=$(ProjectCreatorIDEOptions) \
|
||||
-define_compiler1 COMPILER1 \
|
||||
-define_compiler1 INCLUDE_JVMCI=0 \
|
||||
$(ProjectCreatorIDEOptionsIgnoreJVMCI:TARGET=compiler1) \
|
||||
$(ProjectCreatorIDEOptionsIgnoreCompiler2:TARGET=compiler1)
|
||||
|
||||
##################################################
|
||||
|
@ -40,7 +40,7 @@ CXX_FLAGS=$(CXX_FLAGS) /homeparams
|
||||
!endif
|
||||
|
||||
!if "$(Variant)" == "compiler1"
|
||||
CXX_FLAGS=$(CXX_FLAGS) /D "COMPILER1"
|
||||
CXX_FLAGS=$(CXX_FLAGS) /D "COMPILER1" /D INCLUDE_JVMCI=0
|
||||
!endif
|
||||
|
||||
!if "$(Variant)" == "compiler2"
|
||||
@ -152,6 +152,7 @@ VM_PATH=$(VM_PATH);../generated/adfiles
|
||||
VM_PATH=$(VM_PATH);../generated/jvmtifiles
|
||||
VM_PATH=$(VM_PATH);../generated/tracefiles
|
||||
VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/c1
|
||||
VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/jvmci
|
||||
VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/compiler
|
||||
VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/code
|
||||
VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/interpreter
|
||||
@ -232,6 +233,9 @@ bytecodeInterpreterWithChecks.obj: ..\generated\jvmtifiles\bytecodeInterpreterWi
|
||||
{$(COMMONSRC)\share\vm\classfile}.cpp.obj::
|
||||
$(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $<
|
||||
|
||||
{$(COMMONSRC)\share\vm\jvmci}.cpp.obj::
|
||||
$(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $<
|
||||
|
||||
{$(COMMONSRC)\share\vm\gc\parallel}.cpp.obj::
|
||||
$(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $<
|
||||
|
||||
|
@ -51,13 +51,15 @@ bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site) {
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#define __ _masm.
|
||||
address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) {
|
||||
address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark) {
|
||||
// Stub is fixed up when the corresponding call is converted from
|
||||
// calling compiled code to calling interpreted code.
|
||||
// mov rmethod, 0
|
||||
// jmp -4 # to self
|
||||
|
||||
address mark = cbuf.insts_mark(); // Get mark within main instrs section.
|
||||
if (mark == NULL) {
|
||||
mark = cbuf.insts_mark(); // Get mark within main instrs section.
|
||||
}
|
||||
|
||||
// Note that the code buffer's insts_mark is always relative to insts.
|
||||
// That's why we must use the macroassembler to generate a stub.
|
||||
|
@ -30,5 +30,6 @@
|
||||
|
||||
void generate_more_monitors();
|
||||
void generate_deopt_handling();
|
||||
void lock_method(void);
|
||||
|
||||
#endif // CPU_AARCH64_VM_CPPINTERPRETERGENERATOR_AARCH64_HPP
|
||||
|
@ -48,7 +48,6 @@ private:
|
||||
address generate_CRC32_update_entry();
|
||||
address generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind);
|
||||
address generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) { return NULL; }
|
||||
void lock_method(void);
|
||||
void generate_stack_overflow_check(void);
|
||||
|
||||
void generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue);
|
||||
|
68
hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp
Normal file
68
hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "jvmci/jvmciCodeInstaller.hpp"
|
||||
#include "jvmci/jvmciRuntime.hpp"
|
||||
#include "jvmci/jvmciCompilerToVM.hpp"
|
||||
#include "jvmci/jvmciJavaClasses.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
#include "vmreg_aarch64.inline.hpp"
|
||||
|
||||
jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, oop method) {
|
||||
Unimplemented();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle& constant) {
|
||||
Unimplemented();
|
||||
}
|
||||
|
||||
void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset) {
|
||||
Unimplemented();
|
||||
}
|
||||
|
||||
void CodeInstaller::pd_relocate_CodeBlob(CodeBlob* cb, NativeInstruction* inst) {
|
||||
Unimplemented();
|
||||
}
|
||||
|
||||
void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination) {
|
||||
Unimplemented();
|
||||
}
|
||||
|
||||
void CodeInstaller::pd_relocate_JavaMethod(oop hotspot_method, jint pc_offset) {
|
||||
Unimplemented();
|
||||
}
|
||||
|
||||
void CodeInstaller::pd_relocate_poll(address pc, jint mark) {
|
||||
Unimplemented();
|
||||
}
|
||||
|
||||
// convert JVMCI register indices (as used in oop maps) to HotSpot registers
|
||||
VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool CodeInstaller::is_general_purpose_reg(VMReg hotspotRegister) {
|
||||
return false;
|
||||
}
|
@ -102,12 +102,5 @@ void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffe
|
||||
}
|
||||
}
|
||||
|
||||
void poll_return_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) {
|
||||
if (NativeInstruction::maybe_cpool_ref(addr())) {
|
||||
address old_addr = old_addr_for(addr(), src, dest);
|
||||
MacroAssembler::pd_patch_instruction(addr(), MacroAssembler::target_addr_for_insn(old_addr));
|
||||
}
|
||||
}
|
||||
|
||||
void metadata_Relocation::pd_fix_value(address x) {
|
||||
}
|
||||
|
@ -473,11 +473,11 @@ static void gen_c2i_adapter(MacroAssembler *masm,
|
||||
}
|
||||
|
||||
|
||||
static void gen_i2c_adapter(MacroAssembler *masm,
|
||||
int total_args_passed,
|
||||
int comp_args_on_stack,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs) {
|
||||
void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm,
|
||||
int total_args_passed,
|
||||
int comp_args_on_stack,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs) {
|
||||
|
||||
// Note: r13 contains the senderSP on entry. We must preserve it since
|
||||
// we may do a i2c -> c2i transition if we lose a race where compiled
|
||||
|
@ -535,7 +535,7 @@ void InterpreterGenerator::generate_stack_overflow_check(void) {
|
||||
// r0
|
||||
// c_rarg0, c_rarg1, c_rarg2, c_rarg3, ...(param regs)
|
||||
// rscratch1, rscratch2 (scratch regs)
|
||||
void InterpreterGenerator::lock_method(void) {
|
||||
void TemplateInterpreterGenerator::lock_method() {
|
||||
// synchronize method
|
||||
const Address access_flags(rmethod, Method::access_flags_offset());
|
||||
const Address monitor_block_top(
|
||||
|
@ -94,10 +94,12 @@ bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site) {
|
||||
|
||||
const int IC_pos_in_java_to_interp_stub = 8;
|
||||
#define __ _masm.
|
||||
address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) {
|
||||
address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark/* = NULL*/) {
|
||||
#ifdef COMPILER2
|
||||
// Get the mark within main instrs section which is set to the address of the call.
|
||||
address call_addr = cbuf.insts_mark();
|
||||
if (mark == NULL) {
|
||||
// Get the mark within main instrs section which is set to the address of the call.
|
||||
mark = cbuf.insts_mark();
|
||||
}
|
||||
|
||||
// Note that the code buffer's insts_mark is always relative to insts.
|
||||
// That's why we must use the macroassembler to generate a stub.
|
||||
@ -117,7 +119,7 @@ address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) {
|
||||
// Create a static stub relocation which relates this stub
|
||||
// with the call instruction at insts_call_instruction_offset in the
|
||||
// instructions code-section.
|
||||
__ relocate(static_stub_Relocation::spec(call_addr));
|
||||
__ relocate(static_stub_Relocation::spec(mark));
|
||||
const int stub_start_offset = __ offset();
|
||||
|
||||
// Now, create the stub's code:
|
||||
|
68
hotspot/src/cpu/ppc/vm/jvmciCodeInstaller_ppc.cpp
Normal file
68
hotspot/src/cpu/ppc/vm/jvmciCodeInstaller_ppc.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "jvmci/jvmciCodeInstaller.hpp"
|
||||
#include "jvmci/jvmciRuntime.hpp"
|
||||
#include "jvmci/jvmciCompilerToVM.hpp"
|
||||
#include "jvmci/jvmciJavaClasses.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
#include "vmreg_ppc.inline.hpp"
|
||||
|
||||
jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, oop method) {
|
||||
Unimplemented();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle& constant) {
|
||||
Unimplemented();
|
||||
}
|
||||
|
||||
void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset) {
|
||||
Unimplemented();
|
||||
}
|
||||
|
||||
void CodeInstaller::pd_relocate_CodeBlob(CodeBlob* cb, NativeInstruction* inst) {
|
||||
Unimplemented();
|
||||
}
|
||||
|
||||
void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination) {
|
||||
Unimplemented();
|
||||
}
|
||||
|
||||
void CodeInstaller::pd_relocate_JavaMethod(oop hotspot_method, jint pc_offset) {
|
||||
Unimplemented();
|
||||
}
|
||||
|
||||
void CodeInstaller::pd_relocate_poll(address pc, jint mark) {
|
||||
Unimplemented();
|
||||
}
|
||||
|
||||
// convert JVMCI register indices (as used in oop maps) to HotSpot registers
|
||||
VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool CodeInstaller::is_general_purpose_reg(VMReg hotspotRegister) {
|
||||
return false;
|
||||
}
|
@ -125,8 +125,5 @@ address Relocation::pd_get_address_from_code() {
|
||||
void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) {
|
||||
}
|
||||
|
||||
void poll_return_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) {
|
||||
}
|
||||
|
||||
void metadata_Relocation::pd_fix_value(address x) {
|
||||
}
|
||||
|
@ -957,11 +957,11 @@ static address gen_c2i_adapter(MacroAssembler *masm,
|
||||
return c2i_entrypoint;
|
||||
}
|
||||
|
||||
static void gen_i2c_adapter(MacroAssembler *masm,
|
||||
int total_args_passed,
|
||||
int comp_args_on_stack,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs) {
|
||||
void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm,
|
||||
int total_args_passed,
|
||||
int comp_args_on_stack,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs) {
|
||||
|
||||
// Load method's entry-point from method.
|
||||
__ ld(R12_scratch2, in_bytes(Method::from_compiled_offset()), R19_method);
|
||||
|
@ -53,14 +53,15 @@ bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site) {
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#define __ _masm.
|
||||
address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) {
|
||||
#ifdef COMPILER2
|
||||
address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark) {
|
||||
// Stub is fixed up when the corresponding call is converted from calling
|
||||
// compiled code to calling interpreted code.
|
||||
// set (empty), G5
|
||||
// jmp -1
|
||||
|
||||
address mark = cbuf.insts_mark(); // Get mark within main instrs section.
|
||||
if (mark == NULL) {
|
||||
mark = cbuf.insts_mark(); // Get mark within main instrs section.
|
||||
}
|
||||
|
||||
MacroAssembler _masm(&cbuf);
|
||||
|
||||
@ -80,12 +81,11 @@ address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) {
|
||||
|
||||
__ delayed()->nop();
|
||||
|
||||
assert(__ pc() - base <= to_interp_stub_size(), "wrong stub size");
|
||||
|
||||
// Update current stubs pointer and restore code_end.
|
||||
__ end_a_stub();
|
||||
return base;
|
||||
#else
|
||||
ShouldNotReachHere();
|
||||
#endif
|
||||
}
|
||||
#undef __
|
||||
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
void generate_more_monitors();
|
||||
void generate_deopt_handling();
|
||||
void lock_method(void);
|
||||
void adjust_callers_stack(Register args);
|
||||
void generate_compute_interpreter_state(const Register state,
|
||||
const Register prev_state,
|
||||
|
@ -1164,7 +1164,7 @@ void CppInterpreterGenerator::generate_compute_interpreter_state(const Register
|
||||
}
|
||||
// Find preallocated monitor and lock method (C++ interpreter)
|
||||
//
|
||||
void InterpreterGenerator::lock_method(void) {
|
||||
void CppInterpreterGenerator::lock_method() {
|
||||
// Lock the current method.
|
||||
// Destroys registers L2_scratch, L3_scratch, O0
|
||||
//
|
||||
|
@ -1650,26 +1650,73 @@ void InterpreterMacroAssembler::profile_virtual_call(Register receiver,
|
||||
bind(skip_receiver_profile);
|
||||
|
||||
// The method data pointer needs to be updated to reflect the new target.
|
||||
#if INCLUDE_JVMCI
|
||||
if (MethodProfileWidth == 0) {
|
||||
update_mdp_by_constant(in_bytes(VirtualCallData::virtual_call_data_size()));
|
||||
}
|
||||
#else
|
||||
update_mdp_by_constant(in_bytes(VirtualCallData::virtual_call_data_size()));
|
||||
bind (profile_continue);
|
||||
#endif
|
||||
bind(profile_continue);
|
||||
}
|
||||
}
|
||||
|
||||
void InterpreterMacroAssembler::record_klass_in_profile_helper(
|
||||
Register receiver, Register scratch,
|
||||
int start_row, Label& done, bool is_virtual_call) {
|
||||
#if INCLUDE_JVMCI
|
||||
void InterpreterMacroAssembler::profile_called_method(Register method, Register scratch) {
|
||||
assert_different_registers(method, scratch);
|
||||
if (ProfileInterpreter && MethodProfileWidth > 0) {
|
||||
Label profile_continue;
|
||||
|
||||
// If no method data exists, go to profile_continue.
|
||||
test_method_data_pointer(profile_continue);
|
||||
|
||||
Label done;
|
||||
record_item_in_profile_helper(method, scratch, 0, done, MethodProfileWidth,
|
||||
&VirtualCallData::method_offset, &VirtualCallData::method_count_offset, in_bytes(VirtualCallData::nonprofiled_receiver_count_offset()));
|
||||
bind(done);
|
||||
|
||||
update_mdp_by_constant(in_bytes(VirtualCallData::virtual_call_data_size()));
|
||||
bind(profile_continue);
|
||||
}
|
||||
}
|
||||
#endif // INCLUDE_JVMCI
|
||||
|
||||
void InterpreterMacroAssembler::record_klass_in_profile_helper(Register receiver, Register scratch,
|
||||
Label& done, bool is_virtual_call) {
|
||||
if (TypeProfileWidth == 0) {
|
||||
if (is_virtual_call) {
|
||||
increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#if INCLUDE_JVMCI
|
||||
else if (EnableJVMCI) {
|
||||
increment_mdp_data_at(in_bytes(ReceiverTypeData::nonprofiled_receiver_count_offset()), scratch);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
int non_profiled_offset = -1;
|
||||
if (is_virtual_call) {
|
||||
non_profiled_offset = in_bytes(CounterData::count_offset());
|
||||
}
|
||||
#if INCLUDE_JVMCI
|
||||
else if (EnableJVMCI) {
|
||||
non_profiled_offset = in_bytes(ReceiverTypeData::nonprofiled_receiver_count_offset());
|
||||
}
|
||||
#endif
|
||||
|
||||
int last_row = VirtualCallData::row_limit() - 1;
|
||||
record_item_in_profile_helper(receiver, scratch, 0, done, TypeProfileWidth,
|
||||
&VirtualCallData::receiver_offset, &VirtualCallData::receiver_count_offset, non_profiled_offset);
|
||||
}
|
||||
}
|
||||
|
||||
void InterpreterMacroAssembler::record_item_in_profile_helper(Register item,
|
||||
Register scratch, int start_row, Label& done, int total_rows,
|
||||
OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn,
|
||||
int non_profiled_offset) {
|
||||
int last_row = total_rows - 1;
|
||||
assert(start_row <= last_row, "must be work left to do");
|
||||
// Test this row for both the receiver and for null.
|
||||
// Test this row for both the item and for null.
|
||||
// Take any of three different outcomes:
|
||||
// 1. found receiver => increment count and goto done
|
||||
// 1. found item => increment count and goto done
|
||||
// 2. found null => keep looking for case 1, maybe allocate this cell
|
||||
// 3. found something else => keep looking for cases 1 and 2
|
||||
// Case 3 is handled by a recursive call.
|
||||
@ -1677,28 +1724,28 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper(
|
||||
Label next_test;
|
||||
bool test_for_null_also = (row == start_row);
|
||||
|
||||
// See if the receiver is receiver[n].
|
||||
int recvr_offset = in_bytes(VirtualCallData::receiver_offset(row));
|
||||
test_mdp_data_at(recvr_offset, receiver, next_test, scratch);
|
||||
// See if the item is item[n].
|
||||
int item_offset = in_bytes(item_offset_fn(row));
|
||||
test_mdp_data_at(item_offset, item, next_test, scratch);
|
||||
// delayed()->tst(scratch);
|
||||
|
||||
// The receiver is receiver[n]. Increment count[n].
|
||||
int count_offset = in_bytes(VirtualCallData::receiver_count_offset(row));
|
||||
// The receiver is item[n]. Increment count[n].
|
||||
int count_offset = in_bytes(item_count_offset_fn(row));
|
||||
increment_mdp_data_at(count_offset, scratch);
|
||||
ba_short(done);
|
||||
bind(next_test);
|
||||
|
||||
if (test_for_null_also) {
|
||||
Label found_null;
|
||||
// Failed the equality check on receiver[n]... Test for null.
|
||||
// Failed the equality check on item[n]... Test for null.
|
||||
if (start_row == last_row) {
|
||||
// The only thing left to do is handle the null case.
|
||||
if (is_virtual_call) {
|
||||
if (non_profiled_offset >= 0) {
|
||||
brx(Assembler::zero, false, Assembler::pn, found_null);
|
||||
delayed()->nop();
|
||||
// Receiver did not match any saved receiver and there is no empty row for it.
|
||||
// Item did not match any saved item and there is no empty row for it.
|
||||
// Increment total counter to indicate polymorphic case.
|
||||
increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch);
|
||||
increment_mdp_data_at(non_profiled_offset, scratch);
|
||||
ba_short(done);
|
||||
bind(found_null);
|
||||
} else {
|
||||
@ -1712,21 +1759,22 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper(
|
||||
delayed()->nop();
|
||||
|
||||
// Put all the "Case 3" tests here.
|
||||
record_klass_in_profile_helper(receiver, scratch, start_row + 1, done, is_virtual_call);
|
||||
record_item_in_profile_helper(item, scratch, start_row + 1, done, total_rows,
|
||||
item_offset_fn, item_count_offset_fn, non_profiled_offset);
|
||||
|
||||
// Found a null. Keep searching for a matching receiver,
|
||||
// Found a null. Keep searching for a matching item,
|
||||
// but remember that this is an empty (unused) slot.
|
||||
bind(found_null);
|
||||
}
|
||||
}
|
||||
|
||||
// In the fall-through case, we found no matching receiver, but we
|
||||
// observed the receiver[start_row] is NULL.
|
||||
// In the fall-through case, we found no matching item, but we
|
||||
// observed the item[start_row] is NULL.
|
||||
|
||||
// Fill in the receiver field and increment the count.
|
||||
int recvr_offset = in_bytes(VirtualCallData::receiver_offset(start_row));
|
||||
set_mdp_data_at(recvr_offset, receiver);
|
||||
int count_offset = in_bytes(VirtualCallData::receiver_count_offset(start_row));
|
||||
// Fill in the item field and increment the count.
|
||||
int item_offset = in_bytes(item_offset_fn(start_row));
|
||||
set_mdp_data_at(item_offset, item);
|
||||
int count_offset = in_bytes(item_count_offset_fn(start_row));
|
||||
mov(DataLayout::counter_increment, scratch);
|
||||
set_mdp_data_at(count_offset, scratch);
|
||||
if (start_row > 0) {
|
||||
@ -1739,7 +1787,7 @@ void InterpreterMacroAssembler::record_klass_in_profile(Register receiver,
|
||||
assert(ProfileInterpreter, "must be profiling");
|
||||
Label done;
|
||||
|
||||
record_klass_in_profile_helper(receiver, scratch, 0, done, is_virtual_call);
|
||||
record_klass_in_profile_helper(receiver, scratch, done, is_virtual_call);
|
||||
|
||||
bind (done);
|
||||
}
|
||||
@ -1795,7 +1843,7 @@ void InterpreterMacroAssembler::profile_null_seen(Register scratch) {
|
||||
// The method data pointer needs to be updated.
|
||||
int mdp_delta = in_bytes(BitData::bit_data_size());
|
||||
if (TypeProfileCasts) {
|
||||
mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size());
|
||||
mdp_delta = in_bytes(ReceiverTypeData::receiver_type_data_size());
|
||||
}
|
||||
update_mdp_by_constant(mdp_delta);
|
||||
|
||||
@ -1813,7 +1861,7 @@ void InterpreterMacroAssembler::profile_typecheck(Register klass,
|
||||
|
||||
int mdp_delta = in_bytes(BitData::bit_data_size());
|
||||
if (TypeProfileCasts) {
|
||||
mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size());
|
||||
mdp_delta = in_bytes(ReceiverTypeData::receiver_type_data_size());
|
||||
|
||||
// Record the object type.
|
||||
record_klass_in_profile(klass, scratch, false);
|
||||
@ -1835,7 +1883,7 @@ void InterpreterMacroAssembler::profile_typecheck_failed(Register scratch) {
|
||||
|
||||
int count_offset = in_bytes(CounterData::count_offset());
|
||||
// Back up the address, since we have already bumped the mdp.
|
||||
count_offset -= in_bytes(VirtualCallData::virtual_call_data_size());
|
||||
count_offset -= in_bytes(ReceiverTypeData::receiver_type_data_size());
|
||||
|
||||
// *Decrement* the counter. We expect to see zero or small negatives.
|
||||
increment_mdp_data_at(count_offset, scratch, true);
|
||||
|
@ -30,6 +30,8 @@
|
||||
|
||||
// This file specializes the assember with interpreter-specific macros
|
||||
|
||||
typedef ByteSize (*OffsetFunction)(uint);
|
||||
|
||||
REGISTER_DECLARATION( Register, Otos_i , O0); // tos for ints, etc
|
||||
REGISTER_DECLARATION( Register, Otos_l , O0); // for longs
|
||||
REGISTER_DECLARATION( Register, Otos_l1, O0); // for 1st part of longs
|
||||
@ -301,7 +303,11 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
||||
|
||||
void record_klass_in_profile(Register receiver, Register scratch, bool is_virtual_call);
|
||||
void record_klass_in_profile_helper(Register receiver, Register scratch,
|
||||
int start_row, Label& done, bool is_virtual_call);
|
||||
Label& done, bool is_virtual_call);
|
||||
void record_item_in_profile_helper(Register item,
|
||||
Register scratch, int start_row, Label& done, int total_rows,
|
||||
OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn,
|
||||
int non_profiled_offset);
|
||||
|
||||
void update_mdp_by_offset(int offset_of_disp, Register scratch);
|
||||
void update_mdp_by_offset(Register reg, int offset_of_disp,
|
||||
@ -314,6 +320,7 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
||||
void profile_call(Register scratch);
|
||||
void profile_final_call(Register scratch);
|
||||
void profile_virtual_call(Register receiver, Register scratch, bool receiver_can_be_null = false);
|
||||
void profile_called_method(Register method, Register scratch) NOT_JVMCI_RETURN;
|
||||
void profile_ret(TosState state, Register return_bci, Register scratch);
|
||||
void profile_null_seen(Register scratch);
|
||||
void profile_typecheck(Register klass, Register scratch);
|
||||
|
@ -37,7 +37,6 @@
|
||||
address generate_accessor_entry(void) { return NULL; }
|
||||
address generate_empty_entry(void) { return NULL; }
|
||||
address generate_Reference_get_entry(void);
|
||||
void lock_method(void);
|
||||
void save_native_result(void);
|
||||
void restore_native_result(void);
|
||||
|
||||
|
186
hotspot/src/cpu/sparc/vm/jvmciCodeInstaller_sparc.cpp
Normal file
186
hotspot/src/cpu/sparc/vm/jvmciCodeInstaller_sparc.cpp
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "jvmci/jvmciCodeInstaller.hpp"
|
||||
#include "jvmci/jvmciRuntime.hpp"
|
||||
#include "jvmci/jvmciCompilerToVM.hpp"
|
||||
#include "jvmci/jvmciJavaClasses.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
#include "vmreg_sparc.inline.hpp"
|
||||
|
||||
jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, oop method) {
|
||||
if (inst->is_call() || inst->is_jump()) {
|
||||
return pc_offset + NativeCall::instruction_size;
|
||||
} else if (inst->is_call_reg()) {
|
||||
return pc_offset + NativeCallReg::instruction_size;
|
||||
} else if (inst->is_sethi()) {
|
||||
return pc_offset + NativeFarCall::instruction_size;
|
||||
} else {
|
||||
fatal("unsupported type of instruction for call site");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle& constant) {
|
||||
address pc = _instructions->start() + pc_offset;
|
||||
Handle obj = HotSpotObjectConstantImpl::object(constant);
|
||||
jobject value = JNIHandles::make_local(obj());
|
||||
if (HotSpotObjectConstantImpl::compressed(constant)) {
|
||||
#ifdef _LP64
|
||||
int oop_index = _oop_recorder->find_index(value);
|
||||
RelocationHolder rspec = oop_Relocation::spec(oop_index);
|
||||
_instructions->relocate(pc, rspec, 1);
|
||||
#else
|
||||
fatal("compressed oop on 32bit");
|
||||
#endif
|
||||
} else {
|
||||
NativeMovConstReg* move = nativeMovConstReg_at(pc);
|
||||
move->set_data((intptr_t) value);
|
||||
|
||||
// We need two relocations: one on the sethi and one on the add.
|
||||
int oop_index = _oop_recorder->find_index(value);
|
||||
RelocationHolder rspec = oop_Relocation::spec(oop_index);
|
||||
_instructions->relocate(pc + NativeMovConstReg::sethi_offset, rspec);
|
||||
_instructions->relocate(pc + NativeMovConstReg::add_offset, rspec);
|
||||
}
|
||||
}
|
||||
|
||||
void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset) {
|
||||
address pc = _instructions->start() + pc_offset;
|
||||
NativeInstruction* inst = nativeInstruction_at(pc);
|
||||
NativeInstruction* inst1 = nativeInstruction_at(pc + 4);
|
||||
if(inst->is_sethi() && inst1->is_nop()) {
|
||||
address const_start = _constants->start();
|
||||
address dest = _constants->start() + data_offset;
|
||||
if(_constants_size > 0) {
|
||||
_instructions->relocate(pc + NativeMovConstReg::sethi_offset, internal_word_Relocation::spec((address) dest));
|
||||
_instructions->relocate(pc + NativeMovConstReg::add_offset, internal_word_Relocation::spec((address) dest));
|
||||
}
|
||||
TRACE_jvmci_3("relocating at " PTR_FORMAT " (+%d) with destination at %d", p2i(pc), pc_offset, data_offset);
|
||||
}else {
|
||||
int const_size = align_size_up(_constants->end()-_constants->start(), CodeEntryAlignment);
|
||||
NativeMovRegMem* load = nativeMovRegMem_at(pc);
|
||||
// This offset must match with SPARCLoadConstantTableBaseOp.emitCode
|
||||
load->set_offset(- (const_size - data_offset + Assembler::min_simm13()));
|
||||
TRACE_jvmci_3("relocating ld at " PTR_FORMAT " (+%d) with destination at %d", p2i(pc), pc_offset, data_offset);
|
||||
}
|
||||
}
|
||||
|
||||
void CodeInstaller::pd_relocate_CodeBlob(CodeBlob* cb, NativeInstruction* inst) {
|
||||
fatal("CodeInstaller::pd_relocate_CodeBlob - sparc unimp");
|
||||
}
|
||||
|
||||
void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination) {
|
||||
address pc = (address) inst;
|
||||
if (inst->is_call()) {
|
||||
NativeCall* call = nativeCall_at(pc);
|
||||
call->set_destination((address) foreign_call_destination);
|
||||
_instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec());
|
||||
} else if (inst->is_sethi()) {
|
||||
NativeJump* jump = nativeJump_at(pc);
|
||||
jump->set_jump_destination((address) foreign_call_destination);
|
||||
_instructions->relocate(jump->instruction_address(), runtime_call_Relocation::spec());
|
||||
} else {
|
||||
fatal(err_msg("unknown call or jump instruction at " PTR_FORMAT, p2i(pc)));
|
||||
}
|
||||
TRACE_jvmci_3("relocating (foreign call) at " PTR_FORMAT, p2i(inst));
|
||||
}
|
||||
|
||||
void CodeInstaller::pd_relocate_JavaMethod(oop hotspot_method, jint pc_offset) {
|
||||
#ifdef ASSERT
|
||||
Method* method = NULL;
|
||||
// we need to check, this might also be an unresolved method
|
||||
if (hotspot_method->is_a(HotSpotResolvedJavaMethodImpl::klass())) {
|
||||
method = getMethodFromHotSpotMethod(hotspot_method);
|
||||
}
|
||||
#endif
|
||||
switch (_next_call_type) {
|
||||
case INLINE_INVOKE:
|
||||
break;
|
||||
case INVOKEVIRTUAL:
|
||||
case INVOKEINTERFACE: {
|
||||
assert(method == NULL || !method->is_static(), "cannot call static method with invokeinterface");
|
||||
NativeCall* call = nativeCall_at(_instructions->start() + pc_offset);
|
||||
call->set_destination(SharedRuntime::get_resolve_virtual_call_stub());
|
||||
_instructions->relocate(call->instruction_address(), virtual_call_Relocation::spec(_invoke_mark_pc));
|
||||
break;
|
||||
}
|
||||
case INVOKESTATIC: {
|
||||
assert(method == NULL || method->is_static(), "cannot call non-static method with invokestatic");
|
||||
NativeCall* call = nativeCall_at(_instructions->start() + pc_offset);
|
||||
call->set_destination(SharedRuntime::get_resolve_static_call_stub());
|
||||
_instructions->relocate(call->instruction_address(), relocInfo::static_call_type);
|
||||
break;
|
||||
}
|
||||
case INVOKESPECIAL: {
|
||||
assert(method == NULL || !method->is_static(), "cannot call static method with invokespecial");
|
||||
NativeCall* call = nativeCall_at(_instructions->start() + pc_offset);
|
||||
call->set_destination(SharedRuntime::get_resolve_opt_virtual_call_stub());
|
||||
_instructions->relocate(call->instruction_address(), relocInfo::opt_virtual_call_type);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fatal("invalid _next_call_type value");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CodeInstaller::pd_relocate_poll(address pc, jint mark) {
|
||||
switch (mark) {
|
||||
case POLL_NEAR:
|
||||
fatal("unimplemented");
|
||||
break;
|
||||
case POLL_FAR:
|
||||
_instructions->relocate(pc, relocInfo::poll_type);
|
||||
break;
|
||||
case POLL_RETURN_NEAR:
|
||||
fatal("unimplemented");
|
||||
break;
|
||||
case POLL_RETURN_FAR:
|
||||
_instructions->relocate(pc, relocInfo::poll_return_type);
|
||||
break;
|
||||
default:
|
||||
fatal("invalid mark value");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// convert JVMCI register indices (as used in oop maps) to HotSpot registers
|
||||
VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg) {
|
||||
if (jvmci_reg < RegisterImpl::number_of_registers) {
|
||||
return as_Register(jvmci_reg)->as_VMReg();
|
||||
} else {
|
||||
jint floatRegisterNumber = jvmci_reg - RegisterImpl::number_of_registers;
|
||||
floatRegisterNumber += MAX2(0, floatRegisterNumber-32); // Beginning with f32, only every second register is going to be addressed
|
||||
if (floatRegisterNumber < FloatRegisterImpl::number_of_registers) {
|
||||
return as_FloatRegister(floatRegisterNumber)->as_VMReg();
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool CodeInstaller::is_general_purpose_reg(VMReg hotspotRegister) {
|
||||
return !hotspotRegister->is_FloatRegister();
|
||||
}
|
@ -53,6 +53,7 @@ class NativeInstruction VALUE_OBJ_CLASS_SPEC {
|
||||
|
||||
bool is_nop() { return long_at(0) == nop_instruction(); }
|
||||
bool is_call() { return is_op(long_at(0), Assembler::call_op); }
|
||||
bool is_call_reg() { return is_op(long_at(0), Assembler::arith_op); }
|
||||
bool is_sethi() { return (is_op2(long_at(0), Assembler::sethi_op2)
|
||||
&& inv_rd(long_at(0)) != G0); }
|
||||
|
||||
@ -415,6 +416,19 @@ inline NativeCall* nativeCall_at(address instr) {
|
||||
return call;
|
||||
}
|
||||
|
||||
class NativeCallReg: public NativeInstruction {
|
||||
public:
|
||||
enum Sparc_specific_constants {
|
||||
instruction_size = 8,
|
||||
return_address_offset = 8,
|
||||
instruction_offset = 0
|
||||
};
|
||||
|
||||
address next_instruction_address() const {
|
||||
return addr_at(instruction_size);
|
||||
}
|
||||
};
|
||||
|
||||
// The NativeFarCall is an abstraction for accessing/manipulating native call-anywhere
|
||||
// instructions in the sparcv9 vm. Used to call native methods which may be loaded
|
||||
// anywhere in the address space, possibly out of reach of a call instruction.
|
||||
|
@ -197,8 +197,5 @@ address Relocation::pd_get_address_from_code() {
|
||||
void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) {
|
||||
}
|
||||
|
||||
void poll_return_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) {
|
||||
}
|
||||
|
||||
void metadata_Relocation::pd_fix_value(address x) {
|
||||
}
|
||||
|
@ -43,6 +43,9 @@
|
||||
#include "compiler/compileBroker.hpp"
|
||||
#include "shark/sharkCompiler.hpp"
|
||||
#endif
|
||||
#if INCLUDE_JVMCI
|
||||
#include "jvmci/jvmciJavaClasses.hpp"
|
||||
#endif
|
||||
|
||||
#define __ masm->
|
||||
|
||||
@ -513,10 +516,10 @@ class AdapterGenerator {
|
||||
const VMRegPair *regs,
|
||||
Label& skip_fixup);
|
||||
void gen_i2c_adapter(int total_args_passed,
|
||||
// VMReg max_arg,
|
||||
int comp_args_on_stack, // VMRegStackSlots
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs);
|
||||
// VMReg max_arg,
|
||||
int comp_args_on_stack, // VMRegStackSlots
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs);
|
||||
|
||||
AdapterGenerator(MacroAssembler *_masm) : masm(_masm) {}
|
||||
};
|
||||
@ -760,13 +763,11 @@ static void range_check(MacroAssembler* masm, Register pc_reg, Register temp_reg
|
||||
__ bind(L_fail);
|
||||
}
|
||||
|
||||
void AdapterGenerator::gen_i2c_adapter(
|
||||
int total_args_passed,
|
||||
// VMReg max_arg,
|
||||
int comp_args_on_stack, // VMRegStackSlots
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs) {
|
||||
|
||||
void AdapterGenerator::gen_i2c_adapter(int total_args_passed,
|
||||
// VMReg max_arg,
|
||||
int comp_args_on_stack, // VMRegStackSlots
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs) {
|
||||
// Generate an I2C adapter: adjust the I-frame to make space for the C-frame
|
||||
// layout. Lesp was saved by the calling I-frame and will be restored on
|
||||
// return. Meanwhile, outgoing arg space is all owned by the callee
|
||||
@ -990,6 +991,21 @@ void AdapterGenerator::gen_i2c_adapter(
|
||||
|
||||
// Jump to the compiled code just as if compiled code was doing it.
|
||||
__ ld_ptr(G5_method, in_bytes(Method::from_compiled_offset()), G3);
|
||||
#if INCLUDE_JVMCI
|
||||
if (EnableJVMCI) {
|
||||
// check if this call should be routed towards a specific entry point
|
||||
__ ld(Address(G2_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset())), G1);
|
||||
__ cmp(G0, G1);
|
||||
Label no_alternative_target;
|
||||
__ br(Assembler::equal, false, Assembler::pn, no_alternative_target);
|
||||
__ delayed()->nop();
|
||||
|
||||
__ ld_ptr(G2_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset()), G3);
|
||||
__ st(G0, Address(G2_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset())));
|
||||
|
||||
__ bind(no_alternative_target);
|
||||
}
|
||||
#endif // INCLUDE_JVMCI
|
||||
|
||||
// 6243940 We might end up in handle_wrong_method if
|
||||
// the callee is deoptimized as we race thru here. If that
|
||||
@ -1006,6 +1022,15 @@ void AdapterGenerator::gen_i2c_adapter(
|
||||
__ delayed()->nop();
|
||||
}
|
||||
|
||||
void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm,
|
||||
int total_args_passed,
|
||||
int comp_args_on_stack,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs) {
|
||||
AdapterGenerator agen(masm);
|
||||
agen.gen_i2c_adapter(total_args_passed, comp_args_on_stack, sig_bt, regs);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
|
||||
int total_args_passed,
|
||||
@ -1016,9 +1041,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
||||
AdapterFingerPrint* fingerprint) {
|
||||
address i2c_entry = __ pc();
|
||||
|
||||
AdapterGenerator agen(masm);
|
||||
|
||||
agen.gen_i2c_adapter(total_args_passed, comp_args_on_stack, sig_bt, regs);
|
||||
gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@ -1063,7 +1086,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
||||
}
|
||||
|
||||
address c2i_entry = __ pc();
|
||||
|
||||
AdapterGenerator agen(masm);
|
||||
agen.gen_c2i_adapter(total_args_passed, comp_args_on_stack, sig_bt, regs, L_skip_fixup);
|
||||
|
||||
__ flush();
|
||||
@ -2916,6 +2939,11 @@ void SharedRuntime::generate_deopt_blob() {
|
||||
pad += StackShadowPages*16 + 32;
|
||||
}
|
||||
#endif
|
||||
#if INCLUDE_JVMCI
|
||||
if (EnableJVMCI) {
|
||||
pad += 1000; // Increase the buffer size when compiling for JVMCI
|
||||
}
|
||||
#endif
|
||||
#ifdef _LP64
|
||||
CodeBuffer buffer("deopt_blob", 2100+pad, 512);
|
||||
#else
|
||||
@ -2982,6 +3010,45 @@ void SharedRuntime::generate_deopt_blob() {
|
||||
__ ba(cont);
|
||||
__ delayed()->mov(Deoptimization::Unpack_deopt, L0deopt_mode);
|
||||
|
||||
|
||||
#if INCLUDE_JVMCI
|
||||
Label after_fetch_unroll_info_call;
|
||||
int implicit_exception_uncommon_trap_offset = 0;
|
||||
int uncommon_trap_offset = 0;
|
||||
|
||||
if (EnableJVMCI) {
|
||||
masm->block_comment("BEGIN implicit_exception_uncommon_trap");
|
||||
implicit_exception_uncommon_trap_offset = __ offset() - start;
|
||||
|
||||
__ ld_ptr(G2_thread, in_bytes(JavaThread::jvmci_implicit_exception_pc_offset()), O7);
|
||||
__ st_ptr(G0, Address(G2_thread, in_bytes(JavaThread::jvmci_implicit_exception_pc_offset())));
|
||||
__ add(O7, -8, O7);
|
||||
|
||||
uncommon_trap_offset = __ offset() - start;
|
||||
|
||||
// Save everything in sight.
|
||||
(void) RegisterSaver::save_live_registers(masm, 0, &frame_size_words);
|
||||
__ set_last_Java_frame(SP, NULL);
|
||||
|
||||
__ ld(G2_thread, in_bytes(JavaThread::pending_deoptimization_offset()), O1);
|
||||
__ sub(G0, 1, L1);
|
||||
__ st(L1, G2_thread, in_bytes(JavaThread::pending_deoptimization_offset()));
|
||||
|
||||
__ mov((int32_t)Deoptimization::Unpack_reexecute, L0deopt_mode);
|
||||
__ mov(G2_thread, O0);
|
||||
__ call(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap));
|
||||
__ delayed()->nop();
|
||||
oop_maps->add_gc_map( __ offset()-start, map->deep_copy());
|
||||
__ get_thread();
|
||||
__ add(O7, 8, O7);
|
||||
__ reset_last_Java_frame();
|
||||
|
||||
__ ba(after_fetch_unroll_info_call);
|
||||
__ delayed()->nop(); // Delay slot
|
||||
masm->block_comment("END implicit_exception_uncommon_trap");
|
||||
} // EnableJVMCI
|
||||
#endif // INCLUDE_JVMCI
|
||||
|
||||
int exception_offset = __ offset() - start;
|
||||
|
||||
// restore G2, the trampoline destroyed it
|
||||
@ -3004,6 +3071,7 @@ void SharedRuntime::generate_deopt_blob() {
|
||||
int exception_in_tls_offset = __ offset() - start;
|
||||
|
||||
// No need to update oop_map as each call to save_live_registers will produce identical oopmap
|
||||
// Opens a new stack frame
|
||||
(void) RegisterSaver::save_live_registers(masm, 0, &frame_size_words);
|
||||
|
||||
// Restore G2_thread
|
||||
@ -3035,7 +3103,12 @@ void SharedRuntime::generate_deopt_blob() {
|
||||
// Reexecute entry, similar to c2 uncommon trap
|
||||
//
|
||||
int reexecute_offset = __ offset() - start;
|
||||
|
||||
#if INCLUDE_JVMCI && !defined(COMPILER1)
|
||||
if (EnableJVMCI && UseJVMCICompiler) {
|
||||
// JVMCI does not use this kind of deoptimization
|
||||
__ should_not_reach_here();
|
||||
}
|
||||
#endif
|
||||
// No need to update oop_map as each call to save_live_registers will produce identical oopmap
|
||||
(void) RegisterSaver::save_live_registers(masm, 0, &frame_size_words);
|
||||
|
||||
@ -3059,6 +3132,11 @@ void SharedRuntime::generate_deopt_blob() {
|
||||
|
||||
__ reset_last_Java_frame();
|
||||
|
||||
#if INCLUDE_JVMCI
|
||||
if (EnableJVMCI) {
|
||||
__ bind(after_fetch_unroll_info_call);
|
||||
}
|
||||
#endif
|
||||
// NOTE: we know that only O0/O1 will be reloaded by restore_result_registers
|
||||
// so this move will survive
|
||||
|
||||
@ -3124,6 +3202,12 @@ void SharedRuntime::generate_deopt_blob() {
|
||||
masm->flush();
|
||||
_deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, reexecute_offset, frame_size_words);
|
||||
_deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset);
|
||||
#if INCLUDE_JVMCI
|
||||
if (EnableJVMCI) {
|
||||
_deopt_blob->set_uncommon_trap_offset(uncommon_trap_offset);
|
||||
_deopt_blob->set_implicit_exception_uncommon_trap_offset(implicit_exception_uncommon_trap_offset);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef COMPILER2
|
||||
|
@ -204,6 +204,20 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state,
|
||||
address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state, int step) {
|
||||
address entry = __ pc();
|
||||
__ get_constant_pool_cache(LcpoolCache); // load LcpoolCache
|
||||
#if INCLUDE_JVMCI
|
||||
// Check if we need to take lock at entry of synchronized method.
|
||||
if (UseJVMCICompiler) {
|
||||
Label L;
|
||||
Address pending_monitor_enter_addr(G2_thread, JavaThread::pending_monitorenter_offset());
|
||||
__ ldbool(pending_monitor_enter_addr, Gtemp); // Load if pending monitor enter
|
||||
__ cmp_and_br_short(Gtemp, G0, Assembler::equal, Assembler::pn, L);
|
||||
// Clear flag.
|
||||
__ stbool(G0, pending_monitor_enter_addr);
|
||||
// Take lock.
|
||||
lock_method();
|
||||
__ bind(L);
|
||||
}
|
||||
#endif
|
||||
{ Label L;
|
||||
Address exception_addr(G2_thread, Thread::pending_exception_offset());
|
||||
__ ld_ptr(exception_addr, Gtemp); // Load pending exception.
|
||||
@ -349,7 +363,7 @@ void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile
|
||||
// Allocate monitor and lock method (asm interpreter)
|
||||
// ebx - Method*
|
||||
//
|
||||
void InterpreterGenerator::lock_method(void) {
|
||||
void TemplateInterpreterGenerator::lock_method() {
|
||||
__ ld(Lmethod, in_bytes(Method::access_flags_offset()), O0); // Load access flags.
|
||||
|
||||
#ifdef ASSERT
|
||||
|
@ -37,9 +37,9 @@
|
||||
#ifdef _LP64
|
||||
// The sethi() instruction generates lots more instructions when shell
|
||||
// stack limit is unlimited, so that's why this is much bigger.
|
||||
const static int InterpreterCodeSize = 210 * K;
|
||||
const static int InterpreterCodeSize = 260 * K;
|
||||
#else
|
||||
const static int InterpreterCodeSize = 180 * K;
|
||||
const static int InterpreterCodeSize = 230 * K;
|
||||
#endif
|
||||
|
||||
#endif // CPU_SPARC_VM_TEMPLATEINTERPRETER_SPARC_HPP
|
||||
|
@ -2949,12 +2949,14 @@ void TemplateTable::prepare_invoke(int byte_no,
|
||||
|
||||
|
||||
void TemplateTable::generate_vtable_call(Register Rrecv, Register Rindex, Register Rret) {
|
||||
Register Rtemp = G4_scratch;
|
||||
Register Rcall = Rindex;
|
||||
assert_different_registers(Rcall, G5_method, Gargs, Rret);
|
||||
|
||||
// get target Method* & entry point
|
||||
__ lookup_virtual_method(Rrecv, Rindex, G5_method);
|
||||
__ profile_arguments_type(G5_method, Rcall, Gargs, true);
|
||||
__ profile_called_method(G5_method, Rtemp);
|
||||
__ call_from_interpreter(Rcall, Gargs, Rret);
|
||||
}
|
||||
|
||||
@ -3211,6 +3213,7 @@ void TemplateTable::invokeinterface(int byte_no) {
|
||||
assert_different_registers(Rcall, G5_method, Gargs, Rret);
|
||||
|
||||
__ profile_arguments_type(G5_method, Rcall, Gargs, true);
|
||||
__ profile_called_method(G5_method, Rscratch);
|
||||
__ call_from_interpreter(Rcall, Gargs, Rret);
|
||||
}
|
||||
|
||||
@ -3486,7 +3489,8 @@ void TemplateTable::checkcast() {
|
||||
Register RspecifiedKlass = O4;
|
||||
|
||||
// Check for casting a NULL
|
||||
__ br_null_short(Otos_i, Assembler::pn, is_null);
|
||||
__ br_null(Otos_i, false, Assembler::pn, is_null);
|
||||
__ delayed()->nop();
|
||||
|
||||
// Get value klass in RobjKlass
|
||||
__ load_klass(Otos_i, RobjKlass); // get value klass
|
||||
@ -3542,7 +3546,8 @@ void TemplateTable::instanceof() {
|
||||
Register RspecifiedKlass = O4;
|
||||
|
||||
// Check for casting a NULL
|
||||
__ br_null_short(Otos_i, Assembler::pt, is_null);
|
||||
__ br_null(Otos_i, false, Assembler::pt, is_null);
|
||||
__ delayed()->nop();
|
||||
|
||||
// Get value klass in RobjKlass
|
||||
__ load_klass(Otos_i, RobjKlass); // get value klass
|
||||
|
@ -37,10 +37,11 @@
|
||||
/******************************/ \
|
||||
/* JavaFrameAnchor */ \
|
||||
/******************************/ \
|
||||
volatile_nonstatic_field(JavaFrameAnchor, _flags, int)
|
||||
|
||||
#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type)
|
||||
volatile_nonstatic_field(JavaFrameAnchor, _flags, int) \
|
||||
static_field(VM_Version, _features, int)
|
||||
|
||||
#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \
|
||||
declare_toplevel_type(VM_Version)
|
||||
|
||||
#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \
|
||||
/******************************/ \
|
||||
@ -78,7 +79,11 @@
|
||||
declare_c2_constant(R_G4_num) \
|
||||
declare_c2_constant(R_G5_num) \
|
||||
declare_c2_constant(R_G6_num) \
|
||||
declare_c2_constant(R_G7_num)
|
||||
declare_c2_constant(R_G7_num) \
|
||||
declare_constant(VM_Version::vis1_instructions_m) \
|
||||
declare_constant(VM_Version::vis2_instructions_m) \
|
||||
declare_constant(VM_Version::vis3_instructions_m) \
|
||||
declare_constant(VM_Version::cbcond_instructions_m)
|
||||
|
||||
#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "runtime/vm_version.hpp"
|
||||
|
||||
class VM_Version: public Abstract_VM_Version {
|
||||
friend class VMStructs;
|
||||
protected:
|
||||
enum Feature_Flag {
|
||||
v8_instructions = 0,
|
||||
|
@ -878,21 +878,35 @@ address Assembler::locate_operand(address inst, WhichOperand which) {
|
||||
// Check second byte
|
||||
NOT_LP64(assert((0xC0 & *ip) == 0xC0, "shouldn't have LDS and LES instructions"));
|
||||
|
||||
int vex_opcode;
|
||||
// First byte
|
||||
if ((0xFF & *inst) == VEX_3bytes) {
|
||||
vex_opcode = VEX_OPCODE_MASK & *ip;
|
||||
ip++; // third byte
|
||||
is_64bit = ((VEX_W & *ip) == VEX_W);
|
||||
} else {
|
||||
vex_opcode = VEX_OPCODE_0F;
|
||||
}
|
||||
ip++; // opcode
|
||||
// To find the end of instruction (which == end_pc_operand).
|
||||
switch (0xFF & *ip) {
|
||||
case 0x61: // pcmpestri r, r/a, #8
|
||||
case 0x70: // pshufd r, r/a, #8
|
||||
case 0x73: // psrldq r, #8
|
||||
tail_size = 1; // the imm8
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
switch (vex_opcode) {
|
||||
case VEX_OPCODE_0F:
|
||||
switch (0xFF & *ip) {
|
||||
case 0x70: // pshufd r, r/a, #8
|
||||
case 0x71: // ps[rl|ra|ll]w r, #8
|
||||
case 0x72: // ps[rl|ra|ll]d r, #8
|
||||
case 0x73: // ps[rl|ra|ll]q r, #8
|
||||
case 0xC2: // cmp[ps|pd|ss|sd] r, r, r/a, #8
|
||||
case 0xC4: // pinsrw r, r, r/a, #8
|
||||
case 0xC5: // pextrw r/a, r, #8
|
||||
case 0xC6: // shufp[s|d] r, r, r/a, #8
|
||||
tail_size = 1; // the imm8
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case VEX_OPCODE_0F_3A:
|
||||
tail_size = 1;
|
||||
break;
|
||||
}
|
||||
ip++; // skip opcode
|
||||
debug_only(has_disp32 = true); // has both kinds of operands!
|
||||
@ -2479,7 +2493,7 @@ void Assembler::movsbl(Register dst, Address src) { // movsxb
|
||||
|
||||
void Assembler::movsbl(Register dst, Register src) { // movsxb
|
||||
NOT_LP64(assert(src->has_byte_register(), "must have byte register"));
|
||||
int encode = prefix_and_encode(dst->encoding(), src->encoding(), true);
|
||||
int encode = prefix_and_encode(dst->encoding(), false, src->encoding(), true);
|
||||
emit_int8(0x0F);
|
||||
emit_int8((unsigned char)0xBE);
|
||||
emit_int8((unsigned char)(0xC0 | encode));
|
||||
@ -2596,7 +2610,7 @@ void Assembler::movzbl(Register dst, Address src) { // movzxb
|
||||
|
||||
void Assembler::movzbl(Register dst, Register src) { // movzxb
|
||||
NOT_LP64(assert(src->has_byte_register(), "must have byte register"));
|
||||
int encode = prefix_and_encode(dst->encoding(), src->encoding(), true);
|
||||
int encode = prefix_and_encode(dst->encoding(), false, src->encoding(), true);
|
||||
emit_int8(0x0F);
|
||||
emit_int8((unsigned char)0xB6);
|
||||
emit_int8(0xC0 | encode);
|
||||
@ -6510,12 +6524,12 @@ int Assembler::prefixq_and_encode(int reg_enc) {
|
||||
return reg_enc;
|
||||
}
|
||||
|
||||
int Assembler::prefix_and_encode(int dst_enc, int src_enc, bool byteinst) {
|
||||
int Assembler::prefix_and_encode(int dst_enc, bool dst_is_byte, int src_enc, bool src_is_byte) {
|
||||
if (dst_enc < 8) {
|
||||
if (src_enc >= 8) {
|
||||
prefix(REX_B);
|
||||
src_enc -= 8;
|
||||
} else if (byteinst && src_enc >= 4) {
|
||||
} else if ((src_is_byte && src_enc >= 4) || (dst_is_byte && dst_enc >= 4)) {
|
||||
prefix(REX);
|
||||
}
|
||||
} else {
|
||||
|
@ -536,7 +536,8 @@ class Assembler : public AbstractAssembler {
|
||||
VEX_OPCODE_NONE = 0x0,
|
||||
VEX_OPCODE_0F = 0x1,
|
||||
VEX_OPCODE_0F_38 = 0x2,
|
||||
VEX_OPCODE_0F_3A = 0x3
|
||||
VEX_OPCODE_0F_3A = 0x3,
|
||||
VEX_OPCODE_MASK = 0x1F
|
||||
};
|
||||
|
||||
enum AvxVectorLen {
|
||||
@ -612,7 +613,10 @@ private:
|
||||
int prefix_and_encode(int reg_enc, bool byteinst = false);
|
||||
int prefixq_and_encode(int reg_enc);
|
||||
|
||||
int prefix_and_encode(int dst_enc, int src_enc, bool byteinst = false);
|
||||
int prefix_and_encode(int dst_enc, int src_enc) {
|
||||
return prefix_and_encode(dst_enc, false, src_enc, false);
|
||||
}
|
||||
int prefix_and_encode(int dst_enc, bool dst_is_byte, int src_enc, bool src_is_byte);
|
||||
int prefixq_and_encode(int dst_enc, int src_enc);
|
||||
|
||||
void prefix(Register reg);
|
||||
|
@ -33,7 +33,7 @@
|
||||
inline int Assembler::prefix_and_encode(int reg_enc, bool byteinst) { return reg_enc; }
|
||||
inline int Assembler::prefixq_and_encode(int reg_enc) { return reg_enc; }
|
||||
|
||||
inline int Assembler::prefix_and_encode(int dst_enc, int src_enc, bool byteinst) { return dst_enc << 3 | src_enc; }
|
||||
inline int Assembler::prefix_and_encode(int dst_enc, bool dst_is_byte, int src_enc, bool src_is_byte) { return dst_enc << 3 | src_enc; }
|
||||
inline int Assembler::prefixq_and_encode(int dst_enc, int src_enc) { return dst_enc << 3 | src_enc; }
|
||||
|
||||
inline void Assembler::prefix(Register reg) {}
|
||||
|
@ -50,13 +50,15 @@ bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site) {
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#define __ _masm.
|
||||
address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) {
|
||||
address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark) {
|
||||
// Stub is fixed up when the corresponding call is converted from
|
||||
// calling compiled code to calling interpreted code.
|
||||
// movq rbx, 0
|
||||
// jmp -5 # to self
|
||||
|
||||
address mark = cbuf.insts_mark(); // Get mark within main instrs section.
|
||||
if (mark == NULL) {
|
||||
mark = cbuf.insts_mark(); // Get mark within main instrs section.
|
||||
}
|
||||
|
||||
// Note that the code buffer's insts_mark is always relative to insts.
|
||||
// That's why we must use the macroassembler to generate a stub.
|
||||
@ -73,6 +75,8 @@ address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) {
|
||||
// This is recognized as unresolved by relocs/nativeinst/ic code.
|
||||
__ jump(RuntimeAddress(__ pc()));
|
||||
|
||||
assert(__ pc() - base <= to_interp_stub_size(), "wrong stub size");
|
||||
|
||||
// Update current stubs pointer and restore insts_end.
|
||||
__ end_a_stub();
|
||||
return base;
|
||||
@ -104,10 +108,15 @@ void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry)
|
||||
NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
|
||||
NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());
|
||||
|
||||
assert(method_holder->data() == 0 || method_holder->data() == (intptr_t)callee(),
|
||||
#ifdef ASSERT
|
||||
// read the value once
|
||||
intptr_t data = method_holder->data();
|
||||
address destination = jump->jump_destination();
|
||||
assert(data == 0 || data == (intptr_t)callee(),
|
||||
"a) MT-unsafe modification of inline cache");
|
||||
assert(jump->jump_destination() == (address)-1 || jump->jump_destination() == entry,
|
||||
assert(destination == (address)-1 || destination == entry,
|
||||
"b) MT-unsafe modification of inline cache");
|
||||
#endif
|
||||
|
||||
// Update stub.
|
||||
method_holder->set_data((intptr_t)callee());
|
||||
@ -124,11 +133,12 @@ void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub)
|
||||
assert(stub != NULL, "stub not found");
|
||||
// Creation also verifies the object.
|
||||
NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
|
||||
NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());
|
||||
method_holder->set_data(0);
|
||||
NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());
|
||||
jump->set_jump_destination((address)-1);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Non-product mode code
|
||||
#ifndef PRODUCT
|
||||
@ -150,5 +160,4 @@ void CompiledStaticCall::verify() {
|
||||
// Verify state.
|
||||
assert(is_clean() || is_call_to_compiled() || is_call_to_interpreted(), "sanity check");
|
||||
}
|
||||
|
||||
#endif // !PRODUCT
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
void generate_more_monitors();
|
||||
void generate_deopt_handling();
|
||||
void lock_method(void);
|
||||
address generate_interpreter_frame_manager(bool synchronized); // C++ interpreter only
|
||||
void generate_compute_interpreter_state(const Register state,
|
||||
const Register prev_state,
|
||||
|
@ -741,7 +741,7 @@ void InterpreterGenerator::generate_stack_overflow_check(void) {
|
||||
// Find preallocated monitor and lock method (C++ interpreter)
|
||||
// rbx - Method*
|
||||
//
|
||||
void InterpreterGenerator::lock_method(void) {
|
||||
void CppInterpreterGenerator::lock_method() {
|
||||
// assumes state == rsi/r13 == pointer to current interpreterState
|
||||
// minimally destroys rax, rdx|c_rarg1, rdi
|
||||
//
|
||||
|
@ -458,11 +458,11 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const {
|
||||
// This is the sp before any possible extension (adapter/locals).
|
||||
intptr_t* unextended_sp = interpreter_frame_sender_sp();
|
||||
|
||||
#ifdef COMPILER2
|
||||
#if defined(COMPILER2) || INCLUDE_JVMCI
|
||||
if (map->update_map()) {
|
||||
update_map_with_saved_link(map, (intptr_t**) addr_at(link_offset));
|
||||
}
|
||||
#endif // COMPILER2
|
||||
#endif // COMPILER2 || INCLUDE_JVMCI
|
||||
|
||||
return frame(sender_sp, unextended_sp, link(), sender_pc());
|
||||
}
|
||||
@ -683,10 +683,19 @@ void frame::describe_pd(FrameValues& values, int frame_no) {
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_locals);
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_bcp);
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_initial_sp);
|
||||
#endif
|
||||
#ifdef AMD64
|
||||
} else if (is_entry_frame()) {
|
||||
// This could be more descriptive if we use the enum in
|
||||
// stubGenerator to map to real names but it's most important to
|
||||
// claim these frame slots so the error checking works.
|
||||
for (int i = 0; i < entry_frame_after_call_words; i++) {
|
||||
values.describe(frame_no, fp() - i, err_msg("call_stub word fp - %d", i));
|
||||
}
|
||||
#endif // AMD64
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif // !PRODUCT
|
||||
|
||||
intptr_t *frame::initial_deoptimization_info() {
|
||||
// used to reset the saved FP
|
||||
|
@ -78,7 +78,11 @@ inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address
|
||||
assert(((nmethod*)_cb)->insts_contains(_pc), "original PC must be in nmethod");
|
||||
_deopt_state = is_deoptimized;
|
||||
} else {
|
||||
_deopt_state = not_deoptimized;
|
||||
if (_cb->is_deoptimization_stub()) {
|
||||
_deopt_state = is_deoptimized;
|
||||
} else {
|
||||
_deopt_state = not_deoptimized;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ define_pd_global(bool, UncommonNullCast, true); // Uncommon-trap NULLs
|
||||
// the the vep is aligned at CodeEntryAlignment whereas c2 only aligns
|
||||
// the uep and the vep doesn't get real alignment but just slops on by
|
||||
// only assured that the entry instruction meets the 5 byte size requirement.
|
||||
#ifdef COMPILER2
|
||||
#if defined(COMPILER2) || INCLUDE_JVMCI
|
||||
define_pd_global(intx, CodeEntryAlignment, 32);
|
||||
#else
|
||||
define_pd_global(intx, CodeEntryAlignment, 16);
|
||||
|
@ -1502,13 +1502,39 @@ void InterpreterMacroAssembler::profile_virtual_call(Register receiver,
|
||||
bind(skip_receiver_profile);
|
||||
|
||||
// The method data pointer needs to be updated to reflect the new target.
|
||||
#if INCLUDE_JVMCI
|
||||
if (MethodProfileWidth == 0) {
|
||||
update_mdp_by_constant(mdp, in_bytes(VirtualCallData::virtual_call_data_size()));
|
||||
}
|
||||
#else // INCLUDE_JVMCI
|
||||
update_mdp_by_constant(mdp,
|
||||
in_bytes(VirtualCallData::
|
||||
virtual_call_data_size()));
|
||||
#endif // INCLUDE_JVMCI
|
||||
bind(profile_continue);
|
||||
}
|
||||
}
|
||||
|
||||
#if INCLUDE_JVMCI
|
||||
void InterpreterMacroAssembler::profile_called_method(Register method, Register mdp, Register reg2) {
|
||||
assert_different_registers(method, mdp, reg2);
|
||||
if (ProfileInterpreter && MethodProfileWidth > 0) {
|
||||
Label profile_continue;
|
||||
|
||||
// If no method data exists, go to profile_continue.
|
||||
test_method_data_pointer(mdp, profile_continue);
|
||||
|
||||
Label done;
|
||||
record_item_in_profile_helper(method, mdp, reg2, 0, done, MethodProfileWidth,
|
||||
&VirtualCallData::method_offset, &VirtualCallData::method_count_offset, in_bytes(VirtualCallData::nonprofiled_receiver_count_offset()));
|
||||
bind(done);
|
||||
|
||||
update_mdp_by_constant(mdp, in_bytes(VirtualCallData::virtual_call_data_size()));
|
||||
bind(profile_continue);
|
||||
}
|
||||
}
|
||||
#endif // INCLUDE_JVMCI
|
||||
|
||||
// This routine creates a state machine for updating the multi-row
|
||||
// type profile at a virtual call site (or other type-sensitive bytecode).
|
||||
// The machine visits each row (of receiver/count) until the receiver type
|
||||
@ -1528,14 +1554,36 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper(
|
||||
if (is_virtual_call) {
|
||||
increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()));
|
||||
}
|
||||
return;
|
||||
}
|
||||
#if INCLUDE_JVMCI
|
||||
else if (EnableJVMCI) {
|
||||
increment_mdp_data_at(mdp, in_bytes(ReceiverTypeData::nonprofiled_receiver_count_offset()));
|
||||
}
|
||||
#endif // INCLUDE_JVMCI
|
||||
} else {
|
||||
int non_profiled_offset = -1;
|
||||
if (is_virtual_call) {
|
||||
non_profiled_offset = in_bytes(CounterData::count_offset());
|
||||
}
|
||||
#if INCLUDE_JVMCI
|
||||
else if (EnableJVMCI) {
|
||||
non_profiled_offset = in_bytes(ReceiverTypeData::nonprofiled_receiver_count_offset());
|
||||
}
|
||||
#endif // INCLUDE_JVMCI
|
||||
|
||||
int last_row = VirtualCallData::row_limit() - 1;
|
||||
record_item_in_profile_helper(receiver, mdp, reg2, 0, done, TypeProfileWidth,
|
||||
&VirtualCallData::receiver_offset, &VirtualCallData::receiver_count_offset, non_profiled_offset);
|
||||
}
|
||||
}
|
||||
|
||||
void InterpreterMacroAssembler::record_item_in_profile_helper(Register item, Register mdp,
|
||||
Register reg2, int start_row, Label& done, int total_rows,
|
||||
OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn,
|
||||
int non_profiled_offset) {
|
||||
int last_row = total_rows - 1;
|
||||
assert(start_row <= last_row, "must be work left to do");
|
||||
// Test this row for both the receiver and for null.
|
||||
// Test this row for both the item and for null.
|
||||
// Take any of three different outcomes:
|
||||
// 1. found receiver => increment count and goto done
|
||||
// 1. found item => increment count and goto done
|
||||
// 2. found null => keep looking for case 1, maybe allocate this cell
|
||||
// 3. found something else => keep looking for cases 1 and 2
|
||||
// Case 3 is handled by a recursive call.
|
||||
@ -1543,30 +1591,30 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper(
|
||||
Label next_test;
|
||||
bool test_for_null_also = (row == start_row);
|
||||
|
||||
// See if the receiver is receiver[n].
|
||||
int recvr_offset = in_bytes(VirtualCallData::receiver_offset(row));
|
||||
test_mdp_data_at(mdp, recvr_offset, receiver,
|
||||
// See if the item is item[n].
|
||||
int item_offset = in_bytes(item_offset_fn(row));
|
||||
test_mdp_data_at(mdp, item_offset, item,
|
||||
(test_for_null_also ? reg2 : noreg),
|
||||
next_test);
|
||||
// (Reg2 now contains the receiver from the CallData.)
|
||||
// (Reg2 now contains the item from the CallData.)
|
||||
|
||||
// The receiver is receiver[n]. Increment count[n].
|
||||
int count_offset = in_bytes(VirtualCallData::receiver_count_offset(row));
|
||||
// The item is item[n]. Increment count[n].
|
||||
int count_offset = in_bytes(item_count_offset_fn(row));
|
||||
increment_mdp_data_at(mdp, count_offset);
|
||||
jmp(done);
|
||||
bind(next_test);
|
||||
|
||||
if (test_for_null_also) {
|
||||
Label found_null;
|
||||
// Failed the equality check on receiver[n]... Test for null.
|
||||
// Failed the equality check on item[n]... Test for null.
|
||||
testptr(reg2, reg2);
|
||||
if (start_row == last_row) {
|
||||
// The only thing left to do is handle the null case.
|
||||
if (is_virtual_call) {
|
||||
if (non_profiled_offset >= 0) {
|
||||
jccb(Assembler::zero, found_null);
|
||||
// Receiver did not match any saved receiver and there is no empty row for it.
|
||||
// Item did not match any saved item and there is no empty row for it.
|
||||
// Increment total counter to indicate polymorphic case.
|
||||
increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()));
|
||||
increment_mdp_data_at(mdp, non_profiled_offset);
|
||||
jmp(done);
|
||||
bind(found_null);
|
||||
} else {
|
||||
@ -1578,21 +1626,22 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper(
|
||||
jcc(Assembler::zero, found_null);
|
||||
|
||||
// Put all the "Case 3" tests here.
|
||||
record_klass_in_profile_helper(receiver, mdp, reg2, start_row + 1, done, is_virtual_call);
|
||||
record_item_in_profile_helper(item, mdp, reg2, start_row + 1, done, total_rows,
|
||||
item_offset_fn, item_count_offset_fn, non_profiled_offset);
|
||||
|
||||
// Found a null. Keep searching for a matching receiver,
|
||||
// Found a null. Keep searching for a matching item,
|
||||
// but remember that this is an empty (unused) slot.
|
||||
bind(found_null);
|
||||
}
|
||||
}
|
||||
|
||||
// In the fall-through case, we found no matching receiver, but we
|
||||
// observed the receiver[start_row] is NULL.
|
||||
// In the fall-through case, we found no matching item, but we
|
||||
// observed the item[start_row] is NULL.
|
||||
|
||||
// Fill in the receiver field and increment the count.
|
||||
int recvr_offset = in_bytes(VirtualCallData::receiver_offset(start_row));
|
||||
set_mdp_data_at(mdp, recvr_offset, receiver);
|
||||
int count_offset = in_bytes(VirtualCallData::receiver_count_offset(start_row));
|
||||
// Fill in the item field and increment the count.
|
||||
int item_offset = in_bytes(item_offset_fn(start_row));
|
||||
set_mdp_data_at(mdp, item_offset, item);
|
||||
int count_offset = in_bytes(item_count_offset_fn(start_row));
|
||||
movl(reg2, DataLayout::counter_increment);
|
||||
set_mdp_data_at(mdp, count_offset, reg2);
|
||||
if (start_row > 0) {
|
||||
|
@ -32,6 +32,7 @@
|
||||
|
||||
// This file specializes the assember with interpreter-specific macros
|
||||
|
||||
typedef ByteSize (*OffsetFunction)(uint);
|
||||
|
||||
class InterpreterMacroAssembler: public MacroAssembler {
|
||||
|
||||
@ -251,6 +252,10 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
||||
void record_klass_in_profile_helper(Register receiver, Register mdp,
|
||||
Register reg2, int start_row,
|
||||
Label& done, bool is_virtual_call);
|
||||
void record_item_in_profile_helper(Register item, Register mdp,
|
||||
Register reg2, int start_row, Label& done, int total_rows,
|
||||
OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn,
|
||||
int non_profiled_offset);
|
||||
|
||||
void update_mdp_by_offset(Register mdp_in, int offset_of_offset);
|
||||
void update_mdp_by_offset(Register mdp_in, Register reg, int offset_of_disp);
|
||||
@ -264,6 +269,7 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
||||
void profile_virtual_call(Register receiver, Register mdp,
|
||||
Register scratch2,
|
||||
bool receiver_can_be_null = false);
|
||||
void profile_called_method(Register method, Register mdp, Register reg2) NOT_JVMCI_RETURN;
|
||||
void profile_ret(Register return_bci, Register mdp);
|
||||
void profile_null_seen(Register mdp);
|
||||
void profile_typecheck(Register mdp, Register klass, Register scratch);
|
||||
|
@ -48,7 +48,6 @@
|
||||
address generate_Double_longBitsToDouble_entry();
|
||||
address generate_Double_doubleToRawLongBits_entry();
|
||||
#endif
|
||||
void lock_method(void);
|
||||
void generate_stack_overflow_check(void);
|
||||
|
||||
void generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue);
|
||||
|
239
hotspot/src/cpu/x86/vm/jvmciCodeInstaller_x86.cpp
Normal file
239
hotspot/src/cpu/x86/vm/jvmciCodeInstaller_x86.cpp
Normal file
@ -0,0 +1,239 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "compiler/disassembler.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/javaCalls.hpp"
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
#include "jvmci/jvmciEnv.hpp"
|
||||
#include "jvmci/jvmciCodeInstaller.hpp"
|
||||
#include "jvmci/jvmciJavaClasses.hpp"
|
||||
#include "jvmci/jvmciCompilerToVM.hpp"
|
||||
#include "jvmci/jvmciRuntime.hpp"
|
||||
#include "asm/register.hpp"
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
#include "code/vmreg.hpp"
|
||||
#include "vmreg_x86.inline.hpp"
|
||||
|
||||
jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, oop method) {
|
||||
if (inst->is_call() || inst->is_jump()) {
|
||||
assert(NativeCall::instruction_size == (int)NativeJump::instruction_size, "unexpected size");
|
||||
return (pc_offset + NativeCall::instruction_size);
|
||||
} else if (inst->is_mov_literal64()) {
|
||||
// mov+call instruction pair
|
||||
jint offset = pc_offset + NativeMovConstReg::instruction_size;
|
||||
u_char* call = (u_char*) (_instructions->start() + offset);
|
||||
if (call[0] == Assembler::REX_B) {
|
||||
offset += 1; /* prefix byte for extended register R8-R15 */
|
||||
call++;
|
||||
}
|
||||
assert(call[0] == 0xFF, "expected call");
|
||||
offset += 2; /* opcode byte + modrm byte */
|
||||
return (offset);
|
||||
} else if (inst->is_call_reg()) {
|
||||
// the inlined vtable stub contains a "call register" instruction
|
||||
assert(method != NULL, "only valid for virtual calls");
|
||||
return (pc_offset + ((NativeCallReg *) inst)->next_instruction_offset());
|
||||
} else if (inst->is_cond_jump()) {
|
||||
address pc = (address) (inst);
|
||||
return pc_offset + (jint) (Assembler::locate_next_instruction(pc) - pc);
|
||||
} else {
|
||||
fatal("unsupported type of instruction for call site");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle& constant) {
|
||||
address pc = _instructions->start() + pc_offset;
|
||||
Handle obj = HotSpotObjectConstantImpl::object(constant);
|
||||
jobject value = JNIHandles::make_local(obj());
|
||||
if (HotSpotObjectConstantImpl::compressed(constant)) {
|
||||
#ifdef _LP64
|
||||
address operand = Assembler::locate_operand(pc, Assembler::narrow_oop_operand);
|
||||
int oop_index = _oop_recorder->find_index(value);
|
||||
_instructions->relocate(pc, oop_Relocation::spec(oop_index), Assembler::narrow_oop_operand);
|
||||
TRACE_jvmci_3("relocating (narrow oop constant) at " PTR_FORMAT "/" PTR_FORMAT, p2i(pc), p2i(operand));
|
||||
#else
|
||||
fatal("compressed oop on 32bit");
|
||||
#endif
|
||||
} else {
|
||||
address operand = Assembler::locate_operand(pc, Assembler::imm_operand);
|
||||
*((jobject*) operand) = value;
|
||||
_instructions->relocate(pc, oop_Relocation::spec_for_immediate(), Assembler::imm_operand);
|
||||
TRACE_jvmci_3("relocating (oop constant) at " PTR_FORMAT "/" PTR_FORMAT, p2i(pc), p2i(operand));
|
||||
}
|
||||
}
|
||||
|
||||
void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset) {
|
||||
address pc = _instructions->start() + pc_offset;
|
||||
|
||||
address operand = Assembler::locate_operand(pc, Assembler::disp32_operand);
|
||||
address next_instruction = Assembler::locate_next_instruction(pc);
|
||||
address dest = _constants->start() + data_offset;
|
||||
|
||||
long disp = dest - next_instruction;
|
||||
assert(disp == (jint) disp, "disp doesn't fit in 32 bits");
|
||||
*((jint*) operand) = (jint) disp;
|
||||
|
||||
_instructions->relocate(pc, section_word_Relocation::spec((address) dest, CodeBuffer::SECT_CONSTS), Assembler::disp32_operand);
|
||||
TRACE_jvmci_3("relocating at " PTR_FORMAT "/" PTR_FORMAT " with destination at " PTR_FORMAT " (%d)", p2i(pc), p2i(operand), p2i(dest), data_offset);
|
||||
}
|
||||
|
||||
void CodeInstaller::pd_relocate_CodeBlob(CodeBlob* cb, NativeInstruction* inst) {
|
||||
if (cb->is_nmethod()) {
|
||||
nmethod* nm = (nmethod*) cb;
|
||||
nativeJump_at((address)inst)->set_jump_destination(nm->verified_entry_point());
|
||||
} else {
|
||||
nativeJump_at((address)inst)->set_jump_destination(cb->code_begin());
|
||||
}
|
||||
_instructions->relocate((address)inst, runtime_call_Relocation::spec(), Assembler::call32_operand);
|
||||
}
|
||||
|
||||
void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination) {
|
||||
address pc = (address) inst;
|
||||
if (inst->is_call()) {
|
||||
// NOTE: for call without a mov, the offset must fit a 32-bit immediate
|
||||
// see also CompilerToVM.getMaxCallTargetOffset()
|
||||
NativeCall* call = nativeCall_at(pc);
|
||||
call->set_destination((address) foreign_call_destination);
|
||||
_instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec(), Assembler::call32_operand);
|
||||
} else if (inst->is_mov_literal64()) {
|
||||
NativeMovConstReg* mov = nativeMovConstReg_at(pc);
|
||||
mov->set_data((intptr_t) foreign_call_destination);
|
||||
_instructions->relocate(mov->instruction_address(), runtime_call_Relocation::spec(), Assembler::imm_operand);
|
||||
} else if (inst->is_jump()) {
|
||||
NativeJump* jump = nativeJump_at(pc);
|
||||
jump->set_jump_destination((address) foreign_call_destination);
|
||||
_instructions->relocate(jump->instruction_address(), runtime_call_Relocation::spec(), Assembler::call32_operand);
|
||||
} else if (inst->is_cond_jump()) {
|
||||
address old_dest = nativeGeneralJump_at(pc)->jump_destination();
|
||||
address disp = Assembler::locate_operand(pc, Assembler::call32_operand);
|
||||
*(jint*) disp += ((address) foreign_call_destination) - old_dest;
|
||||
_instructions->relocate(pc, runtime_call_Relocation::spec(), Assembler::call32_operand);
|
||||
} else {
|
||||
fatal("unsupported relocation for foreign call");
|
||||
}
|
||||
|
||||
TRACE_jvmci_3("relocating (foreign call) at " PTR_FORMAT, p2i(inst));
|
||||
}
|
||||
|
||||
void CodeInstaller::pd_relocate_JavaMethod(oop hotspot_method, jint pc_offset) {
|
||||
#ifdef ASSERT
|
||||
Method* method = NULL;
|
||||
// we need to check, this might also be an unresolved method
|
||||
if (hotspot_method->is_a(HotSpotResolvedJavaMethodImpl::klass())) {
|
||||
method = getMethodFromHotSpotMethod(hotspot_method);
|
||||
}
|
||||
#endif
|
||||
switch (_next_call_type) {
|
||||
case INLINE_INVOKE:
|
||||
break;
|
||||
case INVOKEVIRTUAL:
|
||||
case INVOKEINTERFACE: {
|
||||
assert(method == NULL || !method->is_static(), "cannot call static method with invokeinterface");
|
||||
|
||||
NativeCall* call = nativeCall_at(_instructions->start() + pc_offset);
|
||||
call->set_destination(SharedRuntime::get_resolve_virtual_call_stub());
|
||||
_instructions->relocate(call->instruction_address(),
|
||||
virtual_call_Relocation::spec(_invoke_mark_pc),
|
||||
Assembler::call32_operand);
|
||||
break;
|
||||
}
|
||||
case INVOKESTATIC: {
|
||||
assert(method == NULL || method->is_static(), "cannot call non-static method with invokestatic");
|
||||
|
||||
NativeCall* call = nativeCall_at(_instructions->start() + pc_offset);
|
||||
call->set_destination(SharedRuntime::get_resolve_static_call_stub());
|
||||
_instructions->relocate(call->instruction_address(),
|
||||
relocInfo::static_call_type, Assembler::call32_operand);
|
||||
break;
|
||||
}
|
||||
case INVOKESPECIAL: {
|
||||
assert(method == NULL || !method->is_static(), "cannot call static method with invokespecial");
|
||||
NativeCall* call = nativeCall_at(_instructions->start() + pc_offset);
|
||||
call->set_destination(SharedRuntime::get_resolve_opt_virtual_call_stub());
|
||||
_instructions->relocate(call->instruction_address(),
|
||||
relocInfo::opt_virtual_call_type, Assembler::call32_operand);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void relocate_poll_near(address pc) {
|
||||
NativeInstruction* ni = nativeInstruction_at(pc);
|
||||
int32_t* disp = (int32_t*) Assembler::locate_operand(pc, Assembler::disp32_operand);
|
||||
int32_t offset = *disp; // The Java code installed the polling page offset into the disp32 operand
|
||||
intptr_t new_disp = (intptr_t) (os::get_polling_page() + offset) - (intptr_t) ni;
|
||||
*disp = (int32_t)new_disp;
|
||||
}
|
||||
|
||||
|
||||
void CodeInstaller::pd_relocate_poll(address pc, jint mark) {
|
||||
switch (mark) {
|
||||
case POLL_NEAR: {
|
||||
relocate_poll_near(pc);
|
||||
_instructions->relocate(pc, relocInfo::poll_type, Assembler::disp32_operand);
|
||||
break;
|
||||
}
|
||||
case POLL_FAR:
|
||||
// This is a load from a register so there is no relocatable operand.
|
||||
// We just have to ensure that the format is not disp32_operand
|
||||
// so that poll_Relocation::fix_relocation_after_move does the right
|
||||
// thing (i.e. ignores this relocation record)
|
||||
_instructions->relocate(pc, relocInfo::poll_type, Assembler::imm_operand);
|
||||
break;
|
||||
case POLL_RETURN_NEAR: {
|
||||
relocate_poll_near(pc);
|
||||
_instructions->relocate(pc, relocInfo::poll_return_type, Assembler::disp32_operand);
|
||||
break;
|
||||
}
|
||||
case POLL_RETURN_FAR:
|
||||
// see comment above for POLL_FAR
|
||||
_instructions->relocate(pc, relocInfo::poll_return_type, Assembler::imm_operand);
|
||||
break;
|
||||
default:
|
||||
fatal("invalid mark value");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// convert JVMCI register indices (as used in oop maps) to HotSpot registers
|
||||
VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg) {
|
||||
if (jvmci_reg < RegisterImpl::number_of_registers) {
|
||||
return as_Register(jvmci_reg)->as_VMReg();
|
||||
} else {
|
||||
jint floatRegisterNumber = jvmci_reg - RegisterImpl::number_of_registers;
|
||||
if (floatRegisterNumber < XMMRegisterImpl::number_of_registers) {
|
||||
return as_XMMRegister(floatRegisterNumber)->as_VMReg();
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool CodeInstaller::is_general_purpose_reg(VMReg hotspotRegister) {
|
||||
return !(hotspotRegister->is_FloatRegister() || hotspotRegister->is_XMMRegister());
|
||||
}
|
@ -2889,7 +2889,7 @@ void MacroAssembler::divss(XMMRegister dst, AddressLiteral src) {
|
||||
}
|
||||
|
||||
// !defined(COMPILER2) is because of stupid core builds
|
||||
#if !defined(_LP64) || defined(COMPILER1) || !defined(COMPILER2)
|
||||
#if !defined(_LP64) || defined(COMPILER1) || !defined(COMPILER2) || INCLUDE_JVMCI
|
||||
void MacroAssembler::empty_FPU_stack() {
|
||||
if (VM_Version::supports_mmx()) {
|
||||
emms();
|
||||
@ -2897,7 +2897,7 @@ void MacroAssembler::empty_FPU_stack() {
|
||||
for (int i = 8; i-- > 0; ) ffree(i);
|
||||
}
|
||||
}
|
||||
#endif // !LP64 || C1 || !C2
|
||||
#endif // !LP64 || C1 || !C2 || INCLUDE_JVMCI
|
||||
|
||||
|
||||
// Defines obj, preserves var_size_in_bytes
|
||||
|
@ -41,7 +41,6 @@ void NativeInstruction::wrote(int offset) {
|
||||
ICache::invalidate_word(addr_at(offset));
|
||||
}
|
||||
|
||||
|
||||
void NativeCall::verify() {
|
||||
// Make sure code pattern is actually a call imm32 instruction.
|
||||
int inst = ubyte_at(0);
|
||||
@ -474,6 +473,7 @@ void NativeJump::check_verified_entry_alignment(address entry, address verified_
|
||||
//
|
||||
// In C2 the 5+ byte sized instruction is enforced by code in MachPrologNode::emit.
|
||||
// In C1 the restriction is enforced by CodeEmitter::method_entry
|
||||
// In JVMCI, the restriction is enforced by HotSpotFrameContext.enter(...)
|
||||
//
|
||||
void NativeJump::patch_verified_entry(address entry, address verified_entry, address dest) {
|
||||
// complete jump instruction (to be inserted) is in code_buffer;
|
||||
|
@ -60,6 +60,7 @@ class NativeInstruction VALUE_OBJ_CLASS_SPEC {
|
||||
|
||||
bool is_nop() { return ubyte_at(0) == nop_instruction_code; }
|
||||
inline bool is_call();
|
||||
inline bool is_call_reg();
|
||||
inline bool is_illegal();
|
||||
inline bool is_return();
|
||||
inline bool is_jump();
|
||||
@ -180,6 +181,24 @@ inline NativeCall* nativeCall_before(address return_address) {
|
||||
return call;
|
||||
}
|
||||
|
||||
class NativeCallReg: public NativeInstruction {
|
||||
public:
|
||||
enum Intel_specific_constants {
|
||||
instruction_code = 0xFF,
|
||||
instruction_offset = 0,
|
||||
return_address_offset_norex = 2,
|
||||
return_address_offset_rex = 3
|
||||
};
|
||||
|
||||
int next_instruction_offset() const {
|
||||
if (ubyte_at(0) == NativeCallReg::instruction_code) {
|
||||
return return_address_offset_norex;
|
||||
} else {
|
||||
return return_address_offset_rex;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// An interface for accessing/manipulating native mov reg, imm32 instructions.
|
||||
// (used to manipulate inlined 32bit data dll calls, etc.)
|
||||
class NativeMovConstReg: public NativeInstruction {
|
||||
@ -519,6 +538,9 @@ class NativeTstRegMem: public NativeInstruction {
|
||||
|
||||
inline bool NativeInstruction::is_illegal() { return (short)int_at(0) == (short)NativeIllegalInstruction::instruction_code; }
|
||||
inline bool NativeInstruction::is_call() { return ubyte_at(0) == NativeCall::instruction_code; }
|
||||
inline bool NativeInstruction::is_call_reg() { return ubyte_at(0) == NativeCallReg::instruction_code ||
|
||||
(ubyte_at(1) == NativeCallReg::instruction_code &&
|
||||
(ubyte_at(0) == Assembler::REX || ubyte_at(0) == Assembler::REX_B)); }
|
||||
inline bool NativeInstruction::is_return() { return ubyte_at(0) == NativeReturn::instruction_code ||
|
||||
ubyte_at(0) == NativeReturnX::instruction_code; }
|
||||
inline bool NativeInstruction::is_jump() { return ubyte_at(0) == NativeJump::instruction_code ||
|
||||
@ -527,26 +549,24 @@ inline bool NativeInstruction::is_cond_jump() { return (int_at(0) & 0xF0FF) =
|
||||
(ubyte_at(0) & 0xF0) == 0x70; /* short jump */ }
|
||||
inline bool NativeInstruction::is_safepoint_poll() {
|
||||
#ifdef AMD64
|
||||
if (Assembler::is_polling_page_far()) {
|
||||
// two cases, depending on the choice of the base register in the address.
|
||||
if (((ubyte_at(0) & NativeTstRegMem::instruction_rex_prefix_mask) == NativeTstRegMem::instruction_rex_prefix &&
|
||||
ubyte_at(1) == NativeTstRegMem::instruction_code_memXregl &&
|
||||
(ubyte_at(2) & NativeTstRegMem::modrm_mask) == NativeTstRegMem::modrm_reg) ||
|
||||
ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl &&
|
||||
(ubyte_at(1) & NativeTstRegMem::modrm_mask) == NativeTstRegMem::modrm_reg) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl &&
|
||||
ubyte_at(1) == 0x05) { // 00 rax 101
|
||||
address fault = addr_at(6) + int_at(2);
|
||||
return os::is_poll_address(fault);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
// Try decoding a near safepoint first:
|
||||
if (ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl &&
|
||||
ubyte_at(1) == 0x05) { // 00 rax 101
|
||||
address fault = addr_at(6) + int_at(2);
|
||||
NOT_JVMCI(assert(!Assembler::is_polling_page_far(), "unexpected poll encoding");)
|
||||
return os::is_poll_address(fault);
|
||||
}
|
||||
// Now try decoding a far safepoint:
|
||||
// two cases, depending on the choice of the base register in the address.
|
||||
if (((ubyte_at(0) & NativeTstRegMem::instruction_rex_prefix_mask) == NativeTstRegMem::instruction_rex_prefix &&
|
||||
ubyte_at(1) == NativeTstRegMem::instruction_code_memXregl &&
|
||||
(ubyte_at(2) & NativeTstRegMem::modrm_mask) == NativeTstRegMem::modrm_reg) ||
|
||||
ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl &&
|
||||
(ubyte_at(1) & NativeTstRegMem::modrm_mask) == NativeTstRegMem::modrm_reg) {
|
||||
NOT_JVMCI(assert(Assembler::is_polling_page_far(), "unexpected poll encoding");)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#else
|
||||
return ( ubyte_at(0) == NativeMovRegMem::instruction_code_mem2reg ||
|
||||
ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl ) &&
|
||||
|
51
hotspot/src/cpu/x86/vm/registerMap_x86.cpp
Normal file
51
hotspot/src/cpu/x86/vm/registerMap_x86.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "runtime/registerMap.hpp"
|
||||
#include "vmreg_x86.inline.hpp"
|
||||
|
||||
address RegisterMap::pd_location(VMReg reg) const {
|
||||
if (reg->is_XMMRegister()) {
|
||||
int regBase = reg->value() - ConcreteRegisterImpl::max_fpr;
|
||||
if (regBase % 4 == 0) {
|
||||
// Reads of the low and high 16 byte parts should be handled by location itself
|
||||
// because they have separate callee saved entries.
|
||||
// See RegisterSaver::save_live_registers().
|
||||
return NULL;
|
||||
}
|
||||
VMReg baseReg = as_XMMRegister(regBase / XMMRegisterImpl::max_slots_per_register)->as_VMReg();
|
||||
intptr_t offset = (reg->value() - baseReg->value()) * VMRegImpl::stack_slot_size; // offset in bytes
|
||||
if (offset >= 16) {
|
||||
// The high part of YMM registers are saved in a their own area in the frame
|
||||
baseReg = baseReg->next()->next()->next()->next();
|
||||
offset -= 16;
|
||||
}
|
||||
address baseLocation = location(baseReg);
|
||||
if (baseLocation != NULL) {
|
||||
return baseLocation + offset;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
@ -31,11 +31,7 @@
|
||||
private:
|
||||
// This is the hook for finding a register in an "well-known" location,
|
||||
// such as a register block of a predetermined format.
|
||||
// Since there is none, we just return NULL.
|
||||
// See registerMap_sparc.hpp for an example of grabbing registers
|
||||
// from register save areas of a standard layout.
|
||||
address pd_location(VMReg reg) const {return NULL;}
|
||||
|
||||
address pd_location(VMReg reg) const;
|
||||
// no PD state to clear or copy:
|
||||
void pd_clear() {}
|
||||
void pd_initialize() {}
|
||||
|
@ -69,6 +69,31 @@ const char* XMMRegisterImpl::name() const {
|
||||
return is_valid() ? names[encoding()] : "xnoreg";
|
||||
}
|
||||
|
||||
const char* XMMRegisterImpl::sub_word_name(int i) const {
|
||||
const char* names[number_of_registers * 8] = {
|
||||
"xmm0:0", "xmm0:1", "xmm0:2", "xmm0:3", "xmm0:4", "xmm0:5", "xmm0:6", "xmm0:7",
|
||||
"xmm1:0", "xmm1:1", "xmm1:2", "xmm1:3", "xmm1:4", "xmm1:5", "xmm1:6", "xmm1:7",
|
||||
"xmm2:0", "xmm2:1", "xmm2:2", "xmm2:3", "xmm2:4", "xmm2:5", "xmm2:6", "xmm2:7",
|
||||
"xmm3:0", "xmm3:1", "xmm3:2", "xmm3:3", "xmm3:4", "xmm3:5", "xmm3:6", "xmm3:7",
|
||||
"xmm4:0", "xmm4:1", "xmm4:2", "xmm4:3", "xmm4:4", "xmm4:5", "xmm4:6", "xmm4:7",
|
||||
"xmm5:0", "xmm5:1", "xmm5:2", "xmm5:3", "xmm5:4", "xmm5:5", "xmm5:6", "xmm5:7",
|
||||
"xmm6:0", "xmm6:1", "xmm6:2", "xmm6:3", "xmm6:4", "xmm6:5", "xmm6:6", "xmm6:7",
|
||||
"xmm7:0", "xmm7:1", "xmm7:2", "xmm7:3", "xmm7:4", "xmm7:5", "xmm7:6", "xmm7:7",
|
||||
#ifdef AMD64
|
||||
"xmm8:0", "xmm8:1", "xmm8:2", "xmm8:3", "xmm8:4", "xmm8:5", "xmm8:6", "xmm8:7",
|
||||
"xmm9:0", "xmm9:1", "xmm9:2", "xmm9:3", "xmm9:4", "xmm9:5", "xmm9:6", "xmm9:7",
|
||||
"xmm10:0", "xmm10:1", "xmm10:2", "xmm10:3", "xmm10:4", "xmm10:5", "xmm10:6", "xmm10:7",
|
||||
"xmm11:0", "xmm11:1", "xmm11:2", "xmm11:3", "xmm11:4", "xmm11:5", "xmm11:6", "xmm11:7",
|
||||
"xmm12:0", "xmm12:1", "xmm12:2", "xmm12:3", "xmm12:4", "xmm12:5", "xmm12:6", "xmm12:7",
|
||||
"xmm13:0", "xmm13:1", "xmm13:2", "xmm13:3", "xmm13:4", "xmm13:5", "xmm13:6", "xmm13:7",
|
||||
"xmm14:0", "xmm14:1", "xmm14:2", "xmm14:3", "xmm14:4", "xmm14:5", "xmm14:6", "xmm14:7",
|
||||
"xmm15:0", "xmm15:1", "xmm15:2", "xmm15:3", "xmm15:4", "xmm15:5", "xmm15:6", "xmm15:7",
|
||||
#endif // AMD64
|
||||
};
|
||||
assert(i >= 0 && i < 8, "offset too large");
|
||||
return is_valid() ? names[encoding() * 8 + i] : "xnoreg";
|
||||
}
|
||||
|
||||
const char* KRegisterImpl::name() const {
|
||||
const char* names[number_of_registers] = {
|
||||
"k0", "k1", "k2", "k3", "k4", "k5", "k6", "k7"
|
||||
|
@ -165,6 +165,7 @@ class XMMRegisterImpl: public AbstractRegisterImpl {
|
||||
int encoding() const { assert(is_valid(), err_msg("invalid register (%d)", (int)(intptr_t)this )); return (intptr_t)this; }
|
||||
bool is_valid() const { return 0 <= (intptr_t)this && (intptr_t)this < number_of_registers; }
|
||||
const char* name() const;
|
||||
const char* sub_word_name(int offset) const;
|
||||
};
|
||||
|
||||
|
||||
|
@ -180,39 +180,17 @@ address Relocation::pd_get_address_from_code() {
|
||||
|
||||
void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) {
|
||||
#ifdef _LP64
|
||||
if (!Assembler::is_polling_page_far()) {
|
||||
typedef Assembler::WhichOperand WhichOperand;
|
||||
WhichOperand which = (WhichOperand) format();
|
||||
// This format is imm but it is really disp32
|
||||
which = Assembler::disp32_operand;
|
||||
typedef Assembler::WhichOperand WhichOperand;
|
||||
WhichOperand which = (WhichOperand) format();
|
||||
#if !INCLUDE_JVMCI
|
||||
assert((which == Assembler::disp32_operand) == !Assembler::is_polling_page_far(), "format not set correctly");
|
||||
#endif
|
||||
if (which == Assembler::disp32_operand) {
|
||||
address orig_addr = old_addr_for(addr(), src, dest);
|
||||
NativeInstruction* oni = nativeInstruction_at(orig_addr);
|
||||
int32_t* orig_disp = (int32_t*) Assembler::locate_operand(orig_addr, which);
|
||||
// This poll_addr is incorrect by the size of the instruction it is irrelevant
|
||||
intptr_t poll_addr = (intptr_t)oni + *orig_disp;
|
||||
|
||||
NativeInstruction* ni = nativeInstruction_at(addr());
|
||||
intptr_t new_disp = poll_addr - (intptr_t) ni;
|
||||
|
||||
int32_t* disp = (int32_t*) Assembler::locate_operand(addr(), which);
|
||||
* disp = (int32_t)new_disp;
|
||||
}
|
||||
#endif // _LP64
|
||||
}
|
||||
|
||||
void poll_return_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) {
|
||||
#ifdef _LP64
|
||||
if (!Assembler::is_polling_page_far()) {
|
||||
typedef Assembler::WhichOperand WhichOperand;
|
||||
WhichOperand which = (WhichOperand) format();
|
||||
// This format is imm but it is really disp32
|
||||
which = Assembler::disp32_operand;
|
||||
address orig_addr = old_addr_for(addr(), src, dest);
|
||||
NativeInstruction* oni = nativeInstruction_at(orig_addr);
|
||||
int32_t* orig_disp = (int32_t*) Assembler::locate_operand(orig_addr, which);
|
||||
// This poll_addr is incorrect by the size of the instruction it is irrelevant
|
||||
intptr_t poll_addr = (intptr_t)oni + *orig_disp;
|
||||
|
||||
NativeInstruction* ni = nativeInstruction_at(addr());
|
||||
intptr_t new_disp = poll_addr - (intptr_t) ni;
|
||||
|
||||
|
@ -699,12 +699,11 @@ static void range_check(MacroAssembler* masm, Register pc_reg, Register temp_reg
|
||||
__ bind(L_fail);
|
||||
}
|
||||
|
||||
static void gen_i2c_adapter(MacroAssembler *masm,
|
||||
int total_args_passed,
|
||||
int comp_args_on_stack,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs) {
|
||||
|
||||
void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm,
|
||||
int total_args_passed,
|
||||
int comp_args_on_stack,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs) {
|
||||
// Note: rsi contains the senderSP on entry. We must preserve it since
|
||||
// we may do a i2c -> c2i transition if we lose a race where compiled
|
||||
// code goes non-entrant while we get args ready.
|
||||
|
@ -43,6 +43,9 @@
|
||||
#ifdef COMPILER2
|
||||
#include "opto/runtime.hpp"
|
||||
#endif
|
||||
#if INCLUDE_JVMCI
|
||||
#include "jvmci/jvmciJavaClasses.hpp"
|
||||
#endif
|
||||
|
||||
#define __ masm->
|
||||
|
||||
@ -158,23 +161,25 @@ class RegisterSaver {
|
||||
|
||||
OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_frame_words, int* total_frame_words, bool save_vectors) {
|
||||
int vect_words = 0;
|
||||
int ymmhi_offset = -1;
|
||||
int off = 0;
|
||||
int num_xmm_regs = XMMRegisterImpl::number_of_registers;
|
||||
if (UseAVX < 3) {
|
||||
num_xmm_regs = num_xmm_regs/2;
|
||||
}
|
||||
#ifdef COMPILER2
|
||||
#if defined(COMPILER2) || INCLUDE_JVMCI
|
||||
if (save_vectors) {
|
||||
assert(UseAVX > 0, "512bit vectors are supported only with EVEX");
|
||||
assert(MaxVectorSize == 64, "only 512bit vectors are supported now");
|
||||
// Save upper half of YMM registers
|
||||
vect_words = 16 * num_xmm_regs / wordSize;
|
||||
if (UseAVX < 3) {
|
||||
ymmhi_offset = additional_frame_words;
|
||||
additional_frame_words += vect_words;
|
||||
}
|
||||
}
|
||||
#else
|
||||
assert(!save_vectors, "vectors are generated only by C2");
|
||||
assert(!save_vectors, "vectors are generated only by C2 and JVMCI");
|
||||
#endif
|
||||
|
||||
// Always make the frame size 16-byte aligned
|
||||
@ -220,6 +225,7 @@ OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_
|
||||
OopMap* map = new OopMap(frame_size_in_slots, 0);
|
||||
|
||||
#define STACK_OFFSET(x) VMRegImpl::stack2reg((x) + additional_frame_slots)
|
||||
#define YMMHI_STACK_OFFSET(x) VMRegImpl::stack2reg((x / VMRegImpl::stack_slot_size) + ymmhi_offset)
|
||||
|
||||
map->set_callee_saved(STACK_OFFSET( rax_off ), rax->as_VMReg());
|
||||
map->set_callee_saved(STACK_OFFSET( rcx_off ), rcx->as_VMReg());
|
||||
@ -257,6 +263,28 @@ OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(COMPILER2) || INCLUDE_JVMCI
|
||||
if (save_vectors) {
|
||||
assert(ymmhi_offset != -1, "save area must exist");
|
||||
map->set_callee_saved(YMMHI_STACK_OFFSET( 0), xmm0->as_VMReg()->next(4));
|
||||
map->set_callee_saved(YMMHI_STACK_OFFSET( 16), xmm1->as_VMReg()->next(4));
|
||||
map->set_callee_saved(YMMHI_STACK_OFFSET( 32), xmm2->as_VMReg()->next(4));
|
||||
map->set_callee_saved(YMMHI_STACK_OFFSET( 48), xmm3->as_VMReg()->next(4));
|
||||
map->set_callee_saved(YMMHI_STACK_OFFSET( 64), xmm4->as_VMReg()->next(4));
|
||||
map->set_callee_saved(YMMHI_STACK_OFFSET( 80), xmm5->as_VMReg()->next(4));
|
||||
map->set_callee_saved(YMMHI_STACK_OFFSET( 96), xmm6->as_VMReg()->next(4));
|
||||
map->set_callee_saved(YMMHI_STACK_OFFSET(112), xmm7->as_VMReg()->next(4));
|
||||
map->set_callee_saved(YMMHI_STACK_OFFSET(128), xmm8->as_VMReg()->next(4));
|
||||
map->set_callee_saved(YMMHI_STACK_OFFSET(144), xmm9->as_VMReg()->next(4));
|
||||
map->set_callee_saved(YMMHI_STACK_OFFSET(160), xmm10->as_VMReg()->next(4));
|
||||
map->set_callee_saved(YMMHI_STACK_OFFSET(176), xmm11->as_VMReg()->next(4));
|
||||
map->set_callee_saved(YMMHI_STACK_OFFSET(192), xmm12->as_VMReg()->next(4));
|
||||
map->set_callee_saved(YMMHI_STACK_OFFSET(208), xmm13->as_VMReg()->next(4));
|
||||
map->set_callee_saved(YMMHI_STACK_OFFSET(224), xmm14->as_VMReg()->next(4));
|
||||
map->set_callee_saved(YMMHI_STACK_OFFSET(240), xmm15->as_VMReg()->next(4));
|
||||
}
|
||||
#endif // COMPILER2 || INCLUDE_JVMCI
|
||||
|
||||
// %%% These should all be a waste but we'll keep things as they were for now
|
||||
if (true) {
|
||||
map->set_callee_saved(STACK_OFFSET( raxH_off ), rax->as_VMReg()->next());
|
||||
@ -307,7 +335,7 @@ void RegisterSaver::restore_live_registers(MacroAssembler* masm, bool restore_ve
|
||||
// Pop arg register save area
|
||||
__ addptr(rsp, frame::arg_reg_save_area_bytes);
|
||||
}
|
||||
#ifdef COMPILER2
|
||||
#if defined(COMPILER2) || INCLUDE_JVMCI
|
||||
// On EVEX enabled targets everything is handled in pop fpu state
|
||||
if ((restore_vectors) && (UseAVX < 3)) {
|
||||
assert(UseAVX > 0, "256/512-bit vectors are supported only with AVX");
|
||||
@ -320,7 +348,7 @@ void RegisterSaver::restore_live_registers(MacroAssembler* masm, bool restore_ve
|
||||
__ addptr(rsp, num_xmm_regs*16);
|
||||
}
|
||||
#else
|
||||
assert(!restore_vectors, "vectors are generated only by C2");
|
||||
assert(!restore_vectors, "vectors are generated only by C2 and JVMCI");
|
||||
#endif
|
||||
// Recover CPU state
|
||||
__ pop_CPU_state();
|
||||
@ -655,11 +683,11 @@ static void range_check(MacroAssembler* masm, Register pc_reg, Register temp_reg
|
||||
__ bind(L_fail);
|
||||
}
|
||||
|
||||
static void gen_i2c_adapter(MacroAssembler *masm,
|
||||
int total_args_passed,
|
||||
int comp_args_on_stack,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs) {
|
||||
void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm,
|
||||
int total_args_passed,
|
||||
int comp_args_on_stack,
|
||||
const BasicType *sig_bt,
|
||||
const VMRegPair *regs) {
|
||||
|
||||
// Note: r13 contains the senderSP on entry. We must preserve it since
|
||||
// we may do a i2c -> c2i transition if we lose a race where compiled
|
||||
@ -752,6 +780,18 @@ static void gen_i2c_adapter(MacroAssembler *masm,
|
||||
// Pre-load the register-jump target early, to schedule it better.
|
||||
__ movptr(r11, Address(rbx, in_bytes(Method::from_compiled_offset())));
|
||||
|
||||
#if INCLUDE_JVMCI
|
||||
if (EnableJVMCI) {
|
||||
// check if this call should be routed towards a specific entry point
|
||||
__ cmpptr(Address(r15_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset())), 0);
|
||||
Label no_alternative_target;
|
||||
__ jcc(Assembler::equal, no_alternative_target);
|
||||
__ movptr(r11, Address(r15_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset())));
|
||||
__ movptr(Address(r15_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset())), 0);
|
||||
__ bind(no_alternative_target);
|
||||
}
|
||||
#endif // INCLUDE_JVMCI
|
||||
|
||||
// Now generate the shuffle code. Pick up all register args and move the
|
||||
// rest through the floating point stack top.
|
||||
for (int i = 0; i < total_args_passed; i++) {
|
||||
@ -2685,7 +2725,13 @@ void SharedRuntime::generate_deopt_blob() {
|
||||
// Allocate space for the code
|
||||
ResourceMark rm;
|
||||
// Setup code generation tools
|
||||
CodeBuffer buffer("deopt_blob", 2048, 1024);
|
||||
int pad = 0;
|
||||
#if INCLUDE_JVMCI
|
||||
if (EnableJVMCI) {
|
||||
pad += 512; // Increase the buffer size when compiling for JVMCI
|
||||
}
|
||||
#endif
|
||||
CodeBuffer buffer("deopt_blob", 2048+pad, 1024);
|
||||
MacroAssembler* masm = new MacroAssembler(&buffer);
|
||||
int frame_size_in_words;
|
||||
OopMap* map = NULL;
|
||||
@ -2734,6 +2780,12 @@ void SharedRuntime::generate_deopt_blob() {
|
||||
__ jmp(cont);
|
||||
|
||||
int reexecute_offset = __ pc() - start;
|
||||
#if INCLUDE_JVMCI && !defined(COMPILER1)
|
||||
if (EnableJVMCI && UseJVMCICompiler) {
|
||||
// JVMCI does not use this kind of deoptimization
|
||||
__ should_not_reach_here();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Reexecute case
|
||||
// return address is the pc describes what bci to do re-execute at
|
||||
@ -2744,6 +2796,38 @@ void SharedRuntime::generate_deopt_blob() {
|
||||
__ movl(r14, Deoptimization::Unpack_reexecute); // callee-saved
|
||||
__ jmp(cont);
|
||||
|
||||
#if INCLUDE_JVMCI
|
||||
Label after_fetch_unroll_info_call;
|
||||
int implicit_exception_uncommon_trap_offset = 0;
|
||||
int uncommon_trap_offset = 0;
|
||||
|
||||
if (EnableJVMCI) {
|
||||
implicit_exception_uncommon_trap_offset = __ pc() - start;
|
||||
|
||||
__ pushptr(Address(r15_thread, in_bytes(JavaThread::jvmci_implicit_exception_pc_offset())));
|
||||
__ movptr(Address(r15_thread, in_bytes(JavaThread::jvmci_implicit_exception_pc_offset())), (int32_t)NULL_WORD);
|
||||
|
||||
uncommon_trap_offset = __ pc() - start;
|
||||
|
||||
// Save everything in sight.
|
||||
RegisterSaver::save_live_registers(masm, 0, &frame_size_in_words);
|
||||
// fetch_unroll_info needs to call last_java_frame()
|
||||
__ set_last_Java_frame(noreg, noreg, NULL);
|
||||
|
||||
__ movl(c_rarg1, Address(r15_thread, in_bytes(JavaThread::pending_deoptimization_offset())));
|
||||
__ movl(Address(r15_thread, in_bytes(JavaThread::pending_deoptimization_offset())), -1);
|
||||
|
||||
__ movl(r14, (int32_t)Deoptimization::Unpack_reexecute);
|
||||
__ mov(c_rarg0, r15_thread);
|
||||
__ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap)));
|
||||
oop_maps->add_gc_map( __ pc()-start, map->deep_copy());
|
||||
|
||||
__ reset_last_Java_frame(false, false);
|
||||
|
||||
__ jmp(after_fetch_unroll_info_call);
|
||||
} // EnableJVMCI
|
||||
#endif // INCLUDE_JVMCI
|
||||
|
||||
int exception_offset = __ pc() - start;
|
||||
|
||||
// Prolog for exception case
|
||||
@ -2829,6 +2913,12 @@ void SharedRuntime::generate_deopt_blob() {
|
||||
|
||||
__ reset_last_Java_frame(false, false);
|
||||
|
||||
#if INCLUDE_JVMCI
|
||||
if (EnableJVMCI) {
|
||||
__ bind(after_fetch_unroll_info_call);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Load UnrollBlock* into rdi
|
||||
__ mov(rdi, rax);
|
||||
|
||||
@ -3003,6 +3093,12 @@ void SharedRuntime::generate_deopt_blob() {
|
||||
|
||||
_deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, reexecute_offset, frame_size_in_words);
|
||||
_deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset);
|
||||
#if INCLUDE_JVMCI
|
||||
if (EnableJVMCI) {
|
||||
_deopt_blob->set_uncommon_trap_offset(uncommon_trap_offset);
|
||||
_deopt_blob->set_implicit_exception_uncommon_trap_offset(implicit_exception_uncommon_trap_offset);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef COMPILER2
|
||||
|
@ -538,7 +538,7 @@ void InterpreterGenerator::generate_stack_overflow_check(void) {
|
||||
// Allocate monitor and lock method (asm interpreter)
|
||||
// rbx, - Method*
|
||||
//
|
||||
void InterpreterGenerator::lock_method(void) {
|
||||
void TemplateInterpreterGenerator::lock_method() {
|
||||
// synchronize method
|
||||
const Address access_flags (rbx, Method::access_flags_offset());
|
||||
const Address monitor_block_top (rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize);
|
||||
|
@ -198,13 +198,27 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state,
|
||||
}
|
||||
|
||||
|
||||
address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state,
|
||||
int step) {
|
||||
address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state, int step) {
|
||||
address entry = __ pc();
|
||||
// NULL last_sp until next java call
|
||||
__ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD);
|
||||
__ restore_bcp();
|
||||
__ restore_locals();
|
||||
#if INCLUDE_JVMCI
|
||||
// Check if we need to take lock at entry of synchronized method.
|
||||
if (UseJVMCICompiler) {
|
||||
Label L;
|
||||
__ cmpb(Address(r15_thread, JavaThread::pending_monitorenter_offset()), 0);
|
||||
__ jcc(Assembler::zero, L);
|
||||
// Clear flag.
|
||||
__ movb(Address(r15_thread, JavaThread::pending_monitorenter_offset()), 0);
|
||||
// Satisfy calling convention for lock_method().
|
||||
__ get_method(rbx);
|
||||
// Take lock.
|
||||
lock_method();
|
||||
__ bind(L);
|
||||
}
|
||||
#endif
|
||||
// handle exceptions
|
||||
{
|
||||
Label L;
|
||||
@ -500,7 +514,7 @@ void InterpreterGenerator::generate_stack_overflow_check(void) {
|
||||
// rax
|
||||
// c_rarg0, c_rarg1, c_rarg2, c_rarg3, ...(param regs)
|
||||
// rscratch1, rscratch2 (scratch regs)
|
||||
void InterpreterGenerator::lock_method(void) {
|
||||
void TemplateInterpreterGenerator::lock_method() {
|
||||
// synchronize method
|
||||
const Address access_flags(rbx, Method::access_flags_offset());
|
||||
const Address monitor_block_top(
|
||||
|
@ -3595,6 +3595,8 @@ void TemplateTable::invokevirtual_helper(Register index,
|
||||
__ profile_virtual_call(rax, rlocals, rdx);
|
||||
// get target Method* & entry point
|
||||
__ lookup_virtual_method(rax, index, method);
|
||||
__ profile_called_method(method, rdx, rbcp);
|
||||
|
||||
__ profile_arguments_type(rdx, method, rbcp, true);
|
||||
__ jump_from_interpreted(method, rdx);
|
||||
}
|
||||
@ -3694,6 +3696,7 @@ void TemplateTable::invokeinterface(int byte_no) {
|
||||
__ testptr(rbx, rbx);
|
||||
__ jcc(Assembler::zero, no_such_method);
|
||||
|
||||
__ profile_called_method(rbx, rbcp, rdx);
|
||||
__ profile_arguments_type(rdx, rbx, rbcp, true);
|
||||
|
||||
// do the call
|
||||
|
@ -37,13 +37,50 @@
|
||||
/******************************/ \
|
||||
/* JavaFrameAnchor */ \
|
||||
/******************************/ \
|
||||
volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*)
|
||||
volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*) \
|
||||
static_field(VM_Version, _cpuFeatures, uint64_t)
|
||||
|
||||
|
||||
|
||||
#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type)
|
||||
#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \
|
||||
declare_toplevel_type(VM_Version)
|
||||
|
||||
#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
|
||||
#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \
|
||||
LP64_ONLY(declare_constant(frame::arg_reg_save_area_bytes)) \
|
||||
declare_constant(frame::interpreter_frame_sender_sp_offset) \
|
||||
declare_constant(frame::interpreter_frame_last_sp_offset) \
|
||||
declare_constant(VM_Version::CPU_CX8) \
|
||||
declare_constant(VM_Version::CPU_CMOV) \
|
||||
declare_constant(VM_Version::CPU_FXSR) \
|
||||
declare_constant(VM_Version::CPU_HT) \
|
||||
declare_constant(VM_Version::CPU_MMX) \
|
||||
declare_constant(VM_Version::CPU_3DNOW_PREFETCH) \
|
||||
declare_constant(VM_Version::CPU_SSE) \
|
||||
declare_constant(VM_Version::CPU_SSE2) \
|
||||
declare_constant(VM_Version::CPU_SSE3) \
|
||||
declare_constant(VM_Version::CPU_SSSE3) \
|
||||
declare_constant(VM_Version::CPU_SSE4A) \
|
||||
declare_constant(VM_Version::CPU_SSE4_1) \
|
||||
declare_constant(VM_Version::CPU_SSE4_2) \
|
||||
declare_constant(VM_Version::CPU_POPCNT) \
|
||||
declare_constant(VM_Version::CPU_LZCNT) \
|
||||
declare_constant(VM_Version::CPU_TSC) \
|
||||
declare_constant(VM_Version::CPU_TSCINV) \
|
||||
declare_constant(VM_Version::CPU_AVX) \
|
||||
declare_constant(VM_Version::CPU_AVX2) \
|
||||
declare_constant(VM_Version::CPU_AES) \
|
||||
declare_constant(VM_Version::CPU_ERMS) \
|
||||
declare_constant(VM_Version::CPU_CLMUL) \
|
||||
declare_constant(VM_Version::CPU_BMI1) \
|
||||
declare_constant(VM_Version::CPU_BMI2) \
|
||||
declare_constant(VM_Version::CPU_RTM) \
|
||||
declare_constant(VM_Version::CPU_ADX) \
|
||||
declare_constant(VM_Version::CPU_AVX512F) \
|
||||
declare_constant(VM_Version::CPU_AVX512DQ) \
|
||||
declare_constant(VM_Version::CPU_AVX512PF) \
|
||||
declare_constant(VM_Version::CPU_AVX512ER) \
|
||||
declare_constant(VM_Version::CPU_AVX512CD) \
|
||||
declare_constant(VM_Version::CPU_AVX512BW)
|
||||
|
||||
#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
|
||||
|
||||
|
@ -787,6 +787,8 @@ void VM_Version::get_processor_features() {
|
||||
FLAG_SET_DEFAULT(UseFPUForSpilling, false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if defined(COMPILER2) || INCLUDE_JVMCI
|
||||
if (MaxVectorSize > 0) {
|
||||
if (!is_power_of_2(MaxVectorSize)) {
|
||||
warning("MaxVectorSize must be a power of 2");
|
||||
@ -803,7 +805,7 @@ void VM_Version::get_processor_features() {
|
||||
// Vectors (in XMM) are only supported with SSE2+
|
||||
FLAG_SET_DEFAULT(MaxVectorSize, 0);
|
||||
}
|
||||
#ifdef ASSERT
|
||||
#if defined(COMPILER2) && defined(ASSERT)
|
||||
if (supports_avx() && PrintMiscellaneous && Verbose && TraceNewVectors) {
|
||||
tty->print_cr("State of YMM registers after signal handle:");
|
||||
int nreg = 2 LP64_ONLY(+2);
|
||||
@ -816,9 +818,11 @@ void VM_Version::get_processor_features() {
|
||||
tty->cr();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif // COMPILER2 && ASSERT
|
||||
}
|
||||
#endif // COMPILER2 || INCLUDE_JVMCI
|
||||
|
||||
#ifdef COMPILER2
|
||||
#ifdef _LP64
|
||||
if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) {
|
||||
UseMultiplyToLenIntrinsic = true;
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "runtime/vm_version.hpp"
|
||||
|
||||
class VM_Version : public Abstract_VM_Version {
|
||||
friend class VMStructs;
|
||||
public:
|
||||
// cpuid result register layouts. These are all unions of a uint32_t
|
||||
// (in case anyone wants access to the register as a whole) and a bitfield.
|
||||
|
@ -2136,12 +2136,13 @@ encode %{
|
||||
RELOC_DISP32);
|
||||
}
|
||||
if (_method) {
|
||||
// Emit stub for static call.
|
||||
address stub = CompiledStaticCall::emit_to_interp_stub(cbuf);
|
||||
// Emit stubs for static call.
|
||||
address mark = cbuf.insts_mark();
|
||||
address stub = CompiledStaticCall::emit_to_interp_stub(cbuf, mark);
|
||||
if (stub == NULL) {
|
||||
ciEnv::current()->record_failure("CodeCache is full");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
%}
|
||||
|
||||
|
@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.vm.ci.amd64;
|
||||
|
||||
import static jdk.vm.ci.code.MemoryBarriers.*;
|
||||
import static jdk.vm.ci.code.Register.*;
|
||||
|
||||
import java.nio.*;
|
||||
import java.util.*;
|
||||
|
||||
import jdk.vm.ci.code.*;
|
||||
import jdk.vm.ci.code.Register.RegisterCategory;
|
||||
import jdk.vm.ci.meta.*;
|
||||
|
||||
/**
|
||||
* Represents the AMD64 architecture.
|
||||
*/
|
||||
public class AMD64 extends Architecture {
|
||||
|
||||
public static final RegisterCategory CPU = new RegisterCategory("CPU");
|
||||
|
||||
// @formatter:off
|
||||
|
||||
// General purpose CPU registers
|
||||
public static final Register rax = new Register(0, 0, "rax", CPU);
|
||||
public static final Register rcx = new Register(1, 1, "rcx", CPU);
|
||||
public static final Register rdx = new Register(2, 2, "rdx", CPU);
|
||||
public static final Register rbx = new Register(3, 3, "rbx", CPU);
|
||||
public static final Register rsp = new Register(4, 4, "rsp", CPU);
|
||||
public static final Register rbp = new Register(5, 5, "rbp", CPU);
|
||||
public static final Register rsi = new Register(6, 6, "rsi", CPU);
|
||||
public static final Register rdi = new Register(7, 7, "rdi", CPU);
|
||||
|
||||
public static final Register r8 = new Register(8, 8, "r8", CPU);
|
||||
public static final Register r9 = new Register(9, 9, "r9", CPU);
|
||||
public static final Register r10 = new Register(10, 10, "r10", CPU);
|
||||
public static final Register r11 = new Register(11, 11, "r11", CPU);
|
||||
public static final Register r12 = new Register(12, 12, "r12", CPU);
|
||||
public static final Register r13 = new Register(13, 13, "r13", CPU);
|
||||
public static final Register r14 = new Register(14, 14, "r14", CPU);
|
||||
public static final Register r15 = new Register(15, 15, "r15", CPU);
|
||||
|
||||
public static final Register[] cpuRegisters = {
|
||||
rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi,
|
||||
r8, r9, r10, r11, r12, r13, r14, r15
|
||||
};
|
||||
|
||||
private static final int XMM_REFERENCE_MAP_SHIFT = 2;
|
||||
|
||||
public static final RegisterCategory XMM = new RegisterCategory("XMM", cpuRegisters.length, XMM_REFERENCE_MAP_SHIFT);
|
||||
|
||||
// XMM registers
|
||||
public static final Register xmm0 = new Register(16, 0, "xmm0", XMM);
|
||||
public static final Register xmm1 = new Register(17, 1, "xmm1", XMM);
|
||||
public static final Register xmm2 = new Register(18, 2, "xmm2", XMM);
|
||||
public static final Register xmm3 = new Register(19, 3, "xmm3", XMM);
|
||||
public static final Register xmm4 = new Register(20, 4, "xmm4", XMM);
|
||||
public static final Register xmm5 = new Register(21, 5, "xmm5", XMM);
|
||||
public static final Register xmm6 = new Register(22, 6, "xmm6", XMM);
|
||||
public static final Register xmm7 = new Register(23, 7, "xmm7", XMM);
|
||||
|
||||
public static final Register xmm8 = new Register(24, 8, "xmm8", XMM);
|
||||
public static final Register xmm9 = new Register(25, 9, "xmm9", XMM);
|
||||
public static final Register xmm10 = new Register(26, 10, "xmm10", XMM);
|
||||
public static final Register xmm11 = new Register(27, 11, "xmm11", XMM);
|
||||
public static final Register xmm12 = new Register(28, 12, "xmm12", XMM);
|
||||
public static final Register xmm13 = new Register(29, 13, "xmm13", XMM);
|
||||
public static final Register xmm14 = new Register(30, 14, "xmm14", XMM);
|
||||
public static final Register xmm15 = new Register(31, 15, "xmm15", XMM);
|
||||
|
||||
public static final Register[] xmmRegisters = {
|
||||
xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
|
||||
xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15
|
||||
};
|
||||
|
||||
public static final Register[] cpuxmmRegisters = {
|
||||
rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi,
|
||||
r8, r9, r10, r11, r12, r13, r14, r15,
|
||||
xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
|
||||
xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15
|
||||
};
|
||||
|
||||
/**
|
||||
* Register used to construct an instruction-relative address.
|
||||
*/
|
||||
public static final Register rip = new Register(32, -1, "rip", SPECIAL);
|
||||
|
||||
public static final Register[] allRegisters = {
|
||||
rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi,
|
||||
r8, r9, r10, r11, r12, r13, r14, r15,
|
||||
xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
|
||||
xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15,
|
||||
rip
|
||||
};
|
||||
|
||||
// @formatter:on
|
||||
|
||||
/**
|
||||
* Basic set of CPU features mirroring what is returned from the cpuid instruction. See:
|
||||
* {@code VM_Version::cpuFeatureFlags}.
|
||||
*/
|
||||
public static enum CPUFeature {
|
||||
CX8,
|
||||
CMOV,
|
||||
FXSR,
|
||||
HT,
|
||||
MMX,
|
||||
AMD_3DNOW_PREFETCH,
|
||||
SSE,
|
||||
SSE2,
|
||||
SSE3,
|
||||
SSSE3,
|
||||
SSE4A,
|
||||
SSE4_1,
|
||||
SSE4_2,
|
||||
POPCNT,
|
||||
LZCNT,
|
||||
TSC,
|
||||
TSCINV,
|
||||
AVX,
|
||||
AVX2,
|
||||
AES,
|
||||
ERMS,
|
||||
CLMUL,
|
||||
BMI1,
|
||||
BMI2,
|
||||
RTM,
|
||||
ADX,
|
||||
AVX512F,
|
||||
AVX512DQ,
|
||||
AVX512PF,
|
||||
AVX512ER,
|
||||
AVX512CD,
|
||||
AVX512BW
|
||||
}
|
||||
|
||||
private final EnumSet<CPUFeature> features;
|
||||
|
||||
/**
|
||||
* Set of flags to control code emission.
|
||||
*/
|
||||
public static enum Flag {
|
||||
UseCountLeadingZerosInstruction,
|
||||
UseCountTrailingZerosInstruction
|
||||
}
|
||||
|
||||
private final EnumSet<Flag> flags;
|
||||
|
||||
public AMD64(EnumSet<CPUFeature> features, EnumSet<Flag> flags) {
|
||||
super("AMD64", JavaKind.Long, ByteOrder.LITTLE_ENDIAN, true, allRegisters, LOAD_STORE | STORE_STORE, 1, cpuRegisters.length + (xmmRegisters.length << XMM_REFERENCE_MAP_SHIFT), 8);
|
||||
this.features = features;
|
||||
this.flags = flags;
|
||||
assert features.contains(CPUFeature.SSE2) : "minimum config for x64";
|
||||
}
|
||||
|
||||
public EnumSet<CPUFeature> getFeatures() {
|
||||
return features;
|
||||
}
|
||||
|
||||
public EnumSet<Flag> getFlags() {
|
||||
return flags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformKind getPlatformKind(JavaKind javaKind) {
|
||||
if (javaKind.isObject()) {
|
||||
return getWordKind();
|
||||
} else {
|
||||
return javaKind;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canStoreValue(RegisterCategory category, PlatformKind platformKind) {
|
||||
if (!(platformKind instanceof JavaKind)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JavaKind kind = (JavaKind) platformKind;
|
||||
if (category.equals(CPU)) {
|
||||
switch (kind) {
|
||||
case Boolean:
|
||||
case Byte:
|
||||
case Char:
|
||||
case Short:
|
||||
case Int:
|
||||
case Long:
|
||||
return true;
|
||||
}
|
||||
} else if (category.equals(XMM)) {
|
||||
switch (kind) {
|
||||
case Float:
|
||||
case Double:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformKind getLargestStorableKind(RegisterCategory category) {
|
||||
if (category.equals(CPU)) {
|
||||
return JavaKind.Long;
|
||||
} else if (category.equals(XMM)) {
|
||||
return JavaKind.Double;
|
||||
} else {
|
||||
return JavaKind.Illegal;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
||||
<html>
|
||||
<head>
|
||||
<!--
|
||||
|
||||
Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
|
||||
This code is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License version 2 only, as
|
||||
published by the Free Software Foundation. Oracle designates this
|
||||
particular file as subject to the "Classpath" exception as provided
|
||||
by Oracle in the LICENSE file that accompanied this code.
|
||||
|
||||
This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
version 2 for more details (a copy is included in the LICENSE file that
|
||||
accompanied this code).
|
||||
|
||||
You should have received a copy of the GNU General Public License version
|
||||
2 along with this work; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
or visit www.oracle.com if you need additional information or have any
|
||||
questions.
|
||||
-->
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
The <code>jdk.vm.ci.code</code> project provides an API to the runtime's native code cache.
|
||||
It allows installation and execution of native code.
|
||||
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.vm.ci.code;
|
||||
|
||||
/**
|
||||
* Abstract base class that represents a platform specific address.
|
||||
*/
|
||||
public abstract class AbstractAddress {
|
||||
}
|
@ -0,0 +1,225 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.vm.ci.code;
|
||||
|
||||
import java.nio.*;
|
||||
import java.util.*;
|
||||
|
||||
import jdk.vm.ci.code.Register.RegisterCategory;
|
||||
import jdk.vm.ci.meta.*;
|
||||
|
||||
/**
|
||||
* Represents a CPU architecture, including information such as its endianness, CPU registers, word
|
||||
* width, etc.
|
||||
*/
|
||||
public abstract class Architecture {
|
||||
|
||||
/**
|
||||
* The number of entries required in a {@link ReferenceMap} covering all the registers that may
|
||||
* store references. The index of a register in the reference map is given by
|
||||
* {@link Register#getReferenceMapIndex()}.
|
||||
*/
|
||||
private final int registerReferenceMapSize;
|
||||
|
||||
/**
|
||||
* The architecture specific type of a native word.
|
||||
*/
|
||||
private final PlatformKind wordKind;
|
||||
|
||||
/**
|
||||
* The name of this architecture (e.g. "AMD64", "SPARCv9").
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* Array of all available registers on this architecture. The index of each register in this
|
||||
* array is equal to its {@linkplain Register#number number}.
|
||||
*/
|
||||
private final Register[] registers;
|
||||
|
||||
/**
|
||||
* The byte ordering can be either little or big endian.
|
||||
*/
|
||||
private final ByteOrder byteOrder;
|
||||
|
||||
/**
|
||||
* Whether the architecture supports unaligned memory accesses.
|
||||
*/
|
||||
private final boolean unalignedMemoryAccess;
|
||||
|
||||
/**
|
||||
* Mask of the barrier constants denoting the barriers that are not required to be explicitly
|
||||
* inserted under this architecture.
|
||||
*/
|
||||
private final int implicitMemoryBarriers;
|
||||
|
||||
/**
|
||||
* Offset in bytes from the beginning of a call instruction to the displacement.
|
||||
*/
|
||||
private final int machineCodeCallDisplacementOffset;
|
||||
|
||||
/**
|
||||
* The size of the return address pushed to the stack by a call instruction. A value of 0
|
||||
* denotes that call linkage uses registers instead (e.g. SPARC).
|
||||
*/
|
||||
private final int returnAddressSize;
|
||||
|
||||
protected Architecture(String name, PlatformKind wordKind, ByteOrder byteOrder, boolean unalignedMemoryAccess, Register[] registers, int implicitMemoryBarriers, int nativeCallDisplacementOffset,
|
||||
int registerReferenceMapSize, int returnAddressSize) {
|
||||
this.name = name;
|
||||
this.registers = registers;
|
||||
this.wordKind = wordKind;
|
||||
this.byteOrder = byteOrder;
|
||||
this.unalignedMemoryAccess = unalignedMemoryAccess;
|
||||
this.implicitMemoryBarriers = implicitMemoryBarriers;
|
||||
this.machineCodeCallDisplacementOffset = nativeCallDisplacementOffset;
|
||||
this.registerReferenceMapSize = registerReferenceMapSize;
|
||||
this.returnAddressSize = returnAddressSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this architecture to a string.
|
||||
*
|
||||
* @return the string representation of this architecture
|
||||
*/
|
||||
@Override
|
||||
public final String toString() {
|
||||
return getName().toLowerCase();
|
||||
}
|
||||
|
||||
public int getRegisterReferenceMapSize() {
|
||||
return registerReferenceMapSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the natural size of words (typically registers and pointers) of this architecture, in
|
||||
* bytes.
|
||||
*/
|
||||
public int getWordSize() {
|
||||
return wordKind.getSizeInBytes();
|
||||
}
|
||||
|
||||
public PlatformKind getWordKind() {
|
||||
return wordKind;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of this architecture.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of all available registers on this architecture. The index of each register in
|
||||
* this array is equal to its {@linkplain Register#number number}.
|
||||
*/
|
||||
public Register[] getRegisters() {
|
||||
return registers.clone();
|
||||
}
|
||||
|
||||
public ByteOrder getByteOrder() {
|
||||
return byteOrder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the architecture supports unaligned memory accesses.
|
||||
*/
|
||||
public boolean supportsUnalignedMemoryAccess() {
|
||||
return unalignedMemoryAccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the size of the return address pushed to the stack by a call instruction. A value of 0
|
||||
* denotes that call linkage uses registers instead.
|
||||
*/
|
||||
public int getReturnAddressSize() {
|
||||
return returnAddressSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the offset in bytes from the beginning of a call instruction to the displacement.
|
||||
*/
|
||||
public int getMachineCodeCallDisplacementOffset() {
|
||||
return machineCodeCallDisplacementOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the barriers in a given barrier mask that are explicitly required on this
|
||||
* architecture.
|
||||
*
|
||||
* @param barriers a mask of the barrier constants
|
||||
* @return the value of {@code barriers} minus the barriers unnecessary on this architecture
|
||||
*/
|
||||
public final int requiredBarriers(int barriers) {
|
||||
return barriers & ~implicitMemoryBarriers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether a kind can be stored in a register of a given category.
|
||||
*
|
||||
* @param category the category of the register
|
||||
* @param kind the kind that should be stored in the register
|
||||
*/
|
||||
public abstract boolean canStoreValue(RegisterCategory category, PlatformKind kind);
|
||||
|
||||
/**
|
||||
* Return the largest kind that can be stored in a register of a given category.
|
||||
*
|
||||
* @param category the category of the register
|
||||
* @return the largest kind that can be stored in a register {@code category}
|
||||
*/
|
||||
public abstract PlatformKind getLargestStorableKind(RegisterCategory category);
|
||||
|
||||
/**
|
||||
* Return the {@link PlatformKind} that is used to store values of a given {@link JavaKind}.
|
||||
*/
|
||||
public abstract PlatformKind getPlatformKind(JavaKind javaKind);
|
||||
|
||||
@Override
|
||||
public final boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof Architecture) {
|
||||
Architecture that = (Architecture) obj;
|
||||
if (this.name.equals(that.name)) {
|
||||
assert this.byteOrder.equals(that.byteOrder);
|
||||
assert this.implicitMemoryBarriers == that.implicitMemoryBarriers;
|
||||
assert this.machineCodeCallDisplacementOffset == that.machineCodeCallDisplacementOffset;
|
||||
assert this.registerReferenceMapSize == that.registerReferenceMapSize;
|
||||
assert Arrays.equals(this.registers, that.registers);
|
||||
assert this.returnAddressSize == that.returnAddressSize;
|
||||
assert this.unalignedMemoryAccess == that.unalignedMemoryAccess;
|
||||
assert this.wordKind == that.wordKind;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return name.hashCode();
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.vm.ci.code;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Exception thrown when the compiler refuses to compile a method because of problems with the
|
||||
* method. e.g. bytecode wouldn't verify, too big, JSR/ret too complicated, etc. This exception is
|
||||
* <i>not</i> meant to indicate problems with the compiler itself.
|
||||
*/
|
||||
public class BailoutException extends RuntimeException {
|
||||
|
||||
public static final long serialVersionUID = 8974598793458772L;
|
||||
private final boolean permanent;
|
||||
|
||||
/**
|
||||
* Creates a new {@link BailoutException}.
|
||||
*
|
||||
*
|
||||
* @param args parameters to the formatter
|
||||
*/
|
||||
public BailoutException(String format, Object... args) {
|
||||
super(String.format(Locale.ENGLISH, format, args));
|
||||
this.permanent = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link BailoutException}.
|
||||
*
|
||||
*
|
||||
* @param args parameters to the formatter
|
||||
*/
|
||||
public BailoutException(Throwable cause, String format, Object... args) {
|
||||
super(String.format(Locale.ENGLISH, format, args), cause);
|
||||
this.permanent = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link BailoutException}.
|
||||
*
|
||||
* @param permanent specifies whether this exception will occur again if compilation is retried
|
||||
* @param args parameters to the formatter
|
||||
*/
|
||||
public BailoutException(boolean permanent, String format, Object... args) {
|
||||
super(String.format(Locale.ENGLISH, format, args));
|
||||
this.permanent = permanent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether this exception will occur again if compilation is retried
|
||||
*/
|
||||
public boolean isPermanent() {
|
||||
return permanent;
|
||||
}
|
||||
}
|
@ -0,0 +1,278 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.vm.ci.code;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import jdk.vm.ci.meta.*;
|
||||
|
||||
/**
|
||||
* Represents the Java bytecode frame state(s) at a given position including {@link Value locations}
|
||||
* where to find the local variables, operand stack values and locked objects of the bytecode
|
||||
* frame(s).
|
||||
*/
|
||||
public class BytecodeFrame extends BytecodePosition {
|
||||
|
||||
/**
|
||||
* An array of values representing how to reconstruct the state of the Java frame. This is array
|
||||
* is partitioned as follows:
|
||||
* <p>
|
||||
* <table summary="" border="1" cellpadding="5" frame="void" rules="all">
|
||||
* <tr>
|
||||
* <th>Start index (inclusive)</th>
|
||||
* <th>End index (exclusive)</th>
|
||||
* <th>Description</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>0</td>
|
||||
* <td>numLocals</td>
|
||||
* <td>Local variables</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>numLocals</td>
|
||||
* <td>numLocals + numStack</td>
|
||||
* <td>Operand stack</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>numLocals + numStack</td>
|
||||
* <td>values.length</td>
|
||||
* <td>Locked objects</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
* <p>
|
||||
* Note that the number of locals and the number of stack slots may be smaller than the maximum
|
||||
* number of locals and stack slots as specified in the compiled method.
|
||||
*/
|
||||
public final JavaValue[] values;
|
||||
|
||||
/**
|
||||
* An array describing the Java kind of the {@link #values}. It records a kind for the locals
|
||||
* and the operand stack.
|
||||
*/
|
||||
public final JavaKind[] slotKinds;
|
||||
|
||||
/**
|
||||
* The number of locals in the values array.
|
||||
*/
|
||||
public final int numLocals;
|
||||
|
||||
/**
|
||||
* The number of stack slots in the values array.
|
||||
*/
|
||||
public final int numStack;
|
||||
|
||||
/**
|
||||
* The number of locks in the values array.
|
||||
*/
|
||||
public final int numLocks;
|
||||
|
||||
/**
|
||||
* True if this is a position inside an exception handler before the exception object has been
|
||||
* consumed. In this case, {@link #numStack} {@code == 1} and {@link #getStackValue(int)
|
||||
* getStackValue(0)} is the location of the exception object. If deoptimization happens at this
|
||||
* position, the interpreter will rethrow the exception instead of executing the bytecode
|
||||
* instruction at this position.
|
||||
*/
|
||||
public final boolean rethrowException;
|
||||
|
||||
public final boolean duringCall;
|
||||
|
||||
/**
|
||||
* This BCI should be used for frame states that are built for code with no meaningful BCI.
|
||||
*/
|
||||
public static final int UNKNOWN_BCI = -5;
|
||||
|
||||
/**
|
||||
* The BCI for exception unwind. This is synthetic code and has no representation in bytecode.
|
||||
* In contrast with {@link #AFTER_EXCEPTION_BCI}, at this point, if the method is synchronized,
|
||||
* the monitor is still held.
|
||||
*/
|
||||
public static final int UNWIND_BCI = -1;
|
||||
|
||||
/**
|
||||
* The BCI for the state before starting to execute a method. Note that if the method is
|
||||
* synchronized, the monitor is not yet held.
|
||||
*/
|
||||
public static final int BEFORE_BCI = -2;
|
||||
|
||||
/**
|
||||
* The BCI for the state after finishing the execution of a method and returning normally. Note
|
||||
* that if the method was synchronized the monitor is already released.
|
||||
*/
|
||||
public static final int AFTER_BCI = -3;
|
||||
|
||||
/**
|
||||
* The BCI for exception unwind. This is synthetic code and has no representation in bytecode.
|
||||
* In contrast with {@link #UNWIND_BCI}, at this point, if the method is synchronized, the
|
||||
* monitor is already released.
|
||||
*/
|
||||
public static final int AFTER_EXCEPTION_BCI = -4;
|
||||
|
||||
/**
|
||||
* This BCI should be used for states that cannot be the target of a deoptimization, like
|
||||
* snippet frame states.
|
||||
*/
|
||||
public static final int INVALID_FRAMESTATE_BCI = -6;
|
||||
|
||||
/**
|
||||
* Determines if a given BCI matches one of the placeholder BCI constants defined in this class.
|
||||
*/
|
||||
public static boolean isPlaceholderBci(int bci) {
|
||||
return bci < 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of a given placeholder BCI.
|
||||
*/
|
||||
public static String getPlaceholderBciName(int bci) {
|
||||
assert isPlaceholderBci(bci);
|
||||
if (bci == BytecodeFrame.AFTER_BCI) {
|
||||
return "AFTER_BCI";
|
||||
} else if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI) {
|
||||
return "AFTER_EXCEPTION_BCI";
|
||||
} else if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) {
|
||||
return "INVALID_FRAMESTATE_BCI";
|
||||
} else if (bci == BytecodeFrame.BEFORE_BCI) {
|
||||
return "BEFORE_BCI";
|
||||
} else if (bci == BytecodeFrame.UNKNOWN_BCI) {
|
||||
return "UNKNOWN_BCI";
|
||||
} else {
|
||||
assert bci == BytecodeFrame.UNWIND_BCI;
|
||||
return "UNWIND_BCI";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new frame object.
|
||||
*
|
||||
* @param caller the caller frame (which may be {@code null})
|
||||
* @param method the method
|
||||
* @param bci a BCI within the method
|
||||
* @param rethrowException specifies if the VM should re-throw the pending exception when
|
||||
* deopt'ing using this frame
|
||||
* @param values the frame state {@link #values}
|
||||
* @param numLocals the number of local variables
|
||||
* @param numStack the depth of the stack
|
||||
* @param numLocks the number of locked objects
|
||||
*/
|
||||
public BytecodeFrame(BytecodeFrame caller, ResolvedJavaMethod method, int bci, boolean rethrowException, boolean duringCall, JavaValue[] values, JavaKind[] slotKinds, int numLocals, int numStack,
|
||||
int numLocks) {
|
||||
super(caller, method, bci);
|
||||
assert values != null;
|
||||
this.rethrowException = rethrowException;
|
||||
this.duringCall = duringCall;
|
||||
this.values = values;
|
||||
this.slotKinds = slotKinds;
|
||||
this.numLocals = numLocals;
|
||||
this.numStack = numStack;
|
||||
this.numLocks = numLocks;
|
||||
assert !rethrowException || numStack == 1 : "must have exception on top of the stack";
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the frame state is formatted as expected by the JVM, with null or Illegal in the
|
||||
* slot following a double word item. This should really be checked in FrameState itself but
|
||||
* because of Word type rewriting and alternative backends that can't be done.
|
||||
*/
|
||||
public boolean validateFormat() {
|
||||
if (caller() != null) {
|
||||
caller().validateFormat();
|
||||
}
|
||||
for (int i = 0; i < numLocals + numStack; i++) {
|
||||
if (values[i] != null) {
|
||||
JavaKind kind = slotKinds[i];
|
||||
if (kind.needsTwoSlots()) {
|
||||
assert slotKinds.length > i + 1 : String.format("missing second word %s", this);
|
||||
assert slotKinds[i + 1] == JavaKind.Illegal : this;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value representing the specified local variable.
|
||||
*
|
||||
* @param i the local variable index
|
||||
* @return the value that can be used to reconstruct the local's current value
|
||||
*/
|
||||
public JavaValue getLocalValue(int i) {
|
||||
return values[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value representing the specified stack slot.
|
||||
*
|
||||
* @param i the stack index
|
||||
* @return the value that can be used to reconstruct the stack slot's current value
|
||||
*/
|
||||
public JavaValue getStackValue(int i) {
|
||||
return values[i + numLocals];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value representing the specified lock.
|
||||
*
|
||||
* @param i the lock index
|
||||
* @return the value that can be used to reconstruct the lock's current value
|
||||
*/
|
||||
public JavaValue getLockValue(int i) {
|
||||
return values[i + numLocals + numStack];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the caller of this frame.
|
||||
*
|
||||
* @return {@code null} if this frame has no caller
|
||||
*/
|
||||
public BytecodeFrame caller() {
|
||||
return (BytecodeFrame) getCaller();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof BytecodeFrame && super.equals(obj)) {
|
||||
BytecodeFrame that = (BytecodeFrame) obj;
|
||||
// @formatter:off
|
||||
if (this.duringCall == that.duringCall &&
|
||||
this.rethrowException == that.rethrowException &&
|
||||
this.numLocals == that.numLocals &&
|
||||
this.numLocks == that.numLocks &&
|
||||
this.numStack == that.numStack &&
|
||||
Arrays.equals(this.values, that.values)) {
|
||||
return true;
|
||||
}
|
||||
// @formatter:off
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return CodeUtil.append(new StringBuilder(100), this).toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.vm.ci.code;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import jdk.vm.ci.meta.*;
|
||||
|
||||
/**
|
||||
* Represents a code position, that is, a chain of inlined methods with bytecode locations, that is
|
||||
* communicated from the compiler to the runtime system. A code position can be used by the runtime
|
||||
* system to reconstruct a source-level stack trace for exceptions and to create
|
||||
* {@linkplain BytecodeFrame frames} for deoptimization.
|
||||
*/
|
||||
public class BytecodePosition {
|
||||
|
||||
private final BytecodePosition caller;
|
||||
private final ResolvedJavaMethod method;
|
||||
private final int bci;
|
||||
|
||||
/**
|
||||
* Constructs a new object representing a given parent/caller, a given method, and a given BCI.
|
||||
*
|
||||
* @param caller the parent position
|
||||
* @param method the method
|
||||
* @param bci a BCI within the method
|
||||
*/
|
||||
public BytecodePosition(BytecodePosition caller, ResolvedJavaMethod method, int bci) {
|
||||
assert method != null;
|
||||
this.caller = caller;
|
||||
this.method = method;
|
||||
this.bci = bci;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this code position to a string representation.
|
||||
*
|
||||
* @return a string representation of this code position
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return CodeUtil.append(new StringBuilder(100), this).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deep equality test.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (obj != null && getClass() == obj.getClass()) {
|
||||
BytecodePosition that = (BytecodePosition) obj;
|
||||
if (this.bci == that.bci && Objects.equals(this.getMethod(), that.getMethod()) && Objects.equals(this.caller, that.caller)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getBCI();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The location within the method, as a bytecode index. The constant {@code -1} may be
|
||||
* used to indicate the location is unknown, for example within code synthesized by the
|
||||
* compiler.
|
||||
*/
|
||||
public int getBCI() {
|
||||
return bci;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The runtime interface method for this position.
|
||||
*/
|
||||
public ResolvedJavaMethod getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
/**
|
||||
* The position where this position has been called, {@code null} if none.
|
||||
*/
|
||||
public BytecodePosition getCaller() {
|
||||
return caller;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a caller to the current position returning the new position.
|
||||
*/
|
||||
public BytecodePosition addCaller(BytecodePosition link) {
|
||||
if (getCaller() == null) {
|
||||
return new BytecodePosition(link, getMethod(), getBCI());
|
||||
} else {
|
||||
return new BytecodePosition(getCaller().addCaller(link), getMethod(), getBCI());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.vm.ci.code;
|
||||
|
||||
import static jdk.vm.ci.code.ValueUtil.*;
|
||||
|
||||
import jdk.vm.ci.meta.*;
|
||||
|
||||
/**
|
||||
* A calling convention describes the locations in which the arguments for a call are placed and the
|
||||
* location in which the return value is placed if the call is not void.
|
||||
*/
|
||||
public class CallingConvention {
|
||||
|
||||
/**
|
||||
* Constants denoting the type of a call for which a calling convention is requested.
|
||||
*/
|
||||
public enum Type {
|
||||
/**
|
||||
* A request for the outgoing argument locations at a call site to Java code.
|
||||
*/
|
||||
JavaCall(true),
|
||||
|
||||
/**
|
||||
* A request for the incoming argument locations.
|
||||
*/
|
||||
JavaCallee(false),
|
||||
|
||||
/**
|
||||
* A request for the outgoing argument locations at a call site to external native code that
|
||||
* complies with the platform ABI.
|
||||
*/
|
||||
NativeCall(true);
|
||||
|
||||
/**
|
||||
* Determines if this is a request for the outgoing argument locations at a call site.
|
||||
*/
|
||||
public final boolean out;
|
||||
|
||||
public static final Type[] VALUES = values();
|
||||
|
||||
private Type(boolean out) {
|
||||
this.out = out;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The amount of stack space (in bytes) required for the stack-based arguments of the call.
|
||||
*/
|
||||
private final int stackSize;
|
||||
|
||||
private final AllocatableValue returnLocation;
|
||||
|
||||
/**
|
||||
* The ordered locations in which the arguments are placed.
|
||||
*/
|
||||
private final AllocatableValue[] argumentLocations;
|
||||
|
||||
/**
|
||||
* Creates a description of the registers and stack locations used by a call.
|
||||
*
|
||||
* @param stackSize amount of stack space (in bytes) required for the stack-based arguments of
|
||||
* the call
|
||||
* @param returnLocation the location for the return value or {@link Value#ILLEGAL} if a void
|
||||
* call
|
||||
* @param argumentLocations the ordered locations in which the arguments are placed
|
||||
*/
|
||||
public CallingConvention(int stackSize, AllocatableValue returnLocation, AllocatableValue... argumentLocations) {
|
||||
assert argumentLocations != null;
|
||||
assert returnLocation != null;
|
||||
this.argumentLocations = argumentLocations;
|
||||
this.stackSize = stackSize;
|
||||
this.returnLocation = returnLocation;
|
||||
assert verify();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location for the return value or {@link Value#ILLEGAL} if a void call.
|
||||
*/
|
||||
public AllocatableValue getReturn() {
|
||||
return returnLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location for the {@code index}'th argument.
|
||||
*/
|
||||
public AllocatableValue getArgument(int index) {
|
||||
return argumentLocations[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the amount of stack space (in bytes) required for the stack-based arguments of the call.
|
||||
*/
|
||||
public int getStackSize() {
|
||||
return stackSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of locations required for the arguments.
|
||||
*/
|
||||
public int getArgumentCount() {
|
||||
return argumentLocations.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the locations required for the arguments.
|
||||
*/
|
||||
public AllocatableValue[] getArguments() {
|
||||
if (argumentLocations.length == 0) {
|
||||
return argumentLocations;
|
||||
}
|
||||
return argumentLocations.clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("CallingConvention[");
|
||||
String sep = "";
|
||||
for (Value op : argumentLocations) {
|
||||
sb.append(sep).append(op);
|
||||
sep = ", ";
|
||||
}
|
||||
if (!returnLocation.equals(Value.ILLEGAL)) {
|
||||
sb.append(" -> ").append(returnLocation);
|
||||
}
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private boolean verify() {
|
||||
for (int i = 0; i < argumentLocations.length; i++) {
|
||||
Value location = argumentLocations[i];
|
||||
assert isStackSlot(location) || isAllocatableValue(location);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.vm.ci.code;
|
||||
|
||||
import jdk.vm.ci.code.CompilationResult.*;
|
||||
import jdk.vm.ci.code.DataSection.*;
|
||||
import jdk.vm.ci.meta.*;
|
||||
|
||||
/**
|
||||
* Access to code cache related details and requirements.
|
||||
*/
|
||||
public interface CodeCacheProvider {
|
||||
|
||||
/**
|
||||
* Adds the given compilation result as an implementation of the given method without making it
|
||||
* the default implementation.
|
||||
*
|
||||
* @param method a method to which the executable code is begin added
|
||||
* @param compResult the compilation result to be added
|
||||
* @param speculationLog the speculation log to be used
|
||||
* @return a reference to the compiled and ready-to-run code or throws a
|
||||
* {@link BailoutException} if the code installation failed
|
||||
*/
|
||||
InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult, SpeculationLog speculationLog, InstalledCode predefinedInstalledCode);
|
||||
|
||||
/**
|
||||
* Sets the given compilation result as the default implementation of the given method.
|
||||
*
|
||||
* @param method a method to which the executable code is begin added
|
||||
* @param compResult the compilation result to be added
|
||||
* @return a reference to the compiled and ready-to-run code or null if the code installation
|
||||
* failed
|
||||
*/
|
||||
InstalledCode setDefaultMethod(ResolvedJavaMethod method, CompilationResult compResult);
|
||||
|
||||
/**
|
||||
* Gets a name for a {@link Mark} mark.
|
||||
*/
|
||||
default String getMarkName(Mark mark) {
|
||||
return String.valueOf(mark.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a name for the {@linkplain Call#target target} of a {@link Call}.
|
||||
*/
|
||||
default String getTargetName(Call call) {
|
||||
return String.valueOf(call.target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the register configuration to use when compiling a given method.
|
||||
*/
|
||||
RegisterConfig getRegisterConfig();
|
||||
|
||||
/**
|
||||
* Minimum size of the stack area reserved for outgoing parameters. This area is reserved in all
|
||||
* cases, even when the compiled method has no regular call instructions.
|
||||
*
|
||||
* @return the minimum size of the outgoing parameter area in bytes
|
||||
*/
|
||||
int getMinimumOutgoingSize();
|
||||
|
||||
/**
|
||||
* Determines if a {@link DataPatch} should be created for a given primitive constant that is
|
||||
* part of a {@link CompilationResult}. A data patch is always created for an object constant.
|
||||
*/
|
||||
boolean needsDataPatch(JavaConstant constant);
|
||||
|
||||
/**
|
||||
* Create a {@link Data} item for one or more {@link Constant Constants}, that can be used in a
|
||||
* {@link DataPatch}. If more than one {@link Constant} is given, then they are tightly packed
|
||||
* into a single {@link Data} item.
|
||||
*/
|
||||
Data createDataItem(Constant... constants);
|
||||
|
||||
/**
|
||||
* Gets a description of the target architecture.
|
||||
*/
|
||||
TargetDescription getTarget();
|
||||
|
||||
/**
|
||||
* Create a new speculation log for the target runtime.
|
||||
*/
|
||||
SpeculationLog createSpeculationLog();
|
||||
}
|
@ -0,0 +1,471 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.vm.ci.code;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import jdk.vm.ci.meta.*;
|
||||
|
||||
/**
|
||||
* Miscellaneous collection of utility methods used by {@code jdk.vm.ci.code} and its clients.
|
||||
*/
|
||||
public class CodeUtil {
|
||||
|
||||
public static final String NEW_LINE = String.format("%n");
|
||||
|
||||
public static final int K = 1024;
|
||||
public static final int M = 1024 * 1024;
|
||||
|
||||
public static boolean isOdd(int n) {
|
||||
return (n & 1) == 1;
|
||||
}
|
||||
|
||||
public static boolean isEven(int n) {
|
||||
return (n & 1) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the specified integer is a power of two.
|
||||
*
|
||||
* @param val the value to check
|
||||
* @return {@code true} if the value is a power of two; {@code false} otherwise
|
||||
*/
|
||||
public static boolean isPowerOf2(int val) {
|
||||
return val > 0 && (val & val - 1) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the specified long is a power of two.
|
||||
*
|
||||
* @param val the value to check
|
||||
* @return {@code true} if the value is a power of two; {@code false} otherwise
|
||||
*/
|
||||
public static boolean isPowerOf2(long val) {
|
||||
return val > 0 && (val & val - 1) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the log (base 2) of the specified integer, rounding down. (E.g {@code log2(8) = 3},
|
||||
* {@code log2(21) = 4} )
|
||||
*
|
||||
* @param val the value
|
||||
* @return the log base 2 of the value
|
||||
*/
|
||||
public static int log2(int val) {
|
||||
assert val > 0;
|
||||
return (Integer.SIZE - 1) - Integer.numberOfLeadingZeros(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the log (base 2) of the specified long, rounding down. (E.g {@code log2(8) = 3},
|
||||
* {@code log2(21) = 4})
|
||||
*
|
||||
* @param val the value
|
||||
* @return the log base 2 of the value
|
||||
*/
|
||||
public static int log2(long val) {
|
||||
assert val > 0;
|
||||
return (Long.SIZE - 1) - Long.numberOfLeadingZeros(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Narrow an integer value to a given bit width, and return the result as a signed long.
|
||||
*
|
||||
* @param value the value
|
||||
* @param resultBits the result bit width
|
||||
* @return {@code value} interpreted as {@code resultBits} bit number, encoded as signed long
|
||||
*/
|
||||
public static long narrow(long value, int resultBits) {
|
||||
long ret = value & mask(resultBits);
|
||||
return signExtend(ret, resultBits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign extend an integer.
|
||||
*
|
||||
* @param value the input value
|
||||
* @param inputBits the bit width of the input value
|
||||
* @return a signed long with the same value as the signed {@code inputBits}-bit number
|
||||
* {@code value}
|
||||
*/
|
||||
public static long signExtend(long value, int inputBits) {
|
||||
if (inputBits < 64) {
|
||||
if ((value >>> (inputBits - 1) & 1) == 1) {
|
||||
return value | (-1L << inputBits);
|
||||
} else {
|
||||
return value & ~(-1L << inputBits);
|
||||
}
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Zero extend an integer.
|
||||
*
|
||||
* @param value the input value
|
||||
* @param inputBits the bit width of the input value
|
||||
* @return an unsigned long with the same value as the unsigned {@code inputBits}-bit number
|
||||
* {@code value}
|
||||
*/
|
||||
public static long zeroExtend(long value, int inputBits) {
|
||||
if (inputBits < 64) {
|
||||
return value & ~(-1L << inputBits);
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an integer to long.
|
||||
*
|
||||
* @param value the input value
|
||||
* @param inputBits the bit width of the input value
|
||||
* @param unsigned whether the values should be interpreted as signed or unsigned
|
||||
* @return a long with the same value as the {@code inputBits}-bit number {@code value}
|
||||
*/
|
||||
public static long convert(long value, int inputBits, boolean unsigned) {
|
||||
if (unsigned) {
|
||||
return zeroExtend(value, inputBits);
|
||||
} else {
|
||||
return signExtend(value, inputBits);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a bitmask with the low {@code bits} bit set and the high {@code 64 - bits} bit clear.
|
||||
*/
|
||||
public static long mask(int bits) {
|
||||
assert 0 <= bits && bits <= 64;
|
||||
if (bits == 64) {
|
||||
return 0xffffffffffffffffL;
|
||||
} else {
|
||||
return (1L << bits) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the minimum value representable in a {@code bits} bit signed integer.
|
||||
*/
|
||||
public static long minValue(int bits) {
|
||||
assert 0 < bits && bits <= 64;
|
||||
return -1L << (bits - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum value representable in a {@code bits} bit signed integer.
|
||||
*/
|
||||
public static long maxValue(int bits) {
|
||||
assert 0 < bits && bits <= 64;
|
||||
return mask(bits - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the values in a frame as a tabulated string.
|
||||
*
|
||||
* @param frame
|
||||
* @return the values in {@code frame} as a tabulated string
|
||||
*/
|
||||
public static String tabulateValues(BytecodeFrame frame) {
|
||||
int cols = Math.max(frame.numLocals, Math.max(frame.numStack, frame.numLocks));
|
||||
assert cols > 0;
|
||||
ArrayList<Object> cells = new ArrayList<>();
|
||||
cells.add("");
|
||||
for (int i = 0; i < cols; i++) {
|
||||
cells.add(i);
|
||||
}
|
||||
cols++;
|
||||
if (frame.numLocals != 0) {
|
||||
cells.add("locals:");
|
||||
cells.addAll(Arrays.asList(frame.values).subList(0, frame.numLocals));
|
||||
cells.addAll(Collections.nCopies(cols - frame.numLocals - 1, ""));
|
||||
}
|
||||
if (frame.numStack != 0) {
|
||||
cells.add("stack:");
|
||||
cells.addAll(Arrays.asList(frame.values).subList(frame.numLocals, frame.numLocals + frame.numStack));
|
||||
cells.addAll(Collections.nCopies(cols - frame.numStack - 1, ""));
|
||||
}
|
||||
if (frame.numLocks != 0) {
|
||||
cells.add("locks:");
|
||||
cells.addAll(Arrays.asList(frame.values).subList(frame.numLocals + frame.numStack, frame.values.length));
|
||||
cells.addAll(Collections.nCopies(cols - frame.numLocks - 1, ""));
|
||||
}
|
||||
Object[] cellArray = cells.toArray();
|
||||
for (int i = 0; i < cellArray.length; i++) {
|
||||
if ((i % cols) != 0) {
|
||||
cellArray[i] = "|" + cellArray[i];
|
||||
}
|
||||
}
|
||||
return CodeUtil.tabulate(cellArray, cols, 1, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a given table as a string. The value of each cell is produced by
|
||||
* {@link String#valueOf(Object)}.
|
||||
*
|
||||
* @param cells the cells of the table in row-major order
|
||||
* @param cols the number of columns per row
|
||||
* @param lpad the number of space padding inserted before each formatted cell value
|
||||
* @param rpad the number of space padding inserted after each formatted cell value
|
||||
* @return a string with one line per row and each column left-aligned
|
||||
*/
|
||||
public static String tabulate(Object[] cells, int cols, int lpad, int rpad) {
|
||||
int rows = (cells.length + (cols - 1)) / cols;
|
||||
int[] colWidths = new int[cols];
|
||||
for (int col = 0; col < cols; col++) {
|
||||
for (int row = 0; row < rows; row++) {
|
||||
int index = col + (row * cols);
|
||||
if (index < cells.length) {
|
||||
Object cell = cells[index];
|
||||
colWidths[col] = Math.max(colWidths[col], String.valueOf(cell).length());
|
||||
}
|
||||
}
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String nl = NEW_LINE;
|
||||
for (int row = 0; row < rows; row++) {
|
||||
for (int col = 0; col < cols; col++) {
|
||||
int index = col + (row * cols);
|
||||
if (index < cells.length) {
|
||||
for (int i = 0; i < lpad; i++) {
|
||||
sb.append(' ');
|
||||
}
|
||||
Object cell = cells[index];
|
||||
String s = String.valueOf(cell);
|
||||
int w = s.length();
|
||||
sb.append(s);
|
||||
while (w < colWidths[col]) {
|
||||
sb.append(' ');
|
||||
w++;
|
||||
}
|
||||
for (int i = 0; i < rpad; i++) {
|
||||
sb.append(' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
sb.append(nl);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a formatted code position to a {@link StringBuilder}.
|
||||
*
|
||||
* @param sb the {@link StringBuilder} to append to
|
||||
* @param pos the code position to format and append to {@code sb}
|
||||
* @return the value of {@code sb}
|
||||
*/
|
||||
public static StringBuilder append(StringBuilder sb, BytecodePosition pos) {
|
||||
MetaUtil.appendLocation(sb.append("at "), pos.getMethod(), pos.getBCI());
|
||||
if (pos.getCaller() != null) {
|
||||
sb.append(NEW_LINE);
|
||||
append(sb, pos.getCaller());
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a formatted frame to a {@link StringBuilder}.
|
||||
*
|
||||
* @param sb the {@link StringBuilder} to append to
|
||||
* @param frame the frame to format and append to {@code sb}
|
||||
* @return the value of {@code sb}
|
||||
*/
|
||||
public static StringBuilder append(StringBuilder sb, BytecodeFrame frame) {
|
||||
MetaUtil.appendLocation(sb.append("at "), frame.getMethod(), frame.getBCI());
|
||||
assert sb.charAt(sb.length() - 1) == ']';
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
sb.append(", duringCall: ").append(frame.duringCall).append(", rethrow: ").append(frame.rethrowException).append(']');
|
||||
if (frame.values != null && frame.values.length > 0) {
|
||||
sb.append(NEW_LINE);
|
||||
String table = tabulateValues(frame);
|
||||
String[] rows = table.split(NEW_LINE);
|
||||
for (int i = 0; i < rows.length; i++) {
|
||||
String row = rows[i];
|
||||
if (!row.trim().isEmpty()) {
|
||||
sb.append(" ").append(row);
|
||||
if (i != rows.length - 1) {
|
||||
sb.append(NEW_LINE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (frame.caller() != null) {
|
||||
sb.append(NEW_LINE);
|
||||
append(sb, frame.caller());
|
||||
} else if (frame.getCaller() != null) {
|
||||
sb.append(NEW_LINE);
|
||||
append(sb, frame.getCaller());
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
public interface RefMapFormatter {
|
||||
|
||||
String formatStackSlot(int frameRefMapIndex);
|
||||
|
||||
String formatRegister(int regRefMapIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a location in a register reference map.
|
||||
*/
|
||||
public static class DefaultRegFormatter implements RefMapFormatter {
|
||||
|
||||
private final Register[] registers;
|
||||
|
||||
public DefaultRegFormatter(Architecture arch) {
|
||||
registers = new Register[arch.getRegisterReferenceMapSize()];
|
||||
for (Register r : arch.getRegisters()) {
|
||||
if (r.getReferenceMapIndex() >= 0) {
|
||||
registers[r.getReferenceMapIndex()] = r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String formatStackSlot(int frameRefMapIndex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String formatRegister(int regRefMapIndex) {
|
||||
int i = regRefMapIndex;
|
||||
int idx = 0;
|
||||
while (registers[i] == null) {
|
||||
i--;
|
||||
idx++;
|
||||
}
|
||||
if (idx == 0) {
|
||||
return registers[i].toString();
|
||||
} else {
|
||||
return String.format("%s+%d", registers[i].toString(), idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a location present in a register or frame reference map.
|
||||
*/
|
||||
public static class DefaultRefMapFormatter extends DefaultRegFormatter {
|
||||
|
||||
/**
|
||||
* The size of a stack slot.
|
||||
*/
|
||||
public final int slotSize;
|
||||
|
||||
/**
|
||||
* The register used as the frame pointer.
|
||||
*/
|
||||
public final Register fp;
|
||||
|
||||
/**
|
||||
* The offset (in bytes) from the slot pointed to by {@link #fp} to the slot corresponding
|
||||
* to bit 0 in the frame reference map.
|
||||
*/
|
||||
public final int refMapToFPOffset;
|
||||
|
||||
public DefaultRefMapFormatter(Architecture arch, int slotSize, Register fp, int refMapToFPOffset) {
|
||||
super(arch);
|
||||
this.slotSize = slotSize;
|
||||
this.fp = fp;
|
||||
this.refMapToFPOffset = refMapToFPOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String formatStackSlot(int frameRefMapIndex) {
|
||||
int refMapOffset = frameRefMapIndex * slotSize;
|
||||
int fpOffset = refMapOffset + refMapToFPOffset;
|
||||
if (fpOffset >= 0) {
|
||||
return fp + "+" + fpOffset;
|
||||
}
|
||||
return fp.name + fpOffset;
|
||||
}
|
||||
}
|
||||
|
||||
public static class NumberedRefMapFormatter implements RefMapFormatter {
|
||||
|
||||
public String formatStackSlot(int frameRefMapIndex) {
|
||||
return "s" + frameRefMapIndex;
|
||||
}
|
||||
|
||||
public String formatRegister(int regRefMapIndex) {
|
||||
return "r" + regRefMapIndex;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a formatted debug info to a {@link StringBuilder}.
|
||||
*
|
||||
* @param sb the {@link StringBuilder} to append to
|
||||
* @param info the debug info to format and append to {@code sb}
|
||||
* @return the value of {@code sb}
|
||||
*/
|
||||
public static StringBuilder append(StringBuilder sb, DebugInfo info, RefMapFormatter formatterArg) {
|
||||
RefMapFormatter formatter = formatterArg;
|
||||
if (formatter == null) {
|
||||
formatter = new NumberedRefMapFormatter();
|
||||
}
|
||||
String nl = NEW_LINE;
|
||||
ReferenceMap refMap = info.getReferenceMap();
|
||||
if (refMap != null) {
|
||||
sb.append(refMap.toString());
|
||||
}
|
||||
RegisterSaveLayout calleeSaveInfo = info.getCalleeSaveInfo();
|
||||
if (calleeSaveInfo != null) {
|
||||
sb.append("callee-save-info:").append(nl);
|
||||
Map<Integer, Register> map = calleeSaveInfo.slotsToRegisters(true);
|
||||
for (Map.Entry<Integer, Register> e : map.entrySet()) {
|
||||
sb.append(" ").append(e.getValue()).append(" -> ").append(formatter.formatStackSlot(e.getKey())).append(nl);
|
||||
}
|
||||
}
|
||||
BytecodeFrame frame = info.frame();
|
||||
if (frame != null) {
|
||||
append(sb, frame);
|
||||
} else if (info.getBytecodePosition() != null) {
|
||||
append(sb, info.getBytecodePosition());
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a calling convention from a {@link ResolvedJavaMethod}.
|
||||
*/
|
||||
public static CallingConvention getCallingConvention(CodeCacheProvider codeCache, CallingConvention.Type type, ResolvedJavaMethod method, boolean stackOnly) {
|
||||
Signature sig = method.getSignature();
|
||||
JavaType retType = sig.getReturnType(null);
|
||||
int sigCount = sig.getParameterCount(false);
|
||||
JavaType[] argTypes;
|
||||
int argIndex = 0;
|
||||
if (!method.isStatic()) {
|
||||
argTypes = new JavaType[sigCount + 1];
|
||||
argTypes[argIndex++] = method.getDeclaringClass();
|
||||
} else {
|
||||
argTypes = new JavaType[sigCount];
|
||||
}
|
||||
for (int i = 0; i < sigCount; i++) {
|
||||
argTypes[argIndex++] = sig.getParameterType(i, null);
|
||||
}
|
||||
|
||||
RegisterConfig registerConfig = codeCache.getRegisterConfig();
|
||||
return registerConfig.getCallingConvention(type, retType, argTypes, codeCache.getTarget(), stackOnly);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,288 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.vm.ci.code;
|
||||
|
||||
import static jdk.vm.ci.meta.MetaUtil.*;
|
||||
|
||||
import java.nio.*;
|
||||
import java.util.*;
|
||||
import java.util.function.*;
|
||||
|
||||
import jdk.vm.ci.code.CompilationResult.*;
|
||||
import jdk.vm.ci.code.DataSection.*;
|
||||
import jdk.vm.ci.meta.*;
|
||||
|
||||
public final class DataSection implements Iterable<Data> {
|
||||
|
||||
@FunctionalInterface
|
||||
public interface DataBuilder {
|
||||
|
||||
void emit(ByteBuffer buffer, Consumer<DataPatch> patch);
|
||||
|
||||
static DataBuilder raw(byte[] data) {
|
||||
return (buffer, patch) -> buffer.put(data);
|
||||
}
|
||||
|
||||
static DataBuilder serializable(SerializableConstant c) {
|
||||
return (buffer, patch) -> c.serialize(buffer);
|
||||
}
|
||||
|
||||
static DataBuilder zero(int size) {
|
||||
switch (size) {
|
||||
case 1:
|
||||
return (buffer, patch) -> buffer.put((byte) 0);
|
||||
case 2:
|
||||
return (buffer, patch) -> buffer.putShort((short) 0);
|
||||
case 4:
|
||||
return (buffer, patch) -> buffer.putInt(0);
|
||||
case 8:
|
||||
return (buffer, patch) -> buffer.putLong(0L);
|
||||
default:
|
||||
return (buffer, patch) -> {
|
||||
int rest = size;
|
||||
while (rest > 8) {
|
||||
buffer.putLong(0L);
|
||||
rest -= 8;
|
||||
}
|
||||
while (rest > 0) {
|
||||
buffer.put((byte) 0);
|
||||
rest--;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Data {
|
||||
|
||||
private int alignment;
|
||||
private final int size;
|
||||
private final DataBuilder builder;
|
||||
|
||||
private DataSectionReference ref;
|
||||
|
||||
public Data(int alignment, int size, DataBuilder builder) {
|
||||
this.alignment = alignment;
|
||||
this.size = size;
|
||||
this.builder = builder;
|
||||
|
||||
// initialized in DataSection.insertData(Data)
|
||||
ref = null;
|
||||
}
|
||||
|
||||
public void updateAlignment(int newAlignment) {
|
||||
if (newAlignment == alignment) {
|
||||
return;
|
||||
}
|
||||
alignment = lcm(alignment, newAlignment);
|
||||
}
|
||||
|
||||
public int getAlignment() {
|
||||
return alignment;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public DataBuilder getBuilder() {
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
// Data instances should not be used as hash map keys
|
||||
throw new UnsupportedOperationException("hashCode");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return identityHashCodeString(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
assert ref != null;
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof Data) {
|
||||
Data that = (Data) obj;
|
||||
if (this.alignment == that.alignment && this.size == that.size && this.ref.equals(that.ref)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private final ArrayList<Data> dataItems = new ArrayList<>();
|
||||
|
||||
private boolean finalLayout;
|
||||
private int sectionAlignment;
|
||||
private int sectionSize;
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
// DataSection instances should not be used as hash map keys
|
||||
throw new UnsupportedOperationException("hashCode");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return identityHashCodeString(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof DataSection) {
|
||||
DataSection that = (DataSection) obj;
|
||||
if (this.finalLayout == that.finalLayout && this.sectionAlignment == that.sectionAlignment && this.sectionSize == that.sectionSize && Objects.equals(this.dataItems, that.dataItems)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a {@link Data} item into the data section. If the item is already in the data section,
|
||||
* the same {@link DataSectionReference} is returned.
|
||||
*
|
||||
* @param data the {@link Data} item to be inserted
|
||||
* @return a unique {@link DataSectionReference} identifying the {@link Data} item
|
||||
*/
|
||||
public DataSectionReference insertData(Data data) {
|
||||
assert !finalLayout;
|
||||
if (data.ref == null) {
|
||||
data.ref = new DataSectionReference();
|
||||
dataItems.add(data);
|
||||
}
|
||||
return data.ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the layout of the data section. This can be called only once, and after it has been
|
||||
* called, the data section can no longer be modified.
|
||||
*/
|
||||
public void finalizeLayout() {
|
||||
assert !finalLayout;
|
||||
finalLayout = true;
|
||||
|
||||
// simple heuristic: put items with larger alignment requirement first
|
||||
dataItems.sort((a, b) -> a.alignment - b.alignment);
|
||||
|
||||
int position = 0;
|
||||
for (Data d : dataItems) {
|
||||
sectionAlignment = lcm(sectionAlignment, d.alignment);
|
||||
position = align(position, d.alignment);
|
||||
|
||||
d.ref.setOffset(position);
|
||||
position += d.size;
|
||||
}
|
||||
|
||||
sectionSize = position;
|
||||
}
|
||||
|
||||
public boolean isFinalized() {
|
||||
return finalLayout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size of the data section. Can only be called after {@link #finalizeLayout}.
|
||||
*/
|
||||
public int getSectionSize() {
|
||||
assert finalLayout;
|
||||
return sectionSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the minimum alignment requirement of the data section. Can only be called after
|
||||
* {@link #finalizeLayout}.
|
||||
*/
|
||||
public int getSectionAlignment() {
|
||||
assert finalLayout;
|
||||
return sectionAlignment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the data section. Can only be called after {@link #finalizeLayout}.
|
||||
*
|
||||
* @param buffer The {@link ByteBuffer} where the data section should be built. The buffer must
|
||||
* hold at least {@link #getSectionSize()} bytes.
|
||||
* @param patch A {@link Consumer} to receive {@link DataPatch data patches} for relocations in
|
||||
* the data section.
|
||||
*/
|
||||
public void buildDataSection(ByteBuffer buffer, Consumer<DataPatch> patch) {
|
||||
assert finalLayout;
|
||||
for (Data d : dataItems) {
|
||||
buffer.position(d.ref.getOffset());
|
||||
d.builder.emit(buffer, patch);
|
||||
}
|
||||
}
|
||||
|
||||
public Data findData(DataSectionReference ref) {
|
||||
for (Data d : dataItems) {
|
||||
if (d.ref == ref) {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Iterator<Data> iterator() {
|
||||
return dataItems.iterator();
|
||||
}
|
||||
|
||||
public static int lcm(int x, int y) {
|
||||
if (x == 0) {
|
||||
return y;
|
||||
} else if (y == 0) {
|
||||
return x;
|
||||
}
|
||||
|
||||
int a = Math.max(x, y);
|
||||
int b = Math.min(x, y);
|
||||
while (b > 0) {
|
||||
int tmp = a % b;
|
||||
a = b;
|
||||
b = tmp;
|
||||
}
|
||||
|
||||
int gcd = a;
|
||||
return x * y / gcd;
|
||||
}
|
||||
|
||||
private static int align(int position, int alignment) {
|
||||
return ((position + alignment - 1) / alignment) * alignment;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
assert !finalLayout;
|
||||
this.dataItems.clear();
|
||||
this.sectionAlignment = 0;
|
||||
this.sectionSize = 0;
|
||||
}
|
||||
}
|
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.vm.ci.code;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Represents the debugging information for a particular point of execution. This information
|
||||
* includes:
|
||||
* <ul>
|
||||
* <li>a {@linkplain #getBytecodePosition() bytecode position}</li>
|
||||
* <li>a reference map for registers and stack slots in the current frame</li>
|
||||
* <li>a map from bytecode locals and operand stack slots to their values or locations from which
|
||||
* their values can be read</li>
|
||||
* <li>a map from the registers (in the caller's frame) to the slots where they are saved in the
|
||||
* current frame</li>
|
||||
* </ul>
|
||||
*/
|
||||
public final class DebugInfo {
|
||||
|
||||
private final BytecodePosition bytecodePosition;
|
||||
private ReferenceMap referenceMap;
|
||||
@SuppressWarnings("unused") private final VirtualObject[] virtualObjectMapping;
|
||||
private RegisterSaveLayout calleeSaveInfo;
|
||||
|
||||
/**
|
||||
* Creates a new {@link DebugInfo} from the given values.
|
||||
*
|
||||
* @param codePos the {@linkplain BytecodePosition code position} or {@linkplain BytecodeFrame
|
||||
* frame} info
|
||||
* @param virtualObjectMapping the mapping of {@link VirtualObject}s to their real values
|
||||
*/
|
||||
public DebugInfo(BytecodePosition codePos, VirtualObject[] virtualObjectMapping) {
|
||||
this.bytecodePosition = codePos;
|
||||
this.virtualObjectMapping = virtualObjectMapping;
|
||||
}
|
||||
|
||||
public DebugInfo(BytecodePosition codePos) {
|
||||
this(codePos, null);
|
||||
}
|
||||
|
||||
public void setReferenceMap(ReferenceMap referenceMap) {
|
||||
this.referenceMap = referenceMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if this debug information has a frame
|
||||
*/
|
||||
public boolean hasFrame() {
|
||||
return getBytecodePosition() instanceof BytecodeFrame;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the deoptimization information for each inlined frame (if available).
|
||||
*
|
||||
* @return {@code null} if no frame de-opt info is {@linkplain #hasFrame() available}
|
||||
*/
|
||||
public BytecodeFrame frame() {
|
||||
if (hasFrame()) {
|
||||
return (BytecodeFrame) getBytecodePosition();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return CodeUtil.append(new StringBuilder(100), this, null).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The code position (including all inlined methods) of this debug info. If this is a
|
||||
* {@link BytecodeFrame} instance, then it is also the deoptimization information for
|
||||
* each inlined frame.
|
||||
*/
|
||||
public BytecodePosition getBytecodePosition() {
|
||||
return bytecodePosition;
|
||||
}
|
||||
|
||||
public ReferenceMap getReferenceMap() {
|
||||
return referenceMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the map from the registers (in the caller's frame) to the slots where they are saved in
|
||||
* the current frame.
|
||||
*/
|
||||
public void setCalleeSaveInfo(RegisterSaveLayout calleeSaveInfo) {
|
||||
this.calleeSaveInfo = calleeSaveInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the map from the registers (in the caller's frame) to the slots where they are saved in
|
||||
* the current frame. If no such information is available, {@code null} is returned.
|
||||
*/
|
||||
public RegisterSaveLayout getCalleeSaveInfo() {
|
||||
return calleeSaveInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
throw new UnsupportedOperationException("hashCode");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof DebugInfo) {
|
||||
DebugInfo that = (DebugInfo) obj;
|
||||
if (Objects.equals(this.bytecodePosition, that.bytecodePosition) && Objects.equals(this.calleeSaveInfo, that.calleeSaveInfo) && Objects.equals(this.referenceMap, that.referenceMap)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.vm.ci.code;
|
||||
|
||||
/**
|
||||
* A reason for infopoint insertion.
|
||||
*/
|
||||
public enum InfopointReason {
|
||||
UNKNOWN(false),
|
||||
SAFEPOINT(false),
|
||||
CALL(false),
|
||||
IMPLICIT_EXCEPTION(false),
|
||||
METHOD_START(true),
|
||||
METHOD_END(true),
|
||||
LINE_NUMBER(true),
|
||||
METASPACE_ACCESS(true);
|
||||
|
||||
private InfopointReason(boolean canBeOmitted) {
|
||||
this.canBeOmitted = canBeOmitted;
|
||||
}
|
||||
|
||||
private final boolean canBeOmitted;
|
||||
|
||||
public boolean canBeOmitted() {
|
||||
return canBeOmitted;
|
||||
}
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.vm.ci.code;
|
||||
|
||||
/**
|
||||
* Represents a compiled instance of a method. It may have been invalidated or removed in the
|
||||
* meantime.
|
||||
*/
|
||||
public class InstalledCode {
|
||||
|
||||
/**
|
||||
* Raw address of this code blob.
|
||||
*/
|
||||
private long address;
|
||||
|
||||
/**
|
||||
* Counts how often the address field was reassigned.
|
||||
*/
|
||||
private long version;
|
||||
|
||||
protected final String name;
|
||||
|
||||
public InstalledCode(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public final void setAddress(long address) {
|
||||
this.address = address;
|
||||
version++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the address of this code blob
|
||||
*/
|
||||
public final long getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the address of this code blob
|
||||
*/
|
||||
public final long getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this code blob.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the start address of this installed code if it is {@linkplain #isValid() valid}, 0
|
||||
* otherwise.
|
||||
*/
|
||||
public long getStart() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of instruction bytes for this code.
|
||||
*/
|
||||
public long getCodeSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of this installed code if it is {@linkplain #isValid() valid}, null otherwise.
|
||||
*/
|
||||
public byte[] getCode() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the code represented by this object is still valid, false otherwise (may
|
||||
* happen due to deopt, etc.)
|
||||
*/
|
||||
public boolean isValid() {
|
||||
return address != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates this installed code such that any subsequent
|
||||
* {@linkplain #executeVarargs(Object...) invocation} will throw an
|
||||
* {@link InvalidInstalledCodeException}.
|
||||
*/
|
||||
public void invalidate() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the installed code with a variable number of arguments.
|
||||
*
|
||||
* @param args the array of object arguments
|
||||
* @return the value returned by the executed code
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public Object executeVarargs(Object... args) throws InvalidInstalledCodeException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.vm.ci.code;
|
||||
|
||||
/**
|
||||
* Exception thrown by the runtime in case an invalidated machine code is called.
|
||||
*/
|
||||
public final class InvalidInstalledCodeException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = -3540232440794244844L;
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.vm.ci.code;
|
||||
|
||||
/**
|
||||
* Represents a location where a value can be stored. This can be either a {@link Register} or a
|
||||
* stack slot.
|
||||
*/
|
||||
public final class Location {
|
||||
|
||||
public final Register reg;
|
||||
public final int offset;
|
||||
|
||||
private Location(Register reg, int offset) {
|
||||
this.reg = reg;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link Location} for a register.
|
||||
*/
|
||||
public static Location register(Register reg) {
|
||||
return new Location(reg, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link Location} for a vector subregister.
|
||||
*
|
||||
* @param reg the {@link Register vector register}
|
||||
* @param offset the offset in bytes into the vector register
|
||||
*/
|
||||
public static Location subregister(Register reg, int offset) {
|
||||
return new Location(reg, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link Location} for a stack slot.
|
||||
*/
|
||||
public static Location stack(int offset) {
|
||||
return new Location(null, offset);
|
||||
}
|
||||
|
||||
public boolean isRegister() {
|
||||
return reg != null;
|
||||
}
|
||||
|
||||
public boolean isStack() {
|
||||
return reg == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String regName;
|
||||
if (isRegister()) {
|
||||
regName = reg.name + ":";
|
||||
} else {
|
||||
regName = "stack:";
|
||||
}
|
||||
return regName + offset;
|
||||
}
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.vm.ci.code;
|
||||
|
||||
/**
|
||||
* Constants and intrinsic definition for memory barriers.
|
||||
*
|
||||
* The documentation for each constant is taken from Doug Lea's <a
|
||||
* href="http://gee.cs.oswego.edu/dl/jmm/cookbook.html">The JSR-133 Cookbook for Compiler
|
||||
* Writers</a>.
|
||||
* <p>
|
||||
* The {@code JMM_*} constants capture the memory barriers necessary to implement the Java Memory
|
||||
* Model with respect to volatile field accesses. Their values are explained by this comment from
|
||||
* templateTable_i486.cpp in the HotSpot source code:
|
||||
*
|
||||
* <pre>
|
||||
* Volatile variables demand their effects be made known to all CPU's in
|
||||
* order. Store buffers on most chips allow reads & writes to reorder; the
|
||||
* JMM's ReadAfterWrite.java test fails in -Xint mode without some kind of
|
||||
* memory barrier (i.e., it's not sufficient that the interpreter does not
|
||||
* reorder volatile references, the hardware also must not reorder them).
|
||||
*
|
||||
* According to the new Java Memory Model (JMM):
|
||||
* (1) All volatiles are serialized wrt to each other.
|
||||
* ALSO reads & writes act as acquire & release, so:
|
||||
* (2) A read cannot let unrelated NON-volatile memory refs that happen after
|
||||
* the read float up to before the read. It's OK for non-volatile memory refs
|
||||
* that happen before the volatile read to float down below it.
|
||||
* (3) Similarly, a volatile write cannot let unrelated NON-volatile memory refs
|
||||
* that happen BEFORE the write float down to after the write. It's OK for
|
||||
* non-volatile memory refs that happen after the volatile write to float up
|
||||
* before it.
|
||||
*
|
||||
* We only put in barriers around volatile refs (they are expensive), not
|
||||
* _between_ memory refs (which would require us to track the flavor of the
|
||||
* previous memory refs). Requirements (2) and (3) require some barriers
|
||||
* before volatile stores and after volatile loads. These nearly cover
|
||||
* requirement (1) but miss the volatile-store-volatile-load case. This final
|
||||
* case is placed after volatile-stores although it could just as well go
|
||||
* before volatile-loads.
|
||||
* </pre>
|
||||
*/
|
||||
public class MemoryBarriers {
|
||||
|
||||
/**
|
||||
* The sequence {@code Load1; LoadLoad; Load2} ensures that {@code Load1}'s data are loaded
|
||||
* before data accessed by {@code Load2} and all subsequent load instructions are loaded. In
|
||||
* general, explicit {@code LoadLoad} barriers are needed on processors that perform speculative
|
||||
* loads and/or out-of-order processing in which waiting load instructions can bypass waiting
|
||||
* stores. On processors that guarantee to always preserve load ordering, these barriers amount
|
||||
* to no-ops.
|
||||
*/
|
||||
public static final int LOAD_LOAD = 0x0001;
|
||||
|
||||
/**
|
||||
* The sequence {@code Load1; LoadStore; Store2} ensures that {@code Load1}'s data are loaded
|
||||
* before all data associated with {@code Store2} and subsequent store instructions are flushed.
|
||||
* {@code LoadStore} barriers are needed only on those out-of-order processors in which waiting
|
||||
* store instructions can bypass loads.
|
||||
*/
|
||||
public static final int LOAD_STORE = 0x0002;
|
||||
|
||||
/**
|
||||
* The sequence {@code Store1; StoreLoad; Load2} ensures that {@code Store1}'s data are made
|
||||
* visible to other processors (i.e., flushed to main memory) before data accessed by
|
||||
* {@code Load2} and all subsequent load instructions are loaded. {@code StoreLoad} barriers
|
||||
* protect against a subsequent load incorrectly using {@code Store1}'s data value rather than
|
||||
* that from a more recent store to the same location performed by a different processor.
|
||||
* Because of this, on the processors discussed below, a {@code StoreLoad} is strictly necessary
|
||||
* only for separating stores from subsequent loads of the same location(s) as were stored
|
||||
* before the barrier. {@code StoreLoad} barriers are needed on nearly all recent
|
||||
* multiprocessors, and are usually the most expensive kind. Part of the reason they are
|
||||
* expensive is that they must disable mechanisms that ordinarily bypass cache to satisfy loads
|
||||
* from write-buffers. This might be implemented by letting the buffer fully flush, among other
|
||||
* possible stalls.
|
||||
*/
|
||||
public static final int STORE_LOAD = 0x0004;
|
||||
|
||||
/**
|
||||
* The sequence {@code Store1; StoreStore; Store2} ensures that {@code Store1}'s data are
|
||||
* visible to other processors (i.e., flushed to memory) before the data associated with
|
||||
* {@code Store2} and all subsequent store instructions. In general, {@code StoreStore} barriers
|
||||
* are needed on processors that do not otherwise guarantee strict ordering of flushes from
|
||||
* write buffers and/or caches to other processors or main memory.
|
||||
*/
|
||||
public static final int STORE_STORE = 0x0008;
|
||||
|
||||
public static final int JMM_PRE_VOLATILE_WRITE = LOAD_STORE | STORE_STORE;
|
||||
public static final int JMM_POST_VOLATILE_WRITE = STORE_LOAD | STORE_STORE;
|
||||
public static final int JMM_PRE_VOLATILE_READ = 0;
|
||||
public static final int JMM_POST_VOLATILE_READ = LOAD_LOAD | LOAD_STORE;
|
||||
|
||||
public static String barriersString(int barriers) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append((barriers & LOAD_LOAD) != 0 ? "LOAD_LOAD " : "");
|
||||
sb.append((barriers & LOAD_STORE) != 0 ? "LOAD_STORE " : "");
|
||||
sb.append((barriers & STORE_LOAD) != 0 ? "STORE_LOAD " : "");
|
||||
sb.append((barriers & STORE_STORE) != 0 ? "STORE_STORE " : "");
|
||||
return sb.toString().trim();
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.vm.ci.code;
|
||||
|
||||
public abstract class ReferenceMap {
|
||||
}
|
@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.vm.ci.code;
|
||||
|
||||
import jdk.vm.ci.meta.*;
|
||||
|
||||
/**
|
||||
* Represents a target machine register.
|
||||
*/
|
||||
public final class Register implements Comparable<Register> {
|
||||
|
||||
public static final RegisterCategory SPECIAL = new RegisterCategory("SPECIAL");
|
||||
|
||||
/**
|
||||
* Invalid register.
|
||||
*/
|
||||
public static final Register None = new Register(-1, -1, "noreg", SPECIAL);
|
||||
|
||||
/**
|
||||
* Frame pointer of the current method. All spill slots and outgoing stack-based arguments are
|
||||
* addressed relative to this register.
|
||||
*/
|
||||
public static final Register Frame = new Register(-2, -2, "framereg", SPECIAL);
|
||||
|
||||
public static final Register CallerFrame = new Register(-3, -3, "callerframereg", SPECIAL);
|
||||
|
||||
/**
|
||||
* The identifier for this register that is unique across all the registers in a
|
||||
* {@link Architecture}. A valid register has {@code number > 0}.
|
||||
*/
|
||||
public final int number;
|
||||
|
||||
/**
|
||||
* The mnemonic of this register.
|
||||
*/
|
||||
public final String name;
|
||||
|
||||
/**
|
||||
* The actual encoding in a target machine instruction for this register, which may or may not
|
||||
* be the same as {@link #number}.
|
||||
*/
|
||||
public final int encoding;
|
||||
|
||||
/**
|
||||
* The assembler calls this method to get the register's encoding.
|
||||
*/
|
||||
public int encoding() {
|
||||
return encoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* A platform specific register category that describes which values can be stored in a
|
||||
* register.
|
||||
*/
|
||||
private final RegisterCategory registerCategory;
|
||||
|
||||
/**
|
||||
* A platform specific register type that describes which values can be stored in a register.
|
||||
*/
|
||||
public static class RegisterCategory {
|
||||
|
||||
private final String name;
|
||||
|
||||
private final int referenceMapOffset;
|
||||
private final int referenceMapShift;
|
||||
|
||||
public RegisterCategory(String name) {
|
||||
this(name, 0, 0);
|
||||
}
|
||||
|
||||
public RegisterCategory(String name, int referenceMapOffset) {
|
||||
this(name, referenceMapOffset, 0);
|
||||
}
|
||||
|
||||
public RegisterCategory(String name, int referenceMapOffset, int referenceMapShift) {
|
||||
this.name = name;
|
||||
this.referenceMapOffset = referenceMapOffset;
|
||||
this.referenceMapShift = referenceMapShift;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 23 + name.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof RegisterCategory) {
|
||||
RegisterCategory that = (RegisterCategory) obj;
|
||||
return this.referenceMapOffset == that.referenceMapOffset && this.referenceMapShift == that.referenceMapShift && this.name.equals(that.name);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Register} instance.
|
||||
*
|
||||
* @param number unique identifier for the register
|
||||
* @param encoding the target machine encoding for the register
|
||||
* @param name the mnemonic name for the register
|
||||
* @param registerCategory the register category
|
||||
*/
|
||||
public Register(int number, int encoding, String name, RegisterCategory registerCategory) {
|
||||
this.number = number;
|
||||
this.name = name;
|
||||
this.registerCategory = registerCategory;
|
||||
this.encoding = encoding;
|
||||
}
|
||||
|
||||
public RegisterCategory getRegisterCategory() {
|
||||
return registerCategory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the start index of this register in the {@link ReferenceMap}.
|
||||
*/
|
||||
public int getReferenceMapIndex() {
|
||||
return (encoding << registerCategory.referenceMapShift) + registerCategory.referenceMapOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this register as a {@linkplain RegisterValue value} with a specified kind.
|
||||
*
|
||||
* @param kind the specified kind
|
||||
* @return the {@link RegisterValue}
|
||||
*/
|
||||
public RegisterValue asValue(LIRKind kind) {
|
||||
return new RegisterValue(kind, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this register as a {@linkplain RegisterValue value} with no particular kind.
|
||||
*
|
||||
* @return a {@link RegisterValue} with {@link JavaKind#Illegal} kind.
|
||||
*/
|
||||
public RegisterValue asValue() {
|
||||
return asValue(LIRKind.Illegal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if this is a valid register.
|
||||
*
|
||||
* @return {@code true} iff this register is valid
|
||||
*/
|
||||
public boolean isValid() {
|
||||
return number >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum register {@linkplain #number number} in a given set of registers.
|
||||
*
|
||||
* @param registers the set of registers to process
|
||||
* @return the maximum register number for any register in {@code registers}
|
||||
*/
|
||||
public static int maxRegisterNumber(Register[] registers) {
|
||||
int max = Integer.MIN_VALUE;
|
||||
for (Register r : registers) {
|
||||
if (r.number > max) {
|
||||
max = r.number;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum register {@linkplain #encoding encoding} in a given set of registers.
|
||||
*
|
||||
* @param registers the set of registers to process
|
||||
* @return the maximum register encoding for any register in {@code registers}
|
||||
*/
|
||||
public static int maxRegisterEncoding(Register[] registers) {
|
||||
int max = Integer.MIN_VALUE;
|
||||
for (Register r : registers) {
|
||||
if (r.encoding > max) {
|
||||
max = r.encoding;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Register o) {
|
||||
if (number < o.number) {
|
||||
return -1;
|
||||
}
|
||||
if (number > o.number) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 17 + name.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof Register) {
|
||||
Register other = (Register) obj;
|
||||
if (number == other.number) {
|
||||
assert name.equals(other.name);
|
||||
assert encoding == other.encoding;
|
||||
assert registerCategory.equals(other.registerCategory);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.vm.ci.code;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A collection of register attributes. The specific attribute values for a register may be local to
|
||||
* a compilation context. For example, a {@link RegisterConfig} in use during a compilation will
|
||||
* determine which registers are callee saved.
|
||||
*/
|
||||
public class RegisterAttributes {
|
||||
|
||||
private final boolean callerSave;
|
||||
private final boolean calleeSave;
|
||||
private final boolean allocatable;
|
||||
|
||||
public RegisterAttributes(boolean isCallerSave, boolean isCalleeSave, boolean isAllocatable) {
|
||||
this.callerSave = isCallerSave;
|
||||
this.calleeSave = isCalleeSave;
|
||||
this.allocatable = isAllocatable;
|
||||
}
|
||||
|
||||
public static final RegisterAttributes NONE = new RegisterAttributes(false, false, false);
|
||||
|
||||
/**
|
||||
* Creates a map from register {@linkplain Register#number numbers} to register
|
||||
* {@linkplain RegisterAttributes attributes} for a given register configuration and set of
|
||||
* registers.
|
||||
*
|
||||
* @param registerConfig a register configuration
|
||||
* @param registers a set of registers
|
||||
* @return an array whose length is the max register number in {@code registers} plus 1. An
|
||||
* element at index i holds the attributes of the register whose number is i.
|
||||
*/
|
||||
public static RegisterAttributes[] createMap(RegisterConfig registerConfig, Register[] registers) {
|
||||
RegisterAttributes[] map = new RegisterAttributes[registers.length];
|
||||
for (Register reg : registers) {
|
||||
if (reg != null) {
|
||||
Register[] csr = registerConfig.getCalleeSaveRegisters();
|
||||
RegisterAttributes attr = new RegisterAttributes(Arrays.asList(registerConfig.getCallerSaveRegisters()).contains(reg), csr == null ? false : Arrays.asList(csr).contains(reg),
|
||||
Arrays.asList(registerConfig.getAllocatableRegisters()).contains(reg));
|
||||
if (map.length <= reg.number) {
|
||||
map = Arrays.copyOf(map, reg.number + 1);
|
||||
}
|
||||
map[reg.number] = attr;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < map.length; i++) {
|
||||
if (map[i] == null) {
|
||||
map[i] = NONE;
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Denotes a register that is available for use by a register allocator.
|
||||
*/
|
||||
public boolean isAllocatable() {
|
||||
return allocatable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Denotes a register whose value preservation (if required) across a call is the
|
||||
* responsibility of the callee.
|
||||
*/
|
||||
public boolean isCalleeSave() {
|
||||
return calleeSave;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Denotes a register whose value preservation (if required) across a call is the
|
||||
* responsibility of the caller.
|
||||
*/
|
||||
public boolean isCallerSave() {
|
||||
return callerSave;
|
||||
}
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.vm.ci.code;
|
||||
|
||||
import jdk.vm.ci.code.CallingConvention.*;
|
||||
import jdk.vm.ci.meta.*;
|
||||
|
||||
/**
|
||||
* A register configuration binds roles and {@linkplain RegisterAttributes attributes} to physical
|
||||
* registers.
|
||||
*/
|
||||
public interface RegisterConfig {
|
||||
|
||||
/**
|
||||
* Gets the register to be used for returning a value of a given kind.
|
||||
*/
|
||||
Register getReturnRegister(JavaKind kind);
|
||||
|
||||
/**
|
||||
* Gets the maximum allowed size of the frame.
|
||||
*/
|
||||
default int getMaximumFrameSize() {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the register to which {@link Register#Frame} and {@link Register#CallerFrame} are bound.
|
||||
*/
|
||||
Register getFrameRegister();
|
||||
|
||||
/**
|
||||
* Gets the calling convention describing how arguments are passed.
|
||||
*
|
||||
* @param type the type of calling convention being requested
|
||||
* @param returnType the return type (can be null for methods returning {@code void})
|
||||
* @param parameterTypes the types of the arguments of the call
|
||||
* @param target the target platform
|
||||
* @param stackOnly ignore registers
|
||||
*/
|
||||
CallingConvention getCallingConvention(Type type, JavaType returnType, JavaType[] parameterTypes, TargetDescription target, boolean stackOnly);
|
||||
|
||||
/**
|
||||
* Gets the ordered set of registers that are can be used to pass parameters according to a
|
||||
* given calling convention.
|
||||
*
|
||||
* @param type the type of calling convention
|
||||
* @param kind specifies what kind of registers is being requested
|
||||
* @return the ordered set of registers that may be used to pass parameters in a call conforming
|
||||
* to {@code type}
|
||||
*/
|
||||
Register[] getCallingConventionRegisters(Type type, JavaKind kind);
|
||||
|
||||
/**
|
||||
* Gets the set of all registers that might be used by the register allocator.
|
||||
*
|
||||
* To get the set of registers the register allocator is allowed to use see
|
||||
* {@link RegisterAllocationConfig#getAllocatableRegisters()}
|
||||
*/
|
||||
@SuppressWarnings("javadoc")
|
||||
Register[] getAllocatableRegisters();
|
||||
|
||||
/**
|
||||
* Filters a set of registers and returns only those that can be used by the register allocator
|
||||
* for a value of a particular kind.
|
||||
*/
|
||||
Register[] filterAllocatableRegisters(PlatformKind kind, Register[] registers);
|
||||
|
||||
/**
|
||||
* Gets the registers whose values must be preserved by a method across any call it makes.
|
||||
*/
|
||||
Register[] getCallerSaveRegisters();
|
||||
|
||||
/**
|
||||
* Gets the registers whose values must be preserved by the callee.
|
||||
*/
|
||||
Register[] getCalleeSaveRegisters();
|
||||
|
||||
/**
|
||||
* Gets a map from register {@linkplain Register#number numbers} to register
|
||||
* {@linkplain RegisterAttributes attributes} for this register configuration.
|
||||
*
|
||||
* @return an array where an element at index i holds the attributes of the register whose
|
||||
* number is i
|
||||
*/
|
||||
RegisterAttributes[] getAttributesMap();
|
||||
|
||||
/**
|
||||
* Gets the register corresponding to a runtime-defined role.
|
||||
*
|
||||
* @param id the identifier of a runtime-defined register role
|
||||
* @return the register playing the role specified by {@code id}
|
||||
*/
|
||||
Register getRegisterForRole(int id);
|
||||
|
||||
/**
|
||||
* Determines if all {@link #getAllocatableRegisters() allocatable} registers are
|
||||
* {@link #getCallerSaveRegisters() caller saved}.
|
||||
*/
|
||||
boolean areAllAllocatableRegistersCallerSaved();
|
||||
}
|
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.vm.ci.code;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A map from registers to frame slots. This can be used to describe where callee saved registers
|
||||
* are saved in a callee's frame.
|
||||
*/
|
||||
public final class RegisterSaveLayout {
|
||||
|
||||
/**
|
||||
* Keys.
|
||||
*/
|
||||
private final Register[] registers;
|
||||
|
||||
/**
|
||||
* Slot indexes relative to stack pointer.
|
||||
*/
|
||||
private final int[] slots;
|
||||
|
||||
/**
|
||||
* Creates a map from registers to frame slots.
|
||||
*
|
||||
* @param registers the keys in the map
|
||||
* @param slots frame slot index for each register in {@code registers}
|
||||
*/
|
||||
public RegisterSaveLayout(Register[] registers, int[] slots) {
|
||||
assert registers.length == slots.length;
|
||||
this.registers = registers;
|
||||
this.slots = slots;
|
||||
assert registersToSlots(false).size() == registers.length : "non-unique registers";
|
||||
assert new HashSet<>(registersToSlots(false).values()).size() == slots.length : "non-unqiue slots";
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the frame slot index for a given register.
|
||||
*
|
||||
* @param register register to get the frame slot index for
|
||||
* @return frame slot index
|
||||
*/
|
||||
public int registerToSlot(Register register) {
|
||||
for (int i = 0; i < registers.length; i++) {
|
||||
if (register.equals(registers[i])) {
|
||||
return slots[i];
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException(register + " not saved by this layout: " + this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this layout information as a {@link Map} from registers to slots.
|
||||
*/
|
||||
public Map<Register, Integer> registersToSlots(boolean sorted) {
|
||||
Map<Register, Integer> result;
|
||||
if (sorted) {
|
||||
result = new TreeMap<>();
|
||||
} else {
|
||||
result = new HashMap<>();
|
||||
}
|
||||
for (int i = 0; i < registers.length; i++) {
|
||||
result.put(registers[i], slots[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this layout information as a {@link Map} from slots to registers.
|
||||
*/
|
||||
public Map<Integer, Register> slotsToRegisters(boolean sorted) {
|
||||
Map<Integer, Register> result;
|
||||
if (sorted) {
|
||||
result = new TreeMap<>();
|
||||
} else {
|
||||
result = new HashMap<>();
|
||||
}
|
||||
for (int i = 0; i < registers.length; i++) {
|
||||
result.put(slots[i], registers[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof RegisterSaveLayout) {
|
||||
RegisterSaveLayout that = (RegisterSaveLayout) obj;
|
||||
if (Arrays.equals(registers, that.registers) && Arrays.equals(slots, that.slots)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return registersToSlots(true).toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.vm.ci.code;
|
||||
|
||||
import jdk.vm.ci.meta.*;
|
||||
|
||||
/**
|
||||
* Denotes a register that stores a value of a fixed kind. There is exactly one (canonical) instance
|
||||
* of {@link RegisterValue} for each ({@link Register}, {@link JavaKind}) pair. Use
|
||||
* {@link Register#asValue(LIRKind)} to retrieve the canonical {@link RegisterValue} instance for a
|
||||
* given (register,kind) pair.
|
||||
*/
|
||||
public final class RegisterValue extends AllocatableValue {
|
||||
|
||||
private final Register reg;
|
||||
|
||||
/**
|
||||
* Should only be called from {@link Register#Register} to ensure canonicalization.
|
||||
*/
|
||||
protected RegisterValue(LIRKind kind, Register register) {
|
||||
super(kind);
|
||||
this.reg = register;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getRegister().name + getKindSuffix();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the register that contains the value
|
||||
*/
|
||||
public Register getRegister() {
|
||||
return reg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 29 * super.hashCode() + reg.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof RegisterValue) {
|
||||
RegisterValue other = (RegisterValue) obj;
|
||||
return super.equals(obj) && reg.equals(other.reg);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.vm.ci.code;
|
||||
|
||||
/**
|
||||
* Class representing a exception with a stack trace of the currently processed position in the
|
||||
* compiled Java program instead of the stack trace of the compiler. The exception of the compiler
|
||||
* is saved as the cause of this exception.
|
||||
*/
|
||||
public abstract class SourceStackTrace extends BailoutException {
|
||||
private static final long serialVersionUID = 2144811793442316776L;
|
||||
|
||||
public static SourceStackTrace create(Throwable cause, String format, StackTraceElement[] elements) {
|
||||
return new SourceStackTrace(cause, format) {
|
||||
|
||||
private static final long serialVersionUID = 6279381376051787907L;
|
||||
|
||||
@Override
|
||||
public final synchronized Throwable fillInStackTrace() {
|
||||
assert elements != null;
|
||||
setStackTrace(elements);
|
||||
return this;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private SourceStackTrace(Throwable cause, String format) {
|
||||
super(cause, format);
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.vm.ci.code;
|
||||
|
||||
import static jdk.vm.ci.code.ValueUtil.*;
|
||||
|
||||
import jdk.vm.ci.meta.*;
|
||||
|
||||
/**
|
||||
* Represents lock information in the debug information.
|
||||
*/
|
||||
public final class StackLockValue implements JavaValue {
|
||||
|
||||
private JavaValue owner;
|
||||
private StackSlotValue slot;
|
||||
private final boolean eliminated;
|
||||
|
||||
public StackLockValue(JavaValue object, StackSlotValue slot, boolean eliminated) {
|
||||
this.owner = object;
|
||||
this.slot = slot;
|
||||
this.eliminated = eliminated;
|
||||
}
|
||||
|
||||
public JavaValue getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public void setOwner(JavaValue newOwner) {
|
||||
this.owner = newOwner;
|
||||
}
|
||||
|
||||
public Value getSlot() {
|
||||
return slot;
|
||||
}
|
||||
|
||||
public boolean isEliminated() {
|
||||
return eliminated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "monitor[" + owner + (slot != null ? ", " + slot : "") + (eliminated ? ", eliminated" : "") + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 43;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + (eliminated ? 1231 : 1237);
|
||||
result = prime * result + owner.hashCode();
|
||||
result = prime * result + slot.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof StackLockValue) {
|
||||
StackLockValue other = (StackLockValue) obj;
|
||||
return super.equals(obj) && eliminated == other.eliminated && owner.equals(other.owner) && slot.equals(other.slot);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setSlot(StackSlotValue stackSlot) {
|
||||
assert slot == null || (isVirtualStackSlot(slot) && (slot.equals(stackSlot) || isStackSlot(stackSlot))) : String.format("Can not set slot for %s to %s", this, stackSlot);
|
||||
slot = stackSlot;
|
||||
}
|
||||
}
|
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.vm.ci.code;
|
||||
|
||||
import jdk.vm.ci.meta.*;
|
||||
|
||||
/**
|
||||
* Represents a compiler spill slot or an outgoing stack-based argument in a method's frame or an
|
||||
* incoming stack-based argument in a method's {@linkplain #isInCallerFrame() caller's frame}.
|
||||
*/
|
||||
public final class StackSlot extends StackSlotValue {
|
||||
|
||||
private final int offset;
|
||||
private final boolean addFrameSize;
|
||||
|
||||
/**
|
||||
* Gets a {@link StackSlot} instance representing a stack slot at a given index holding a value
|
||||
* of a given kind.
|
||||
*
|
||||
* @param kind The kind of the value stored in the stack slot.
|
||||
* @param offset The offset of the stack slot (in bytes)
|
||||
* @param addFrameSize Specifies if the offset is relative to the stack pointer, or the
|
||||
* beginning of the frame (stack pointer + total frame size).
|
||||
*/
|
||||
public static StackSlot get(LIRKind kind, int offset, boolean addFrameSize) {
|
||||
assert addFrameSize || offset >= 0;
|
||||
return new StackSlot(kind, offset, addFrameSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor to enforce use of {@link #get(LIRKind, int, boolean)} so that a cache can
|
||||
* be used.
|
||||
*/
|
||||
private StackSlot(LIRKind kind, int offset, boolean addFrameSize) {
|
||||
super(kind);
|
||||
this.offset = offset;
|
||||
this.addFrameSize = addFrameSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the offset of this stack slot, relative to the stack pointer.
|
||||
*
|
||||
* @return The offset of this slot (in bytes).
|
||||
*/
|
||||
public int getOffset(int totalFrameSize) {
|
||||
assert totalFrameSize > 0 || !addFrameSize;
|
||||
int result = offset + (addFrameSize ? totalFrameSize : 0);
|
||||
assert result >= 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean isInCallerFrame() {
|
||||
return addFrameSize && offset >= 0;
|
||||
}
|
||||
|
||||
public int getRawOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
public boolean getRawAddFrameSize() {
|
||||
return addFrameSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (!addFrameSize) {
|
||||
return "out:" + offset + getKindSuffix();
|
||||
} else if (offset >= 0) {
|
||||
return "in:" + offset + getKindSuffix();
|
||||
} else {
|
||||
return "stack:" + (-offset) + getKindSuffix();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this stack slot used to pass an argument from the perspective of a caller.
|
||||
*/
|
||||
public StackSlot asOutArg() {
|
||||
assert offset >= 0;
|
||||
if (addFrameSize) {
|
||||
return get(getLIRKind(), offset, false);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this stack slot used to pass an argument from the perspective of a callee.
|
||||
*/
|
||||
public StackSlot asInArg() {
|
||||
assert offset >= 0;
|
||||
if (!addFrameSize) {
|
||||
return get(getLIRKind(), offset, true);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 37;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + (addFrameSize ? 1231 : 1237);
|
||||
result = prime * result + offset;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof StackSlot) {
|
||||
StackSlot other = (StackSlot) obj;
|
||||
return super.equals(obj) && addFrameSize == other.addFrameSize && offset == other.offset;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.vm.ci.code;
|
||||
|
||||
import jdk.vm.ci.meta.*;
|
||||
|
||||
/**
|
||||
* Common base class for {@linkplain StackSlot real} and {@linkplain VirtualStackSlot virtual} stack
|
||||
* slots.
|
||||
*/
|
||||
public abstract class StackSlotValue extends AllocatableValue {
|
||||
|
||||
public StackSlotValue(LIRKind lirKind) {
|
||||
super(lirKind);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.vm.ci.code;
|
||||
|
||||
import static jdk.vm.ci.meta.MetaUtil.*;
|
||||
|
||||
import jdk.vm.ci.meta.*;
|
||||
|
||||
/**
|
||||
* Represents the target machine for a compiler, including the CPU architecture, the size of
|
||||
* pointers and references, alignment of stacks, caches, etc.
|
||||
*/
|
||||
public class TargetDescription {
|
||||
|
||||
public final Architecture arch;
|
||||
|
||||
/**
|
||||
* Specifies if this is a multi-processor system.
|
||||
*/
|
||||
public final boolean isMP;
|
||||
|
||||
/**
|
||||
* Specifies if this target supports encoding objects inline in the machine code.
|
||||
*/
|
||||
public final boolean inlineObjects;
|
||||
|
||||
/**
|
||||
* The machine word size on this target.
|
||||
*/
|
||||
public final int wordSize;
|
||||
|
||||
/**
|
||||
* The kind to be used for representing raw pointers and CPU registers.
|
||||
*/
|
||||
public final JavaKind wordKind;
|
||||
|
||||
/**
|
||||
* The stack alignment requirement of the platform. For example, from Appendix D of <a
|
||||
* href="http://www.intel.com/Assets/PDF/manual/248966.pdf">Intel 64 and IA-32 Architectures
|
||||
* Optimization Reference Manual</a>:
|
||||
*
|
||||
* <pre>
|
||||
* "It is important to ensure that the stack frame is aligned to a
|
||||
* 16-byte boundary upon function entry to keep local __m128 data,
|
||||
* parameters, and XMM register spill locations aligned throughout
|
||||
* a function invocation."
|
||||
* </pre>
|
||||
*/
|
||||
public final int stackAlignment;
|
||||
|
||||
/**
|
||||
* Maximum constant displacement at which a memory access can no longer be an implicit null
|
||||
* check.
|
||||
*/
|
||||
public final int implicitNullCheckLimit;
|
||||
|
||||
public TargetDescription(Architecture arch, boolean isMP, int stackAlignment, int implicitNullCheckLimit, boolean inlineObjects) {
|
||||
this.arch = arch;
|
||||
this.isMP = isMP;
|
||||
this.wordSize = arch.getWordSize();
|
||||
this.wordKind = JavaKind.fromWordSize(wordSize);
|
||||
this.stackAlignment = stackAlignment;
|
||||
this.implicitNullCheckLimit = implicitNullCheckLimit;
|
||||
this.inlineObjects = inlineObjects;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof TargetDescription) {
|
||||
TargetDescription that = (TargetDescription) obj;
|
||||
// @formatter:off
|
||||
if (this.implicitNullCheckLimit == that.implicitNullCheckLimit &&
|
||||
this.inlineObjects == that.inlineObjects &&
|
||||
this.isMP == that.isMP &&
|
||||
this.stackAlignment == that.stackAlignment &&
|
||||
this.wordKind.equals(that.wordKind) &&
|
||||
this.wordSize == that.wordSize &&
|
||||
this.arch.equals(that.arch)) {
|
||||
return true;
|
||||
}
|
||||
// @formatter:on
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return identityHashCodeString(this);
|
||||
}
|
||||
|
||||
public int getSizeInBytes(PlatformKind kind) {
|
||||
return kind.getSizeInBytes();
|
||||
}
|
||||
|
||||
public LIRKind getLIRKind(JavaKind javaKind) {
|
||||
PlatformKind platformKind = arch.getPlatformKind(javaKind);
|
||||
if (javaKind.isObject()) {
|
||||
return LIRKind.reference(platformKind);
|
||||
} else {
|
||||
return LIRKind.value(platformKind);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.vm.ci.code;
|
||||
|
||||
import java.math.*;
|
||||
|
||||
//JaCoCo Exclude
|
||||
|
||||
/**
|
||||
* Utilities for unsigned comparisons. All methods have correct, but slow, standard Java
|
||||
* implementations so that they can be used with compilers not supporting the intrinsics.
|
||||
*/
|
||||
public class UnsignedMath {
|
||||
|
||||
private static final long MASK = 0xffffffffL;
|
||||
|
||||
/**
|
||||
* Unsigned comparison aboveThan for two numbers.
|
||||
*/
|
||||
public static boolean aboveThan(int a, int b) {
|
||||
return (a & MASK) > (b & MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsigned comparison aboveOrEqual for two numbers.
|
||||
*/
|
||||
public static boolean aboveOrEqual(int a, int b) {
|
||||
return (a & MASK) >= (b & MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsigned comparison belowThan for two numbers.
|
||||
*/
|
||||
public static boolean belowThan(int a, int b) {
|
||||
return (a & MASK) < (b & MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsigned comparison belowOrEqual for two numbers.
|
||||
*/
|
||||
public static boolean belowOrEqual(int a, int b) {
|
||||
return (a & MASK) <= (b & MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsigned comparison aboveThan for two numbers.
|
||||
*/
|
||||
public static boolean aboveThan(long a, long b) {
|
||||
return (a > b) ^ ((a < 0) != (b < 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsigned comparison aboveOrEqual for two numbers.
|
||||
*/
|
||||
public static boolean aboveOrEqual(long a, long b) {
|
||||
return (a >= b) ^ ((a < 0) != (b < 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsigned comparison belowThan for two numbers.
|
||||
*/
|
||||
public static boolean belowThan(long a, long b) {
|
||||
return (a < b) ^ ((a < 0) != (b < 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsigned comparison belowOrEqual for two numbers.
|
||||
*/
|
||||
public static boolean belowOrEqual(long a, long b) {
|
||||
return (a <= b) ^ ((a < 0) != (b < 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsigned division for two numbers.
|
||||
*/
|
||||
public static int divide(int a, int b) {
|
||||
return (int) ((a & MASK) / (b & MASK));
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsigned remainder for two numbers.
|
||||
*/
|
||||
public static int remainder(int a, int b) {
|
||||
return (int) ((a & MASK) % (b & MASK));
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsigned division for two numbers.
|
||||
*/
|
||||
public static long divide(long a, long b) {
|
||||
return bi(a).divide(bi(b)).longValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsigned remainder for two numbers.
|
||||
*/
|
||||
public static long remainder(long a, long b) {
|
||||
return bi(a).remainder(bi(b)).longValue();
|
||||
}
|
||||
|
||||
private static BigInteger bi(long unsigned) {
|
||||
return unsigned >= 0 ? BigInteger.valueOf(unsigned) : BigInteger.valueOf(unsigned & 0x7fffffffffffffffL).setBit(63);
|
||||
}
|
||||
}
|
@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.vm.ci.code;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import jdk.vm.ci.meta.*;
|
||||
|
||||
/**
|
||||
* Utility class for working with the {@link Value} class and its subclasses.
|
||||
*/
|
||||
public final class ValueUtil {
|
||||
|
||||
public static boolean isIllegal(Value value) {
|
||||
assert value != null;
|
||||
return Value.ILLEGAL.equals(value);
|
||||
}
|
||||
|
||||
public static boolean isIllegalJavaValue(JavaValue value) {
|
||||
assert value != null;
|
||||
return Value.ILLEGAL.equals(value);
|
||||
}
|
||||
|
||||
public static boolean isLegal(Value value) {
|
||||
return !isIllegal(value);
|
||||
}
|
||||
|
||||
public static boolean isVirtualObject(JavaValue value) {
|
||||
assert value != null;
|
||||
return value instanceof VirtualObject;
|
||||
}
|
||||
|
||||
public static VirtualObject asVirtualObject(JavaValue value) {
|
||||
assert value != null;
|
||||
return (VirtualObject) value;
|
||||
}
|
||||
|
||||
public static boolean isConstantJavaValue(JavaValue value) {
|
||||
assert value != null;
|
||||
return value instanceof JavaConstant;
|
||||
}
|
||||
|
||||
public static boolean isAllocatableValue(Value value) {
|
||||
assert value != null;
|
||||
return value instanceof AllocatableValue;
|
||||
}
|
||||
|
||||
public static AllocatableValue asAllocatableValue(Value value) {
|
||||
assert value != null;
|
||||
return (AllocatableValue) value;
|
||||
}
|
||||
|
||||
public static boolean isStackSlot(Value value) {
|
||||
assert value != null;
|
||||
return value instanceof StackSlot;
|
||||
}
|
||||
|
||||
public static StackSlot asStackSlot(Value value) {
|
||||
assert value != null;
|
||||
return (StackSlot) value;
|
||||
}
|
||||
|
||||
public static boolean isStackSlotValue(Value value) {
|
||||
assert value != null;
|
||||
return value instanceof StackSlotValue;
|
||||
}
|
||||
|
||||
public static StackSlotValue asStackSlotValue(Value value) {
|
||||
assert value != null;
|
||||
return (StackSlotValue) value;
|
||||
}
|
||||
|
||||
public static boolean isVirtualStackSlot(Value value) {
|
||||
assert value != null;
|
||||
return value instanceof VirtualStackSlot;
|
||||
}
|
||||
|
||||
public static VirtualStackSlot asVirtualStackSlot(Value value) {
|
||||
assert value != null;
|
||||
return (VirtualStackSlot) value;
|
||||
}
|
||||
|
||||
public static boolean isRegister(Value value) {
|
||||
assert value != null;
|
||||
return value instanceof RegisterValue;
|
||||
}
|
||||
|
||||
public static Register asRegister(Value value) {
|
||||
return asRegisterValue(value).getRegister();
|
||||
}
|
||||
|
||||
public static RegisterValue asRegisterValue(Value value) {
|
||||
assert value != null;
|
||||
return (RegisterValue) value;
|
||||
}
|
||||
|
||||
public static Register asRegister(Value value, PlatformKind kind) {
|
||||
if (value.getPlatformKind() != kind) {
|
||||
throw new InternalError("needed: " + kind + " got: " + value.getPlatformKind());
|
||||
} else {
|
||||
return asRegister(value);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean sameRegister(Value v1, Value v2) {
|
||||
return isRegister(v1) && isRegister(v2) && asRegister(v1).equals(asRegister(v2));
|
||||
}
|
||||
|
||||
public static boolean sameRegister(Value v1, Value v2, Value v3) {
|
||||
return sameRegister(v1, v2) && sameRegister(v1, v3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if all the provided values are different physical registers. The parameters can be
|
||||
* either {@link Register registers}, {@link Value values} or arrays of them. All values that
|
||||
* are not {@link RegisterValue registers} are ignored.
|
||||
*/
|
||||
public static boolean differentRegisters(Object... values) {
|
||||
List<Register> registers = collectRegisters(values, new ArrayList<Register>());
|
||||
for (int i = 1; i < registers.size(); i++) {
|
||||
Register r1 = registers.get(i);
|
||||
for (int j = 0; j < i; j++) {
|
||||
Register r2 = registers.get(j);
|
||||
if (r1.equals(r2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static List<Register> collectRegisters(Object[] values, List<Register> registers) {
|
||||
for (Object o : values) {
|
||||
if (o instanceof Register) {
|
||||
registers.add((Register) o);
|
||||
} else if (o instanceof Value) {
|
||||
if (isRegister((Value) o)) {
|
||||
registers.add(asRegister((Value) o));
|
||||
}
|
||||
} else if (o instanceof Object[]) {
|
||||
collectRegisters((Object[]) o, registers);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Not a Register or Value: " + o);
|
||||
}
|
||||
}
|
||||
return registers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtract sets of registers (x - y).
|
||||
*
|
||||
* @param x a set of register to subtract from.
|
||||
* @param y a set of registers to subtract.
|
||||
* @return resulting set of registers (x - y).
|
||||
*/
|
||||
public static Value[] subtractRegisters(Value[] x, Value[] y) {
|
||||
ArrayList<Value> result = new ArrayList<>(x.length);
|
||||
for (Value i : x) {
|
||||
boolean append = true;
|
||||
for (Value j : y) {
|
||||
if (ValueUtil.sameRegister(i, j)) {
|
||||
append = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (append) {
|
||||
result.add(i);
|
||||
}
|
||||
}
|
||||
Value[] resultArray = new Value[result.size()];
|
||||
return result.toArray(resultArray);
|
||||
}
|
||||
}
|
@ -0,0 +1,221 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.vm.ci.code;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import jdk.vm.ci.meta.*;
|
||||
|
||||
/**
|
||||
* An instance of this class represents an object whose allocation was removed by escape analysis.
|
||||
* The information stored in the {@link VirtualObject} is used during deoptimization to recreate the
|
||||
* object.
|
||||
*/
|
||||
public final class VirtualObject implements JavaValue {
|
||||
|
||||
private final ResolvedJavaType type;
|
||||
private JavaValue[] values;
|
||||
private JavaKind[] slotKinds;
|
||||
private final int id;
|
||||
|
||||
/**
|
||||
* Creates a new {@link VirtualObject} for the given type, with the given fields. If
|
||||
* {@code type} is an instance class then {@code values} provides the values for the fields
|
||||
* returned by {@link ResolvedJavaType#getInstanceFields(boolean) getInstanceFields(true)}. If
|
||||
* {@code type} is an array then the length of the values array determines the reallocated array
|
||||
* length.
|
||||
*
|
||||
* @param type the type of the object whose allocation was removed during compilation. This can
|
||||
* be either an instance of an array type.
|
||||
* @param id a unique id that identifies the object within the debug information for one
|
||||
* position in the compiled code.
|
||||
* @return a new {@link VirtualObject} instance.
|
||||
*/
|
||||
public static VirtualObject get(ResolvedJavaType type, int id) {
|
||||
return new VirtualObject(type, id);
|
||||
}
|
||||
|
||||
private VirtualObject(ResolvedJavaType type, int id) {
|
||||
this.type = type;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
private static StringBuilder appendValue(StringBuilder buf, JavaValue value, Set<VirtualObject> visited) {
|
||||
if (value instanceof VirtualObject) {
|
||||
VirtualObject vo = (VirtualObject) value;
|
||||
buf.append("vobject:").append(vo.type.toJavaName(false)).append(':').append(vo.id);
|
||||
if (!visited.contains(vo)) {
|
||||
visited.add(vo);
|
||||
buf.append('{');
|
||||
if (vo.values == null) {
|
||||
buf.append("<uninitialized>");
|
||||
} else {
|
||||
if (vo.type.isArray()) {
|
||||
for (int i = 0; i < vo.values.length; i++) {
|
||||
if (i != 0) {
|
||||
buf.append(',');
|
||||
}
|
||||
buf.append(i).append('=');
|
||||
appendValue(buf, vo.values[i], visited);
|
||||
}
|
||||
} else {
|
||||
ResolvedJavaField[] fields = vo.type.getInstanceFields(true);
|
||||
assert fields.length == vo.values.length : vo.type + ", fields=" + Arrays.toString(fields) + ", values=" + Arrays.toString(vo.values);
|
||||
for (int i = 0; i < vo.values.length; i++) {
|
||||
if (i != 0) {
|
||||
buf.append(',');
|
||||
}
|
||||
buf.append(fields[i].getName()).append('=');
|
||||
appendValue(buf, vo.values[i], visited);
|
||||
}
|
||||
}
|
||||
}
|
||||
buf.append('}');
|
||||
}
|
||||
} else {
|
||||
buf.append(value);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
Set<VirtualObject> visited = Collections.newSetFromMap(new IdentityHashMap<VirtualObject, Boolean>());
|
||||
return appendValue(new StringBuilder(), this, visited).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of the object whose allocation was removed during compilation. This can be
|
||||
* either an instance of an array type.
|
||||
*/
|
||||
public ResolvedJavaType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array containing all the values to be stored into the object when it is recreated.
|
||||
*/
|
||||
public JavaValue[] getValues() {
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array containing the Java kind of all values in the object.
|
||||
*/
|
||||
public JavaKind[] getSlotKinds() {
|
||||
return slotKinds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unique id that identifies the object within the debug information for one
|
||||
* position in the compiled code.
|
||||
*/
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private boolean checkValues() {
|
||||
assert (values == null) == (slotKinds == null);
|
||||
if (values != null) {
|
||||
assert values.length == slotKinds.length;
|
||||
if (!type.isArray()) {
|
||||
ResolvedJavaField[] fields = type.getInstanceFields(true);
|
||||
int fieldIndex = 0;
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
ResolvedJavaField field = fields[fieldIndex++];
|
||||
JavaKind valKind = slotKinds[i].getStackKind();
|
||||
if (field.getJavaKind() == JavaKind.Object) {
|
||||
assert valKind.isObject() : field + ": " + valKind + " != " + field.getJavaKind();
|
||||
} else {
|
||||
if ((valKind == JavaKind.Double || valKind == JavaKind.Long) && field.getJavaKind() == JavaKind.Int) {
|
||||
assert fields[fieldIndex].getJavaKind() == JavaKind.Int;
|
||||
fieldIndex++;
|
||||
} else {
|
||||
assert valKind == field.getJavaKind().getStackKind() : field + ": " + valKind + " != " + field.getJavaKind();
|
||||
}
|
||||
}
|
||||
}
|
||||
assert fields.length == fieldIndex : type + ": fields=" + Arrays.toString(fields) + ", field values=" + Arrays.toString(values);
|
||||
} else {
|
||||
JavaKind componentKind = type.getComponentType().getJavaKind().getStackKind();
|
||||
if (componentKind == JavaKind.Object) {
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
assert slotKinds[i].isObject() : slotKinds[i] + " != " + componentKind;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
assert slotKinds[i] == componentKind || componentKind.getBitCount() >= slotKinds[i].getBitCount() ||
|
||||
(componentKind == JavaKind.Int && slotKinds[i].getBitCount() >= JavaKind.Int.getBitCount()) : slotKinds[i] + " != " + componentKind;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrites the current set of values with a new one.
|
||||
*
|
||||
* @param values an array containing all the values to be stored into the object when it is
|
||||
* recreated.
|
||||
* @param slotKinds an array containing the Java kinds of the values.
|
||||
*/
|
||||
public void setValues(JavaValue[] values, JavaKind[] slotKinds) {
|
||||
this.values = values;
|
||||
this.slotKinds = slotKinds;
|
||||
assert checkValues();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 42 + type.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) {
|
||||
return true;
|
||||
}
|
||||
if (o instanceof VirtualObject) {
|
||||
VirtualObject l = (VirtualObject) o;
|
||||
if (!l.type.equals(type) || l.values.length != values.length) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
/*
|
||||
* Virtual objects can form cycles. Calling equals() could therefore lead to
|
||||
* infinite recursion.
|
||||
*/
|
||||
if (!same(values[i], l.values[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean same(Object o1, Object o2) {
|
||||
return o1 == o2;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user