8136421: JEP 243: Java-Level JVM Compiler Interface

Reviewed-by: ihse, alanb, roland, coleenp, iveresov, kvn, kbarrett
This commit is contained in:
Christian Thalinger 2015-10-08 12:49:30 -10:00
parent f5b4bb46f5
commit 16526e000e
505 changed files with 50394 additions and 915 deletions

View File

@ -28,4 +28,7 @@ TYPE=COMPILER1
VM_SUBDIR = client
# We don't support the JVMCI in a client VM.
INCLUDE_JVMCI := false
CFLAGS += -DCOMPILER1

View File

@ -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)

View File

@ -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\"

View File

@ -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

View 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

View File

@ -28,4 +28,7 @@ TYPE=COMPILER1
VM_SUBDIR = client
# We don't support the JVMCI in a client VM.
INCLUDE_JVMCI := false
CFLAGS += -DCOMPILER1

View File

@ -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\"

View File

@ -28,4 +28,7 @@ TYPE=COMPILER1
VM_SUBDIR = client
# We don't support the JVMCI in a client VM.
INCLUDE_JVMCI := false
CFLAGS += -DCOMPILER1

View File

@ -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

View File

@ -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.

View File

@ -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)
##################################################

View File

@ -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 $<

View File

@ -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.

View File

@ -30,5 +30,6 @@
void generate_more_monitors();
void generate_deopt_handling();
void lock_method(void);
#endif // CPU_AARCH64_VM_CPPINTERPRETERGENERATOR_AARCH64_HPP

View File

@ -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);

View 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;
}

View File

@ -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) {
}

View File

@ -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

View File

@ -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(

View File

@ -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:

View 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;
}

View File

@ -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) {
}

View File

@ -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);

View File

@ -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 __

View File

@ -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,

View File

@ -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
//

View File

@ -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);

View File

@ -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);

View File

@ -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);

View 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();
}

View File

@ -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.

View File

@ -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) {
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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,

View File

@ -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 {

View File

@ -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);

View File

@ -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) {}

View File

@ -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

View File

@ -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,

View File

@ -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
//

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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);

View File

@ -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) {

View File

@ -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);

View File

@ -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);

View 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());
}

View File

@ -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

View File

@ -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;

View File

@ -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 ) &&

View 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;
}

View File

@ -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() {}

View File

@ -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"

View File

@ -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;
};

View File

@ -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;

View File

@ -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.

View File

@ -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

View File

@ -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);

View File

@ -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(

View File

@ -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

View File

@ -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)

View File

@ -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;

View File

@ -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.

View File

@ -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;
}
}
}
%}

View File

@ -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;
}
}
}

View File

@ -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>

View File

@ -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 {
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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());
}
}
}

View File

@ -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;
}
}

View File

@ -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();
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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 &amp; 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 &amp; writes act as acquire &amp; 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();
}
}

View File

@ -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 {
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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();
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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