--- a/hotspot/make/aix/Makefile Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/make/aix/Makefile Fri Dec 04 23:50:05 2015 +0000
@@ -1,6 +1,6 @@
#
# Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
-# Copyright 2012, 2013 SAP AG. All rights reserved.
+# Copyright 2012, 2015 SAP AG. 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
@@ -61,10 +61,6 @@
FORCE_TIERED=1
endif
endif
-# C1 is not ported on ppc64(le), so we cannot build a tiered VM:
-ifneq (,$(filter $(ARCH),ppc64 pp64le))
- FORCE_TIERED=0
-endif
ifdef LP64
ifeq ("$(filter $(LP64_ARCH),$(BUILDARCH))","")
--- a/hotspot/make/aix/makefiles/fastdebug.make Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/make/aix/makefiles/fastdebug.make Fri Dec 04 23:50:05 2015 +0000
@@ -68,5 +68,5 @@
LFLAGS_QIPA=
VERSION = optimized
-SYSDEFS += -DASSERT -DFASTDEBUG
+SYSDEFS += -DASSERT
PICFLAGS = DEFAULT
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/make/aix/makefiles/tiered.make Fri Dec 04 23:50:05 2015 +0000
@@ -0,0 +1,32 @@
+#
+# Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2012, 2015 SAP AG. 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.
+#
+#
+
+# Sets make macros for making tiered version of VM
+
+TYPE=TIERED
+
+VM_SUBDIR = server
+
+CFLAGS += -DCOMPILER2 -DCOMPILER1
--- a/hotspot/make/linux/Makefile Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/make/linux/Makefile Fri Dec 04 23:50:05 2015 +0000
@@ -57,14 +57,6 @@
FORCE_TIERED=1
endif
endif
-# C1 is not ported on ppc64, so we cannot build a tiered VM:
-# Notice: after 8046471 ARCH will be 'ppc' for top-level ppc64 builds but
-# 'ppc64' for HotSpot-only ppc64 builds. Need to detect both variants here!
-ifneq (,$(findstring $(ARCH), ppc ppc64))
- ifeq ($(ARCH_DATA_MODEL), 64)
- FORCE_TIERED=0
- endif
-endif
ifdef LP64
ifeq ("$(filter $(LP64_ARCH),$(BUILDARCH))","")
--- a/hotspot/src/cpu/aarch64/vm/aarch64.ad Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad Fri Dec 04 23:50:05 2015 +0000
@@ -4667,17 +4667,12 @@
if (!_method) {
// A call to a runtime wrapper, e.g. new, new_typeArray_Java, uncommon_trap.
call = __ trampoline_call(Address(addr, relocInfo::runtime_call_type), &cbuf);
- } else if (_optimized_virtual) {
- call = __ trampoline_call(Address(addr, relocInfo::opt_virtual_call_type), &cbuf);
} else {
- call = __ trampoline_call(Address(addr, relocInfo::static_call_type), &cbuf);
- }
- if (call == NULL) {
- ciEnv::current()->record_failure("CodeCache is full");
- return;
- }
-
- if (_method) {
+ int method_index = resolved_method_index(cbuf);
+ RelocationHolder rspec = _optimized_virtual ? opt_virtual_call_Relocation::spec(method_index)
+ : static_call_Relocation::spec(method_index);
+ call = __ trampoline_call(Address(addr, rspec), &cbuf);
+
// Emit stub for static call
address stub = CompiledStaticCall::emit_to_interp_stub(cbuf);
if (stub == NULL) {
@@ -4685,11 +4680,16 @@
return;
}
}
+ if (call == NULL) {
+ ciEnv::current()->record_failure("CodeCache is full");
+ return;
+ }
%}
enc_class aarch64_enc_java_dynamic_call(method meth) %{
MacroAssembler _masm(&cbuf);
- address call = __ ic_call((address)$meth$$method);
+ int method_index = resolved_method_index(cbuf);
+ address call = __ ic_call((address)$meth$$method, method_index);
if (call == NULL) {
ciEnv::current()->record_failure("CodeCache is full");
return;
--- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -732,8 +732,8 @@
return stub;
}
-address MacroAssembler::ic_call(address entry) {
- RelocationHolder rh = virtual_call_Relocation::spec(pc());
+address MacroAssembler::ic_call(address entry, jint method_index) {
+ RelocationHolder rh = virtual_call_Relocation::spec(pc(), method_index);
// address const_ptr = long_constant((jlong)Universe::non_oop_word());
// unsigned long offset;
// ldr_constant(rscratch2, const_ptr);
--- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -983,7 +983,7 @@
}
// Emit the CompiledIC call idiom
- address ic_call(address entry);
+ address ic_call(address entry, jint method_index = 0);
public:
--- a/hotspot/src/cpu/ppc/vm/assembler_ppc.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/assembler_ppc.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -53,9 +53,6 @@
return 0x00; // illegal instruction 0x00000000
}
-void Assembler::print_instruction(int inst) {
- Unimplemented();
-}
// Patch instruction `inst' at offset `inst_pos' to refer to
// `dest_pos' and return the resulting instruction. We should have
@@ -484,7 +481,7 @@
if (d != s) { mr(d, s); }
return 0;
}
- if (return_simm16_rest) {
+ if (return_simm16_rest && (d == s)) {
return xd;
}
addi(d, s, xd);
--- a/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -31,10 +31,37 @@
// Address is an abstraction used to represent a memory location
// as used in assembler instructions.
// PPC instructions grok either baseReg + indexReg or baseReg + disp.
-// So far we do not use this as simplification by this class is low
-// on PPC with its simple addressing mode. Use RegisterOrConstant to
-// represent an offset.
class Address VALUE_OBJ_CLASS_SPEC {
+ private:
+ Register _base; // Base register.
+ Register _index; // Index register.
+ intptr_t _disp; // Displacement.
+
+ public:
+ Address(Register b, Register i, address d = 0)
+ : _base(b), _index(i), _disp((intptr_t)d) {
+ assert(i == noreg || d == 0, "can't have both");
+ }
+
+ Address(Register b, address d = 0)
+ : _base(b), _index(noreg), _disp((intptr_t)d) {}
+
+ Address(Register b, intptr_t d)
+ : _base(b), _index(noreg), _disp(d) {}
+
+ Address(Register b, RegisterOrConstant roc)
+ : _base(b), _index(noreg), _disp(0) {
+ if (roc.is_constant()) _disp = roc.as_constant(); else _index = roc.as_register();
+ }
+
+ Address()
+ : _base(noreg), _index(noreg), _disp(0) {}
+
+ // accessors
+ Register base() const { return _base; }
+ Register index() const { return _index; }
+ int disp() const { return (int)_disp; }
+ bool is_const() const { return _base == noreg && _index == noreg; }
};
class AddressLiteral VALUE_OBJ_CLASS_SPEC {
@@ -164,10 +191,14 @@
};
#endif
+
+// The PPC Assembler: Pure assembler doing NO optimizations on the
+// instruction level; i.e., what you write is what you get. The
+// Assembler is generating code into a CodeBuffer.
+
class Assembler : public AbstractAssembler {
protected:
// Displacement routines
- static void print_instruction(int inst);
static int patched_branch(int dest_pos, int inst, int inst_pos);
static int branch_destination(int inst, int pos);
@@ -839,41 +870,38 @@
enum Predict { pt = 1, pn = 0 }; // pt = predict taken
- // instruction must start at passed address
+ // Instruction must start at passed address.
static int instr_len(unsigned char *instr) { return BytesPerInstWord; }
- // instruction must be left-justified in argument
- static int instr_len(unsigned long instr) { return BytesPerInstWord; }
-
// longest instructions
static int instr_maxlen() { return BytesPerInstWord; }
// Test if x is within signed immediate range for nbits.
static bool is_simm(int x, unsigned int nbits) {
assert(0 < nbits && nbits < 32, "out of bounds");
- const int min = -( ((int)1) << nbits-1 );
- const int maxplus1 = ( ((int)1) << nbits-1 );
+ const int min = -(((int)1) << nbits-1);
+ const int maxplus1 = (((int)1) << nbits-1);
return min <= x && x < maxplus1;
}
static bool is_simm(jlong x, unsigned int nbits) {
assert(0 < nbits && nbits < 64, "out of bounds");
- const jlong min = -( ((jlong)1) << nbits-1 );
- const jlong maxplus1 = ( ((jlong)1) << nbits-1 );
+ const jlong min = -(((jlong)1) << nbits-1);
+ const jlong maxplus1 = (((jlong)1) << nbits-1);
return min <= x && x < maxplus1;
}
- // Test if x is within unsigned immediate range for nbits
+ // Test if x is within unsigned immediate range for nbits.
static bool is_uimm(int x, unsigned int nbits) {
assert(0 < nbits && nbits < 32, "out of bounds");
- const int maxplus1 = ( ((int)1) << nbits );
- return 0 <= x && x < maxplus1;
+ const unsigned int maxplus1 = (((unsigned int)1) << nbits);
+ return (unsigned int)x < maxplus1;
}
static bool is_uimm(jlong x, unsigned int nbits) {
assert(0 < nbits && nbits < 64, "out of bounds");
- const jlong maxplus1 = ( ((jlong)1) << nbits );
- return 0 <= x && x < maxplus1;
+ const julong maxplus1 = (((julong)1) << nbits);
+ return (julong)x < maxplus1;
}
protected:
@@ -1376,8 +1404,11 @@
inline void orc( Register a, Register s, Register b);
inline void orc_( Register a, Register s, Register b);
inline void extsb( Register a, Register s);
+ inline void extsb_( Register a, Register s);
inline void extsh( Register a, Register s);
+ inline void extsh_( Register a, Register s);
inline void extsw( Register a, Register s);
+ inline void extsw_( Register a, Register s);
// extended mnemonics
inline void nop();
@@ -1767,6 +1798,8 @@
inline void smt_yield();
inline void smt_mdoio();
inline void smt_mdoom();
+ // >= Power8
+ inline void smt_miso();
// trap instructions
inline void twi_0(Register a); // for load with acquire semantics use load+twi_0+isync (trap can't occur)
@@ -2168,6 +2201,7 @@
inline void load_const(Register d, void* a, Register tmp = noreg);
inline void load_const(Register d, Label& L, Register tmp = noreg);
inline void load_const(Register d, AddressLiteral& a, Register tmp = noreg);
+ inline void load_const32(Register d, int i); // load signed int (patchable)
// Load a 64 bit constant, optimized, not identifyable.
// Tmp can be used to increase ILP. Set return_simm16_rest = true to get a
--- a/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -206,8 +206,11 @@
inline void Assembler::orc( Register a, Register s, Register b) { emit_int32(ORC_OPCODE | rta(a) | rs(s) | rb(b) | rc(0)); }
inline void Assembler::orc_( Register a, Register s, Register b) { emit_int32(ORC_OPCODE | rta(a) | rs(s) | rb(b) | rc(1)); }
inline void Assembler::extsb( Register a, Register s) { emit_int32(EXTSB_OPCODE | rta(a) | rs(s) | rc(0)); }
+inline void Assembler::extsb_( Register a, Register s) { emit_int32(EXTSB_OPCODE | rta(a) | rs(s) | rc(1)); }
inline void Assembler::extsh( Register a, Register s) { emit_int32(EXTSH_OPCODE | rta(a) | rs(s) | rc(0)); }
+inline void Assembler::extsh_( Register a, Register s) { emit_int32(EXTSH_OPCODE | rta(a) | rs(s) | rc(1)); }
inline void Assembler::extsw( Register a, Register s) { emit_int32(EXTSW_OPCODE | rta(a) | rs(s) | rc(0)); }
+inline void Assembler::extsw_( Register a, Register s) { emit_int32(EXTSW_OPCODE | rta(a) | rs(s) | rc(1)); }
// extended mnemonics
inline void Assembler::nop() { Assembler::ori(R0, R0, 0); }
@@ -609,6 +612,8 @@
inline void Assembler::smt_yield() { Assembler::or_unchecked(R27, R27, R27); }
inline void Assembler::smt_mdoio() { Assembler::or_unchecked(R29, R29, R29); }
inline void Assembler::smt_mdoom() { Assembler::or_unchecked(R30, R30, R30); }
+// >= Power8
+inline void Assembler::smt_miso() { Assembler::or_unchecked(R26, R26, R26); }
inline void Assembler::twi_0(Register a) { twi_unchecked(0, a, 0);}
@@ -967,12 +972,15 @@
// Load a 64 bit constant encoded by an AddressLiteral. patchable.
inline void Assembler::load_const(Register d, AddressLiteral& a, Register tmp) {
- assert(d != R0, "R0 not allowed");
// First relocate (we don't change the offset in the RelocationHolder,
// just pass a.rspec()), then delegate to load_const(Register, long).
relocate(a.rspec());
load_const(d, (long)a.value(), tmp);
}
+inline void Assembler::load_const32(Register d, int i) {
+ lis(d, i >> 16);
+ ori(d, d, i & 0xFFFF);
+}
#endif // CPU_PPC_VM_ASSEMBLER_PPC_INLINE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/cpu/ppc/vm/c1_CodeStubs_ppc.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -0,0 +1,527 @@
+/*
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012, 2015 SAP AG. 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 "c1/c1_CodeStubs.hpp"
+#include "c1/c1_FrameMap.hpp"
+#include "c1/c1_LIRAssembler.hpp"
+#include "c1/c1_MacroAssembler.hpp"
+#include "c1/c1_Runtime1.hpp"
+#include "nativeInst_ppc.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "utilities/macros.hpp"
+#include "vmreg_ppc.inline.hpp"
+#if INCLUDE_ALL_GCS
+#include "gc/g1/g1SATBCardTableModRefBS.hpp"
+#endif // INCLUDE_ALL_GCS
+
+#define __ ce->masm()->
+
+
+RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index,
+ bool throw_index_out_of_bounds_exception)
+ : _throw_index_out_of_bounds_exception(throw_index_out_of_bounds_exception)
+ , _index(index) {
+ assert(info != NULL, "must have info");
+ _info = new CodeEmitInfo(info);
+}
+
+void RangeCheckStub::emit_code(LIR_Assembler* ce) {
+ __ bind(_entry);
+
+ if (_info->deoptimize_on_exception()) {
+ address a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id);
+ // May be used by optimizations like LoopInvariantCodeMotion or RangeCheckEliminator.
+ DEBUG_ONLY( __ untested("RangeCheckStub: predicate_failed_trap_id"); )
+ //__ load_const_optimized(R0, a);
+ __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(a));
+ __ mtctr(R0);
+ __ bctrl();
+ ce->add_call_info_here(_info);
+ ce->verify_oop_map(_info);
+ debug_only(__ illtrap());
+ return;
+ }
+
+ address stub = _throw_index_out_of_bounds_exception ? Runtime1::entry_for(Runtime1::throw_index_exception_id)
+ : Runtime1::entry_for(Runtime1::throw_range_check_failed_id);
+ //__ load_const_optimized(R0, stub);
+ __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
+ __ mtctr(R0);
+
+ Register index = R0; // pass in R0
+ if (_index->is_register()) {
+ __ extsw(index, _index->as_register());
+ } else {
+ __ load_const_optimized(index, _index->as_jint());
+ }
+
+ __ bctrl();
+ ce->add_call_info_here(_info);
+ ce->verify_oop_map(_info);
+ debug_only(__ illtrap());
+}
+
+
+PredicateFailedStub::PredicateFailedStub(CodeEmitInfo* info) {
+ _info = new CodeEmitInfo(info);
+}
+
+void PredicateFailedStub::emit_code(LIR_Assembler* ce) {
+ __ bind(_entry);
+ address a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id);
+ //__ load_const_optimized(R0, a);
+ __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(a));
+ __ mtctr(R0);
+ __ bctrl();
+ ce->add_call_info_here(_info);
+ ce->verify_oop_map(_info);
+ debug_only(__ illtrap());
+}
+
+
+void CounterOverflowStub::emit_code(LIR_Assembler* ce) {
+ __ bind(_entry);
+
+ // Parameter 1: bci
+ __ load_const_optimized(R0, _bci);
+ __ std(R0, -16, R1_SP);
+
+ // Parameter 2: Method*
+ Metadata *m = _method->as_constant_ptr()->as_metadata();
+ AddressLiteral md = __ constant_metadata_address(m); // Notify OOP recorder (don't need the relocation).
+ __ load_const_optimized(R0, md.value());
+ __ std(R0, -8, R1_SP);
+
+ address a = Runtime1::entry_for(Runtime1::counter_overflow_id);
+ //__ load_const_optimized(R0, a);
+ __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(a));
+ __ mtctr(R0);
+ __ bctrl();
+ ce->add_call_info_here(_info);
+ ce->verify_oop_map(_info);
+
+ __ b(_continuation);
+}
+
+
+void DivByZeroStub::emit_code(LIR_Assembler* ce) {
+ if (_offset != -1) {
+ ce->compilation()->implicit_exception_table()->append(_offset, __ offset());
+ }
+ __ bind(_entry);
+ address stub = Runtime1::entry_for(Runtime1::throw_div0_exception_id);
+ //__ load_const_optimized(R0, stub);
+ __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
+ __ mtctr(R0);
+ __ bctrl();
+ ce->add_call_info_here(_info);
+ ce->verify_oop_map(_info);
+ debug_only(__ illtrap());
+}
+
+
+void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) {
+ address a;
+ if (_info->deoptimize_on_exception()) {
+ // Deoptimize, do not throw the exception, because it is probably wrong to do it here.
+ a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id);
+ } else {
+ a = Runtime1::entry_for(Runtime1::throw_null_pointer_exception_id);
+ }
+
+ if (ImplicitNullChecks || TrapBasedNullChecks) {
+ ce->compilation()->implicit_exception_table()->append(_offset, __ offset());
+ }
+ __ bind(_entry);
+ //__ load_const_optimized(R0, a);
+ __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(a));
+ __ mtctr(R0);
+ __ bctrl();
+ ce->add_call_info_here(_info);
+ ce->verify_oop_map(_info);
+ debug_only(__ illtrap());
+}
+
+
+// Implementation of SimpleExceptionStub
+void SimpleExceptionStub::emit_code(LIR_Assembler* ce) {
+ __ bind(_entry);
+ address stub = Runtime1::entry_for(_stub);
+ //__ load_const_optimized(R0, stub);
+ __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
+ if (_obj->is_valid()) { __ mr_if_needed(/*tmp1 in do_CheckCast*/ R4_ARG2, _obj->as_register()); }
+ __ mtctr(R0);
+ __ bctrl();
+ ce->add_call_info_here(_info);
+ debug_only( __ illtrap(); )
+}
+
+
+// Implementation of NewInstanceStub
+NewInstanceStub::NewInstanceStub(LIR_Opr klass_reg, LIR_Opr result, ciInstanceKlass* klass, CodeEmitInfo* info, Runtime1::StubID stub_id) {
+ _result = result;
+ _klass = klass;
+ _klass_reg = klass_reg;
+ _info = new CodeEmitInfo(info);
+ assert(stub_id == Runtime1::new_instance_id ||
+ stub_id == Runtime1::fast_new_instance_id ||
+ stub_id == Runtime1::fast_new_instance_init_check_id,
+ "need new_instance id");
+ _stub_id = stub_id;
+}
+
+void NewInstanceStub::emit_code(LIR_Assembler* ce) {
+ __ bind(_entry);
+
+ address entry = Runtime1::entry_for(_stub_id);
+ //__ load_const_optimized(R0, entry);
+ __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(entry));
+ __ mtctr(R0);
+ __ bctrl();
+ ce->add_call_info_here(_info);
+ ce->verify_oop_map(_info);
+ __ b(_continuation);
+}
+
+
+// Implementation of NewTypeArrayStub
+NewTypeArrayStub::NewTypeArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result, CodeEmitInfo* info) {
+ _klass_reg = klass_reg;
+ _length = length;
+ _result = result;
+ _info = new CodeEmitInfo(info);
+}
+
+void NewTypeArrayStub::emit_code(LIR_Assembler* ce) {
+ __ bind(_entry);
+
+ address entry = Runtime1::entry_for(Runtime1::new_type_array_id);
+ //__ load_const_optimized(R0, entry);
+ __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(entry));
+ __ mr_if_needed(/*op->tmp1()->as_register()*/ R5_ARG3, _length->as_register()); // already sign-extended
+ __ mtctr(R0);
+ __ bctrl();
+ ce->add_call_info_here(_info);
+ ce->verify_oop_map(_info);
+ __ b(_continuation);
+}
+
+
+// Implementation of NewObjectArrayStub
+NewObjectArrayStub::NewObjectArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result, CodeEmitInfo* info) {
+ _klass_reg = klass_reg;
+ _length = length;
+ _result = result;
+ _info = new CodeEmitInfo(info);
+}
+
+void NewObjectArrayStub::emit_code(LIR_Assembler* ce) {
+ __ bind(_entry);
+
+ address entry = Runtime1::entry_for(Runtime1::new_object_array_id);
+ //__ load_const_optimized(R0, entry);
+ __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(entry));
+ __ mr_if_needed(/*op->tmp1()->as_register()*/ R5_ARG3, _length->as_register()); // already sign-extended
+ __ mtctr(R0);
+ __ bctrl();
+ ce->add_call_info_here(_info);
+ ce->verify_oop_map(_info);
+ __ b(_continuation);
+}
+
+
+// Implementation of MonitorAccessStubs
+MonitorEnterStub::MonitorEnterStub(LIR_Opr obj_reg, LIR_Opr lock_reg, CodeEmitInfo* info)
+ : MonitorAccessStub(obj_reg, lock_reg) {
+ _info = new CodeEmitInfo(info);
+}
+
+void MonitorEnterStub::emit_code(LIR_Assembler* ce) {
+ __ bind(_entry);
+ address stub = Runtime1::entry_for(ce->compilation()->has_fpu_code() ? Runtime1::monitorenter_id : Runtime1::monitorenter_nofpu_id);
+ //__ load_const_optimized(R0, stub);
+ __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
+ __ mr_if_needed(/*scratch_opr()->as_register()*/ R4_ARG2, _obj_reg->as_register());
+ assert(_lock_reg->as_register() == R5_ARG3, "");
+ __ mtctr(R0);
+ __ bctrl();
+ ce->add_call_info_here(_info);
+ ce->verify_oop_map(_info);
+ __ b(_continuation);
+}
+
+void MonitorExitStub::emit_code(LIR_Assembler* ce) {
+ __ bind(_entry);
+ if (_compute_lock) {
+ ce->monitor_address(_monitor_ix, _lock_reg);
+ }
+ address stub = Runtime1::entry_for(ce->compilation()->has_fpu_code() ? Runtime1::monitorexit_id : Runtime1::monitorexit_nofpu_id);
+ //__ load_const_optimized(R0, stub);
+ __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
+ assert(_lock_reg->as_register() == R4_ARG2, "");
+ __ mtctr(R0);
+ __ bctrl();
+ __ b(_continuation);
+}
+
+
+// Implementation of patching:
+// - Copy the code at given offset to an inlined buffer (first the bytes, then the number of bytes).
+// - Replace original code with a call to the stub.
+// At Runtime:
+// - call to stub, jump to runtime
+// - in runtime: preserve all registers (especially objects, i.e., source and destination object)
+// - in runtime: after initializing class, restore original code, reexecute instruction
+
+int PatchingStub::_patch_info_offset = -(5 * BytesPerInstWord);
+
+void PatchingStub::align_patch_site(MacroAssembler* ) {
+ // Patch sites on ppc are always properly aligned.
+}
+
+#ifdef ASSERT
+inline void compare_with_patch_site(address template_start, address pc_start, int bytes_to_copy) {
+ address start = template_start;
+ for (int i = 0; i < bytes_to_copy; i++) {
+ address ptr = (address)(pc_start + i);
+ int a_byte = (*ptr) & 0xFF;
+ assert(a_byte == *start++, "should be the same code");
+ }
+}
+#endif
+
+void PatchingStub::emit_code(LIR_Assembler* ce) {
+ // copy original code here
+ assert(NativeGeneralJump::instruction_size <= _bytes_to_copy && _bytes_to_copy <= 0xFF,
+ "not enough room for call");
+ assert((_bytes_to_copy & 0x3) == 0, "must copy a multiple of four bytes");
+
+ Label call_patch;
+
+ int being_initialized_entry = __ offset();
+
+ if (_id == load_klass_id) {
+ // Produce a copy of the load klass instruction for use by the being initialized case.
+ AddressLiteral addrlit((address)NULL, metadata_Relocation::spec(_index));
+ __ load_const(_obj, addrlit, R0);
+ DEBUG_ONLY( compare_with_patch_site(__ code_section()->start() + being_initialized_entry, _pc_start, _bytes_to_copy); )
+ } else if (_id == load_mirror_id || _id == load_appendix_id) {
+ // Produce a copy of the load mirror instruction for use by the being initialized case.
+ AddressLiteral addrlit((address)NULL, oop_Relocation::spec(_index));
+ __ load_const(_obj, addrlit, R0);
+ DEBUG_ONLY( compare_with_patch_site(__ code_section()->start() + being_initialized_entry, _pc_start, _bytes_to_copy); )
+ } else {
+ // Make a copy the code which is going to be patched.
+ for (int i = 0; i < _bytes_to_copy; i++) {
+ address ptr = (address)(_pc_start + i);
+ int a_byte = (*ptr) & 0xFF;
+ __ emit_int8 (a_byte);
+ }
+ }
+
+ address end_of_patch = __ pc();
+ int bytes_to_skip = 0;
+ if (_id == load_mirror_id) {
+ int offset = __ offset();
+ __ block_comment(" being_initialized check");
+
+ // Static field accesses have special semantics while the class
+ // initializer is being run so we emit a test which can be used to
+ // check that this code is being executed by the initializing
+ // thread.
+ assert(_obj != noreg, "must be a valid register");
+ assert(_index >= 0, "must have oop index");
+ __ mr(R0, _obj); // spill
+ __ ld(_obj, java_lang_Class::klass_offset_in_bytes(), _obj);
+ __ ld(_obj, in_bytes(InstanceKlass::init_thread_offset()), _obj);
+ __ cmpd(CCR0, _obj, R16_thread);
+ __ mr(_obj, R0); // restore
+ __ bne(CCR0, call_patch);
+
+ // Load_klass patches may execute the patched code before it's
+ // copied back into place so we need to jump back into the main
+ // code of the nmethod to continue execution.
+ __ b(_patch_site_continuation);
+
+ // Make sure this extra code gets skipped.
+ bytes_to_skip += __ offset() - offset;
+ }
+
+ // Now emit the patch record telling the runtime how to find the
+ // pieces of the patch. We only need 3 bytes but it has to be
+ // aligned as an instruction so emit 4 bytes.
+ int sizeof_patch_record = 4;
+ bytes_to_skip += sizeof_patch_record;
+
+ // Emit the offsets needed to find the code to patch.
+ int being_initialized_entry_offset = __ offset() - being_initialized_entry + sizeof_patch_record;
+
+ // Emit the patch record. We need to emit a full word, so emit an extra empty byte.
+ __ emit_int8(0);
+ __ emit_int8(being_initialized_entry_offset);
+ __ emit_int8(bytes_to_skip);
+ __ emit_int8(_bytes_to_copy);
+ address patch_info_pc = __ pc();
+ assert(patch_info_pc - end_of_patch == bytes_to_skip, "incorrect patch info");
+
+ address entry = __ pc();
+ NativeGeneralJump::insert_unconditional((address)_pc_start, entry);
+ address target = NULL;
+ relocInfo::relocType reloc_type = relocInfo::none;
+ switch (_id) {
+ case access_field_id: target = Runtime1::entry_for(Runtime1::access_field_patching_id); break;
+ case load_klass_id: target = Runtime1::entry_for(Runtime1::load_klass_patching_id);
+ reloc_type = relocInfo::metadata_type; break;
+ case load_mirror_id: target = Runtime1::entry_for(Runtime1::load_mirror_patching_id);
+ reloc_type = relocInfo::oop_type; break;
+ case load_appendix_id: target = Runtime1::entry_for(Runtime1::load_appendix_patching_id);
+ reloc_type = relocInfo::oop_type; break;
+ default: ShouldNotReachHere();
+ }
+ __ bind(call_patch);
+
+ __ block_comment("patch entry point");
+ //__ load_const(R0, target); + mtctr + bctrl must have size -_patch_info_offset
+ __ load_const32(R0, MacroAssembler::offset_to_global_toc(target));
+ __ add(R0, R29_TOC, R0);
+ __ mtctr(R0);
+ __ bctrl();
+ assert(_patch_info_offset == (patch_info_pc - __ pc()), "must not change");
+ ce->add_call_info_here(_info);
+ __ b(_patch_site_entry);
+ if (_id == load_klass_id || _id == load_mirror_id || _id == load_appendix_id) {
+ CodeSection* cs = __ code_section();
+ address pc = (address)_pc_start;
+ RelocIterator iter(cs, pc, pc + 1);
+ relocInfo::change_reloc_info_for_address(&iter, (address) pc, reloc_type, relocInfo::none);
+ }
+}
+
+
+void DeoptimizeStub::emit_code(LIR_Assembler* ce) {
+ __ bind(_entry);
+ address stub = Runtime1::entry_for(Runtime1::deoptimize_id);
+ //__ load_const_optimized(R0, stub);
+ __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
+ __ mtctr(R0);
+
+ __ load_const_optimized(R0, _trap_request); // Pass trap request in R0.
+ __ bctrl();
+ ce->add_call_info_here(_info);
+ debug_only(__ illtrap());
+}
+
+
+void ArrayCopyStub::emit_code(LIR_Assembler* ce) {
+ //---------------slow case: call to native-----------------
+ __ bind(_entry);
+ __ mr(R3_ARG1, src()->as_register());
+ __ extsw(R4_ARG2, src_pos()->as_register());
+ __ mr(R5_ARG3, dst()->as_register());
+ __ extsw(R6_ARG4, dst_pos()->as_register());
+ __ extsw(R7_ARG5, length()->as_register());
+
+ ce->emit_static_call_stub();
+
+ bool success = ce->emit_trampoline_stub_for_call(SharedRuntime::get_resolve_static_call_stub());
+ if (!success) { return; }
+
+ __ relocate(relocInfo::static_call_type);
+ // Note: At this point we do not have the address of the trampoline
+ // stub, and the entry point might be too far away for bl, so __ pc()
+ // serves as dummy and the bl will be patched later.
+ __ code()->set_insts_mark();
+ __ bl(__ pc());
+ ce->add_call_info_here(info());
+ ce->verify_oop_map(info());
+
+#ifndef PRODUCT
+ const address counter = (address)&Runtime1::_arraycopy_slowcase_cnt;
+ const Register tmp = R3, tmp2 = R4;
+ int simm16_offs = __ load_const_optimized(tmp, counter, tmp2, true);
+ __ lwz(tmp2, simm16_offs, tmp);
+ __ addi(tmp2, tmp2, 1);
+ __ stw(tmp2, simm16_offs, tmp);
+#endif
+
+ __ b(_continuation);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////
+#if INCLUDE_ALL_GCS
+
+void G1PreBarrierStub::emit_code(LIR_Assembler* ce) {
+ // At this point we know that marking is in progress.
+ // If do_load() is true then we have to emit the
+ // load of the previous value; otherwise it has already
+ // been loaded into _pre_val.
+
+ __ bind(_entry);
+
+ assert(pre_val()->is_register(), "Precondition.");
+ Register pre_val_reg = pre_val()->as_register();
+
+ if (do_load()) {
+ ce->mem2reg(addr(), pre_val(), T_OBJECT, patch_code(), info(), false /*wide*/, false /*unaligned*/);
+ }
+
+ __ cmpdi(CCR0, pre_val_reg, 0);
+ __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CCR0, Assembler::equal), _continuation);
+
+ address stub = Runtime1::entry_for(Runtime1::Runtime1::g1_pre_barrier_slow_id);
+ //__ load_const_optimized(R0, stub);
+ __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
+ __ std(pre_val_reg, -8, R1_SP); // Pass pre_val on stack.
+ __ mtctr(R0);
+ __ bctrl();
+ __ b(_continuation);
+}
+
+void G1PostBarrierStub::emit_code(LIR_Assembler* ce) {
+ __ bind(_entry);
+
+ assert(addr()->is_register(), "Precondition.");
+ assert(new_val()->is_register(), "Precondition.");
+ Register addr_reg = addr()->as_pointer_register();
+ Register new_val_reg = new_val()->as_register();
+
+ __ cmpdi(CCR0, new_val_reg, 0);
+ __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CCR0, Assembler::equal), _continuation);
+
+ address stub = Runtime1::entry_for(Runtime1::Runtime1::g1_post_barrier_slow_id);
+ //__ load_const_optimized(R0, stub);
+ __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
+ __ mtctr(R0);
+ __ mr(R0, addr_reg); // Pass addr in R0.
+ __ bctrl();
+ __ b(_continuation);
+}
+
+#endif // INCLUDE_ALL_GCS
+///////////////////////////////////////////////////////////////////////////////////
+
+#undef __
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/cpu/ppc/vm/c1_Defs_ppc.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012, 2015 SAP AG. 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.
+ *
+ */
+
+#ifndef CPU_PPC_VM_C1_DEFS_PPC_HPP
+#define CPU_PPC_VM_C1_DEFS_PPC_HPP
+
+// Native word offsets from memory address.
+enum {
+#if defined(VM_LITTLE_ENDIAN)
+ pd_lo_word_offset_in_bytes = 0,
+ pd_hi_word_offset_in_bytes = BytesPerInt
+#else
+ pd_lo_word_offset_in_bytes = BytesPerInt,
+ pd_hi_word_offset_in_bytes = 0
+#endif
+};
+
+
+// Explicit rounding operations are not required to implement the strictFP mode.
+enum {
+ pd_strict_fp_requires_explicit_rounding = false
+};
+
+
+// registers
+enum {
+ pd_nof_cpu_regs_frame_map = 32, // Number of registers used during code emission.
+ pd_nof_caller_save_cpu_regs_frame_map = 27, // Number of cpu registers killed by calls. (At least R3_ARG1 ... R10_ARG8, but using all like C2.)
+ pd_nof_cpu_regs_reg_alloc = 27, // Number of registers that are visible to register allocator.
+ pd_nof_cpu_regs_linearscan = 32, // Number of registers visible linear scan.
+ pd_first_callee_saved_reg = pd_nof_caller_save_cpu_regs_frame_map,
+ pd_last_callee_saved_reg = pd_nof_cpu_regs_reg_alloc - 1,
+ pd_first_cpu_reg = 0,
+ pd_last_cpu_reg = pd_nof_cpu_regs_reg_alloc - 1,
+
+ pd_nof_fpu_regs_frame_map = 32, // Number of registers used during code emission.
+ pd_nof_caller_save_fpu_regs_frame_map = 32, // Number of fpu registers killed by calls.
+ pd_nof_fpu_regs_reg_alloc = 32, // Number of registers that are visible to register allocator.
+ pd_nof_fpu_regs_linearscan = 32, // Number of registers visible to linear scan.
+ pd_first_fpu_reg = pd_nof_cpu_regs_frame_map,
+ pd_last_fpu_reg = pd_nof_cpu_regs_frame_map + pd_nof_fpu_regs_reg_alloc - 1,
+
+ pd_nof_xmm_regs_linearscan = 0,
+ pd_nof_caller_save_xmm_regs = 0,
+ pd_first_xmm_reg = -1,
+ pd_last_xmm_reg = -1
+};
+
+// For debug info: a float value in a register is saved in single precision by runtime stubs.
+enum {
+ pd_float_saved_as_double = true
+};
+
+#endif // CPU_PPC_VM_C1_DEFS_PPC_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/cpu/ppc/vm/c1_FpuStackSim_ppc.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012, 2015 SAP AG. 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.
+ *
+ */
+
+#ifndef CPU_PPC_VM_C1_FPUSTACKSIM_PPC_HPP
+#define CPU_PPC_VM_C1_FPUSTACKSIM_PPC_HPP
+
+// No FPU stack on PPC.
+class FpuStackSim;
+
+#endif // CPU_PPC_VM_C1_FPUSTACKSIM_PPC_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/cpu/ppc/vm/c1_FrameMap_ppc.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -0,0 +1,394 @@
+/*
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012, 2015 SAP AG. 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 "c1/c1_FrameMap.hpp"
+#include "c1/c1_LIR.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "vmreg_ppc.inline.hpp"
+
+
+const int FrameMap::pd_c_runtime_reserved_arg_size = 7;
+
+
+LIR_Opr FrameMap::map_to_opr(BasicType type, VMRegPair* reg, bool outgoing) {
+ LIR_Opr opr = LIR_OprFact::illegalOpr;
+ VMReg r_1 = reg->first();
+ VMReg r_2 = reg->second();
+ if (r_1->is_stack()) {
+ // Convert stack slot to an SP offset.
+ // The calling convention does not count the SharedRuntime::out_preserve_stack_slots() value
+ // so we must add it in here.
+ int st_off = (r_1->reg2stack() + SharedRuntime::out_preserve_stack_slots()) * VMRegImpl::stack_slot_size;
+ opr = LIR_OprFact::address(new LIR_Address(SP_opr, st_off + STACK_BIAS, type));
+ } else if (r_1->is_Register()) {
+ Register reg = r_1->as_Register();
+ //if (outgoing) {
+ // assert(!reg->is_in(), "should be using I regs");
+ //} else {
+ // assert(!reg->is_out(), "should be using O regs");
+ //}
+ if (r_2->is_Register() && (type == T_LONG || type == T_DOUBLE)) {
+ opr = as_long_opr(reg);
+ } else if (type == T_OBJECT || type == T_ARRAY) {
+ opr = as_oop_opr(reg);
+ } else {
+ opr = as_opr(reg);
+ }
+ } else if (r_1->is_FloatRegister()) {
+ assert(type == T_DOUBLE || type == T_FLOAT, "wrong type");
+ FloatRegister f = r_1->as_FloatRegister();
+ if (type == T_DOUBLE) {
+ opr = as_double_opr(f);
+ } else {
+ opr = as_float_opr(f);
+ }
+ }
+ return opr;
+}
+
+// FrameMap
+//--------------------------------------------------------
+
+FloatRegister FrameMap::_fpu_regs [FrameMap::nof_fpu_regs];
+
+LIR_Opr FrameMap::R0_opr;
+LIR_Opr FrameMap::R1_opr;
+LIR_Opr FrameMap::R2_opr;
+LIR_Opr FrameMap::R3_opr;
+LIR_Opr FrameMap::R4_opr;
+LIR_Opr FrameMap::R5_opr;
+LIR_Opr FrameMap::R6_opr;
+LIR_Opr FrameMap::R7_opr;
+LIR_Opr FrameMap::R8_opr;
+LIR_Opr FrameMap::R9_opr;
+LIR_Opr FrameMap::R10_opr;
+LIR_Opr FrameMap::R11_opr;
+LIR_Opr FrameMap::R12_opr;
+LIR_Opr FrameMap::R13_opr;
+LIR_Opr FrameMap::R14_opr;
+LIR_Opr FrameMap::R15_opr;
+LIR_Opr FrameMap::R16_opr;
+LIR_Opr FrameMap::R17_opr;
+LIR_Opr FrameMap::R18_opr;
+LIR_Opr FrameMap::R19_opr;
+LIR_Opr FrameMap::R20_opr;
+LIR_Opr FrameMap::R21_opr;
+LIR_Opr FrameMap::R22_opr;
+LIR_Opr FrameMap::R23_opr;
+LIR_Opr FrameMap::R24_opr;
+LIR_Opr FrameMap::R25_opr;
+LIR_Opr FrameMap::R26_opr;
+LIR_Opr FrameMap::R27_opr;
+LIR_Opr FrameMap::R28_opr;
+LIR_Opr FrameMap::R29_opr;
+LIR_Opr FrameMap::R30_opr;
+LIR_Opr FrameMap::R31_opr;
+
+LIR_Opr FrameMap::R0_oop_opr;
+//LIR_Opr FrameMap::R1_oop_opr;
+LIR_Opr FrameMap::R2_oop_opr;
+LIR_Opr FrameMap::R3_oop_opr;
+LIR_Opr FrameMap::R4_oop_opr;
+LIR_Opr FrameMap::R5_oop_opr;
+LIR_Opr FrameMap::R6_oop_opr;
+LIR_Opr FrameMap::R7_oop_opr;
+LIR_Opr FrameMap::R8_oop_opr;
+LIR_Opr FrameMap::R9_oop_opr;
+LIR_Opr FrameMap::R10_oop_opr;
+LIR_Opr FrameMap::R11_oop_opr;
+LIR_Opr FrameMap::R12_oop_opr;
+//LIR_Opr FrameMap::R13_oop_opr;
+LIR_Opr FrameMap::R14_oop_opr;
+LIR_Opr FrameMap::R15_oop_opr;
+//LIR_Opr FrameMap::R16_oop_opr;
+LIR_Opr FrameMap::R17_oop_opr;
+LIR_Opr FrameMap::R18_oop_opr;
+LIR_Opr FrameMap::R19_oop_opr;
+LIR_Opr FrameMap::R20_oop_opr;
+LIR_Opr FrameMap::R21_oop_opr;
+LIR_Opr FrameMap::R22_oop_opr;
+LIR_Opr FrameMap::R23_oop_opr;
+LIR_Opr FrameMap::R24_oop_opr;
+LIR_Opr FrameMap::R25_oop_opr;
+LIR_Opr FrameMap::R26_oop_opr;
+LIR_Opr FrameMap::R27_oop_opr;
+LIR_Opr FrameMap::R28_oop_opr;
+//LIR_Opr FrameMap::R29_oop_opr;
+LIR_Opr FrameMap::R30_oop_opr;
+LIR_Opr FrameMap::R31_oop_opr;
+
+LIR_Opr FrameMap::R0_metadata_opr;
+//LIR_Opr FrameMap::R1_metadata_opr;
+LIR_Opr FrameMap::R2_metadata_opr;
+LIR_Opr FrameMap::R3_metadata_opr;
+LIR_Opr FrameMap::R4_metadata_opr;
+LIR_Opr FrameMap::R5_metadata_opr;
+LIR_Opr FrameMap::R6_metadata_opr;
+LIR_Opr FrameMap::R7_metadata_opr;
+LIR_Opr FrameMap::R8_metadata_opr;
+LIR_Opr FrameMap::R9_metadata_opr;
+LIR_Opr FrameMap::R10_metadata_opr;
+LIR_Opr FrameMap::R11_metadata_opr;
+LIR_Opr FrameMap::R12_metadata_opr;
+//LIR_Opr FrameMap::R13_metadata_opr;
+LIR_Opr FrameMap::R14_metadata_opr;
+LIR_Opr FrameMap::R15_metadata_opr;
+//LIR_Opr FrameMap::R16_metadata_opr;
+LIR_Opr FrameMap::R17_metadata_opr;
+LIR_Opr FrameMap::R18_metadata_opr;
+LIR_Opr FrameMap::R19_metadata_opr;
+LIR_Opr FrameMap::R20_metadata_opr;
+LIR_Opr FrameMap::R21_metadata_opr;
+LIR_Opr FrameMap::R22_metadata_opr;
+LIR_Opr FrameMap::R23_metadata_opr;
+LIR_Opr FrameMap::R24_metadata_opr;
+LIR_Opr FrameMap::R25_metadata_opr;
+LIR_Opr FrameMap::R26_metadata_opr;
+LIR_Opr FrameMap::R27_metadata_opr;
+LIR_Opr FrameMap::R28_metadata_opr;
+//LIR_Opr FrameMap::R29_metadata_opr;
+LIR_Opr FrameMap::R30_metadata_opr;
+LIR_Opr FrameMap::R31_metadata_opr;
+
+LIR_Opr FrameMap::SP_opr;
+
+LIR_Opr FrameMap::R0_long_opr;
+LIR_Opr FrameMap::R3_long_opr;
+
+LIR_Opr FrameMap::F1_opr;
+LIR_Opr FrameMap::F1_double_opr;
+
+LIR_Opr FrameMap::_caller_save_cpu_regs[] = { 0, };
+LIR_Opr FrameMap::_caller_save_fpu_regs[] = { 0, };
+
+FloatRegister FrameMap::nr2floatreg (int rnr) {
+ assert(_init_done, "tables not initialized");
+ debug_only(fpu_range_check(rnr);)
+ return _fpu_regs[rnr];
+}
+
+
+// Returns true if reg could be smashed by a callee.
+bool FrameMap::is_caller_save_register (LIR_Opr reg) {
+ if (reg->is_single_fpu() || reg->is_double_fpu()) { return true; }
+ if (reg->is_double_cpu()) {
+ return is_caller_save_register(reg->as_register_lo()) ||
+ is_caller_save_register(reg->as_register_hi());
+ }
+ return is_caller_save_register(reg->as_register());
+}
+
+
+bool FrameMap::is_caller_save_register (Register r) {
+ // not visible to allocator: R0: scratch, R1: SP
+ // r->encoding() < 2 + nof_caller_save_cpu_regs();
+ return true; // Currently all regs are caller save.
+}
+
+
+void FrameMap::initialize() {
+ assert(!_init_done, "once");
+
+ int i = 0;
+
+ // Put generally available registers at the beginning (allocated, saved for GC).
+ for (int j = 0; j < nof_cpu_regs; ++j) {
+ Register rj = as_Register(j);
+ if (reg_needs_save(rj)) {
+ map_register(i++, rj);
+ }
+ }
+ assert(i == nof_cpu_regs_reg_alloc, "number of allocated registers");
+
+ // The following registers are not normally available.
+ for (int j = 0; j < nof_cpu_regs; ++j) {
+ Register rj = as_Register(j);
+ if (!reg_needs_save(rj)) {
+ map_register(i++, rj);
+ }
+ }
+ assert(i == nof_cpu_regs, "number of CPU registers");
+
+ for (i = 0; i < nof_fpu_regs; i++) {
+ _fpu_regs[i] = as_FloatRegister(i);
+ }
+
+ _init_done = true;
+
+ R0_opr = as_opr(R0);
+ R1_opr = as_opr(R1);
+ R2_opr = as_opr(R2);
+ R3_opr = as_opr(R3);
+ R4_opr = as_opr(R4);
+ R5_opr = as_opr(R5);
+ R6_opr = as_opr(R6);
+ R7_opr = as_opr(R7);
+ R8_opr = as_opr(R8);
+ R9_opr = as_opr(R9);
+ R10_opr = as_opr(R10);
+ R11_opr = as_opr(R11);
+ R12_opr = as_opr(R12);
+ R13_opr = as_opr(R13);
+ R14_opr = as_opr(R14);
+ R15_opr = as_opr(R15);
+ R16_opr = as_opr(R16);
+ R17_opr = as_opr(R17);
+ R18_opr = as_opr(R18);
+ R19_opr = as_opr(R19);
+ R20_opr = as_opr(R20);
+ R21_opr = as_opr(R21);
+ R22_opr = as_opr(R22);
+ R23_opr = as_opr(R23);
+ R24_opr = as_opr(R24);
+ R25_opr = as_opr(R25);
+ R26_opr = as_opr(R26);
+ R27_opr = as_opr(R27);
+ R28_opr = as_opr(R28);
+ R29_opr = as_opr(R29);
+ R30_opr = as_opr(R30);
+ R31_opr = as_opr(R31);
+
+ R0_oop_opr = as_oop_opr(R0);
+ //R1_oop_opr = as_oop_opr(R1);
+ R2_oop_opr = as_oop_opr(R2);
+ R3_oop_opr = as_oop_opr(R3);
+ R4_oop_opr = as_oop_opr(R4);
+ R5_oop_opr = as_oop_opr(R5);
+ R6_oop_opr = as_oop_opr(R6);
+ R7_oop_opr = as_oop_opr(R7);
+ R8_oop_opr = as_oop_opr(R8);
+ R9_oop_opr = as_oop_opr(R9);
+ R10_oop_opr = as_oop_opr(R10);
+ R11_oop_opr = as_oop_opr(R11);
+ R12_oop_opr = as_oop_opr(R12);
+ //R13_oop_opr = as_oop_opr(R13);
+ R14_oop_opr = as_oop_opr(R14);
+ R15_oop_opr = as_oop_opr(R15);
+ //R16_oop_opr = as_oop_opr(R16);
+ R17_oop_opr = as_oop_opr(R17);
+ R18_oop_opr = as_oop_opr(R18);
+ R19_oop_opr = as_oop_opr(R19);
+ R20_oop_opr = as_oop_opr(R20);
+ R21_oop_opr = as_oop_opr(R21);
+ R22_oop_opr = as_oop_opr(R22);
+ R23_oop_opr = as_oop_opr(R23);
+ R24_oop_opr = as_oop_opr(R24);
+ R25_oop_opr = as_oop_opr(R25);
+ R26_oop_opr = as_oop_opr(R26);
+ R27_oop_opr = as_oop_opr(R27);
+ R28_oop_opr = as_oop_opr(R28);
+ //R29_oop_opr = as_oop_opr(R29);
+ R30_oop_opr = as_oop_opr(R30);
+ R31_oop_opr = as_oop_opr(R31);
+
+ R0_metadata_opr = as_metadata_opr(R0);
+ //R1_metadata_opr = as_metadata_opr(R1);
+ R2_metadata_opr = as_metadata_opr(R2);
+ R3_metadata_opr = as_metadata_opr(R3);
+ R4_metadata_opr = as_metadata_opr(R4);
+ R5_metadata_opr = as_metadata_opr(R5);
+ R6_metadata_opr = as_metadata_opr(R6);
+ R7_metadata_opr = as_metadata_opr(R7);
+ R8_metadata_opr = as_metadata_opr(R8);
+ R9_metadata_opr = as_metadata_opr(R9);
+ R10_metadata_opr = as_metadata_opr(R10);
+ R11_metadata_opr = as_metadata_opr(R11);
+ R12_metadata_opr = as_metadata_opr(R12);
+ //R13_metadata_opr = as_metadata_opr(R13);
+ R14_metadata_opr = as_metadata_opr(R14);
+ R15_metadata_opr = as_metadata_opr(R15);
+ //R16_metadata_opr = as_metadata_opr(R16);
+ R17_metadata_opr = as_metadata_opr(R17);
+ R18_metadata_opr = as_metadata_opr(R18);
+ R19_metadata_opr = as_metadata_opr(R19);
+ R20_metadata_opr = as_metadata_opr(R20);
+ R21_metadata_opr = as_metadata_opr(R21);
+ R22_metadata_opr = as_metadata_opr(R22);
+ R23_metadata_opr = as_metadata_opr(R23);
+ R24_metadata_opr = as_metadata_opr(R24);
+ R25_metadata_opr = as_metadata_opr(R25);
+ R26_metadata_opr = as_metadata_opr(R26);
+ R27_metadata_opr = as_metadata_opr(R27);
+ R28_metadata_opr = as_metadata_opr(R28);
+ //R29_metadata_opr = as_metadata_opr(R29);
+ R30_metadata_opr = as_metadata_opr(R30);
+ R31_metadata_opr = as_metadata_opr(R31);
+
+ SP_opr = as_pointer_opr(R1_SP);
+
+ R0_long_opr = LIR_OprFact::double_cpu(cpu_reg2rnr(R0), cpu_reg2rnr(R0));
+ R3_long_opr = LIR_OprFact::double_cpu(cpu_reg2rnr(R3), cpu_reg2rnr(R3));
+
+ F1_opr = as_float_opr(F1);
+ F1_double_opr = as_double_opr(F1);
+
+ // All the allocated cpu regs are caller saved.
+ for (int i = 0; i < max_nof_caller_save_cpu_regs; i++) {
+ _caller_save_cpu_regs[i] = LIR_OprFact::single_cpu(i);
+ }
+
+ // All the fpu regs are caller saved.
+ for (int i = 0; i < nof_caller_save_fpu_regs; i++) {
+ _caller_save_fpu_regs[i] = LIR_OprFact::single_fpu(i);
+ }
+}
+
+
+Address FrameMap::make_new_address(ByteSize sp_offset) const {
+ return Address(R1_SP, STACK_BIAS + in_bytes(sp_offset));
+}
+
+
+VMReg FrameMap::fpu_regname (int n) {
+ return as_FloatRegister(n)->as_VMReg();
+}
+
+
+LIR_Opr FrameMap::stack_pointer() {
+ return SP_opr;
+}
+
+
+// JSR 292
+// On PPC64, there is no need to save the SP, because neither
+// method handle intrinsics, nor compiled lambda forms modify it.
+LIR_Opr FrameMap::method_handle_invoke_SP_save_opr() {
+ return LIR_OprFact::illegalOpr;
+}
+
+
+bool FrameMap::validate_frame() {
+ int max_offset = in_bytes(framesize_in_bytes());
+ int java_index = 0;
+ for (int i = 0; i < _incoming_arguments->length(); i++) {
+ LIR_Opr opr = _incoming_arguments->at(i);
+ if (opr->is_stack()) {
+ max_offset = MAX2(_argument_locations->at(java_index), max_offset);
+ }
+ java_index += type2size[opr->type()];
+ }
+ return Assembler::is_simm16(max_offset + STACK_BIAS);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/cpu/ppc/vm/c1_FrameMap_ppc.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012, 2015 SAP AG. 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.
+ *
+ */
+
+#ifndef CPU_PPC_VM_C1_FRAMEMAP_PPC_HPP
+#define CPU_PPC_VM_C1_FRAMEMAP_PPC_HPP
+
+ public:
+
+ enum {
+ nof_reg_args = 8, // Registers R3-R10 are available for parameter passing.
+ first_available_sp_in_frame = frame::jit_out_preserve_size,
+ frame_pad_in_bytes = 0
+ };
+
+ static const int pd_c_runtime_reserved_arg_size;
+
+ static LIR_Opr R0_opr;
+ static LIR_Opr R1_opr;
+ static LIR_Opr R2_opr;
+ static LIR_Opr R3_opr;
+ static LIR_Opr R4_opr;
+ static LIR_Opr R5_opr;
+ static LIR_Opr R6_opr;
+ static LIR_Opr R7_opr;
+ static LIR_Opr R8_opr;
+ static LIR_Opr R9_opr;
+ static LIR_Opr R10_opr;
+ static LIR_Opr R11_opr;
+ static LIR_Opr R12_opr;
+ static LIR_Opr R13_opr;
+ static LIR_Opr R14_opr;
+ static LIR_Opr R15_opr;
+ static LIR_Opr R16_opr;
+ static LIR_Opr R17_opr;
+ static LIR_Opr R18_opr;
+ static LIR_Opr R19_opr;
+ static LIR_Opr R20_opr;
+ static LIR_Opr R21_opr;
+ static LIR_Opr R22_opr;
+ static LIR_Opr R23_opr;
+ static LIR_Opr R24_opr;
+ static LIR_Opr R25_opr;
+ static LIR_Opr R26_opr;
+ static LIR_Opr R27_opr;
+ static LIR_Opr R28_opr;
+ static LIR_Opr R29_opr;
+ static LIR_Opr R30_opr;
+ static LIR_Opr R31_opr;
+
+ static LIR_Opr R0_oop_opr;
+ //R1: Stack pointer. Not an oop.
+ static LIR_Opr R2_oop_opr;
+ static LIR_Opr R3_oop_opr;
+ static LIR_Opr R4_oop_opr;
+ static LIR_Opr R5_oop_opr;
+ static LIR_Opr R6_oop_opr;
+ static LIR_Opr R7_oop_opr;
+ static LIR_Opr R8_oop_opr;
+ static LIR_Opr R9_oop_opr;
+ static LIR_Opr R10_oop_opr;
+ static LIR_Opr R11_oop_opr;
+ static LIR_Opr R12_oop_opr;
+ //R13: System thread register. Not usable.
+ static LIR_Opr R14_oop_opr;
+ static LIR_Opr R15_oop_opr;
+ //R16: Java thread register. Not an oop.
+ static LIR_Opr R17_oop_opr;
+ static LIR_Opr R18_oop_opr;
+ static LIR_Opr R19_oop_opr;
+ static LIR_Opr R20_oop_opr;
+ static LIR_Opr R21_oop_opr;
+ static LIR_Opr R22_oop_opr;
+ static LIR_Opr R23_oop_opr;
+ static LIR_Opr R24_oop_opr;
+ static LIR_Opr R25_oop_opr;
+ static LIR_Opr R26_oop_opr;
+ static LIR_Opr R27_oop_opr;
+ static LIR_Opr R28_oop_opr;
+ static LIR_Opr R29_oop_opr;
+ //R29: TOC register. Not an oop.
+ static LIR_Opr R30_oop_opr;
+ static LIR_Opr R31_oop_opr;
+
+ static LIR_Opr R0_metadata_opr;
+ //R1: Stack pointer. Not metadata.
+ static LIR_Opr R2_metadata_opr;
+ static LIR_Opr R3_metadata_opr;
+ static LIR_Opr R4_metadata_opr;
+ static LIR_Opr R5_metadata_opr;
+ static LIR_Opr R6_metadata_opr;
+ static LIR_Opr R7_metadata_opr;
+ static LIR_Opr R8_metadata_opr;
+ static LIR_Opr R9_metadata_opr;
+ static LIR_Opr R10_metadata_opr;
+ static LIR_Opr R11_metadata_opr;
+ static LIR_Opr R12_metadata_opr;
+ //R13: System thread register. Not usable.
+ static LIR_Opr R14_metadata_opr;
+ static LIR_Opr R15_metadata_opr;
+ //R16: Java thread register. Not metadata.
+ static LIR_Opr R17_metadata_opr;
+ static LIR_Opr R18_metadata_opr;
+ static LIR_Opr R19_metadata_opr;
+ static LIR_Opr R20_metadata_opr;
+ static LIR_Opr R21_metadata_opr;
+ static LIR_Opr R22_metadata_opr;
+ static LIR_Opr R23_metadata_opr;
+ static LIR_Opr R24_metadata_opr;
+ static LIR_Opr R25_metadata_opr;
+ static LIR_Opr R26_metadata_opr;
+ static LIR_Opr R27_metadata_opr;
+ static LIR_Opr R28_metadata_opr;
+ //R29: TOC register. Not metadata.
+ static LIR_Opr R30_metadata_opr;
+ static LIR_Opr R31_metadata_opr;
+
+ static LIR_Opr SP_opr;
+
+ static LIR_Opr R0_long_opr;
+ static LIR_Opr R3_long_opr;
+
+ static LIR_Opr F1_opr;
+ static LIR_Opr F1_double_opr;
+
+ private:
+ static FloatRegister _fpu_regs [nof_fpu_regs];
+
+ static LIR_Opr as_long_single_opr(Register r) {
+ return LIR_OprFact::double_cpu(cpu_reg2rnr(r), cpu_reg2rnr(r));
+ }
+ static LIR_Opr as_long_pair_opr(Register r) {
+ return LIR_OprFact::double_cpu(cpu_reg2rnr(r->successor()), cpu_reg2rnr(r));
+ }
+
+ public:
+
+#ifdef _LP64
+ static LIR_Opr as_long_opr(Register r) {
+ return as_long_single_opr(r);
+ }
+ static LIR_Opr as_pointer_opr(Register r) {
+ return as_long_single_opr(r);
+ }
+#else
+ static LIR_Opr as_long_opr(Register r) {
+ Unimplemented(); return 0;
+// return as_long_pair_opr(r);
+ }
+ static LIR_Opr as_pointer_opr(Register r) {
+ Unimplemented(); return 0;
+// return as_opr(r);
+ }
+#endif
+ static LIR_Opr as_float_opr(FloatRegister r) {
+ return LIR_OprFact::single_fpu(r->encoding());
+ }
+ static LIR_Opr as_double_opr(FloatRegister r) {
+ return LIR_OprFact::double_fpu(r->encoding());
+ }
+
+ static FloatRegister nr2floatreg (int rnr);
+
+ static VMReg fpu_regname (int n);
+
+ static bool is_caller_save_register(LIR_Opr reg);
+ static bool is_caller_save_register(Register r);
+
+ static int nof_caller_save_cpu_regs() { return pd_nof_caller_save_cpu_regs_frame_map; }
+ static int last_cpu_reg() { return pd_last_cpu_reg; }
+
+ // Registers which need to be saved in the frames (e.g. for GC).
+ // Register usage:
+ // R0: scratch
+ // R1: sp
+ // R13: system thread id
+ // R16: java thread
+ // R29: global TOC
+ static bool reg_needs_save(Register r) { return r != R0 && r != R1 && r != R13 && r != R16 && r != R29; }
+
+#endif // CPU_PPC_VM_C1_FRAMEMAP_PPC_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -0,0 +1,3133 @@
+/*
+ * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012, 2015 SAP AG. 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 "c1/c1_Compilation.hpp"
+#include "c1/c1_LIRAssembler.hpp"
+#include "c1/c1_MacroAssembler.hpp"
+#include "c1/c1_Runtime1.hpp"
+#include "c1/c1_ValueStack.hpp"
+#include "ci/ciArrayKlass.hpp"
+#include "ci/ciInstance.hpp"
+#include "gc/shared/collectedHeap.hpp"
+#include "gc/shared/barrierSet.hpp"
+#include "gc/shared/cardTableModRefBS.hpp"
+#include "nativeInst_ppc.hpp"
+#include "oops/objArrayKlass.hpp"
+#include "runtime/sharedRuntime.hpp"
+
+#define __ _masm->
+
+
+const ConditionRegister LIR_Assembler::BOOL_RESULT = CCR5;
+
+
+bool LIR_Assembler::is_small_constant(LIR_Opr opr) {
+ Unimplemented(); return false; // Currently not used on this platform.
+}
+
+
+LIR_Opr LIR_Assembler::receiverOpr() {
+ return FrameMap::R3_oop_opr;
+}
+
+
+LIR_Opr LIR_Assembler::osrBufferPointer() {
+ return FrameMap::R3_opr;
+}
+
+
+// This specifies the stack pointer decrement needed to build the frame.
+int LIR_Assembler::initial_frame_size_in_bytes() const {
+ return in_bytes(frame_map()->framesize_in_bytes());
+}
+
+
+// Inline cache check: the inline cached class is in inline_cache_reg;
+// we fetch the class of the receiver and compare it with the cached class.
+// If they do not match we jump to slow case.
+int LIR_Assembler::check_icache() {
+ int offset = __ offset();
+ __ inline_cache_check(R3_ARG1, R19_inline_cache_reg);
+ return offset;
+}
+
+
+void LIR_Assembler::osr_entry() {
+ // On-stack-replacement entry sequence:
+ //
+ // 1. Create a new compiled activation.
+ // 2. Initialize local variables in the compiled activation. The expression
+ // stack must be empty at the osr_bci; it is not initialized.
+ // 3. Jump to the continuation address in compiled code to resume execution.
+
+ // OSR entry point
+ offsets()->set_value(CodeOffsets::OSR_Entry, code_offset());
+ BlockBegin* osr_entry = compilation()->hir()->osr_entry();
+ ValueStack* entry_state = osr_entry->end()->state();
+ int number_of_locks = entry_state->locks_size();
+
+ // Create a frame for the compiled activation.
+ __ build_frame(initial_frame_size_in_bytes(), bang_size_in_bytes());
+
+ // OSR buffer is
+ //
+ // locals[nlocals-1..0]
+ // monitors[number_of_locks-1..0]
+ //
+ // Locals is a direct copy of the interpreter frame so in the osr buffer
+ // the first slot in the local array is the last local from the interpreter
+ // and the last slot is local[0] (receiver) from the interpreter.
+ //
+ // Similarly with locks. The first lock slot in the osr buffer is the nth lock
+ // from the interpreter frame, the nth lock slot in the osr buffer is 0th lock
+ // in the interpreter frame (the method lock if a sync method).
+
+ // Initialize monitors in the compiled activation.
+ // R3: pointer to osr buffer
+ //
+ // All other registers are dead at this point and the locals will be
+ // copied into place by code emitted in the IR.
+
+ Register OSR_buf = osrBufferPointer()->as_register();
+ { assert(frame::interpreter_frame_monitor_size() == BasicObjectLock::size(), "adjust code below");
+ int monitor_offset = BytesPerWord * method()->max_locals() +
+ (2 * BytesPerWord) * (number_of_locks - 1);
+ // SharedRuntime::OSR_migration_begin() packs BasicObjectLocks in
+ // the OSR buffer using 2 word entries: first the lock and then
+ // the oop.
+ for (int i = 0; i < number_of_locks; i++) {
+ int slot_offset = monitor_offset - ((i * 2) * BytesPerWord);
+#ifdef ASSERT
+ // Verify the interpreter's monitor has a non-null object.
+ {
+ Label L;
+ __ ld(R0, slot_offset + 1*BytesPerWord, OSR_buf);
+ __ cmpdi(CCR0, R0, 0);
+ __ bne(CCR0, L);
+ __ stop("locked object is NULL");
+ __ bind(L);
+ }
+#endif // ASSERT
+ // Copy the lock field into the compiled activation.
+ Address ml = frame_map()->address_for_monitor_lock(i),
+ mo = frame_map()->address_for_monitor_object(i);
+ assert(ml.index() == noreg && mo.index() == noreg, "sanity");
+ __ ld(R0, slot_offset + 0, OSR_buf);
+ __ std(R0, ml.disp(), ml.base());
+ __ ld(R0, slot_offset + 1*BytesPerWord, OSR_buf);
+ __ std(R0, mo.disp(), mo.base());
+ }
+ }
+}
+
+
+int LIR_Assembler::emit_exception_handler() {
+ // If the last instruction is a call (typically to do a throw which
+ // is coming at the end after block reordering) the return address
+ // must still point into the code area in order to avoid assertion
+ // failures when searching for the corresponding bci => add a nop
+ // (was bug 5/14/1999 - gri).
+ __ nop();
+
+ // Generate code for the exception handler.
+ address handler_base = __ start_a_stub(exception_handler_size);
+
+ if (handler_base == NULL) {
+ // Not enough space left for the handler.
+ bailout("exception handler overflow");
+ return -1;
+ }
+
+ int offset = code_offset();
+ address entry_point = CAST_FROM_FN_PTR(address, Runtime1::entry_for(Runtime1::handle_exception_from_callee_id));
+ //__ load_const_optimized(R0, entry_point);
+ __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(entry_point));
+ __ mtctr(R0);
+ __ bctr();
+
+ guarantee(code_offset() - offset <= exception_handler_size, "overflow");
+ __ end_a_stub();
+
+ return offset;
+}
+
+
+// Emit the code to remove the frame from the stack in the exception
+// unwind path.
+int LIR_Assembler::emit_unwind_handler() {
+ _masm->block_comment("Unwind handler");
+
+ int offset = code_offset();
+ bool preserve_exception = method()->is_synchronized() || compilation()->env()->dtrace_method_probes();
+ const Register Rexception = R3 /*LIRGenerator::exceptionOopOpr()*/, Rexception_save = R31;
+
+ // Fetch the exception from TLS and clear out exception related thread state.
+ __ ld(Rexception, in_bytes(JavaThread::exception_oop_offset()), R16_thread);
+ __ li(R0, 0);
+ __ std(R0, in_bytes(JavaThread::exception_oop_offset()), R16_thread);
+ __ std(R0, in_bytes(JavaThread::exception_pc_offset()), R16_thread);
+
+ __ bind(_unwind_handler_entry);
+ __ verify_not_null_oop(Rexception);
+ if (preserve_exception) { __ mr(Rexception_save, Rexception); }
+
+ // Perform needed unlocking
+ MonitorExitStub* stub = NULL;
+ if (method()->is_synchronized()) {
+ monitor_address(0, FrameMap::R4_opr);
+ stub = new MonitorExitStub(FrameMap::R4_opr, true, 0);
+ __ unlock_object(R5, R6, R4, *stub->entry());
+ __ bind(*stub->continuation());
+ }
+
+ if (compilation()->env()->dtrace_method_probes()) {
+ Unimplemented();
+ }
+
+ // Dispatch to the unwind logic.
+ address unwind_stub = Runtime1::entry_for(Runtime1::unwind_exception_id);
+ //__ load_const_optimized(R0, unwind_stub);
+ __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(unwind_stub));
+ if (preserve_exception) { __ mr(Rexception, Rexception_save); }
+ __ mtctr(R0);
+ __ bctr();
+
+ // Emit the slow path assembly.
+ if (stub != NULL) {
+ stub->emit_code(this);
+ }
+
+ return offset;
+}
+
+
+int LIR_Assembler::emit_deopt_handler() {
+ // If the last instruction is a call (typically to do a throw which
+ // is coming at the end after block reordering) the return address
+ // must still point into the code area in order to avoid assertion
+ // failures when searching for the corresponding bci => add a nop
+ // (was bug 5/14/1999 - gri).
+ __ nop();
+
+ // Generate code for deopt handler.
+ address handler_base = __ start_a_stub(deopt_handler_size);
+
+ if (handler_base == NULL) {
+ // Not enough space left for the handler.
+ bailout("deopt handler overflow");
+ return -1;
+ }
+
+ int offset = code_offset();
+ __ bl64_patchable(SharedRuntime::deopt_blob()->unpack(), relocInfo::runtime_call_type);
+
+ guarantee(code_offset() - offset <= deopt_handler_size, "overflow");
+ __ end_a_stub();
+
+ return offset;
+}
+
+
+void LIR_Assembler::jobject2reg(jobject o, Register reg) {
+ if (o == NULL) {
+ __ li(reg, 0);
+ } else {
+ AddressLiteral addrlit = __ constant_oop_address(o);
+ __ load_const(reg, addrlit, (reg != R0) ? R0 : noreg);
+ }
+}
+
+
+void LIR_Assembler::jobject2reg_with_patching(Register reg, CodeEmitInfo *info) {
+ // Allocate a new index in table to hold the object once it's been patched.
+ int oop_index = __ oop_recorder()->allocate_oop_index(NULL);
+ PatchingStub* patch = new PatchingStub(_masm, patching_id(info), oop_index);
+
+ AddressLiteral addrlit((address)NULL, oop_Relocation::spec(oop_index));
+ __ load_const(reg, addrlit, R0);
+
+ patching_epilog(patch, lir_patch_normal, reg, info);
+}
+
+
+void LIR_Assembler::metadata2reg(Metadata* o, Register reg) {
+ AddressLiteral md = __ constant_metadata_address(o); // Notify OOP recorder (don't need the relocation)
+ __ load_const_optimized(reg, md.value(), (reg != R0) ? R0 : noreg);
+}
+
+
+void LIR_Assembler::klass2reg_with_patching(Register reg, CodeEmitInfo *info) {
+ // Allocate a new index in table to hold the klass once it's been patched.
+ int index = __ oop_recorder()->allocate_metadata_index(NULL);
+ PatchingStub* patch = new PatchingStub(_masm, PatchingStub::load_klass_id, index);
+
+ AddressLiteral addrlit((address)NULL, metadata_Relocation::spec(index));
+ assert(addrlit.rspec().type() == relocInfo::metadata_type, "must be an metadata reloc");
+ __ load_const(reg, addrlit, R0);
+
+ patching_epilog(patch, lir_patch_normal, reg, info);
+}
+
+
+void LIR_Assembler::emit_op3(LIR_Op3* op) {
+ const bool is_int = op->result_opr()->is_single_cpu();
+ Register Rdividend = is_int ? op->in_opr1()->as_register() : op->in_opr1()->as_register_lo();
+ Register Rdivisor = noreg;
+ Register Rscratch = op->in_opr3()->as_register();
+ Register Rresult = is_int ? op->result_opr()->as_register() : op->result_opr()->as_register_lo();
+ long divisor = -1;
+
+ if (op->in_opr2()->is_register()) {
+ Rdivisor = is_int ? op->in_opr2()->as_register() : op->in_opr2()->as_register_lo();
+ } else {
+ divisor = is_int ? op->in_opr2()->as_constant_ptr()->as_jint()
+ : op->in_opr2()->as_constant_ptr()->as_jlong();
+ }
+
+ assert(Rdividend != Rscratch, "");
+ assert(Rdivisor != Rscratch, "");
+ assert(op->code() == lir_idiv || op->code() == lir_irem, "Must be irem or idiv");
+
+ if (Rdivisor == noreg) {
+ if (divisor == 1) { // stupid, but can happen
+ if (op->code() == lir_idiv) {
+ __ mr_if_needed(Rresult, Rdividend);
+ } else {
+ __ li(Rresult, 0);
+ }
+
+ } else if (is_power_of_2(divisor)) {
+ // Convert division by a power of two into some shifts and logical operations.
+ int log2 = log2_intptr(divisor);
+
+ // Round towards 0.
+ if (divisor == 2) {
+ if (is_int) {
+ __ srwi(Rscratch, Rdividend, 31);
+ } else {
+ __ srdi(Rscratch, Rdividend, 63);
+ }
+ } else {
+ if (is_int) {
+ __ srawi(Rscratch, Rdividend, 31);
+ } else {
+ __ sradi(Rscratch, Rdividend, 63);
+ }
+ __ clrldi(Rscratch, Rscratch, 64-log2);
+ }
+ __ add(Rscratch, Rdividend, Rscratch);
+
+ if (op->code() == lir_idiv) {
+ if (is_int) {
+ __ srawi(Rresult, Rscratch, log2);
+ } else {
+ __ sradi(Rresult, Rscratch, log2);
+ }
+ } else { // lir_irem
+ __ clrrdi(Rscratch, Rscratch, log2);
+ __ sub(Rresult, Rdividend, Rscratch);
+ }
+
+ } else if (divisor == -1) {
+ if (op->code() == lir_idiv) {
+ __ neg(Rresult, Rdividend);
+ } else {
+ __ li(Rresult, 0);
+ }
+
+ } else {
+ __ load_const_optimized(Rscratch, divisor);
+ if (op->code() == lir_idiv) {
+ if (is_int) {
+ __ divw(Rresult, Rdividend, Rscratch); // Can't divide minint/-1.
+ } else {
+ __ divd(Rresult, Rdividend, Rscratch); // Can't divide minint/-1.
+ }
+ } else {
+ assert(Rscratch != R0, "need both");
+ if (is_int) {
+ __ divw(R0, Rdividend, Rscratch); // Can't divide minint/-1.
+ __ mullw(Rscratch, R0, Rscratch);
+ } else {
+ __ divd(R0, Rdividend, Rscratch); // Can't divide minint/-1.
+ __ mulld(Rscratch, R0, Rscratch);
+ }
+ __ sub(Rresult, Rdividend, Rscratch);
+ }
+
+ }
+ return;
+ }
+
+ Label regular, done;
+ if (is_int) {
+ __ cmpwi(CCR0, Rdivisor, -1);
+ } else {
+ __ cmpdi(CCR0, Rdivisor, -1);
+ }
+ __ bne(CCR0, regular);
+ if (op->code() == lir_idiv) {
+ __ neg(Rresult, Rdividend);
+ __ b(done);
+ __ bind(regular);
+ if (is_int) {
+ __ divw(Rresult, Rdividend, Rdivisor); // Can't divide minint/-1.
+ } else {
+ __ divd(Rresult, Rdividend, Rdivisor); // Can't divide minint/-1.
+ }
+ } else { // lir_irem
+ __ li(Rresult, 0);
+ __ b(done);
+ __ bind(regular);
+ if (is_int) {
+ __ divw(Rscratch, Rdividend, Rdivisor); // Can't divide minint/-1.
+ __ mullw(Rscratch, Rscratch, Rdivisor);
+ } else {
+ __ divd(Rscratch, Rdividend, Rdivisor); // Can't divide minint/-1.
+ __ mulld(Rscratch, Rscratch, Rdivisor);
+ }
+ __ sub(Rresult, Rdividend, Rscratch);
+ }
+ __ bind(done);
+}
+
+
+void LIR_Assembler::emit_opBranch(LIR_OpBranch* op) {
+#ifdef ASSERT
+ assert(op->block() == NULL || op->block()->label() == op->label(), "wrong label");
+ if (op->block() != NULL) _branch_target_blocks.append(op->block());
+ if (op->ublock() != NULL) _branch_target_blocks.append(op->ublock());
+ assert(op->info() == NULL, "shouldn't have CodeEmitInfo");
+#endif
+
+ Label *L = op->label();
+ if (op->cond() == lir_cond_always) {
+ __ b(*L);
+ } else {
+ Label done;
+ bool is_unordered = false;
+ if (op->code() == lir_cond_float_branch) {
+ assert(op->ublock() != NULL, "must have unordered successor");
+ is_unordered = true;
+ } else {
+ assert(op->code() == lir_branch, "just checking");
+ }
+
+ bool positive = false;
+ Assembler::Condition cond = Assembler::equal;
+ switch (op->cond()) {
+ case lir_cond_equal: positive = true ; cond = Assembler::equal ; is_unordered = false; break;
+ case lir_cond_notEqual: positive = false; cond = Assembler::equal ; is_unordered = false; break;
+ case lir_cond_less: positive = true ; cond = Assembler::less ; break;
+ case lir_cond_belowEqual: assert(op->code() != lir_cond_float_branch, ""); // fallthru
+ case lir_cond_lessEqual: positive = false; cond = Assembler::greater; break;
+ case lir_cond_greater: positive = true ; cond = Assembler::greater; break;
+ case lir_cond_aboveEqual: assert(op->code() != lir_cond_float_branch, ""); // fallthru
+ case lir_cond_greaterEqual: positive = false; cond = Assembler::less ; break;
+ default: ShouldNotReachHere();
+ }
+ int bo = positive ? Assembler::bcondCRbiIs1 : Assembler::bcondCRbiIs0;
+ int bi = Assembler::bi0(BOOL_RESULT, cond);
+ if (is_unordered) {
+ if (positive) {
+ if (op->ublock() == op->block()) {
+ __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(BOOL_RESULT, Assembler::summary_overflow), *L);
+ }
+ } else {
+ if (op->ublock() != op->block()) { __ bso(BOOL_RESULT, done); }
+ }
+ }
+ __ bc_far_optimized(bo, bi, *L);
+ __ bind(done);
+ }
+}
+
+
+void LIR_Assembler::emit_opConvert(LIR_OpConvert* op) {
+ Bytecodes::Code code = op->bytecode();
+ LIR_Opr src = op->in_opr(),
+ dst = op->result_opr();
+
+ switch(code) {
+ case Bytecodes::_i2l: {
+ __ extsw(dst->as_register_lo(), src->as_register());
+ break;
+ }
+ case Bytecodes::_l2i: {
+ __ mr_if_needed(dst->as_register(), src->as_register_lo()); // high bits are garbage
+ break;
+ }
+ case Bytecodes::_i2b: {
+ __ extsb(dst->as_register(), src->as_register());
+ break;
+ }
+ case Bytecodes::_i2c: {
+ __ clrldi(dst->as_register(), src->as_register(), 64-16);
+ break;
+ }
+ case Bytecodes::_i2s: {
+ __ extsh(dst->as_register(), src->as_register());
+ break;
+ }
+ case Bytecodes::_i2d:
+ case Bytecodes::_l2d: {
+ __ fcfid(dst->as_double_reg(), src->as_double_reg()); // via mem
+ break;
+ }
+ case Bytecodes::_i2f: {
+ FloatRegister rdst = dst->as_float_reg();
+ FloatRegister rsrc = src->as_double_reg(); // via mem
+ if (VM_Version::has_fcfids()) {
+ __ fcfids(rdst, rsrc);
+ } else {
+ __ fcfid(rdst, rsrc);
+ __ frsp(rdst, rdst);
+ }
+ break;
+ }
+ case Bytecodes::_l2f: { // >= Power7
+ assert(VM_Version::has_fcfids(), "fcfid+frsp needs fixup code to avoid rounding incompatibility");
+ __ fcfids(dst->as_float_reg(), src->as_double_reg()); // via mem
+ break;
+ }
+ case Bytecodes::_f2d: {
+ __ fmr_if_needed(dst->as_double_reg(), src->as_float_reg());
+ break;
+ }
+ case Bytecodes::_d2f: {
+ __ frsp(dst->as_float_reg(), src->as_double_reg());
+ break;
+ }
+ case Bytecodes::_d2i:
+ case Bytecodes::_f2i: {
+ FloatRegister rsrc = (code == Bytecodes::_d2i) ? src->as_double_reg() : src->as_float_reg();
+ Address addr = frame_map()->address_for_slot(dst->double_stack_ix());
+ Label L;
+ // Result must be 0 if value is NaN; test by comparing value to itself.
+ __ fcmpu(CCR0, rsrc, rsrc);
+ __ li(R0, 0); // 0 in case of NAN
+ __ std(R0, addr.disp(), addr.base());
+ __ bso(CCR0, L);
+ __ fctiwz(rsrc, rsrc); // USE_KILL
+ __ stfd(rsrc, addr.disp(), addr.base());
+ __ bind(L);
+ break;
+ }
+ case Bytecodes::_d2l:
+ case Bytecodes::_f2l: {
+ FloatRegister rsrc = (code == Bytecodes::_d2l) ? src->as_double_reg() : src->as_float_reg();
+ Address addr = frame_map()->address_for_slot(dst->double_stack_ix());
+ Label L;
+ // Result must be 0 if value is NaN; test by comparing value to itself.
+ __ fcmpu(CCR0, rsrc, rsrc);
+ __ li(R0, 0); // 0 in case of NAN
+ __ std(R0, addr.disp(), addr.base());
+ __ bso(CCR0, L);
+ __ fctidz(rsrc, rsrc); // USE_KILL
+ __ stfd(rsrc, addr.disp(), addr.base());
+ __ bind(L);
+ break;
+ }
+
+ default: ShouldNotReachHere();
+ }
+}
+
+
+void LIR_Assembler::align_call(LIR_Code) {
+ // do nothing since all instructions are word aligned on ppc
+}
+
+
+bool LIR_Assembler::emit_trampoline_stub_for_call(address target, Register Rtoc) {
+ int start_offset = __ offset();
+ // Put the entry point as a constant into the constant pool.
+ const address entry_point_toc_addr = __ address_constant(target, RelocationHolder::none);
+ if (entry_point_toc_addr == NULL) {
+ bailout("const section overflow");
+ return false;
+ }
+ const int entry_point_toc_offset = __ offset_to_method_toc(entry_point_toc_addr);
+
+ // Emit the trampoline stub which will be related to the branch-and-link below.
+ address stub = __ emit_trampoline_stub(entry_point_toc_offset, start_offset, Rtoc);
+ if (!stub) {
+ bailout("no space for trampoline stub");
+ return false;
+ }
+ return true;
+}
+
+
+void LIR_Assembler::call(LIR_OpJavaCall* op, relocInfo::relocType rtype) {
+ assert(rtype==relocInfo::opt_virtual_call_type || rtype==relocInfo::static_call_type, "unexpected rtype");
+
+ bool success = emit_trampoline_stub_for_call(op->addr());
+ if (!success) { return; }
+
+ __ relocate(rtype);
+ // Note: At this point we do not have the address of the trampoline
+ // stub, and the entry point might be too far away for bl, so __ pc()
+ // serves as dummy and the bl will be patched later.
+ __ code()->set_insts_mark();
+ __ bl(__ pc());
+ add_call_info(code_offset(), op->info());
+}
+
+
+void LIR_Assembler::ic_call(LIR_OpJavaCall* op) {
+ __ calculate_address_from_global_toc(R2_TOC, __ method_toc());
+
+ // Virtual call relocation will point to ic load.
+ address virtual_call_meta_addr = __ pc();
+ // Load a clear inline cache.
+ AddressLiteral empty_ic((address) Universe::non_oop_word());
+ bool success = __ load_const_from_method_toc(R19_inline_cache_reg, empty_ic, R2_TOC);
+ if (!success) {
+ bailout("const section overflow");
+ return;
+ }
+ // Call to fixup routine. Fixup routine uses ScopeDesc info
+ // to determine who we intended to call.
+ __ relocate(virtual_call_Relocation::spec(virtual_call_meta_addr));
+
+ success = emit_trampoline_stub_for_call(op->addr(), R2_TOC);
+ if (!success) { return; }
+
+ // Note: At this point we do not have the address of the trampoline
+ // stub, and the entry point might be too far away for bl, so __ pc()
+ // serves as dummy and the bl will be patched later.
+ __ bl(__ pc());
+ add_call_info(code_offset(), op->info());
+}
+
+
+void LIR_Assembler::vtable_call(LIR_OpJavaCall* op) {
+ ShouldNotReachHere(); // ic_call is used instead.
+}
+
+
+void LIR_Assembler::explicit_null_check(Register addr, CodeEmitInfo* info) {
+ ImplicitNullCheckStub* stub = new ImplicitNullCheckStub(code_offset(), info);
+ __ null_check(addr, stub->entry());
+ append_code_stub(stub);
+}
+
+
+// Attention: caller must encode oop if needed
+int LIR_Assembler::store(LIR_Opr from_reg, Register base, int offset, BasicType type, bool wide, bool unaligned) {
+ int store_offset;
+ if (!Assembler::is_simm16(offset)) {
+ // For offsets larger than a simm16 we setup the offset.
+ assert(wide && !from_reg->is_same_register(FrameMap::R0_opr), "large offset only supported in special case");
+ __ load_const_optimized(R0, offset);
+ store_offset = store(from_reg, base, R0, type, wide);
+ } else {
+ store_offset = code_offset();
+ switch (type) {
+ case T_BOOLEAN: // fall through
+ case T_BYTE : __ stb(from_reg->as_register(), offset, base); break;
+ case T_CHAR :
+ case T_SHORT : __ sth(from_reg->as_register(), offset, base); break;
+ case T_INT : __ stw(from_reg->as_register(), offset, base); break;
+ case T_LONG : __ std(from_reg->as_register_lo(), offset, base); break;
+ case T_ADDRESS:
+ case T_METADATA: __ std(from_reg->as_register(), offset, base); break;
+ case T_ARRAY : // fall through
+ case T_OBJECT:
+ {
+ if (UseCompressedOops && !wide) {
+ // Encoding done in caller
+ __ stw(from_reg->as_register(), offset, base);
+ } else {
+ __ std(from_reg->as_register(), offset, base);
+ }
+ __ verify_oop(from_reg->as_register());
+ break;
+ }
+ case T_FLOAT : __ stfs(from_reg->as_float_reg(), offset, base); break;
+ case T_DOUBLE: __ stfd(from_reg->as_double_reg(), offset, base); break;
+ default : ShouldNotReachHere();
+ }
+ }
+ return store_offset;
+}
+
+
+// Attention: caller must encode oop if needed
+int LIR_Assembler::store(LIR_Opr from_reg, Register base, Register disp, BasicType type, bool wide) {
+ int store_offset = code_offset();
+ switch (type) {
+ case T_BOOLEAN: // fall through
+ case T_BYTE : __ stbx(from_reg->as_register(), base, disp); break;
+ case T_CHAR :
+ case T_SHORT : __ sthx(from_reg->as_register(), base, disp); break;
+ case T_INT : __ stwx(from_reg->as_register(), base, disp); break;
+ case T_LONG :
+#ifdef _LP64
+ __ stdx(from_reg->as_register_lo(), base, disp);
+#else
+ Unimplemented();
+#endif
+ break;
+ case T_ADDRESS:
+ __ stdx(from_reg->as_register(), base, disp);
+ break;
+ case T_ARRAY : // fall through
+ case T_OBJECT:
+ {
+ if (UseCompressedOops && !wide) {
+ // Encoding done in caller.
+ __ stwx(from_reg->as_register(), base, disp);
+ } else {
+ __ stdx(from_reg->as_register(), base, disp);
+ }
+ __ verify_oop(from_reg->as_register()); // kills R0
+ break;
+ }
+ case T_FLOAT : __ stfsx(from_reg->as_float_reg(), base, disp); break;
+ case T_DOUBLE: __ stfdx(from_reg->as_double_reg(), base, disp); break;
+ default : ShouldNotReachHere();
+ }
+ return store_offset;
+}
+
+
+int LIR_Assembler::load(Register base, int offset, LIR_Opr to_reg, BasicType type, bool wide, bool unaligned) {
+ int load_offset;
+ if (!Assembler::is_simm16(offset)) {
+ // For offsets larger than a simm16 we setup the offset.
+ __ load_const_optimized(R0, offset);
+ load_offset = load(base, R0, to_reg, type, wide);
+ } else {
+ load_offset = code_offset();
+ switch(type) {
+ case T_BOOLEAN: // fall through
+ case T_BYTE : __ lbz(to_reg->as_register(), offset, base);
+ __ extsb(to_reg->as_register(), to_reg->as_register()); break;
+ case T_CHAR : __ lhz(to_reg->as_register(), offset, base); break;
+ case T_SHORT : __ lha(to_reg->as_register(), offset, base); break;
+ case T_INT : __ lwa(to_reg->as_register(), offset, base); break;
+ case T_LONG : __ ld(to_reg->as_register_lo(), offset, base); break;
+ case T_METADATA: __ ld(to_reg->as_register(), offset, base); break;
+ case T_ADDRESS:
+ if (offset == oopDesc::klass_offset_in_bytes() && UseCompressedClassPointers) {
+ __ lwz(to_reg->as_register(), offset, base);
+ __ decode_klass_not_null(to_reg->as_register());
+ } else {
+ __ ld(to_reg->as_register(), offset, base);
+ }
+ break;
+ case T_ARRAY : // fall through
+ case T_OBJECT:
+ {
+ if (UseCompressedOops && !wide) {
+ __ lwz(to_reg->as_register(), offset, base);
+ __ decode_heap_oop(to_reg->as_register());
+ } else {
+ __ ld(to_reg->as_register(), offset, base);
+ }
+ __ verify_oop(to_reg->as_register());
+ break;
+ }
+ case T_FLOAT: __ lfs(to_reg->as_float_reg(), offset, base); break;
+ case T_DOUBLE: __ lfd(to_reg->as_double_reg(), offset, base); break;
+ default : ShouldNotReachHere();
+ }
+ }
+ return load_offset;
+}
+
+
+int LIR_Assembler::load(Register base, Register disp, LIR_Opr to_reg, BasicType type, bool wide) {
+ int load_offset = code_offset();
+ switch(type) {
+ case T_BOOLEAN: // fall through
+ case T_BYTE : __ lbzx(to_reg->as_register(), base, disp);
+ __ extsb(to_reg->as_register(), to_reg->as_register()); break;
+ case T_CHAR : __ lhzx(to_reg->as_register(), base, disp); break;
+ case T_SHORT : __ lhax(to_reg->as_register(), base, disp); break;
+ case T_INT : __ lwax(to_reg->as_register(), base, disp); break;
+ case T_ADDRESS: __ ldx(to_reg->as_register(), base, disp); break;
+ case T_ARRAY : // fall through
+ case T_OBJECT:
+ {
+ if (UseCompressedOops && !wide) {
+ __ lwzx(to_reg->as_register(), base, disp);
+ __ decode_heap_oop(to_reg->as_register());
+ } else {
+ __ ldx(to_reg->as_register(), base, disp);
+ }
+ __ verify_oop(to_reg->as_register());
+ break;
+ }
+ case T_FLOAT: __ lfsx(to_reg->as_float_reg() , base, disp); break;
+ case T_DOUBLE: __ lfdx(to_reg->as_double_reg(), base, disp); break;
+ case T_LONG :
+#ifdef _LP64
+ __ ldx(to_reg->as_register_lo(), base, disp);
+#else
+ Unimplemented();
+#endif
+ break;
+ default : ShouldNotReachHere();
+ }
+ return load_offset;
+}
+
+
+void LIR_Assembler::const2stack(LIR_Opr src, LIR_Opr dest) {
+ LIR_Const* c = src->as_constant_ptr();
+ Register src_reg = R0;
+ switch (c->type()) {
+ case T_INT:
+ case T_FLOAT: {
+ int value = c->as_jint_bits();
+ __ load_const_optimized(src_reg, value);
+ Address addr = frame_map()->address_for_slot(dest->single_stack_ix());
+ __ stw(src_reg, addr.disp(), addr.base());
+ break;
+ }
+ case T_ADDRESS: {
+ int value = c->as_jint_bits();
+ __ load_const_optimized(src_reg, value);
+ Address addr = frame_map()->address_for_slot(dest->single_stack_ix());
+ __ std(src_reg, addr.disp(), addr.base());
+ break;
+ }
+ case T_OBJECT: {
+ jobject2reg(c->as_jobject(), src_reg);
+ Address addr = frame_map()->address_for_slot(dest->single_stack_ix());
+ __ std(src_reg, addr.disp(), addr.base());
+ break;
+ }
+ case T_LONG:
+ case T_DOUBLE: {
+ int value = c->as_jlong_bits();
+ __ load_const_optimized(src_reg, value);
+ Address addr = frame_map()->address_for_double_slot(dest->double_stack_ix());
+ __ std(src_reg, addr.disp(), addr.base());
+ break;
+ }
+ default:
+ Unimplemented();
+ }
+}
+
+
+void LIR_Assembler::const2mem(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmitInfo* info, bool wide) {
+ LIR_Const* c = src->as_constant_ptr();
+ LIR_Address* addr = dest->as_address_ptr();
+ Register base = addr->base()->as_pointer_register();
+ LIR_Opr tmp = LIR_OprFact::illegalOpr;
+ int offset = -1;
+ // Null check for large offsets in LIRGenerator::do_StoreField.
+ bool needs_explicit_null_check = !ImplicitNullChecks;
+
+ if (info != NULL && needs_explicit_null_check) {
+ explicit_null_check(base, info);
+ }
+
+ switch (c->type()) {
+ case T_FLOAT: type = T_INT;
+ case T_INT:
+ case T_ADDRESS: {
+ tmp = FrameMap::R0_opr;
+ __ load_const_optimized(tmp->as_register(), c->as_jint_bits());
+ break;
+ }
+ case T_DOUBLE: type = T_LONG;
+ case T_LONG: {
+ tmp = FrameMap::R0_long_opr;
+ __ load_const_optimized(tmp->as_register_lo(), c->as_jlong_bits());
+ break;
+ }
+ case T_OBJECT: {
+ tmp = FrameMap::R0_opr;
+ if (UseCompressedOops && !wide && c->as_jobject() != NULL) {
+ AddressLiteral oop_addr = __ constant_oop_address(c->as_jobject());
+ __ lis(R0, oop_addr.value() >> 16); // Don't care about sign extend (will use stw).
+ __ relocate(oop_addr.rspec(), /*compressed format*/ 1);
+ __ ori(R0, R0, oop_addr.value() & 0xffff);
+ } else {
+ jobject2reg(c->as_jobject(), R0);
+ }
+ break;
+ }
+ default:
+ Unimplemented();
+ }
+
+ // Handle either reg+reg or reg+disp address.
+ if (addr->index()->is_valid()) {
+ assert(addr->disp() == 0, "must be zero");
+ offset = store(tmp, base, addr->index()->as_pointer_register(), type, wide);
+ } else {
+ assert(Assembler::is_simm16(addr->disp()), "can't handle larger addresses");
+ offset = store(tmp, base, addr->disp(), type, wide, false);
+ }
+
+ if (info != NULL) {
+ assert(offset != -1, "offset should've been set");
+ if (!needs_explicit_null_check) {
+ add_debug_info_for_null_check(offset, info);
+ }
+ }
+}
+
+
+void LIR_Assembler::const2reg(LIR_Opr src, LIR_Opr dest, LIR_PatchCode patch_code, CodeEmitInfo* info) {
+ LIR_Const* c = src->as_constant_ptr();
+ LIR_Opr to_reg = dest;
+
+ switch (c->type()) {
+ case T_INT: {
+ assert(patch_code == lir_patch_none, "no patching handled here");
+ __ load_const_optimized(dest->as_register(), c->as_jint(), R0);
+ break;
+ }
+ case T_ADDRESS: {
+ assert(patch_code == lir_patch_none, "no patching handled here");
+ __ load_const_optimized(dest->as_register(), c->as_jint(), R0); // Yes, as_jint ...
+ break;
+ }
+ case T_LONG: {
+ assert(patch_code == lir_patch_none, "no patching handled here");
+ __ load_const_optimized(dest->as_register_lo(), c->as_jlong(), R0);
+ break;
+ }
+
+ case T_OBJECT: {
+ if (patch_code == lir_patch_none) {
+ jobject2reg(c->as_jobject(), to_reg->as_register());
+ } else {
+ jobject2reg_with_patching(to_reg->as_register(), info);
+ }
+ break;
+ }
+
+ case T_METADATA:
+ {
+ if (patch_code == lir_patch_none) {
+ metadata2reg(c->as_metadata(), to_reg->as_register());
+ } else {
+ klass2reg_with_patching(to_reg->as_register(), info);
+ }
+ }
+ break;
+
+ case T_FLOAT:
+ {
+ if (to_reg->is_single_fpu()) {
+ address const_addr = __ float_constant(c->as_jfloat());
+ if (const_addr == NULL) {
+ bailout("const section overflow");
+ break;
+ }
+ RelocationHolder rspec = internal_word_Relocation::spec(const_addr);
+ __ relocate(rspec);
+ __ load_const(R0, const_addr);
+ __ lfsx(to_reg->as_float_reg(), R0);
+ } else {
+ assert(to_reg->is_single_cpu(), "Must be a cpu register.");
+ __ load_const_optimized(to_reg->as_register(), jint_cast(c->as_jfloat()), R0);
+ }
+ }
+ break;
+
+ case T_DOUBLE:
+ {
+ if (to_reg->is_double_fpu()) {
+ address const_addr = __ double_constant(c->as_jdouble());
+ if (const_addr == NULL) {
+ bailout("const section overflow");
+ break;
+ }
+ RelocationHolder rspec = internal_word_Relocation::spec(const_addr);
+ __ relocate(rspec);
+ __ load_const(R0, const_addr);
+ __ lfdx(to_reg->as_double_reg(), R0);
+ } else {
+ assert(to_reg->is_double_cpu(), "Must be a long register.");
+ __ load_const_optimized(to_reg->as_register_lo(), jlong_cast(c->as_jdouble()), R0);
+ }
+ }
+ break;
+
+ default:
+ ShouldNotReachHere();
+ }
+}
+
+
+Address LIR_Assembler::as_Address(LIR_Address* addr) {
+ Unimplemented(); return Address();
+}
+
+
+inline RegisterOrConstant index_or_disp(LIR_Address* addr) {
+ if (addr->index()->is_illegal()) {
+ return (RegisterOrConstant)(addr->disp());
+ } else {
+ return (RegisterOrConstant)(addr->index()->as_pointer_register());
+ }
+}
+
+
+void LIR_Assembler::stack2stack(LIR_Opr src, LIR_Opr dest, BasicType type) {
+ const Register tmp = R0;
+ switch (type) {
+ case T_INT:
+ case T_FLOAT: {
+ Address from = frame_map()->address_for_slot(src->single_stack_ix());
+ Address to = frame_map()->address_for_slot(dest->single_stack_ix());
+ __ lwz(tmp, from.disp(), from.base());
+ __ stw(tmp, to.disp(), to.base());
+ break;
+ }
+ case T_ADDRESS:
+ case T_OBJECT: {
+ Address from = frame_map()->address_for_slot(src->single_stack_ix());
+ Address to = frame_map()->address_for_slot(dest->single_stack_ix());
+ __ ld(tmp, from.disp(), from.base());
+ __ std(tmp, to.disp(), to.base());
+ break;
+ }
+ case T_LONG:
+ case T_DOUBLE: {
+ Address from = frame_map()->address_for_double_slot(src->double_stack_ix());
+ Address to = frame_map()->address_for_double_slot(dest->double_stack_ix());
+ __ ld(tmp, from.disp(), from.base());
+ __ std(tmp, to.disp(), to.base());
+ break;
+ }
+
+ default:
+ ShouldNotReachHere();
+ }
+}
+
+
+Address LIR_Assembler::as_Address_hi(LIR_Address* addr) {
+ Unimplemented(); return Address();
+}
+
+
+Address LIR_Assembler::as_Address_lo(LIR_Address* addr) {
+ Unimplemented(); return Address();
+}
+
+
+void LIR_Assembler::mem2reg(LIR_Opr src_opr, LIR_Opr dest, BasicType type,
+ LIR_PatchCode patch_code, CodeEmitInfo* info, bool wide, bool unaligned) {
+
+ assert(type != T_METADATA, "load of metadata ptr not supported");
+ LIR_Address* addr = src_opr->as_address_ptr();
+ LIR_Opr to_reg = dest;
+
+ Register src = addr->base()->as_pointer_register();
+ Register disp_reg = noreg;
+ int disp_value = addr->disp();
+ bool needs_patching = (patch_code != lir_patch_none);
+ // null check for large offsets in LIRGenerator::do_LoadField
+ bool needs_explicit_null_check = !os::zero_page_read_protected() || !ImplicitNullChecks;
+
+ if (info != NULL && needs_explicit_null_check) {
+ explicit_null_check(src, info);
+ }
+
+ if (addr->base()->type() == T_OBJECT) {
+ __ verify_oop(src);
+ }
+
+ PatchingStub* patch = NULL;
+ if (needs_patching) {
+ patch = new PatchingStub(_masm, PatchingStub::access_field_id);
+ assert(!to_reg->is_double_cpu() ||
+ patch_code == lir_patch_none ||
+ patch_code == lir_patch_normal, "patching doesn't match register");
+ }
+
+ if (addr->index()->is_illegal()) {
+ if (!Assembler::is_simm16(disp_value)) {
+ if (needs_patching) {
+ __ load_const32(R0, 0); // patchable int
+ } else {
+ __ load_const_optimized(R0, disp_value);
+ }
+ disp_reg = R0;
+ }
+ } else {
+ disp_reg = addr->index()->as_pointer_register();
+ assert(disp_value == 0, "can't handle 3 operand addresses");
+ }
+
+ // Remember the offset of the load. The patching_epilog must be done
+ // before the call to add_debug_info, otherwise the PcDescs don't get
+ // entered in increasing order.
+ int offset;
+
+ if (disp_reg == noreg) {
+ assert(Assembler::is_simm16(disp_value), "should have set this up");
+ offset = load(src, disp_value, to_reg, type, wide, unaligned);
+ } else {
+ assert(!unaligned, "unexpected");
+ offset = load(src, disp_reg, to_reg, type, wide);
+ }
+
+ if (patch != NULL) {
+ patching_epilog(patch, patch_code, src, info);
+ }
+ if (info != NULL && !needs_explicit_null_check) {
+ add_debug_info_for_null_check(offset, info);
+ }
+}
+
+
+void LIR_Assembler::stack2reg(LIR_Opr src, LIR_Opr dest, BasicType type) {
+ Address addr;
+ if (src->is_single_word()) {
+ addr = frame_map()->address_for_slot(src->single_stack_ix());
+ } else if (src->is_double_word()) {
+ addr = frame_map()->address_for_double_slot(src->double_stack_ix());
+ }
+
+ bool unaligned = (addr.disp() - STACK_BIAS) % 8 != 0;
+ load(addr.base(), addr.disp(), dest, dest->type(), true /*wide*/, unaligned);
+}
+
+
+void LIR_Assembler::reg2stack(LIR_Opr from_reg, LIR_Opr dest, BasicType type, bool pop_fpu_stack) {
+ Address addr;
+ if (dest->is_single_word()) {
+ addr = frame_map()->address_for_slot(dest->single_stack_ix());
+ } else if (dest->is_double_word()) {
+ addr = frame_map()->address_for_slot(dest->double_stack_ix());
+ }
+ bool unaligned = (addr.disp() - STACK_BIAS) % 8 != 0;
+ store(from_reg, addr.base(), addr.disp(), from_reg->type(), true /*wide*/, unaligned);
+}
+
+
+void LIR_Assembler::reg2reg(LIR_Opr from_reg, LIR_Opr to_reg) {
+ if (from_reg->is_float_kind() && to_reg->is_float_kind()) {
+ if (from_reg->is_double_fpu()) {
+ // double to double moves
+ assert(to_reg->is_double_fpu(), "should match");
+ __ fmr_if_needed(to_reg->as_double_reg(), from_reg->as_double_reg());
+ } else {
+ // float to float moves
+ assert(to_reg->is_single_fpu(), "should match");
+ __ fmr_if_needed(to_reg->as_float_reg(), from_reg->as_float_reg());
+ }
+ } else if (!from_reg->is_float_kind() && !to_reg->is_float_kind()) {
+ if (from_reg->is_double_cpu()) {
+ __ mr_if_needed(to_reg->as_pointer_register(), from_reg->as_pointer_register());
+ } else if (to_reg->is_double_cpu()) {
+ // int to int moves
+ __ mr_if_needed(to_reg->as_register_lo(), from_reg->as_register());
+ } else {
+ // int to int moves
+ __ mr_if_needed(to_reg->as_register(), from_reg->as_register());
+ }
+ } else {
+ ShouldNotReachHere();
+ }
+ if (to_reg->type() == T_OBJECT || to_reg->type() == T_ARRAY) {
+ __ verify_oop(to_reg->as_register());
+ }
+}
+
+
+void LIR_Assembler::reg2mem(LIR_Opr from_reg, LIR_Opr dest, BasicType type,
+ LIR_PatchCode patch_code, CodeEmitInfo* info, bool pop_fpu_stack,
+ bool wide, bool unaligned) {
+ assert(type != T_METADATA, "store of metadata ptr not supported");
+ LIR_Address* addr = dest->as_address_ptr();
+
+ Register src = addr->base()->as_pointer_register();
+ Register disp_reg = noreg;
+ int disp_value = addr->disp();
+ bool needs_patching = (patch_code != lir_patch_none);
+ bool compress_oop = (type == T_ARRAY || type == T_OBJECT) && UseCompressedOops && !wide &&
+ Universe::narrow_oop_mode() != Universe::UnscaledNarrowOop;
+ bool load_disp = addr->index()->is_illegal() && !Assembler::is_simm16(disp_value);
+ bool use_R29 = compress_oop && load_disp; // Avoid register conflict, also do null check before killing R29.
+ // Null check for large offsets in LIRGenerator::do_StoreField.
+ bool needs_explicit_null_check = !ImplicitNullChecks || use_R29;
+
+ if (info != NULL && needs_explicit_null_check) {
+ explicit_null_check(src, info);
+ }
+
+ if (addr->base()->is_oop_register()) {
+ __ verify_oop(src);
+ }
+
+ PatchingStub* patch = NULL;
+ if (needs_patching) {
+ patch = new PatchingStub(_masm, PatchingStub::access_field_id);
+ assert(!from_reg->is_double_cpu() ||
+ patch_code == lir_patch_none ||
+ patch_code == lir_patch_normal, "patching doesn't match register");
+ }
+
+ if (addr->index()->is_illegal()) {
+ if (load_disp) {
+ disp_reg = use_R29 ? R29_TOC : R0;
+ if (needs_patching) {
+ __ load_const32(disp_reg, 0); // patchable int
+ } else {
+ __ load_const_optimized(disp_reg, disp_value);
+ }
+ }
+ } else {
+ disp_reg = addr->index()->as_pointer_register();
+ assert(disp_value == 0, "can't handle 3 operand addresses");
+ }
+
+ // remember the offset of the store. The patching_epilog must be done
+ // before the call to add_debug_info_for_null_check, otherwise the PcDescs don't get
+ // entered in increasing order.
+ int offset;
+
+ if (compress_oop) {
+ Register co = __ encode_heap_oop(R0, from_reg->as_register());
+ from_reg = FrameMap::as_opr(co);
+ }
+
+ if (disp_reg == noreg) {
+ assert(Assembler::is_simm16(disp_value), "should have set this up");
+ offset = store(from_reg, src, disp_value, type, wide, unaligned);
+ } else {
+ assert(!unaligned, "unexpected");
+ offset = store(from_reg, src, disp_reg, type, wide);
+ }
+
+ if (use_R29) {
+ __ load_const_optimized(R29_TOC, MacroAssembler::global_toc(), R0); // reinit
+ }
+
+ if (patch != NULL) {
+ patching_epilog(patch, patch_code, src, info);
+ }
+
+ if (info != NULL && !needs_explicit_null_check) {
+ add_debug_info_for_null_check(offset, info);
+ }
+}
+
+
+void LIR_Assembler::return_op(LIR_Opr result) {
+ const Register return_pc = R11;
+ const Register polling_page = R12;
+
+ // Pop the stack before the safepoint code.
+ int frame_size = initial_frame_size_in_bytes();
+ if (Assembler::is_simm(frame_size, 16)) {
+ __ addi(R1_SP, R1_SP, frame_size);
+ } else {
+ __ pop_frame();
+ }
+
+ if (LoadPollAddressFromThread) {
+ // TODO: PPC port __ ld(polling_page, in_bytes(JavaThread::poll_address_offset()), R16_thread);
+ Unimplemented();
+ } else {
+ __ load_const_optimized(polling_page, (long)(address) os::get_polling_page(), R0); // TODO: PPC port: get_standard_polling_page()
+ }
+
+ // Restore return pc relative to callers' sp.
+ __ ld(return_pc, _abi(lr), R1_SP);
+ // Move return pc to LR.
+ __ mtlr(return_pc);
+
+ // We need to mark the code position where the load from the safepoint
+ // polling page was emitted as relocInfo::poll_return_type here.
+ __ relocate(relocInfo::poll_return_type);
+ __ load_from_polling_page(polling_page);
+
+ // Return.
+ __ blr();
+}
+
+
+int LIR_Assembler::safepoint_poll(LIR_Opr tmp, CodeEmitInfo* info) {
+
+ if (LoadPollAddressFromThread) {
+ const Register poll_addr = tmp->as_register();
+ // TODO: PPC port __ ld(poll_addr, in_bytes(JavaThread::poll_address_offset()), R16_thread);
+ Unimplemented();
+ __ relocate(relocInfo::poll_type); // XXX
+ guarantee(info != NULL, "Shouldn't be NULL");
+ int offset = __ offset();
+ add_debug_info_for_branch(info);
+ __ load_from_polling_page(poll_addr);
+ return offset;
+ }
+
+ __ load_const_optimized(tmp->as_register(), (intptr_t)os::get_polling_page(), R0); // TODO: PPC port: get_standard_polling_page()
+ if (info != NULL) {
+ add_debug_info_for_branch(info);
+ }
+ int offset = __ offset();
+ __ relocate(relocInfo::poll_type);
+ __ load_from_polling_page(tmp->as_register());
+
+ return offset;
+}
+
+
+void LIR_Assembler::emit_static_call_stub() {
+ address call_pc = __ pc();
+ address stub = __ start_a_stub(max_static_call_stub_size);
+ if (stub == NULL) {
+ bailout("static call stub overflow");
+ return;
+ }
+
+ // For java_to_interp stubs we use R11_scratch1 as scratch register
+ // and in call trampoline stubs we use R12_scratch2. This way we
+ // can distinguish them (see is_NativeCallTrampolineStub_at()).
+ const Register reg_scratch = R11_scratch1;
+
+ // Create a static stub relocation which relates this stub
+ // with the call instruction at insts_call_instruction_offset in the
+ // instructions code-section.
+ int start = __ offset();
+ __ relocate(static_stub_Relocation::spec(call_pc));
+
+ // Now, create the stub's code:
+ // - load the TOC
+ // - load the inline cache oop from the constant pool
+ // - load the call target from the constant pool
+ // - call
+ __ calculate_address_from_global_toc(reg_scratch, __ method_toc());
+ AddressLiteral ic = __ allocate_metadata_address((Metadata *)NULL);
+ bool success = __ load_const_from_method_toc(R19_inline_cache_reg, ic, reg_scratch, /*fixed_size*/ true);
+
+ if (ReoptimizeCallSequences) {
+ __ b64_patchable((address)-1, relocInfo::none);
+ } else {
+ AddressLiteral a((address)-1);
+ success = success && __ load_const_from_method_toc(reg_scratch, a, reg_scratch, /*fixed_size*/ true);
+ __ mtctr(reg_scratch);
+ __ bctr();
+ }
+ if (!success) {
+ bailout("const section overflow");
+ return;
+ }
+
+ assert(__ offset() - start <= max_static_call_stub_size, "stub too big");
+ __ end_a_stub();
+}
+
+
+void LIR_Assembler::comp_op(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Op2* op) {
+ bool unsigned_comp = (condition == lir_cond_belowEqual || condition == lir_cond_aboveEqual);
+ if (opr1->is_single_fpu()) {
+ __ fcmpu(BOOL_RESULT, opr1->as_float_reg(), opr2->as_float_reg());
+ } else if (opr1->is_double_fpu()) {
+ __ fcmpu(BOOL_RESULT, opr1->as_double_reg(), opr2->as_double_reg());
+ } else if (opr1->is_single_cpu()) {
+ if (opr2->is_constant()) {
+ switch (opr2->as_constant_ptr()->type()) {
+ case T_INT:
+ {
+ jint con = opr2->as_constant_ptr()->as_jint();
+ if (unsigned_comp) {
+ if (Assembler::is_uimm(con, 16)) {
+ __ cmplwi(BOOL_RESULT, opr1->as_register(), con);
+ } else {
+ __ load_const_optimized(R0, con);
+ __ cmplw(BOOL_RESULT, opr1->as_register(), R0);
+ }
+ } else {
+ if (Assembler::is_simm(con, 16)) {
+ __ cmpwi(BOOL_RESULT, opr1->as_register(), con);
+ } else {
+ __ load_const_optimized(R0, con);
+ __ cmpw(BOOL_RESULT, opr1->as_register(), R0);
+ }
+ }
+ }
+ break;
+
+ case T_OBJECT:
+ // There are only equal/notequal comparisons on objects.
+ {
+ assert(condition == lir_cond_equal || condition == lir_cond_notEqual, "oops");
+ jobject con = opr2->as_constant_ptr()->as_jobject();
+ if (con == NULL) {
+ __ cmpdi(BOOL_RESULT, opr1->as_register(), 0);
+ } else {
+ jobject2reg(con, R0);
+ __ cmpd(BOOL_RESULT, opr1->as_register(), R0);
+ }
+ }
+ break;
+
+ default:
+ ShouldNotReachHere();
+ break;
+ }
+ } else {
+ if (opr2->is_address()) {
+ DEBUG_ONLY( Unimplemented(); ) // Seems to be unused at the moment.
+ LIR_Address *addr = opr2->as_address_ptr();
+ BasicType type = addr->type();
+ if (type == T_OBJECT) { __ ld(R0, index_or_disp(addr), addr->base()->as_register()); }
+ else { __ lwa(R0, index_or_disp(addr), addr->base()->as_register()); }
+ __ cmpd(BOOL_RESULT, opr1->as_register(), R0);
+ } else {
+ if (unsigned_comp) {
+ __ cmplw(BOOL_RESULT, opr1->as_register(), opr2->as_register());
+ } else {
+ __ cmpw(BOOL_RESULT, opr1->as_register(), opr2->as_register());
+ }
+ }
+ }
+ } else if (opr1->is_double_cpu()) {
+ if (opr2->is_constant()) {
+ jlong con = opr2->as_constant_ptr()->as_jlong();
+ if (unsigned_comp) {
+ if (Assembler::is_uimm(con, 16)) {
+ __ cmpldi(BOOL_RESULT, opr1->as_register_lo(), con);
+ } else {
+ __ load_const_optimized(R0, con);
+ __ cmpld(BOOL_RESULT, opr1->as_register_lo(), R0);
+ }
+ } else {
+ if (Assembler::is_simm(con, 16)) {
+ __ cmpdi(BOOL_RESULT, opr1->as_register_lo(), con);
+ } else {
+ __ load_const_optimized(R0, con);
+ __ cmpd(BOOL_RESULT, opr1->as_register_lo(), R0);
+ }
+ }
+ } else if (opr2->is_register()) {
+ if (unsigned_comp) {
+ __ cmpld(BOOL_RESULT, opr1->as_register_lo(), opr2->as_register_lo());
+ } else {
+ __ cmpd(BOOL_RESULT, opr1->as_register_lo(), opr2->as_register_lo());
+ }
+ } else {
+ ShouldNotReachHere();
+ }
+ } else if (opr1->is_address()) {
+ DEBUG_ONLY( Unimplemented(); ) // Seems to be unused at the moment.
+ LIR_Address * addr = opr1->as_address_ptr();
+ BasicType type = addr->type();
+ assert (opr2->is_constant(), "Checking");
+ if (type == T_OBJECT) { __ ld(R0, index_or_disp(addr), addr->base()->as_register()); }
+ else { __ lwa(R0, index_or_disp(addr), addr->base()->as_register()); }
+ __ cmpdi(BOOL_RESULT, R0, opr2->as_constant_ptr()->as_jint());
+ } else {
+ ShouldNotReachHere();
+ }
+}
+
+
+void LIR_Assembler::comp_fl2i(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dst, LIR_Op2* op){
+ const Register Rdst = dst->as_register();
+ Label done;
+ if (code == lir_cmp_fd2i || code == lir_ucmp_fd2i) {
+ bool is_unordered_less = (code == lir_ucmp_fd2i);
+ if (left->is_single_fpu()) {
+ __ fcmpu(CCR0, left->as_float_reg(), right->as_float_reg());
+ } else if (left->is_double_fpu()) {
+ __ fcmpu(CCR0, left->as_double_reg(), right->as_double_reg());
+ } else {
+ ShouldNotReachHere();
+ }
+ __ li(Rdst, is_unordered_less ? -1 : 1);
+ __ bso(CCR0, done);
+ } else if (code == lir_cmp_l2i) {
+ __ cmpd(CCR0, left->as_register_lo(), right->as_register_lo());
+ } else {
+ ShouldNotReachHere();
+ }
+ __ mfcr(R0); // set bit 32..33 as follows: <: 0b10, =: 0b00, >: 0b01
+ __ srwi(Rdst, R0, 30);
+ __ srawi(R0, R0, 31);
+ __ orr(Rdst, R0, Rdst); // set result as follows: <: -1, =: 0, >: 1
+ __ bind(done);
+}
+
+
+inline void load_to_reg(LIR_Assembler *lasm, LIR_Opr src, LIR_Opr dst) {
+ if (src->is_constant()) {
+ lasm->const2reg(src, dst, lir_patch_none, NULL);
+ } else if (src->is_register()) {
+ lasm->reg2reg(src, dst);
+ } else if (src->is_stack()) {
+ lasm->stack2reg(src, dst, dst->type());
+ } else {
+ ShouldNotReachHere();
+ }
+}
+
+
+void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result, BasicType type) {
+ if (opr1->is_equal(opr2) || opr1->is_same_register(opr2)) {
+ load_to_reg(this, opr1, result); // Condition doesn't matter.
+ return;
+ }
+
+ bool positive = false;
+ Assembler::Condition cond = Assembler::equal;
+ switch (condition) {
+ case lir_cond_equal: positive = true ; cond = Assembler::equal ; break;
+ case lir_cond_notEqual: positive = false; cond = Assembler::equal ; break;
+ case lir_cond_less: positive = true ; cond = Assembler::less ; break;
+ case lir_cond_belowEqual:
+ case lir_cond_lessEqual: positive = false; cond = Assembler::greater; break;
+ case lir_cond_greater: positive = true ; cond = Assembler::greater; break;
+ case lir_cond_aboveEqual:
+ case lir_cond_greaterEqual: positive = false; cond = Assembler::less ; break;
+ default: ShouldNotReachHere();
+ }
+
+ // Try to use isel on >=Power7.
+ if (VM_Version::has_isel() && result->is_cpu_register()) {
+ bool o1_is_reg = opr1->is_cpu_register(), o2_is_reg = opr2->is_cpu_register();
+ const Register result_reg = result->is_single_cpu() ? result->as_register() : result->as_register_lo();
+
+ // We can use result_reg to load one operand if not already in register.
+ Register first = o1_is_reg ? (opr1->is_single_cpu() ? opr1->as_register() : opr1->as_register_lo()) : result_reg,
+ second = o2_is_reg ? (opr2->is_single_cpu() ? opr2->as_register() : opr2->as_register_lo()) : result_reg;
+
+ if (first != second) {
+ if (!o1_is_reg) {
+ load_to_reg(this, opr1, result);
+ }
+
+ if (!o2_is_reg) {
+ load_to_reg(this, opr2, result);
+ }
+
+ __ isel(result_reg, BOOL_RESULT, cond, !positive, first, second);
+ return;
+ }
+ } // isel
+
+ load_to_reg(this, opr1, result);
+
+ Label skip;
+ int bo = positive ? Assembler::bcondCRbiIs1 : Assembler::bcondCRbiIs0;
+ int bi = Assembler::bi0(BOOL_RESULT, cond);
+ __ bc(bo, bi, skip);
+
+ load_to_reg(this, opr2, result);
+ __ bind(skip);
+}
+
+
+void LIR_Assembler::arith_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest,
+ CodeEmitInfo* info, bool pop_fpu_stack) {
+ assert(info == NULL, "unused on this code path");
+ assert(left->is_register(), "wrong items state");
+ assert(dest->is_register(), "wrong items state");
+
+ if (right->is_register()) {
+ if (dest->is_float_kind()) {
+
+ FloatRegister lreg, rreg, res;
+ if (right->is_single_fpu()) {
+ lreg = left->as_float_reg();
+ rreg = right->as_float_reg();
+ res = dest->as_float_reg();
+ switch (code) {
+ case lir_add: __ fadds(res, lreg, rreg); break;
+ case lir_sub: __ fsubs(res, lreg, rreg); break;
+ case lir_mul: // fall through
+ case lir_mul_strictfp: __ fmuls(res, lreg, rreg); break;
+ case lir_div: // fall through
+ case lir_div_strictfp: __ fdivs(res, lreg, rreg); break;
+ default: ShouldNotReachHere();
+ }
+ } else {
+ lreg = left->as_double_reg();
+ rreg = right->as_double_reg();
+ res = dest->as_double_reg();
+ switch (code) {
+ case lir_add: __ fadd(res, lreg, rreg); break;
+ case lir_sub: __ fsub(res, lreg, rreg); break;
+ case lir_mul: // fall through
+ case lir_mul_strictfp: __ fmul(res, lreg, rreg); break;
+ case lir_div: // fall through
+ case lir_div_strictfp: __ fdiv(res, lreg, rreg); break;
+ default: ShouldNotReachHere();
+ }
+ }
+
+ } else if (dest->is_double_cpu()) {
+
+ Register dst_lo = dest->as_register_lo();
+ Register op1_lo = left->as_pointer_register();
+ Register op2_lo = right->as_pointer_register();
+
+ switch (code) {
+ case lir_add: __ add(dst_lo, op1_lo, op2_lo); break;
+ case lir_sub: __ sub(dst_lo, op1_lo, op2_lo); break;
+ case lir_mul: __ mulld(dst_lo, op1_lo, op2_lo); break;
+ default: ShouldNotReachHere();
+ }
+ } else {
+ assert (right->is_single_cpu(), "Just Checking");
+
+ Register lreg = left->as_register();
+ Register res = dest->as_register();
+ Register rreg = right->as_register();
+ switch (code) {
+ case lir_add: __ add (res, lreg, rreg); break;
+ case lir_sub: __ sub (res, lreg, rreg); break;
+ case lir_mul: __ mullw(res, lreg, rreg); break;
+ default: ShouldNotReachHere();
+ }
+ }
+ } else {
+ assert (right->is_constant(), "must be constant");
+
+ if (dest->is_single_cpu()) {
+ Register lreg = left->as_register();
+ Register res = dest->as_register();
+ int simm16 = right->as_constant_ptr()->as_jint();
+
+ switch (code) {
+ case lir_sub: assert(Assembler::is_simm16(-simm16), "cannot encode"); // see do_ArithmeticOp_Int
+ simm16 = -simm16;
+ case lir_add: if (res == lreg && simm16 == 0) break;
+ __ addi(res, lreg, simm16); break;
+ case lir_mul: if (res == lreg && simm16 == 1) break;
+ __ mulli(res, lreg, simm16); break;
+ default: ShouldNotReachHere();
+ }
+ } else {
+ Register lreg = left->as_pointer_register();
+ Register res = dest->as_register_lo();
+ long con = right->as_constant_ptr()->as_jlong();
+ assert(Assembler::is_simm16(con), "must be simm16");
+
+ switch (code) {
+ case lir_sub: assert(Assembler::is_simm16(-con), "cannot encode"); // see do_ArithmeticOp_Long
+ con = -con;
+ case lir_add: if (res == lreg && con == 0) break;
+ __ addi(res, lreg, (int)con); break;
+ case lir_mul: if (res == lreg && con == 1) break;
+ __ mulli(res, lreg, (int)con); break;
+ default: ShouldNotReachHere();
+ }
+ }
+ }
+}
+
+
+void LIR_Assembler::fpop() {
+ Unimplemented();
+ // do nothing
+}
+
+
+void LIR_Assembler::intrinsic_op(LIR_Code code, LIR_Opr value, LIR_Opr thread, LIR_Opr dest, LIR_Op* op) {
+ switch (code) {
+ case lir_sqrt: {
+ __ fsqrt(dest->as_double_reg(), value->as_double_reg());
+ break;
+ }
+ case lir_abs: {
+ __ fabs(dest->as_double_reg(), value->as_double_reg());
+ break;
+ }
+ default: {
+ ShouldNotReachHere();
+ break;
+ }
+ }
+}
+
+
+void LIR_Assembler::logic_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest) {
+ if (right->is_constant()) { // see do_LogicOp
+ long uimm;
+ Register d, l;
+ if (dest->is_single_cpu()) {
+ uimm = right->as_constant_ptr()->as_jint();
+ d = dest->as_register();
+ l = left->as_register();
+ } else {
+ uimm = right->as_constant_ptr()->as_jlong();
+ d = dest->as_register_lo();
+ l = left->as_register_lo();
+ }
+ long uimms = (unsigned long)uimm >> 16,
+ uimmss = (unsigned long)uimm >> 32;
+
+ switch (code) {
+ case lir_logic_and:
+ if (uimmss != 0 || (uimms != 0 && (uimm & 0xFFFF) != 0) || is_power_of_2_long(uimm)) {
+ __ andi(d, l, uimm); // special cases
+ } else if (uimms != 0) { __ andis_(d, l, uimms); }
+ else { __ andi_(d, l, uimm); }
+ break;
+
+ case lir_logic_or:
+ if (uimms != 0) { assert((uimm & 0xFFFF) == 0, "sanity"); __ oris(d, l, uimms); }
+ else { __ ori(d, l, uimm); }
+ break;
+
+ case lir_logic_xor:
+ if (uimm == -1) { __ nand(d, l, l); } // special case
+ else if (uimms != 0) { assert((uimm & 0xFFFF) == 0, "sanity"); __ xoris(d, l, uimms); }
+ else { __ xori(d, l, uimm); }
+ break;
+
+ default: ShouldNotReachHere();
+ }
+ } else {
+ assert(right->is_register(), "right should be in register");
+
+ if (dest->is_single_cpu()) {
+ switch (code) {
+ case lir_logic_and: __ andr(dest->as_register(), left->as_register(), right->as_register()); break;
+ case lir_logic_or: __ orr (dest->as_register(), left->as_register(), right->as_register()); break;
+ case lir_logic_xor: __ xorr(dest->as_register(), left->as_register(), right->as_register()); break;
+ default: ShouldNotReachHere();
+ }
+ } else {
+ Register l = (left->is_single_cpu() && left->is_oop_register()) ? left->as_register() :
+ left->as_register_lo();
+ Register r = (right->is_single_cpu() && right->is_oop_register()) ? right->as_register() :
+ right->as_register_lo();
+
+ switch (code) {
+ case lir_logic_and: __ andr(dest->as_register_lo(), l, r); break;
+ case lir_logic_or: __ orr (dest->as_register_lo(), l, r); break;
+ case lir_logic_xor: __ xorr(dest->as_register_lo(), l, r); break;
+ default: ShouldNotReachHere();
+ }
+ }
+ }
+}
+
+
+int LIR_Assembler::shift_amount(BasicType t) {
+ int elem_size = type2aelembytes(t);
+ switch (elem_size) {
+ case 1 : return 0;
+ case 2 : return 1;
+ case 4 : return 2;
+ case 8 : return 3;
+ }
+ ShouldNotReachHere();
+ return -1;
+}
+
+
+void LIR_Assembler::throw_op(LIR_Opr exceptionPC, LIR_Opr exceptionOop, CodeEmitInfo* info) {
+ info->add_register_oop(exceptionOop);
+
+ // Reuse the debug info from the safepoint poll for the throw op itself.
+ address pc_for_athrow = __ pc();
+ int pc_for_athrow_offset = __ offset();
+ //RelocationHolder rspec = internal_word_Relocation::spec(pc_for_athrow);
+ //__ relocate(rspec);
+ //__ load_const(exceptionPC->as_register(), pc_for_athrow, R0);
+ __ calculate_address_from_global_toc(exceptionPC->as_register(), pc_for_athrow, true, true, /*add_relocation*/ true);
+ add_call_info(pc_for_athrow_offset, info); // for exception handler
+
+ address stub = Runtime1::entry_for(compilation()->has_fpu_code() ? Runtime1::handle_exception_id
+ : Runtime1::handle_exception_nofpu_id);
+ //__ load_const_optimized(R0, stub);
+ __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
+ __ mtctr(R0);
+ __ bctr();
+}
+
+
+void LIR_Assembler::unwind_op(LIR_Opr exceptionOop) {
+ // Note: Not used with EnableDebuggingOnDemand.
+ assert(exceptionOop->as_register() == R3, "should match");
+ __ b(_unwind_handler_entry);
+}
+
+
+void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
+ Register src = op->src()->as_register();
+ Register dst = op->dst()->as_register();
+ Register src_pos = op->src_pos()->as_register();
+ Register dst_pos = op->dst_pos()->as_register();
+ Register length = op->length()->as_register();
+ Register tmp = op->tmp()->as_register();
+ Register tmp2 = R0;
+
+ int flags = op->flags();
+ ciArrayKlass* default_type = op->expected_type();
+ BasicType basic_type = default_type != NULL ? default_type->element_type()->basic_type() : T_ILLEGAL;
+ if (basic_type == T_ARRAY) basic_type = T_OBJECT;
+
+ // Set up the arraycopy stub information.
+ ArrayCopyStub* stub = op->stub();
+ const int frame_resize = frame::abi_reg_args_size - sizeof(frame::jit_abi); // C calls need larger frame.
+
+ // Always do stub if no type information is available. It's ok if
+ // the known type isn't loaded since the code sanity checks
+ // in debug mode and the type isn't required when we know the exact type
+ // also check that the type is an array type.
+ if (op->expected_type() == NULL) {
+ assert(src->is_nonvolatile() && src_pos->is_nonvolatile() && dst->is_nonvolatile() && dst_pos->is_nonvolatile() &&
+ length->is_nonvolatile(), "must preserve");
+ // 3 parms are int. Convert to long.
+ __ mr(R3_ARG1, src);
+ __ extsw(R4_ARG2, src_pos);
+ __ mr(R5_ARG3, dst);
+ __ extsw(R6_ARG4, dst_pos);
+ __ extsw(R7_ARG5, length);
+ address copyfunc_addr = StubRoutines::generic_arraycopy();
+
+ if (copyfunc_addr == NULL) { // Use C version if stub was not generated.
+ address entry = CAST_FROM_FN_PTR(address, Runtime1::arraycopy);
+ __ call_c_with_frame_resize(entry, frame_resize);
+ } else {
+#ifndef PRODUCT
+ if (PrintC1Statistics) {
+ address counter = (address)&Runtime1::_generic_arraycopystub_cnt;
+ int simm16_offs = __ load_const_optimized(tmp, counter, tmp2, true);
+ __ lwz(R11_scratch1, simm16_offs, tmp);
+ __ addi(R11_scratch1, R11_scratch1, 1);
+ __ stw(R11_scratch1, simm16_offs, tmp);
+ }
+#endif
+ __ call_c_with_frame_resize(copyfunc_addr, /*stub does not need resized frame*/ 0);
+
+ __ nand(tmp, R3_RET, R3_RET);
+ __ subf(length, tmp, length);
+ __ add(src_pos, tmp, src_pos);
+ __ add(dst_pos, tmp, dst_pos);
+ }
+
+ __ cmpwi(CCR0, R3_RET, 0);
+ __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CCR0, Assembler::less), *stub->entry());
+ __ bind(*stub->continuation());
+ return;
+ }
+
+ assert(default_type != NULL && default_type->is_array_klass(), "must be true at this point");
+ Label cont, slow, copyfunc;
+
+ bool simple_check_flag_set = flags & (LIR_OpArrayCopy::src_null_check |
+ LIR_OpArrayCopy::dst_null_check |
+ LIR_OpArrayCopy::src_pos_positive_check |
+ LIR_OpArrayCopy::dst_pos_positive_check |
+ LIR_OpArrayCopy::length_positive_check);
+
+ // Use only one conditional branch for simple checks.
+ if (simple_check_flag_set) {
+ ConditionRegister combined_check = CCR1, tmp_check = CCR1;
+
+ // Make sure src and dst are non-null.
+ if (flags & LIR_OpArrayCopy::src_null_check) {
+ __ cmpdi(combined_check, src, 0);
+ tmp_check = CCR0;
+ }
+
+ if (flags & LIR_OpArrayCopy::dst_null_check) {
+ __ cmpdi(tmp_check, dst, 0);
+ if (tmp_check != combined_check) {
+ __ cror(combined_check, Assembler::equal, tmp_check, Assembler::equal);
+ }
+ tmp_check = CCR0;
+ }
+
+ // Clear combined_check.eq if not already used.
+ if (tmp_check == combined_check) {
+ __ crandc(combined_check, Assembler::equal, combined_check, Assembler::equal);
+ tmp_check = CCR0;
+ }
+
+ if (flags & LIR_OpArrayCopy::src_pos_positive_check) {
+ // Test src_pos register.
+ __ cmpwi(tmp_check, src_pos, 0);
+ __ cror(combined_check, Assembler::equal, tmp_check, Assembler::less);
+ }
+
+ if (flags & LIR_OpArrayCopy::dst_pos_positive_check) {
+ // Test dst_pos register.
+ __ cmpwi(tmp_check, dst_pos, 0);
+ __ cror(combined_check, Assembler::equal, tmp_check, Assembler::less);
+ }
+
+ if (flags & LIR_OpArrayCopy::length_positive_check) {
+ // Make sure length isn't negative.
+ __ cmpwi(tmp_check, length, 0);
+ __ cror(combined_check, Assembler::equal, tmp_check, Assembler::less);
+ }
+
+ __ beq(combined_check, slow);
+ }
+
+ // Higher 32bits must be null.
+ __ extsw(length, length);
+
+ __ extsw(src_pos, src_pos);
+ if (flags & LIR_OpArrayCopy::src_range_check) {
+ __ lwz(tmp2, arrayOopDesc::length_offset_in_bytes(), src);
+ __ add(tmp, length, src_pos);
+ __ cmpld(CCR0, tmp2, tmp);
+ __ ble(CCR0, slow);
+ }
+
+ __ extsw(dst_pos, dst_pos);
+ if (flags & LIR_OpArrayCopy::dst_range_check) {
+ __ lwz(tmp2, arrayOopDesc::length_offset_in_bytes(), dst);
+ __ add(tmp, length, dst_pos);
+ __ cmpld(CCR0, tmp2, tmp);
+ __ ble(CCR0, slow);
+ }
+
+ int shift = shift_amount(basic_type);
+
+ if (!(flags & LIR_OpArrayCopy::type_check)) {
+ __ b(cont);
+ } else {
+ // We don't know the array types are compatible.
+ if (basic_type != T_OBJECT) {
+ // Simple test for basic type arrays.
+ if (UseCompressedClassPointers) {
+ // We don't need decode because we just need to compare.
+ __ lwz(tmp, oopDesc::klass_offset_in_bytes(), src);
+ __ lwz(tmp2, oopDesc::klass_offset_in_bytes(), dst);
+ __ cmpw(CCR0, tmp, tmp2);
+ } else {
+ __ ld(tmp, oopDesc::klass_offset_in_bytes(), src);
+ __ ld(tmp2, oopDesc::klass_offset_in_bytes(), dst);
+ __ cmpd(CCR0, tmp, tmp2);
+ }
+ __ beq(CCR0, cont);
+ } else {
+ // For object arrays, if src is a sub class of dst then we can
+ // safely do the copy.
+ address copyfunc_addr = StubRoutines::checkcast_arraycopy();
+
+ const Register sub_klass = R5, super_klass = R4; // like CheckCast/InstanceOf
+ assert_different_registers(tmp, tmp2, sub_klass, super_klass);
+
+ __ load_klass(sub_klass, src);
+ __ load_klass(super_klass, dst);
+
+ __ check_klass_subtype_fast_path(sub_klass, super_klass, tmp, tmp2,
+ &cont, copyfunc_addr != NULL ? ©func : &slow, NULL);
+
+ address slow_stc = Runtime1::entry_for(Runtime1::slow_subtype_check_id);
+ //__ load_const_optimized(tmp, slow_stc, tmp2);
+ __ calculate_address_from_global_toc(tmp, slow_stc, true, true, false);
+ __ mtctr(tmp);
+ __ bctrl(); // sets CR0
+ __ beq(CCR0, cont);
+
+ if (copyfunc_addr != NULL) { // Use stub if available.
+ __ bind(copyfunc);
+ // Src is not a sub class of dst so we have to do a
+ // per-element check.
+ int mask = LIR_OpArrayCopy::src_objarray|LIR_OpArrayCopy::dst_objarray;
+ if ((flags & mask) != mask) {
+ assert(flags & mask, "one of the two should be known to be an object array");
+
+ if (!(flags & LIR_OpArrayCopy::src_objarray)) {
+ __ load_klass(tmp, src);
+ } else if (!(flags & LIR_OpArrayCopy::dst_objarray)) {
+ __ load_klass(tmp, dst);
+ }
+
+ __ lwz(tmp2, in_bytes(Klass::layout_helper_offset()), tmp);
+
+ jint objArray_lh = Klass::array_layout_helper(T_OBJECT);
+ __ load_const_optimized(tmp, objArray_lh);
+ __ cmpw(CCR0, tmp, tmp2);
+ __ bne(CCR0, slow);
+ }
+
+ Register src_ptr = R3_ARG1;
+ Register dst_ptr = R4_ARG2;
+ Register len = R5_ARG3;
+ Register chk_off = R6_ARG4;
+ Register super_k = R7_ARG5;
+
+ __ addi(src_ptr, src, arrayOopDesc::base_offset_in_bytes(basic_type));
+ __ addi(dst_ptr, dst, arrayOopDesc::base_offset_in_bytes(basic_type));
+ if (shift == 0) {
+ __ add(src_ptr, src_pos, src_ptr);
+ __ add(dst_ptr, dst_pos, dst_ptr);
+ } else {
+ __ sldi(tmp, src_pos, shift);
+ __ sldi(tmp2, dst_pos, shift);
+ __ add(src_ptr, tmp, src_ptr);
+ __ add(dst_ptr, tmp2, dst_ptr);
+ }
+
+ __ load_klass(tmp, dst);
+ __ mr(len, length);
+
+ int ek_offset = in_bytes(ObjArrayKlass::element_klass_offset());
+ __ ld(super_k, ek_offset, tmp);
+
+ int sco_offset = in_bytes(Klass::super_check_offset_offset());
+ __ lwz(chk_off, sco_offset, super_k);
+
+ __ call_c_with_frame_resize(copyfunc_addr, /*stub does not need resized frame*/ 0);
+
+#ifndef PRODUCT
+ if (PrintC1Statistics) {
+ Label failed;
+ __ cmpwi(CCR0, R3_RET, 0);
+ __ bne(CCR0, failed);
+ address counter = (address)&Runtime1::_arraycopy_checkcast_cnt;
+ int simm16_offs = __ load_const_optimized(tmp, counter, tmp2, true);
+ __ lwz(R11_scratch1, simm16_offs, tmp);
+ __ addi(R11_scratch1, R11_scratch1, 1);
+ __ stw(R11_scratch1, simm16_offs, tmp);
+ __ bind(failed);
+ }
+#endif
+
+ __ nand(tmp, R3_RET, R3_RET);
+ __ cmpwi(CCR0, R3_RET, 0);
+ __ beq(CCR0, *stub->continuation());
+
+#ifndef PRODUCT
+ if (PrintC1Statistics) {
+ address counter = (address)&Runtime1::_arraycopy_checkcast_attempt_cnt;
+ int simm16_offs = __ load_const_optimized(tmp, counter, tmp2, true);
+ __ lwz(R11_scratch1, simm16_offs, tmp);
+ __ addi(R11_scratch1, R11_scratch1, 1);
+ __ stw(R11_scratch1, simm16_offs, tmp);
+ }
+#endif
+
+ __ subf(length, tmp, length);
+ __ add(src_pos, tmp, src_pos);
+ __ add(dst_pos, tmp, dst_pos);
+ }
+ }
+ }
+ __ bind(slow);
+ __ b(*stub->entry());
+ __ bind(cont);
+
+#ifdef ASSERT
+ if (basic_type != T_OBJECT || !(flags & LIR_OpArrayCopy::type_check)) {
+ // Sanity check the known type with the incoming class. For the
+ // primitive case the types must match exactly with src.klass and
+ // dst.klass each exactly matching the default type. For the
+ // object array case, if no type check is needed then either the
+ // dst type is exactly the expected type and the src type is a
+ // subtype which we can't check or src is the same array as dst
+ // but not necessarily exactly of type default_type.
+ Label known_ok, halt;
+ metadata2reg(op->expected_type()->constant_encoding(), tmp);
+ if (UseCompressedClassPointers) {
+ // Tmp holds the default type. It currently comes uncompressed after the
+ // load of a constant, so encode it.
+ __ encode_klass_not_null(tmp);
+ // Load the raw value of the dst klass, since we will be comparing
+ // uncompressed values directly.
+ __ lwz(tmp2, oopDesc::klass_offset_in_bytes(), dst);
+ __ cmpw(CCR0, tmp, tmp2);
+ if (basic_type != T_OBJECT) {
+ __ bne(CCR0, halt);
+ // Load the raw value of the src klass.
+ __ lwz(tmp2, oopDesc::klass_offset_in_bytes(), src);
+ __ cmpw(CCR0, tmp, tmp2);
+ __ beq(CCR0, known_ok);
+ } else {
+ __ beq(CCR0, known_ok);
+ __ cmpw(CCR0, src, dst);
+ __ beq(CCR0, known_ok);
+ }
+ } else {
+ __ ld(tmp2, oopDesc::klass_offset_in_bytes(), dst);
+ __ cmpd(CCR0, tmp, tmp2);
+ if (basic_type != T_OBJECT) {
+ __ bne(CCR0, halt);
+ // Load the raw value of the src klass.
+ __ ld(tmp2, oopDesc::klass_offset_in_bytes(), src);
+ __ cmpd(CCR0, tmp, tmp2);
+ __ beq(CCR0, known_ok);
+ } else {
+ __ beq(CCR0, known_ok);
+ __ cmpd(CCR0, src, dst);
+ __ beq(CCR0, known_ok);
+ }
+ }
+ __ bind(halt);
+ __ stop("incorrect type information in arraycopy");
+ __ bind(known_ok);
+ }
+#endif
+
+#ifndef PRODUCT
+ if (PrintC1Statistics) {
+ address counter = Runtime1::arraycopy_count_address(basic_type);
+ int simm16_offs = __ load_const_optimized(tmp, counter, tmp2, true);
+ __ lwz(R11_scratch1, simm16_offs, tmp);
+ __ addi(R11_scratch1, R11_scratch1, 1);
+ __ stw(R11_scratch1, simm16_offs, tmp);
+ }
+#endif
+
+ Register src_ptr = R3_ARG1;
+ Register dst_ptr = R4_ARG2;
+ Register len = R5_ARG3;
+
+ __ addi(src_ptr, src, arrayOopDesc::base_offset_in_bytes(basic_type));
+ __ addi(dst_ptr, dst, arrayOopDesc::base_offset_in_bytes(basic_type));
+ if (shift == 0) {
+ __ add(src_ptr, src_pos, src_ptr);
+ __ add(dst_ptr, dst_pos, dst_ptr);
+ } else {
+ __ sldi(tmp, src_pos, shift);
+ __ sldi(tmp2, dst_pos, shift);
+ __ add(src_ptr, tmp, src_ptr);
+ __ add(dst_ptr, tmp2, dst_ptr);
+ }
+
+ bool disjoint = (flags & LIR_OpArrayCopy::overlapping) == 0;
+ bool aligned = (flags & LIR_OpArrayCopy::unaligned) == 0;
+ const char *name;
+ address entry = StubRoutines::select_arraycopy_function(basic_type, aligned, disjoint, name, false);
+
+ // Arraycopy stubs takes a length in number of elements, so don't scale it.
+ __ mr(len, length);
+ __ call_c_with_frame_resize(entry, /*stub does not need resized frame*/ 0);
+
+ __ bind(*stub->continuation());
+}
+
+
+void LIR_Assembler::shift_op(LIR_Code code, LIR_Opr left, LIR_Opr count, LIR_Opr dest, LIR_Opr tmp) {
+ if (dest->is_single_cpu()) {
+ __ rldicl(tmp->as_register(), count->as_register(), 0, 64-5);
+#ifdef _LP64
+ if (left->type() == T_OBJECT) {
+ switch (code) {
+ case lir_shl: __ sld(dest->as_register(), left->as_register(), tmp->as_register()); break;
+ case lir_shr: __ srad(dest->as_register(), left->as_register(), tmp->as_register()); break;
+ case lir_ushr: __ srd(dest->as_register(), left->as_register(), tmp->as_register()); break;
+ default: ShouldNotReachHere();
+ }
+ } else
+#endif
+ switch (code) {
+ case lir_shl: __ slw(dest->as_register(), left->as_register(), tmp->as_register()); break;
+ case lir_shr: __ sraw(dest->as_register(), left->as_register(), tmp->as_register()); break;
+ case lir_ushr: __ srw(dest->as_register(), left->as_register(), tmp->as_register()); break;
+ default: ShouldNotReachHere();
+ }
+ } else {
+ __ rldicl(tmp->as_register(), count->as_register(), 0, 64-6);
+ switch (code) {
+ case lir_shl: __ sld(dest->as_register_lo(), left->as_register_lo(), tmp->as_register()); break;
+ case lir_shr: __ srad(dest->as_register_lo(), left->as_register_lo(), tmp->as_register()); break;
+ case lir_ushr: __ srd(dest->as_register_lo(), left->as_register_lo(), tmp->as_register()); break;
+ default: ShouldNotReachHere();
+ }
+ }
+}
+
+
+void LIR_Assembler::shift_op(LIR_Code code, LIR_Opr left, jint count, LIR_Opr dest) {
+#ifdef _LP64
+ if (left->type() == T_OBJECT) {
+ count = count & 63; // Shouldn't shift by more than sizeof(intptr_t).
+ if (count == 0) { __ mr_if_needed(dest->as_register_lo(), left->as_register()); }
+ else {
+ switch (code) {
+ case lir_shl: __ sldi(dest->as_register_lo(), left->as_register(), count); break;
+ case lir_shr: __ sradi(dest->as_register_lo(), left->as_register(), count); break;
+ case lir_ushr: __ srdi(dest->as_register_lo(), left->as_register(), count); break;
+ default: ShouldNotReachHere();
+ }
+ }
+ return;
+ }
+#endif
+
+ if (dest->is_single_cpu()) {
+ count = count & 0x1F; // Java spec
+ if (count == 0) { __ mr_if_needed(dest->as_register(), left->as_register()); }
+ else {
+ switch (code) {
+ case lir_shl: __ slwi(dest->as_register(), left->as_register(), count); break;
+ case lir_shr: __ srawi(dest->as_register(), left->as_register(), count); break;
+ case lir_ushr: __ srwi(dest->as_register(), left->as_register(), count); break;
+ default: ShouldNotReachHere();
+ }
+ }
+ } else if (dest->is_double_cpu()) {
+ count = count & 63; // Java spec
+ if (count == 0) { __ mr_if_needed(dest->as_pointer_register(), left->as_pointer_register()); }
+ else {
+ switch (code) {
+ case lir_shl: __ sldi(dest->as_pointer_register(), left->as_pointer_register(), count); break;
+ case lir_shr: __ sradi(dest->as_pointer_register(), left->as_pointer_register(), count); break;
+ case lir_ushr: __ srdi(dest->as_pointer_register(), left->as_pointer_register(), count); break;
+ default: ShouldNotReachHere();
+ }
+ }
+ } else {
+ ShouldNotReachHere();
+ }
+}
+
+
+void LIR_Assembler::emit_alloc_obj(LIR_OpAllocObj* op) {
+ if (op->init_check()) {
+ if (!os::zero_page_read_protected() || !ImplicitNullChecks) {
+ explicit_null_check(op->klass()->as_register(), op->stub()->info());
+ } else {
+ add_debug_info_for_null_check_here(op->stub()->info());
+ }
+ __ lbz(op->tmp1()->as_register(),
+ in_bytes(InstanceKlass::init_state_offset()), op->klass()->as_register());
+ __ cmpwi(CCR0, op->tmp1()->as_register(), InstanceKlass::fully_initialized);
+ __ bc_far_optimized(Assembler::bcondCRbiIs0, __ bi0(CCR0, Assembler::equal), *op->stub()->entry());
+ }
+ __ allocate_object(op->obj()->as_register(),
+ op->tmp1()->as_register(),
+ op->tmp2()->as_register(),
+ op->tmp3()->as_register(),
+ op->header_size(),
+ op->object_size(),
+ op->klass()->as_register(),
+ *op->stub()->entry());
+
+ __ bind(*op->stub()->continuation());
+ __ verify_oop(op->obj()->as_register());
+}
+
+
+void LIR_Assembler::emit_alloc_array(LIR_OpAllocArray* op) {
+ LP64_ONLY( __ extsw(op->len()->as_register(), op->len()->as_register()); )
+ if (UseSlowPath ||
+ (!UseFastNewObjectArray && (op->type() == T_OBJECT || op->type() == T_ARRAY)) ||
+ (!UseFastNewTypeArray && (op->type() != T_OBJECT && op->type() != T_ARRAY))) {
+ __ b(*op->stub()->entry());
+ } else {
+ __ allocate_array(op->obj()->as_register(),
+ op->len()->as_register(),
+ op->tmp1()->as_register(),
+ op->tmp2()->as_register(),
+ op->tmp3()->as_register(),
+ arrayOopDesc::header_size(op->type()),
+ type2aelembytes(op->type()),
+ op->klass()->as_register(),
+ *op->stub()->entry());
+ }
+ __ bind(*op->stub()->continuation());
+}
+
+
+void LIR_Assembler::type_profile_helper(Register mdo, int mdo_offset_bias,
+ ciMethodData *md, ciProfileData *data,
+ Register recv, Register tmp1, Label* update_done) {
+ uint i;
+ for (i = 0; i < VirtualCallData::row_limit(); i++) {
+ Label next_test;
+ // See if the receiver is receiver[n].
+ __ ld(tmp1, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i)) - mdo_offset_bias, mdo);
+ __ verify_klass_ptr(tmp1);
+ __ cmpd(CCR0, recv, tmp1);
+ __ bne(CCR0, next_test);
+
+ __ ld(tmp1, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i)) - mdo_offset_bias, mdo);
+ __ addi(tmp1, tmp1, DataLayout::counter_increment);
+ __ std(tmp1, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i)) - mdo_offset_bias, mdo);
+ __ b(*update_done);
+
+ __ bind(next_test);
+ }
+
+ // Didn't find receiver; find next empty slot and fill it in.
+ for (i = 0; i < VirtualCallData::row_limit(); i++) {
+ Label next_test;
+ __ ld(tmp1, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i)) - mdo_offset_bias, mdo);
+ __ cmpdi(CCR0, tmp1, 0);
+ __ bne(CCR0, next_test);
+ __ li(tmp1, DataLayout::counter_increment);
+ __ std(recv, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i)) - mdo_offset_bias, mdo);
+ __ std(tmp1, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i)) - mdo_offset_bias, mdo);
+ __ b(*update_done);
+
+ __ bind(next_test);
+ }
+}
+
+
+void LIR_Assembler::setup_md_access(ciMethod* method, int bci,
+ ciMethodData*& md, ciProfileData*& data, int& mdo_offset_bias) {
+ md = method->method_data_or_null();
+ assert(md != NULL, "Sanity");
+ data = md->bci_to_data(bci);
+ assert(data != NULL, "need data for checkcast");
+ assert(data->is_ReceiverTypeData(), "need ReceiverTypeData for type check");
+ if (!Assembler::is_simm16(md->byte_offset_of_slot(data, DataLayout::header_offset()) + data->size_in_bytes())) {
+ // The offset is large so bias the mdo by the base of the slot so
+ // that the ld can use simm16s to reference the slots of the data.
+ mdo_offset_bias = md->byte_offset_of_slot(data, DataLayout::header_offset());
+ }
+}
+
+
+void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, Label* failure, Label* obj_is_null) {
+ Register obj = op->object()->as_register();
+ Register k_RInfo = op->tmp1()->as_register();
+ Register klass_RInfo = op->tmp2()->as_register();
+ Register Rtmp1 = op->tmp3()->as_register();
+ Register dst = op->result_opr()->as_register();
+ ciKlass* k = op->klass();
+ bool should_profile = op->should_profile();
+ bool move_obj_to_dst = (op->code() == lir_checkcast);
+ // Attention: do_temp(opTypeCheck->_object) is not used, i.e. obj may be same as one of the temps.
+ bool reg_conflict = (obj == k_RInfo || obj == klass_RInfo || obj == Rtmp1);
+ bool restore_obj = move_obj_to_dst && reg_conflict;
+
+ __ cmpdi(CCR0, obj, 0);
+ if (move_obj_to_dst || reg_conflict) {
+ __ mr_if_needed(dst, obj);
+ if (reg_conflict) { obj = dst; }
+ }
+
+ ciMethodData* md;
+ ciProfileData* data;
+ int mdo_offset_bias = 0;
+ if (should_profile) {
+ ciMethod* method = op->profiled_method();
+ assert(method != NULL, "Should have method");
+ setup_md_access(method, op->profiled_bci(), md, data, mdo_offset_bias);
+
+ Register mdo = k_RInfo;
+ Register data_val = Rtmp1;
+ Label not_null;
+ __ bne(CCR0, not_null);
+ metadata2reg(md->constant_encoding(), mdo);
+ __ add_const_optimized(mdo, mdo, mdo_offset_bias, R0);
+ __ lbz(data_val, md->byte_offset_of_slot(data, DataLayout::flags_offset()) - mdo_offset_bias, mdo);
+ __ ori(data_val, data_val, BitData::null_seen_byte_constant());
+ __ stb(data_val, md->byte_offset_of_slot(data, DataLayout::flags_offset()) - mdo_offset_bias, mdo);
+ __ b(*obj_is_null);
+ __ bind(not_null);
+ } else {
+ __ beq(CCR0, *obj_is_null);
+ }
+
+ // get object class
+ __ load_klass(klass_RInfo, obj);
+
+ if (k->is_loaded()) {
+ metadata2reg(k->constant_encoding(), k_RInfo);
+ } else {
+ klass2reg_with_patching(k_RInfo, op->info_for_patch());
+ }
+
+ Label profile_cast_failure, failure_restore_obj, profile_cast_success;
+ Label *failure_target = should_profile ? &profile_cast_failure : failure;
+ Label *success_target = should_profile ? &profile_cast_success : success;
+
+ if (op->fast_check()) {
+ assert_different_registers(klass_RInfo, k_RInfo);
+ __ cmpd(CCR0, k_RInfo, klass_RInfo);
+ if (should_profile) {
+ __ bne(CCR0, *failure_target);
+ // Fall through to success case.
+ } else {
+ __ beq(CCR0, *success);
+ // Fall through to failure case.
+ }
+ } else {
+ bool need_slow_path = true;
+ if (k->is_loaded()) {
+ if ((int) k->super_check_offset() != in_bytes(Klass::secondary_super_cache_offset())) {
+ need_slow_path = false;
+ }
+ // Perform the fast part of the checking logic.
+ __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, R0, (need_slow_path ? success_target : NULL),
+ failure_target, NULL, RegisterOrConstant(k->super_check_offset()));
+ } else {
+ // Perform the fast part of the checking logic.
+ __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, R0, success_target, failure_target);
+ }
+ if (!need_slow_path) {
+ if (!should_profile) { __ b(*success); }
+ } else {
+ // Call out-of-line instance of __ check_klass_subtype_slow_path(...):
+ address entry = Runtime1::entry_for(Runtime1::slow_subtype_check_id);
+ //__ load_const_optimized(Rtmp1, entry, R0);
+ __ calculate_address_from_global_toc(Rtmp1, entry, true, true, false);
+ __ mtctr(Rtmp1);
+ __ bctrl(); // sets CR0
+ if (should_profile) {
+ __ bne(CCR0, *failure_target);
+ // Fall through to success case.
+ } else {
+ __ beq(CCR0, *success);
+ // Fall through to failure case.
+ }
+ }
+ }
+
+ if (should_profile) {
+ Register mdo = k_RInfo, recv = klass_RInfo;
+ assert_different_registers(mdo, recv, Rtmp1);
+ __ bind(profile_cast_success);
+ metadata2reg(md->constant_encoding(), mdo);
+ __ add_const_optimized(mdo, mdo, mdo_offset_bias, R0);
+ type_profile_helper(mdo, mdo_offset_bias, md, data, recv, Rtmp1, success);
+ __ b(*success);
+
+ // Cast failure case.
+ __ bind(profile_cast_failure);
+ metadata2reg(md->constant_encoding(), mdo);
+ __ add_const_optimized(mdo, mdo, mdo_offset_bias, R0);
+ __ ld(Rtmp1, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias, mdo);
+ __ addi(Rtmp1, Rtmp1, -DataLayout::counter_increment);
+ __ std(Rtmp1, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias, mdo);
+ }
+
+ __ bind(*failure);
+
+ if (restore_obj) {
+ __ mr(op->object()->as_register(), dst);
+ // Fall through to failure case.
+ }
+}
+
+
+void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) {
+ LIR_Code code = op->code();
+ if (code == lir_store_check) {
+ Register value = op->object()->as_register();
+ Register array = op->array()->as_register();
+ Register k_RInfo = op->tmp1()->as_register();
+ Register klass_RInfo = op->tmp2()->as_register();
+ Register Rtmp1 = op->tmp3()->as_register();
+ bool should_profile = op->should_profile();
+
+ __ verify_oop(value);
+ CodeStub* stub = op->stub();
+ // Check if it needs to be profiled.
+ ciMethodData* md;
+ ciProfileData* data;
+ int mdo_offset_bias = 0;
+ if (should_profile) {
+ ciMethod* method = op->profiled_method();
+ assert(method != NULL, "Should have method");
+ setup_md_access(method, op->profiled_bci(), md, data, mdo_offset_bias);
+ }
+ Label profile_cast_success, failure, done;
+ Label *success_target = should_profile ? &profile_cast_success : &done;
+
+ __ cmpdi(CCR0, value, 0);
+ if (should_profile) {
+ Label not_null;
+ __ bne(CCR0, not_null);
+ Register mdo = k_RInfo;
+ Register data_val = Rtmp1;
+ metadata2reg(md->constant_encoding(), mdo);
+ __ add_const_optimized(mdo, mdo, mdo_offset_bias, R0);
+ __ lbz(data_val, md->byte_offset_of_slot(data, DataLayout::flags_offset()) - mdo_offset_bias, mdo);
+ __ ori(data_val, data_val, BitData::null_seen_byte_constant());
+ __ stb(data_val, md->byte_offset_of_slot(data, DataLayout::flags_offset()) - mdo_offset_bias, mdo);
+ __ b(done);
+ __ bind(not_null);
+ } else {
+ __ beq(CCR0, done);
+ }
+ if (!os::zero_page_read_protected() || !ImplicitNullChecks) {
+ explicit_null_check(array, op->info_for_exception());
+ } else {
+ add_debug_info_for_null_check_here(op->info_for_exception());
+ }
+ __ load_klass(k_RInfo, array);
+ __ load_klass(klass_RInfo, value);
+
+ // Get instance klass.
+ __ ld(k_RInfo, in_bytes(ObjArrayKlass::element_klass_offset()), k_RInfo);
+ // Perform the fast part of the checking logic.
+ __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, R0, success_target, &failure, NULL);
+
+ // Call out-of-line instance of __ check_klass_subtype_slow_path(...):
+ const address slow_path = Runtime1::entry_for(Runtime1::slow_subtype_check_id);
+ //__ load_const_optimized(R0, slow_path);
+ __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(slow_path));
+ __ mtctr(R0);
+ __ bctrl(); // sets CR0
+ if (!should_profile) {
+ __ beq(CCR0, done);
+ __ bind(failure);
+ } else {
+ __ bne(CCR0, failure);
+ // Fall through to the success case.
+
+ Register mdo = klass_RInfo, recv = k_RInfo, tmp1 = Rtmp1;
+ assert_different_registers(value, mdo, recv, tmp1);
+ __ bind(profile_cast_success);
+ metadata2reg(md->constant_encoding(), mdo);
+ __ add_const_optimized(mdo, mdo, mdo_offset_bias, R0);
+ __ load_klass(recv, value);
+ type_profile_helper(mdo, mdo_offset_bias, md, data, recv, tmp1, &done);
+ __ b(done);
+
+ // Cast failure case.
+ __ bind(failure);
+ metadata2reg(md->constant_encoding(), mdo);
+ __ add_const_optimized(mdo, mdo, mdo_offset_bias, R0);
+ Address data_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias);
+ __ ld(tmp1, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias, mdo);
+ __ addi(tmp1, tmp1, -DataLayout::counter_increment);
+ __ std(tmp1, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias, mdo);
+ }
+ __ b(*stub->entry());
+ __ bind(done);
+
+ } else if (code == lir_checkcast) {
+ Label success, failure;
+ emit_typecheck_helper(op, &success, /*fallthru*/&failure, &success); // Moves obj to dst.
+ __ b(*op->stub()->entry());
+ __ align(32, 12);
+ __ bind(success);
+ } else if (code == lir_instanceof) {
+ Register dst = op->result_opr()->as_register();
+ Label success, failure, done;
+ emit_typecheck_helper(op, &success, /*fallthru*/&failure, &failure);
+ __ li(dst, 0);
+ __ b(done);
+ __ align(32, 12);
+ __ bind(success);
+ __ li(dst, 1);
+ __ bind(done);
+ } else {
+ ShouldNotReachHere();
+ }
+}
+
+
+void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) {
+ Register addr = op->addr()->as_pointer_register();
+ Register cmp_value = noreg, new_value = noreg;
+ bool is_64bit = false;
+
+ if (op->code() == lir_cas_long) {
+ cmp_value = op->cmp_value()->as_register_lo();
+ new_value = op->new_value()->as_register_lo();
+ is_64bit = true;
+ } else if (op->code() == lir_cas_int || op->code() == lir_cas_obj) {
+ cmp_value = op->cmp_value()->as_register();
+ new_value = op->new_value()->as_register();
+ if (op->code() == lir_cas_obj) {
+ if (UseCompressedOops) {
+ Register t1 = op->tmp1()->as_register();
+ Register t2 = op->tmp2()->as_register();
+ cmp_value = __ encode_heap_oop(t1, cmp_value);
+ new_value = __ encode_heap_oop(t2, new_value);
+ } else {
+ is_64bit = true;
+ }
+ }
+ } else {
+ Unimplemented();
+ }
+
+ if (is_64bit) {
+ __ cmpxchgd(BOOL_RESULT, /*current_value=*/R0, cmp_value, new_value, addr,
+ MacroAssembler::MemBarFenceAfter,
+ MacroAssembler::cmpxchgx_hint_atomic_update(),
+ noreg, NULL, /*check without ldarx first*/true);
+ } else {
+ __ cmpxchgw(BOOL_RESULT, /*current_value=*/R0, cmp_value, new_value, addr,
+ MacroAssembler::MemBarFenceAfter,
+ MacroAssembler::cmpxchgx_hint_atomic_update(),
+ noreg, /*check without ldarx first*/true);
+ }
+}
+
+
+void LIR_Assembler::set_24bit_FPU() {
+ Unimplemented();
+}
+
+void LIR_Assembler::reset_FPU() {
+ Unimplemented();
+}
+
+
+void LIR_Assembler::breakpoint() {
+ __ illtrap();
+}
+
+
+void LIR_Assembler::push(LIR_Opr opr) {
+ Unimplemented();
+}
+
+void LIR_Assembler::pop(LIR_Opr opr) {
+ Unimplemented();
+}
+
+
+void LIR_Assembler::monitor_address(int monitor_no, LIR_Opr dst_opr) {
+ Address mon_addr = frame_map()->address_for_monitor_lock(monitor_no);
+ Register dst = dst_opr->as_register();
+ Register reg = mon_addr.base();
+ int offset = mon_addr.disp();
+ // Compute pointer to BasicLock.
+ __ add_const_optimized(dst, reg, offset);
+}
+
+
+void LIR_Assembler::emit_lock(LIR_OpLock* op) {
+ Register obj = op->obj_opr()->as_register();
+ Register hdr = op->hdr_opr()->as_register();
+ Register lock = op->lock_opr()->as_register();
+
+ // Obj may not be an oop.
+ if (op->code() == lir_lock) {
+ MonitorEnterStub* stub = (MonitorEnterStub*)op->stub();
+ if (UseFastLocking) {
+ assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
+ // Add debug info for NullPointerException only if one is possible.
+ if (op->info() != NULL) {
+ if (!os::zero_page_read_protected() || !ImplicitNullChecks) {
+ explicit_null_check(obj, op->info());
+ } else {
+ add_debug_info_for_null_check_here(op->info());
+ }
+ }
+ __ lock_object(hdr, obj, lock, op->scratch_opr()->as_register(), *op->stub()->entry());
+ } else {
+ // always do slow locking
+ // note: The slow locking code could be inlined here, however if we use
+ // slow locking, speed doesn't matter anyway and this solution is
+ // simpler and requires less duplicated code - additionally, the
+ // slow locking code is the same in either case which simplifies
+ // debugging.
+ __ b(*op->stub()->entry());
+ }
+ } else {
+ assert (op->code() == lir_unlock, "Invalid code, expected lir_unlock");
+ if (UseFastLocking) {
+ assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
+ __ unlock_object(hdr, obj, lock, *op->stub()->entry());
+ } else {
+ // always do slow unlocking
+ // note: The slow unlocking code could be inlined here, however if we use
+ // slow unlocking, speed doesn't matter anyway and this solution is
+ // simpler and requires less duplicated code - additionally, the
+ // slow unlocking code is the same in either case which simplifies
+ // debugging.
+ __ b(*op->stub()->entry());
+ }
+ }
+ __ bind(*op->stub()->continuation());
+}
+
+
+void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) {
+ ciMethod* method = op->profiled_method();
+ int bci = op->profiled_bci();
+ ciMethod* callee = op->profiled_callee();
+
+ // Update counter for all call types.
+ ciMethodData* md = method->method_data_or_null();
+ assert(md != NULL, "Sanity");
+ ciProfileData* data = md->bci_to_data(bci);
+ assert(data->is_CounterData(), "need CounterData for calls");
+ assert(op->mdo()->is_single_cpu(), "mdo must be allocated");
+ Register mdo = op->mdo()->as_register();
+#ifdef _LP64
+ assert(op->tmp1()->is_double_cpu(), "tmp1 must be allocated");
+ Register tmp1 = op->tmp1()->as_register_lo();
+#else
+ assert(op->tmp1()->is_single_cpu(), "tmp1 must be allocated");
+ Register tmp1 = op->tmp1()->as_register();
+#endif
+ metadata2reg(md->constant_encoding(), mdo);
+ int mdo_offset_bias = 0;
+ if (!Assembler::is_simm16(md->byte_offset_of_slot(data, CounterData::count_offset()) +
+ data->size_in_bytes())) {
+ // The offset is large so bias the mdo by the base of the slot so
+ // that the ld can use simm16s to reference the slots of the data.
+ mdo_offset_bias = md->byte_offset_of_slot(data, CounterData::count_offset());
+ __ add_const_optimized(mdo, mdo, mdo_offset_bias, R0);
+ }
+
+ Bytecodes::Code bc = method->java_code_at_bci(bci);
+ const bool callee_is_static = callee->is_loaded() && callee->is_static();
+ // Perform additional virtual call profiling for invokevirtual and
+ // invokeinterface bytecodes.
+ if ((bc == Bytecodes::_invokevirtual || bc == Bytecodes::_invokeinterface) &&
+ !callee_is_static && // Required for optimized MH invokes.
+ C1ProfileVirtualCalls) {
+ assert(op->recv()->is_single_cpu(), "recv must be allocated");
+ Register recv = op->recv()->as_register();
+ assert_different_registers(mdo, tmp1, recv);
+ assert(data->is_VirtualCallData(), "need VirtualCallData for virtual calls");
+ ciKlass* known_klass = op->known_holder();
+ if (C1OptimizeVirtualCallProfiling && known_klass != NULL) {
+ // We know the type that will be seen at this call site; we can
+ // statically update the MethodData* rather than needing to do
+ // dynamic tests on the receiver type.
+
+ // NOTE: we should probably put a lock around this search to
+ // avoid collisions by concurrent compilations.
+ ciVirtualCallData* vc_data = (ciVirtualCallData*) data;
+ uint i;
+ for (i = 0; i < VirtualCallData::row_limit(); i++) {
+ ciKlass* receiver = vc_data->receiver(i);
+ if (known_klass->equals(receiver)) {
+ __ ld(tmp1, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)) - mdo_offset_bias, mdo);
+ __ addi(tmp1, tmp1, DataLayout::counter_increment);
+ __ std(tmp1, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)) - mdo_offset_bias, mdo);
+ return;
+ }
+ }
+
+ // Receiver type not found in profile data; select an empty slot.
+
+ // Note that this is less efficient than it should be because it
+ // always does a write to the receiver part of the
+ // VirtualCallData rather than just the first time.
+ for (i = 0; i < VirtualCallData::row_limit(); i++) {
+ ciKlass* receiver = vc_data->receiver(i);
+ if (receiver == NULL) {
+ metadata2reg(known_klass->constant_encoding(), tmp1);
+ __ std(tmp1, md->byte_offset_of_slot(data, VirtualCallData::receiver_offset(i)) - mdo_offset_bias, mdo);
+
+ __ ld(tmp1, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)) - mdo_offset_bias, mdo);
+ __ addi(tmp1, tmp1, DataLayout::counter_increment);
+ __ std(tmp1, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)) - mdo_offset_bias, mdo);
+ return;
+ }
+ }
+ } else {
+ __ load_klass(recv, recv);
+ Label update_done;
+ type_profile_helper(mdo, mdo_offset_bias, md, data, recv, tmp1, &update_done);
+ // Receiver did not match any saved receiver and there is no empty row for it.
+ // Increment total counter to indicate polymorphic case.
+ __ ld(tmp1, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias, mdo);
+ __ addi(tmp1, tmp1, DataLayout::counter_increment);
+ __ std(tmp1, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias, mdo);
+
+ __ bind(update_done);
+ }
+ } else {
+ // Static call
+ __ ld(tmp1, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias, mdo);
+ __ addi(tmp1, tmp1, DataLayout::counter_increment);
+ __ std(tmp1, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias, mdo);
+ }
+}
+
+
+void LIR_Assembler::align_backward_branch_target() {
+ __ align(32, 12); // Insert up to 3 nops to align with 32 byte boundary.
+}
+
+
+void LIR_Assembler::emit_delay(LIR_OpDelay* op) {
+ Unimplemented();
+}
+
+
+void LIR_Assembler::negate(LIR_Opr left, LIR_Opr dest) {
+ assert(left->is_register(), "can only handle registers");
+
+ if (left->is_single_cpu()) {
+ __ neg(dest->as_register(), left->as_register());
+ } else if (left->is_single_fpu()) {
+ __ fneg(dest->as_float_reg(), left->as_float_reg());
+ } else if (left->is_double_fpu()) {
+ __ fneg(dest->as_double_reg(), left->as_double_reg());
+ } else {
+ assert (left->is_double_cpu(), "Must be a long");
+ __ neg(dest->as_register_lo(), left->as_register_lo());
+ }
+}
+
+
+void LIR_Assembler::fxch(int i) {
+ Unimplemented();
+}
+
+void LIR_Assembler::fld(int i) {
+ Unimplemented();
+}
+
+void LIR_Assembler::ffree(int i) {
+ Unimplemented();
+}
+
+
+void LIR_Assembler::rt_call(LIR_Opr result, address dest,
+ const LIR_OprList* args, LIR_Opr tmp, CodeEmitInfo* info) {
+ // Stubs: Called via rt_call, but dest is a stub address (no function descriptor).
+ if (dest == Runtime1::entry_for(Runtime1::register_finalizer_id) ||
+ dest == Runtime1::entry_for(Runtime1::new_multi_array_id )) {
+ //__ load_const_optimized(R0, dest);
+ __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(dest));
+ __ mtctr(R0);
+ __ bctrl();
+ assert(info != NULL, "sanity");
+ add_call_info_here(info);
+ return;
+ }
+
+ __ call_c_with_frame_resize(dest, /*no resizing*/ 0);
+ if (info != NULL) {
+ add_call_info_here(info);
+ }
+}
+
+
+void LIR_Assembler::volatile_move_op(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmitInfo* info) {
+ ShouldNotReachHere(); // Not needed on _LP64.
+}
+
+void LIR_Assembler::membar() {
+ __ fence();
+}
+
+void LIR_Assembler::membar_acquire() {
+ __ acquire();
+}
+
+void LIR_Assembler::membar_release() {
+ __ release();
+}
+
+void LIR_Assembler::membar_loadload() {
+ __ membar(Assembler::LoadLoad);
+}
+
+void LIR_Assembler::membar_storestore() {
+ __ membar(Assembler::StoreStore);
+}
+
+void LIR_Assembler::membar_loadstore() {
+ __ membar(Assembler::LoadStore);
+}
+
+void LIR_Assembler::membar_storeload() {
+ __ membar(Assembler::StoreLoad);
+}
+
+
+void LIR_Assembler::leal(LIR_Opr addr_opr, LIR_Opr dest) {
+ LIR_Address* addr = addr_opr->as_address_ptr();
+ assert(addr->scale() == LIR_Address::times_1, "no scaling on this platform");
+ if (addr->index()->is_illegal()) {
+ __ add_const_optimized(dest->as_pointer_register(), addr->base()->as_pointer_register(), addr->disp());
+ } else {
+ assert(addr->disp() == 0, "can't have both: index and disp");
+ __ add(dest->as_pointer_register(), addr->index()->as_pointer_register(), addr->base()->as_pointer_register());
+ }
+}
+
+
+void LIR_Assembler::get_thread(LIR_Opr result_reg) {
+ ShouldNotReachHere();
+}
+
+
+#ifdef ASSERT
+// Emit run-time assertion.
+void LIR_Assembler::emit_assert(LIR_OpAssert* op) {
+ Unimplemented();
+}
+#endif
+
+
+void LIR_Assembler::peephole(LIR_List* lir) {
+ // Optimize instruction pairs before emitting.
+ LIR_OpList* inst = lir->instructions_list();
+ for (int i = 1; i < inst->length(); i++) {
+ LIR_Op* op = inst->at(i);
+
+ // 2 register-register-moves
+ if (op->code() == lir_move) {
+ LIR_Opr in2 = ((LIR_Op1*)op)->in_opr(),
+ res2 = ((LIR_Op1*)op)->result_opr();
+ if (in2->is_register() && res2->is_register()) {
+ LIR_Op* prev = inst->at(i - 1);
+ if (prev && prev->code() == lir_move) {
+ LIR_Opr in1 = ((LIR_Op1*)prev)->in_opr(),
+ res1 = ((LIR_Op1*)prev)->result_opr();
+ if (in1->is_same_register(res2) && in2->is_same_register(res1)) {
+ inst->remove_at(i);
+ }
+ }
+ }
+ }
+
+ }
+ return;
+}
+
+
+void LIR_Assembler::atomic_op(LIR_Code code, LIR_Opr src, LIR_Opr data, LIR_Opr dest, LIR_Opr tmp) {
+ const Register Rptr = src->as_pointer_register(),
+ Rtmp = tmp->as_register();
+ Register Rco = noreg;
+ if (UseCompressedOops && data->is_oop()) {
+ Rco = __ encode_heap_oop(Rtmp, data->as_register());
+ }
+
+ Label Lretry;
+ __ bind(Lretry);
+
+ if (data->type() == T_INT) {
+ const Register Rold = dest->as_register(),
+ Rsrc = data->as_register();
+ assert_different_registers(Rptr, Rtmp, Rold, Rsrc);
+ __ lwarx(Rold, Rptr, MacroAssembler::cmpxchgx_hint_atomic_update());
+ if (code == lir_xadd) {
+ __ add(Rtmp, Rsrc, Rold);
+ __ stwcx_(Rtmp, Rptr);
+ } else {
+ __ stwcx_(Rsrc, Rptr);
+ }
+ } else if (data->is_oop()) {
+ assert(code == lir_xchg, "xadd for oops");
+ const Register Rold = dest->as_register();
+ if (UseCompressedOops) {
+ assert_different_registers(Rptr, Rold, Rco);
+ __ lwarx(Rold, Rptr, MacroAssembler::cmpxchgx_hint_atomic_update());
+ __ stwcx_(Rco, Rptr);
+ } else {
+ const Register Robj = data->as_register();
+ assert_different_registers(Rptr, Rold, Robj);
+ __ ldarx(Rold, Rptr, MacroAssembler::cmpxchgx_hint_atomic_update());
+ __ stdcx_(Robj, Rptr);
+ }
+ } else if (data->type() == T_LONG) {
+ const Register Rold = dest->as_register_lo(),
+ Rsrc = data->as_register_lo();
+ assert_different_registers(Rptr, Rtmp, Rold, Rsrc);
+ __ ldarx(Rold, Rptr, MacroAssembler::cmpxchgx_hint_atomic_update());
+ if (code == lir_xadd) {
+ __ add(Rtmp, Rsrc, Rold);
+ __ stdcx_(Rtmp, Rptr);
+ } else {
+ __ stdcx_(Rsrc, Rptr);
+ }
+ } else {
+ ShouldNotReachHere();
+ }
+
+ if (UseStaticBranchPredictionInCompareAndSwapPPC64) {
+ __ bne_predict_not_taken(CCR0, Lretry);
+ } else {
+ __ bne( CCR0, Lretry);
+ }
+
+ if (UseCompressedOops && data->is_oop()) {
+ __ decode_heap_oop(dest->as_register());
+ }
+}
+
+
+void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) {
+ Register obj = op->obj()->as_register();
+ Register tmp = op->tmp()->as_pointer_register();
+ LIR_Address* mdo_addr = op->mdp()->as_address_ptr();
+ ciKlass* exact_klass = op->exact_klass();
+ intptr_t current_klass = op->current_klass();
+ bool not_null = op->not_null();
+ bool no_conflict = op->no_conflict();
+
+ Label Lupdate, Ldo_update, Ldone;
+
+ bool do_null = !not_null;
+ bool exact_klass_set = exact_klass != NULL && ciTypeEntries::valid_ciklass(current_klass) == exact_klass;
+ bool do_update = !TypeEntries::is_type_unknown(current_klass) && !exact_klass_set;
+
+ assert(do_null || do_update, "why are we here?");
+ assert(!TypeEntries::was_null_seen(current_klass) || do_update, "why are we here?");
+
+ __ verify_oop(obj);
+
+ if (do_null) {
+ if (!TypeEntries::was_null_seen(current_klass)) {
+ __ cmpdi(CCR0, obj, 0);
+ __ bne(CCR0, Lupdate);
+ __ ld(R0, index_or_disp(mdo_addr), mdo_addr->base()->as_pointer_register());
+ __ ori(R0, R0, TypeEntries::null_seen);
+ if (do_update) {
+ __ b(Ldo_update);
+ } else {
+ __ std(R0, index_or_disp(mdo_addr), mdo_addr->base()->as_pointer_register());
+ }
+ } else {
+ if (do_update) {
+ __ cmpdi(CCR0, obj, 0);
+ __ beq(CCR0, Ldone);
+ }
+ }
+#ifdef ASSERT
+ } else {
+ __ cmpdi(CCR0, obj, 0);
+ __ bne(CCR0, Lupdate);
+ __ stop("unexpect null obj", 0x9652);
+#endif
+ }
+
+ __ bind(Lupdate);
+ if (do_update) {
+ Label Lnext;
+ const Register klass = R29_TOC; // kill and reload
+ bool klass_reg_used = false;
+#ifdef ASSERT
+ if (exact_klass != NULL) {
+ Label ok;
+ klass_reg_used = true;
+ __ load_klass(klass, obj);
+ metadata2reg(exact_klass->constant_encoding(), R0);
+ __ cmpd(CCR0, klass, R0);
+ __ beq(CCR0, ok);
+ __ stop("exact klass and actual klass differ", 0x8564);
+ __ bind(ok);
+ }
+#endif
+
+ if (!no_conflict) {
+ if (exact_klass == NULL || TypeEntries::is_type_none(current_klass)) {
+ klass_reg_used = true;
+ if (exact_klass != NULL) {
+ __ ld(tmp, index_or_disp(mdo_addr), mdo_addr->base()->as_pointer_register());
+ metadata2reg(exact_klass->constant_encoding(), klass);
+ } else {
+ __ load_klass(klass, obj);
+ __ ld(tmp, index_or_disp(mdo_addr), mdo_addr->base()->as_pointer_register()); // may kill obj
+ }
+
+ // Like InterpreterMacroAssembler::profile_obj_type
+ __ clrrdi(R0, tmp, exact_log2(-TypeEntries::type_klass_mask));
+ // Basically same as andi(R0, tmp, TypeEntries::type_klass_mask);
+ __ cmpd(CCR1, R0, klass);
+ // Klass seen before, nothing to do (regardless of unknown bit).
+ //beq(CCR1, do_nothing);
+
+ __ andi_(R0, klass, TypeEntries::type_unknown);
+ // Already unknown. Nothing to do anymore.
+ //bne(CCR0, do_nothing);
+ __ crorc(CCR0, Assembler::equal, CCR1, Assembler::equal); // cr0 eq = cr1 eq or cr0 ne
+ __ beq(CCR0, Lnext);
+
+ if (TypeEntries::is_type_none(current_klass)) {
+ __ clrrdi_(R0, tmp, exact_log2(-TypeEntries::type_mask));
+ __ orr(R0, klass, tmp); // Combine klass and null_seen bit (only used if (tmp & type_mask)==0).
+ __ beq(CCR0, Ldo_update); // First time here. Set profile type.
+ }
+
+ } else {
+ assert(ciTypeEntries::valid_ciklass(current_klass) != NULL &&
+ ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "conflict only");
+
+ __ ld(tmp, index_or_disp(mdo_addr), mdo_addr->base()->as_pointer_register());
+ __ andi_(R0, tmp, TypeEntries::type_unknown);
+ // Already unknown. Nothing to do anymore.
+ __ bne(CCR0, Lnext);
+ }
+
+ // Different than before. Cannot keep accurate profile.
+ __ ori(R0, tmp, TypeEntries::type_unknown);
+ } else {
+ // There's a single possible klass at this profile point
+ assert(exact_klass != NULL, "should be");
+ __ ld(tmp, index_or_disp(mdo_addr), mdo_addr->base()->as_pointer_register());
+
+ if (TypeEntries::is_type_none(current_klass)) {
+ klass_reg_used = true;
+ metadata2reg(exact_klass->constant_encoding(), klass);
+
+ __ clrrdi(R0, tmp, exact_log2(-TypeEntries::type_klass_mask));
+ // Basically same as andi(R0, tmp, TypeEntries::type_klass_mask);
+ __ cmpd(CCR1, R0, klass);
+ // Klass seen before, nothing to do (regardless of unknown bit).
+ __ beq(CCR1, Lnext);
+#ifdef ASSERT
+ {
+ Label ok;
+ __ clrrdi_(R0, tmp, exact_log2(-TypeEntries::type_mask));
+ __ beq(CCR0, ok); // First time here.
+
+ __ stop("unexpected profiling mismatch", 0x7865);
+ __ bind(ok);
+ }
+#endif
+ // First time here. Set profile type.
+ __ orr(R0, klass, tmp); // Combine klass and null_seen bit (only used if (tmp & type_mask)==0).
+ } else {
+ assert(ciTypeEntries::valid_ciklass(current_klass) != NULL &&
+ ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "inconsistent");
+
+ // Already unknown. Nothing to do anymore.
+ __ andi_(R0, tmp, TypeEntries::type_unknown);
+ __ bne(CCR0, Lnext);
+
+ // Different than before. Cannot keep accurate profile.
+ __ ori(R0, tmp, TypeEntries::type_unknown);
+ }
+ }
+
+ __ bind(Ldo_update);
+ __ std(R0, index_or_disp(mdo_addr), mdo_addr->base()->as_pointer_register());
+
+ __ bind(Lnext);
+ if (klass_reg_used) { __ load_const_optimized(R29_TOC, MacroAssembler::global_toc(), R0); } // reinit
+ }
+ __ bind(Ldone);
+}
+
+
+void LIR_Assembler::emit_updatecrc32(LIR_OpUpdateCRC32* op) {
+ assert(op->crc()->is_single_cpu(), "crc must be register");
+ assert(op->val()->is_single_cpu(), "byte value must be register");
+ assert(op->result_opr()->is_single_cpu(), "result must be register");
+ Register crc = op->crc()->as_register();
+ Register val = op->val()->as_register();
+ Register res = op->result_opr()->as_register();
+
+ assert_different_registers(val, crc, res);
+
+ __ load_const_optimized(res, StubRoutines::crc_table_addr(), R0);
+ __ nand(crc, crc, crc); // ~crc
+ __ update_byte_crc32(crc, val, res);
+ __ nand(res, crc, crc); // ~crc
+}
+
+#undef __
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012, 2015 SAP AG. 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.
+ *
+ */
+
+#ifndef CPU_PPC_VM_C1_LIRASSEMBLER_PPC_HPP
+#define CPU_PPC_VM_C1_LIRASSEMBLER_PPC_HPP
+
+ private:
+
+ //////////////////////////////////////////////////////////////////////////////
+ // PPC64 load/store emission
+ //
+ // The PPC ld/st instructions cannot accomodate displacements > 16 bits long.
+ // The following "pseudo" instructions (load/store) make it easier to
+ // use the indexed addressing mode by allowing 32 bit displacements:
+ //
+
+ void explicit_null_check(Register addr, CodeEmitInfo* info);
+
+ int store(LIR_Opr from_reg, Register base, int offset, BasicType type, bool wide, bool unaligned);
+ int store(LIR_Opr from_reg, Register base, Register disp, BasicType type, bool wide);
+
+ int load(Register base, int offset, LIR_Opr to_reg, BasicType type, bool wide, bool unaligned);
+ int load(Register base, Register disp, LIR_Opr to_reg, BasicType type, bool wide);
+
+ int shift_amount(BasicType t);
+
+ // Record the type of the receiver in ReceiverTypeData.
+ void type_profile_helper(Register mdo, int mdo_offset_bias,
+ ciMethodData *md, ciProfileData *data,
+ Register recv, Register tmp1, Label* update_done);
+ // Setup pointers to MDO, MDO slot, also compute offset bias to access the slot.
+ void setup_md_access(ciMethod* method, int bci,
+ ciMethodData*& md, ciProfileData*& data, int& mdo_offset_bias);
+ public:
+ static const ConditionRegister BOOL_RESULT;
+
+ // Emit trampoline stub for call. Call bailout() if failed. Return true on success.
+ bool emit_trampoline_stub_for_call(address target, Register Rtoc = noreg);
+
+enum {
+ max_static_call_stub_size = 4 * BytesPerInstWord + MacroAssembler::b64_patchable_size,
+ call_stub_size = max_static_call_stub_size + MacroAssembler::trampoline_stub_size, // or smaller
+ exception_handler_size = MacroAssembler::b64_patchable_size, // or smaller
+ deopt_handler_size = MacroAssembler::bl64_patchable_size
+};
+
+#endif // CPU_PPC_VM_C1_LIRASSEMBLER_PPC_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/cpu/ppc/vm/c1_LIRGenerator_ppc.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -0,0 +1,1429 @@
+/*
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012, 2015 SAP AG. 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 "c1/c1_Compilation.hpp"
+#include "c1/c1_FrameMap.hpp"
+#include "c1/c1_Instruction.hpp"
+#include "c1/c1_LIRAssembler.hpp"
+#include "c1/c1_LIRGenerator.hpp"
+#include "c1/c1_Runtime1.hpp"
+#include "c1/c1_ValueStack.hpp"
+#include "ci/ciArray.hpp"
+#include "ci/ciObjArrayKlass.hpp"
+#include "ci/ciTypeArrayKlass.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/stubRoutines.hpp"
+#include "vmreg_ppc.inline.hpp"
+
+#ifdef ASSERT
+#define __ gen()->lir(__FILE__, __LINE__)->
+#else
+#define __ gen()->lir()->
+#endif
+
+void LIRItem::load_byte_item() {
+ // Byte loads use same registers as other loads.
+ load_item();
+}
+
+
+void LIRItem::load_nonconstant() {
+ LIR_Opr r = value()->operand();
+ if (_gen->can_inline_as_constant(value())) {
+ if (!r->is_constant()) {
+ r = LIR_OprFact::value_type(value()->type());
+ }
+ _result = r;
+ } else {
+ load_item();
+ }
+}
+
+
+inline void load_int_as_long(LIR_List *ll, LIRItem &li, LIR_Opr dst) {
+ LIR_Opr r = li.value()->operand();
+ if (r->is_register()) {
+ LIR_Opr dst_l = FrameMap::as_long_opr(dst->as_register());
+ ll->convert(Bytecodes::_i2l, li.result(), dst_l); // Convert.
+ } else {
+ // Constants or memory get loaded with sign extend on this platform.
+ ll->move(li.result(), dst);
+ }
+}
+
+
+//--------------------------------------------------------------
+// LIRGenerator
+//--------------------------------------------------------------
+
+LIR_Opr LIRGenerator::exceptionOopOpr() { return FrameMap::R3_oop_opr; }
+LIR_Opr LIRGenerator::exceptionPcOpr() { return FrameMap::R4_opr; }
+LIR_Opr LIRGenerator::syncLockOpr() { return FrameMap::R5_opr; } // Need temp effect for MonitorEnterStub.
+LIR_Opr LIRGenerator::syncTempOpr() { return FrameMap::R4_oop_opr; } // Need temp effect for MonitorEnterStub.
+LIR_Opr LIRGenerator::getThreadTemp() { return LIR_OprFact::illegalOpr; } // not needed
+
+LIR_Opr LIRGenerator::result_register_for(ValueType* type, bool callee) {
+ LIR_Opr opr;
+ switch (type->tag()) {
+ case intTag: opr = FrameMap::R3_opr; break;
+ case objectTag: opr = FrameMap::R3_oop_opr; break;
+ case longTag: opr = FrameMap::R3_long_opr; break;
+ case floatTag: opr = FrameMap::F1_opr; break;
+ case doubleTag: opr = FrameMap::F1_double_opr; break;
+
+ case addressTag:
+ default: ShouldNotReachHere(); return LIR_OprFact::illegalOpr;
+ }
+
+ assert(opr->type_field() == as_OprType(as_BasicType(type)), "type mismatch");
+ return opr;
+}
+
+LIR_Opr LIRGenerator::rlock_callee_saved(BasicType type) {
+ ShouldNotReachHere();
+ return LIR_OprFact::illegalOpr;
+}
+
+
+LIR_Opr LIRGenerator::rlock_byte(BasicType type) {
+ return new_register(T_INT);
+}
+
+
+//--------- loading items into registers --------------------------------
+
+// PPC cannot inline all constants.
+bool LIRGenerator::can_store_as_constant(Value v, BasicType type) const {
+ if (v->type()->as_IntConstant() != NULL) {
+ return Assembler::is_simm16(v->type()->as_IntConstant()->value());
+ } else if (v->type()->as_LongConstant() != NULL) {
+ return Assembler::is_simm16(v->type()->as_LongConstant()->value());
+ } else if (v->type()->as_ObjectConstant() != NULL) {
+ return v->type()->as_ObjectConstant()->value()->is_null_object();
+ } else {
+ return false;
+ }
+}
+
+
+// Only simm16 constants can be inlined.
+bool LIRGenerator::can_inline_as_constant(Value i) const {
+ return can_store_as_constant(i, as_BasicType(i->type()));
+}
+
+
+bool LIRGenerator::can_inline_as_constant(LIR_Const* c) const {
+ if (c->type() == T_INT) {
+ return Assembler::is_simm16(c->as_jint());
+ }
+ if (c->type() == T_LONG) {
+ return Assembler::is_simm16(c->as_jlong());
+ }
+ if (c->type() == T_OBJECT) {
+ return c->as_jobject() == NULL;
+ }
+ return false;
+}
+
+
+LIR_Opr LIRGenerator::safepoint_poll_register() {
+ return new_register(T_INT);
+}
+
+
+LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index,
+ int shift, int disp, BasicType type) {
+ assert(base->is_register(), "must be");
+
+ // Accumulate fixed displacements.
+ if (index->is_constant()) {
+ disp += index->as_constant_ptr()->as_jint() << shift;
+ index = LIR_OprFact::illegalOpr;
+ }
+
+ if (index->is_register()) {
+ // Apply the shift and accumulate the displacement.
+ if (shift > 0) {
+ LIR_Opr tmp = new_pointer_register();
+ __ shift_left(index, shift, tmp);
+ index = tmp;
+ }
+ if (disp != 0) {
+ LIR_Opr tmp = new_pointer_register();
+ if (Assembler::is_simm16(disp)) {
+ __ add(index, LIR_OprFact::intptrConst(disp), tmp);
+ index = tmp;
+ } else {
+ __ move(LIR_OprFact::intptrConst(disp), tmp);
+ __ add(tmp, index, tmp);
+ index = tmp;
+ }
+ disp = 0;
+ }
+ } else if (!Assembler::is_simm16(disp)) {
+ // Index is illegal so replace it with the displacement loaded into a register.
+ index = new_pointer_register();
+ __ move(LIR_OprFact::intptrConst(disp), index);
+ disp = 0;
+ }
+
+ // At this point we either have base + index or base + displacement.
+ if (disp == 0) {
+ return new LIR_Address(base, index, type);
+ } else {
+ assert(Assembler::is_simm16(disp), "must be");
+ return new LIR_Address(base, disp, type);
+ }
+}
+
+
+LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_opr,
+ BasicType type, bool needs_card_mark) {
+ int elem_size = type2aelembytes(type);
+ int shift = exact_log2(elem_size);
+
+ LIR_Opr base_opr;
+ int offset = arrayOopDesc::base_offset_in_bytes(type);
+
+ if (index_opr->is_constant()) {
+ int i = index_opr->as_constant_ptr()->as_jint();
+ int array_offset = i * elem_size;
+ if (Assembler::is_simm16(array_offset + offset)) {
+ base_opr = array_opr;
+ offset = array_offset + offset;
+ } else {
+ base_opr = new_pointer_register();
+ if (Assembler::is_simm16(array_offset)) {
+ __ add(array_opr, LIR_OprFact::intptrConst(array_offset), base_opr);
+ } else {
+ __ move(LIR_OprFact::intptrConst(array_offset), base_opr);
+ __ add(base_opr, array_opr, base_opr);
+ }
+ }
+ } else {
+#ifdef _LP64
+ if (index_opr->type() == T_INT) {
+ LIR_Opr tmp = new_register(T_LONG);
+ __ convert(Bytecodes::_i2l, index_opr, tmp);
+ index_opr = tmp;
+ }
+#endif
+
+ base_opr = new_pointer_register();
+ assert (index_opr->is_register(), "Must be register");
+ if (shift > 0) {
+ __ shift_left(index_opr, shift, base_opr);
+ __ add(base_opr, array_opr, base_opr);
+ } else {
+ __ add(index_opr, array_opr, base_opr);
+ }
+ }
+ if (needs_card_mark) {
+ LIR_Opr ptr = new_pointer_register();
+ __ add(base_opr, LIR_OprFact::intptrConst(offset), ptr);
+ return new LIR_Address(ptr, type);
+ } else {
+ return new LIR_Address(base_opr, offset, type);
+ }
+}
+
+
+LIR_Opr LIRGenerator::load_immediate(int x, BasicType type) {
+ LIR_Opr r = NULL;
+ if (type == T_LONG) {
+ r = LIR_OprFact::longConst(x);
+ } else if (type == T_INT) {
+ r = LIR_OprFact::intConst(x);
+ } else {
+ ShouldNotReachHere();
+ }
+ if (!Assembler::is_simm16(x)) {
+ LIR_Opr tmp = new_register(type);
+ __ move(r, tmp);
+ return tmp;
+ }
+ return r;
+}
+
+
+void LIRGenerator::increment_counter(address counter, BasicType type, int step) {
+ LIR_Opr pointer = new_pointer_register();
+ __ move(LIR_OprFact::intptrConst(counter), pointer);
+ LIR_Address* addr = new LIR_Address(pointer, type);
+ increment_counter(addr, step);
+}
+
+
+void LIRGenerator::increment_counter(LIR_Address* addr, int step) {
+ LIR_Opr temp = new_register(addr->type());
+ __ move(addr, temp);
+ __ add(temp, load_immediate(step, addr->type()), temp);
+ __ move(temp, addr);
+}
+
+
+void LIRGenerator::cmp_mem_int(LIR_Condition condition, LIR_Opr base, int disp, int c, CodeEmitInfo* info) {
+ LIR_Opr tmp = FrameMap::R0_opr;
+ __ load(new LIR_Address(base, disp, T_INT), tmp, info);
+ __ cmp(condition, tmp, c);
+}
+
+
+void LIRGenerator::cmp_reg_mem(LIR_Condition condition, LIR_Opr reg, LIR_Opr base,
+ int disp, BasicType type, CodeEmitInfo* info) {
+ LIR_Opr tmp = FrameMap::R0_opr;
+ __ load(new LIR_Address(base, disp, type), tmp, info);
+ __ cmp(condition, reg, tmp);
+}
+
+
+void LIRGenerator::cmp_reg_mem(LIR_Condition condition, LIR_Opr reg, LIR_Opr base,
+ LIR_Opr disp, BasicType type, CodeEmitInfo* info) {
+ LIR_Opr tmp = FrameMap::R0_opr;
+ __ load(new LIR_Address(base, disp, type), tmp, info);
+ __ cmp(condition, reg, tmp);
+}
+
+
+bool LIRGenerator::strength_reduce_multiply(LIR_Opr left, int c, LIR_Opr result, LIR_Opr tmp) {
+ assert(left != result, "should be different registers");
+ if (is_power_of_2(c + 1)) {
+ __ shift_left(left, log2_intptr(c + 1), result);
+ __ sub(result, left, result);
+ return true;
+ } else if (is_power_of_2(c - 1)) {
+ __ shift_left(left, log2_intptr(c - 1), result);
+ __ add(result, left, result);
+ return true;
+ }
+ return false;
+}
+
+
+void LIRGenerator::store_stack_parameter(LIR_Opr item, ByteSize offset_from_sp) {
+ BasicType t = item->type();
+ LIR_Opr sp_opr = FrameMap::SP_opr;
+ if ((t == T_LONG || t == T_DOUBLE) &&
+ ((in_bytes(offset_from_sp) - STACK_BIAS) % 8 != 0)) {
+ __ unaligned_move(item, new LIR_Address(sp_opr, in_bytes(offset_from_sp), t));
+ } else {
+ __ move(item, new LIR_Address(sp_opr, in_bytes(offset_from_sp), t));
+ }
+}
+
+
+//----------------------------------------------------------------------
+// visitor functions
+//----------------------------------------------------------------------
+
+void LIRGenerator::do_StoreIndexed(StoreIndexed* x) {
+ assert(x->is_pinned(),"");
+ bool needs_range_check = x->compute_needs_range_check();
+ bool use_length = x->length() != NULL;
+ bool obj_store = x->elt_type() == T_ARRAY || x->elt_type() == T_OBJECT;
+ bool needs_store_check = obj_store && (x->value()->as_Constant() == NULL ||
+ !get_jobject_constant(x->value())->is_null_object() ||
+ x->should_profile());
+
+ LIRItem array(x->array(), this);
+ LIRItem index(x->index(), this);
+ LIRItem value(x->value(), this);
+ LIRItem length(this);
+
+ array.load_item();
+ index.load_nonconstant();
+
+ if (use_length && needs_range_check) {
+ length.set_instruction(x->length());
+ length.load_item();
+ }
+ if (needs_store_check) {
+ value.load_item();
+ } else {
+ value.load_for_store(x->elt_type());
+ }
+
+ set_no_result(x);
+
+ // The CodeEmitInfo must be duplicated for each different
+ // LIR-instruction because spilling can occur anywhere between two
+ // instructions and so the debug information must be different.
+ CodeEmitInfo* range_check_info = state_for(x);
+ CodeEmitInfo* null_check_info = NULL;
+ if (x->needs_null_check()) {
+ null_check_info = new CodeEmitInfo(range_check_info);
+ }
+
+ // Emit array address setup early so it schedules better.
+ LIR_Address* array_addr = emit_array_address(array.result(), index.result(), x->elt_type(), obj_store);
+
+ if (GenerateRangeChecks && needs_range_check) {
+ if (use_length) {
+ __ cmp(lir_cond_belowEqual, length.result(), index.result());
+ __ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result()));
+ } else {
+ array_range_check(array.result(), index.result(), null_check_info, range_check_info);
+ // Range_check also does the null check.
+ null_check_info = NULL;
+ }
+ }
+
+ if (GenerateArrayStoreCheck && needs_store_check) {
+ // Following registers are used by slow_subtype_check:
+ LIR_Opr tmp1 = FrameMap::R4_opr; // super_klass
+ LIR_Opr tmp2 = FrameMap::R5_opr; // sub_klass
+ LIR_Opr tmp3 = FrameMap::R6_opr; // temp
+
+ CodeEmitInfo* store_check_info = new CodeEmitInfo(range_check_info);
+ __ store_check(value.result(), array.result(), tmp1, tmp2, tmp3,
+ store_check_info, x->profiled_method(), x->profiled_bci());
+ }
+
+ if (obj_store) {
+ // Needs GC write barriers.
+ pre_barrier(LIR_OprFact::address(array_addr), LIR_OprFact::illegalOpr /* pre_val */,
+ true /* do_load */, false /* patch */, NULL);
+ }
+ __ move(value.result(), array_addr, null_check_info);
+ if (obj_store) {
+ // Precise card mark.
+ post_barrier(LIR_OprFact::address(array_addr), value.result());
+ }
+}
+
+
+void LIRGenerator::do_MonitorEnter(MonitorEnter* x) {
+ assert(x->is_pinned(),"");
+ LIRItem obj(x->obj(), this);
+ obj.load_item();
+
+ set_no_result(x);
+
+ // We use R4+R5 in order to get a temp effect. These regs are used in slow path (MonitorEnterStub).
+ LIR_Opr lock = FrameMap::R5_opr;
+ LIR_Opr scratch = FrameMap::R4_opr;
+ LIR_Opr hdr = FrameMap::R6_opr;
+
+ CodeEmitInfo* info_for_exception = NULL;
+ if (x->needs_null_check()) {
+ info_for_exception = state_for(x);
+ }
+
+ // This CodeEmitInfo must not have the xhandlers because here the
+ // object is already locked (xhandlers expects object to be unlocked).
+ CodeEmitInfo* info = state_for(x, x->state(), true);
+ monitor_enter(obj.result(), lock, hdr, scratch, x->monitor_no(), info_for_exception, info);
+}
+
+
+void LIRGenerator::do_MonitorExit(MonitorExit* x) {
+ assert(x->is_pinned(),"");
+ LIRItem obj(x->obj(), this);
+ obj.dont_load_item();
+
+ set_no_result(x);
+ LIR_Opr lock = FrameMap::R5_opr;
+ LIR_Opr hdr = FrameMap::R4_opr; // Used for slow path (MonitorExitStub).
+ LIR_Opr obj_temp = FrameMap::R6_opr;
+ monitor_exit(obj_temp, lock, hdr, LIR_OprFact::illegalOpr, x->monitor_no());
+}
+
+
+// _ineg, _lneg, _fneg, _dneg
+void LIRGenerator::do_NegateOp(NegateOp* x) {
+ LIRItem value(x->x(), this);
+ value.load_item();
+ LIR_Opr reg = rlock_result(x);
+ __ negate(value.result(), reg);
+}
+
+
+// for _fadd, _fmul, _fsub, _fdiv, _frem
+// _dadd, _dmul, _dsub, _ddiv, _drem
+void LIRGenerator::do_ArithmeticOp_FPU(ArithmeticOp* x) {
+ switch (x->op()) {
+ case Bytecodes::_fadd:
+ case Bytecodes::_fmul:
+ case Bytecodes::_fsub:
+ case Bytecodes::_fdiv:
+ case Bytecodes::_dadd:
+ case Bytecodes::_dmul:
+ case Bytecodes::_dsub:
+ case Bytecodes::_ddiv: {
+ LIRItem left(x->x(), this);
+ LIRItem right(x->y(), this);
+ left.load_item();
+ right.load_item();
+ rlock_result(x);
+ arithmetic_op_fpu(x->op(), x->operand(), left.result(), right.result(), x->is_strictfp());
+ }
+ break;
+
+ case Bytecodes::_frem:
+ case Bytecodes::_drem: {
+ address entry = NULL;
+ switch (x->op()) {
+ case Bytecodes::_frem:
+ entry = CAST_FROM_FN_PTR(address, SharedRuntime::frem);
+ break;
+ case Bytecodes::_drem:
+ entry = CAST_FROM_FN_PTR(address, SharedRuntime::drem);
+ break;
+ default:
+ ShouldNotReachHere();
+ }
+ LIR_Opr result = call_runtime(x->x(), x->y(), entry, x->type(), NULL);
+ set_result(x, result);
+ }
+ break;
+
+ default: ShouldNotReachHere();
+ }
+}
+
+
+// for _ladd, _lmul, _lsub, _ldiv, _lrem
+void LIRGenerator::do_ArithmeticOp_Long(ArithmeticOp* x) {
+ bool is_div_rem = x->op() == Bytecodes::_ldiv || x->op() == Bytecodes::_lrem;
+
+ LIRItem right(x->y(), this);
+ // Missing test if instr is commutative and if we should swap.
+ if (right.value()->type()->as_LongConstant() &&
+ (x->op() == Bytecodes::_lsub && right.value()->type()->as_LongConstant()->value() == ((-1)<<15)) ) {
+ // Sub is implemented by addi and can't support min_simm16 as constant..
+ right.load_item();
+ } else {
+ right.load_nonconstant();
+ }
+ assert(right.is_constant() || right.is_register(), "wrong state of right");
+
+ if (is_div_rem) {
+ LIR_Opr divisor = right.result();
+ if (divisor->is_register()) {
+ CodeEmitInfo* null_check_info = state_for(x);
+ __ cmp(lir_cond_equal, divisor, LIR_OprFact::longConst(0));
+ __ branch(lir_cond_equal, T_LONG, new DivByZeroStub(null_check_info));
+ } else {
+ jlong const_divisor = divisor->as_constant_ptr()->as_jlong();
+ if (const_divisor == 0) {
+ CodeEmitInfo* null_check_info = state_for(x);
+ __ jump(new DivByZeroStub(null_check_info));
+ rlock_result(x);
+ __ move(LIR_OprFact::longConst(0), x->operand()); // dummy
+ return;
+ }
+ if (x->op() == Bytecodes::_lrem && !is_power_of_2(const_divisor) && const_divisor != -1) {
+ // Remainder computation would need additional tmp != R0.
+ right.load_item();
+ }
+ }
+ }
+
+ LIRItem left(x->x(), this);
+ left.load_item();
+ rlock_result(x);
+ if (is_div_rem) {
+ CodeEmitInfo* info = NULL; // Null check already done above.
+ LIR_Opr tmp = FrameMap::R0_opr;
+ if (x->op() == Bytecodes::_lrem) {
+ __ irem(left.result(), right.result(), x->operand(), tmp, info);
+ } else if (x->op() == Bytecodes::_ldiv) {
+ __ idiv(left.result(), right.result(), x->operand(), tmp, info);
+ }
+ } else {
+ arithmetic_op_long(x->op(), x->operand(), left.result(), right.result(), NULL);
+ }
+}
+
+
+// for: _iadd, _imul, _isub, _idiv, _irem
+void LIRGenerator::do_ArithmeticOp_Int(ArithmeticOp* x) {
+ bool is_div_rem = x->op() == Bytecodes::_idiv || x->op() == Bytecodes::_irem;
+
+ LIRItem right(x->y(), this);
+ // Missing test if instr is commutative and if we should swap.
+ if (right.value()->type()->as_IntConstant() &&
+ (x->op() == Bytecodes::_isub && right.value()->type()->as_IntConstant()->value() == ((-1)<<15)) ) {
+ // Sub is implemented by addi and can't support min_simm16 as constant.
+ right.load_item();
+ } else {
+ right.load_nonconstant();
+ }
+ assert(right.is_constant() || right.is_register(), "wrong state of right");
+
+ if (is_div_rem) {
+ LIR_Opr divisor = right.result();
+ if (divisor->is_register()) {
+ CodeEmitInfo* null_check_info = state_for(x);
+ __ cmp(lir_cond_equal, divisor, LIR_OprFact::intConst(0));
+ __ branch(lir_cond_equal, T_INT, new DivByZeroStub(null_check_info));
+ } else {
+ jint const_divisor = divisor->as_constant_ptr()->as_jint();
+ if (const_divisor == 0) {
+ CodeEmitInfo* null_check_info = state_for(x);
+ __ jump(new DivByZeroStub(null_check_info));
+ rlock_result(x);
+ __ move(LIR_OprFact::intConst(0), x->operand()); // dummy
+ return;
+ }
+ if (x->op() == Bytecodes::_irem && !is_power_of_2(const_divisor) && const_divisor != -1) {
+ // Remainder computation would need additional tmp != R0.
+ right.load_item();
+ }
+ }
+ }
+
+ LIRItem left(x->x(), this);
+ left.load_item();
+ rlock_result(x);
+ if (is_div_rem) {
+ CodeEmitInfo* info = NULL; // Null check already done above.
+ LIR_Opr tmp = FrameMap::R0_opr;
+ if (x->op() == Bytecodes::_irem) {
+ __ irem(left.result(), right.result(), x->operand(), tmp, info);
+ } else if (x->op() == Bytecodes::_idiv) {
+ __ idiv(left.result(), right.result(), x->operand(), tmp, info);
+ }
+ } else {
+ arithmetic_op_int(x->op(), x->operand(), left.result(), right.result(), FrameMap::R0_opr);
+ }
+}
+
+
+void LIRGenerator::do_ArithmeticOp(ArithmeticOp* x) {
+ ValueTag tag = x->type()->tag();
+ assert(x->x()->type()->tag() == tag && x->y()->type()->tag() == tag, "wrong parameters");
+ switch (tag) {
+ case floatTag:
+ case doubleTag: do_ArithmeticOp_FPU(x); return;
+ case longTag: do_ArithmeticOp_Long(x); return;
+ case intTag: do_ArithmeticOp_Int(x); return;
+ }
+ ShouldNotReachHere();
+}
+
+
+// _ishl, _lshl, _ishr, _lshr, _iushr, _lushr
+void LIRGenerator::do_ShiftOp(ShiftOp* x) {
+ LIRItem value(x->x(), this);
+ LIRItem count(x->y(), this);
+ value.load_item();
+ LIR_Opr reg = rlock_result(x);
+ LIR_Opr mcount;
+ if (count.result()->is_register()) {
+ mcount = FrameMap::R0_opr;
+ } else {
+ mcount = LIR_OprFact::illegalOpr;
+ }
+ shift_op(x->op(), reg, value.result(), count.result(), mcount);
+}
+
+
+inline bool can_handle_logic_op_as_uimm(ValueType *type, Bytecodes::Code bc) {
+ jlong int_or_long_const;
+ if (type->as_IntConstant()) {
+ int_or_long_const = type->as_IntConstant()->value();
+ } else if (type->as_LongConstant()) {
+ int_or_long_const = type->as_LongConstant()->value();
+ } else if (type->as_ObjectConstant()) {
+ return type->as_ObjectConstant()->value()->is_null_object();
+ } else {
+ return false;
+ }
+
+ if (Assembler::is_uimm(int_or_long_const, 16)) return true;
+ if ((int_or_long_const & 0xFFFF) == 0 &&
+ Assembler::is_uimm((jlong)((julong)int_or_long_const >> 16), 16)) return true;
+
+ // see Assembler::andi
+ if (bc == Bytecodes::_iand &&
+ (is_power_of_2_long(int_or_long_const+1) ||
+ is_power_of_2_long(int_or_long_const) ||
+ is_power_of_2_long(-int_or_long_const))) return true;
+ if (bc == Bytecodes::_land &&
+ (is_power_of_2_long(int_or_long_const+1) ||
+ (Assembler::is_uimm(int_or_long_const, 32) && is_power_of_2_long(int_or_long_const)) ||
+ (int_or_long_const != min_jlong && is_power_of_2_long(-int_or_long_const)))) return true;
+
+ // special case: xor -1
+ if ((bc == Bytecodes::_ixor || bc == Bytecodes::_lxor) &&
+ int_or_long_const == -1) return true;
+ return false;
+}
+
+
+// _iand, _land, _ior, _lor, _ixor, _lxor
+void LIRGenerator::do_LogicOp(LogicOp* x) {
+ LIRItem left(x->x(), this);
+ LIRItem right(x->y(), this);
+
+ left.load_item();
+
+ Value rval = right.value();
+ LIR_Opr r = rval->operand();
+ ValueType *type = rval->type();
+ // Logic instructions use unsigned immediate values.
+ if (can_handle_logic_op_as_uimm(type, x->op())) {
+ if (!r->is_constant()) {
+ r = LIR_OprFact::value_type(type);
+ rval->set_operand(r);
+ }
+ right.set_result(r);
+ } else {
+ right.load_item();
+ }
+
+ LIR_Opr reg = rlock_result(x);
+
+ logic_op(x->op(), reg, left.result(), right.result());
+}
+
+
+// _lcmp, _fcmpl, _fcmpg, _dcmpl, _dcmpg
+void LIRGenerator::do_CompareOp(CompareOp* x) {
+ LIRItem left(x->x(), this);
+ LIRItem right(x->y(), this);
+ left.load_item();
+ right.load_item();
+ LIR_Opr reg = rlock_result(x);
+ if (x->x()->type()->is_float_kind()) {
+ Bytecodes::Code code = x->op();
+ __ fcmp2int(left.result(), right.result(), reg, (code == Bytecodes::_fcmpl || code == Bytecodes::_dcmpl));
+ } else if (x->x()->type()->tag() == longTag) {
+ __ lcmp2int(left.result(), right.result(), reg);
+ } else {
+ Unimplemented();
+ }
+}
+
+
+void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) {
+ assert(x->number_of_arguments() == 4, "wrong type");
+ LIRItem obj (x->argument_at(0), this); // object
+ LIRItem offset(x->argument_at(1), this); // offset of field
+ LIRItem cmp (x->argument_at(2), this); // Value to compare with field.
+ LIRItem val (x->argument_at(3), this); // Replace field with val if matches cmp.
+
+ LIR_Opr t1 = LIR_OprFact::illegalOpr;
+ LIR_Opr t2 = LIR_OprFact::illegalOpr;
+ LIR_Opr addr = new_pointer_register();
+
+ // Get address of field.
+ obj.load_item();
+ offset.load_item();
+ cmp.load_item();
+ val.load_item();
+
+ __ add(obj.result(), offset.result(), addr);
+
+ // Volatile load may be followed by Unsafe CAS.
+ if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
+ __ membar(); // To be safe. Unsafe semantics are unclear.
+ } else {
+ __ membar_release();
+ }
+
+ if (type == objectType) { // Write-barrier needed for Object fields.
+ // Only cmp value can get overwritten, no do_load required.
+ pre_barrier(LIR_OprFact::illegalOpr /* addr */, cmp.result() /* pre_val */,
+ false /* do_load */, false /* patch */, NULL);
+ }
+
+ if (type == objectType) {
+ if (UseCompressedOops) {
+ t1 = new_register(T_OBJECT);
+ t2 = new_register(T_OBJECT);
+ }
+ __ cas_obj(addr, cmp.result(), val.result(), t1, t2);
+ } else if (type == intType) {
+ __ cas_int(addr, cmp.result(), val.result(), t1, t2);
+ } else if (type == longType) {
+ __ cas_long(addr, cmp.result(), val.result(), t1, t2);
+ } else {
+ ShouldNotReachHere();
+ }
+ // Benerate conditional move of boolean result.
+ LIR_Opr result = rlock_result(x);
+ __ cmove(lir_cond_equal, LIR_OprFact::intConst(1), LIR_OprFact::intConst(0),
+ result, as_BasicType(type));
+ if (type == objectType) { // Write-barrier needed for Object fields.
+ // Precise card mark since could either be object or array.
+ post_barrier(addr, val.result());
+ }
+}
+
+
+void LIRGenerator::do_MathIntrinsic(Intrinsic* x) {
+ switch (x->id()) {
+ case vmIntrinsics::_dabs: {
+ assert(x->number_of_arguments() == 1, "wrong type");
+ LIRItem value(x->argument_at(0), this);
+ value.load_item();
+ LIR_Opr dst = rlock_result(x);
+ __ abs(value.result(), dst, LIR_OprFact::illegalOpr);
+ break;
+ }
+ case vmIntrinsics::_dsqrt: {
+ if (VM_Version::has_fsqrt()) {
+ assert(x->number_of_arguments() == 1, "wrong type");
+ LIRItem value(x->argument_at(0), this);
+ value.load_item();
+ LIR_Opr dst = rlock_result(x);
+ __ sqrt(value.result(), dst, LIR_OprFact::illegalOpr);
+ break;
+ } // else fallthru
+ }
+ case vmIntrinsics::_dlog10: // fall through
+ case vmIntrinsics::_dlog: // fall through
+ case vmIntrinsics::_dsin: // fall through
+ case vmIntrinsics::_dtan: // fall through
+ case vmIntrinsics::_dcos: // fall through
+ case vmIntrinsics::_dexp: {
+ assert(x->number_of_arguments() == 1, "wrong type");
+
+ address runtime_entry = NULL;
+ switch (x->id()) {
+ case vmIntrinsics::_dsqrt:
+ runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dsqrt);
+ break;
+ case vmIntrinsics::_dsin:
+ runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dsin);
+ break;
+ case vmIntrinsics::_dcos:
+ runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dcos);
+ break;
+ case vmIntrinsics::_dtan:
+ runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dtan);
+ break;
+ case vmIntrinsics::_dlog:
+ runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dlog);
+ break;
+ case vmIntrinsics::_dlog10:
+ runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dlog10);
+ break;
+ case vmIntrinsics::_dexp:
+ runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dexp);
+ break;
+ default:
+ ShouldNotReachHere();
+ }
+
+ LIR_Opr result = call_runtime(x->argument_at(0), runtime_entry, x->type(), NULL);
+ set_result(x, result);
+ break;
+ }
+ case vmIntrinsics::_dpow: {
+ assert(x->number_of_arguments() == 2, "wrong type");
+ address runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dpow);
+ LIR_Opr result = call_runtime(x->argument_at(0), x->argument_at(1), runtime_entry, x->type(), NULL);
+ set_result(x, result);
+ break;
+ }
+ }
+}
+
+
+void LIRGenerator::do_ArrayCopy(Intrinsic* x) {
+ assert(x->number_of_arguments() == 5, "wrong type");
+
+ // Make all state_for calls early since they can emit code.
+ CodeEmitInfo* info = state_for(x, x->state());
+
+ LIRItem src (x->argument_at(0), this);
+ LIRItem src_pos (x->argument_at(1), this);
+ LIRItem dst (x->argument_at(2), this);
+ LIRItem dst_pos (x->argument_at(3), this);
+ LIRItem length (x->argument_at(4), this);
+
+ // Load all values in callee_save_registers (C calling convention),
+ // as this makes the parameter passing to the fast case simpler.
+ src.load_item_force (FrameMap::R14_oop_opr);
+ src_pos.load_item_force (FrameMap::R15_opr);
+ dst.load_item_force (FrameMap::R17_oop_opr);
+ dst_pos.load_item_force (FrameMap::R18_opr);
+ length.load_item_force (FrameMap::R19_opr);
+ LIR_Opr tmp = FrameMap::R20_opr;
+
+ int flags;
+ ciArrayKlass* expected_type;
+ arraycopy_helper(x, &flags, &expected_type);
+
+ __ arraycopy(src.result(), src_pos.result(), dst.result(), dst_pos.result(),
+ length.result(), tmp,
+ expected_type, flags, info);
+ set_no_result(x);
+}
+
+
+// _i2l, _i2f, _i2d, _l2i, _l2f, _l2d, _f2i, _f2l, _f2d, _d2i, _d2l, _d2f
+// _i2b, _i2c, _i2s
+void LIRGenerator::do_Convert(Convert* x) {
+ switch (x->op()) {
+
+ // int -> float: force spill
+ case Bytecodes::_l2f: {
+ if (!VM_Version::has_fcfids()) { // fcfids is >= Power7 only
+ // fcfid+frsp needs fixup code to avoid rounding incompatibility.
+ address entry = CAST_FROM_FN_PTR(address, SharedRuntime::l2f);
+ LIR_Opr result = call_runtime(x->value(), entry, x->type(), NULL);
+ set_result(x, result);
+ break;
+ } // else fallthru
+ }
+ case Bytecodes::_l2d: {
+ LIRItem value(x->value(), this);
+ LIR_Opr reg = rlock_result(x);
+ value.load_item();
+ LIR_Opr tmp = force_to_spill(value.result(), T_DOUBLE);
+ __ convert(x->op(), tmp, reg);
+ break;
+ }
+ case Bytecodes::_i2f:
+ case Bytecodes::_i2d: {
+ LIRItem value(x->value(), this);
+ LIR_Opr reg = rlock_result(x);
+ value.load_item();
+ // Convert i2l first.
+ LIR_Opr tmp1 = new_register(T_LONG);
+ __ convert(Bytecodes::_i2l, value.result(), tmp1);
+ LIR_Opr tmp2 = force_to_spill(tmp1, T_DOUBLE);
+ __ convert(x->op(), tmp2, reg);
+ break;
+ }
+
+ // float -> int: result will be stored
+ case Bytecodes::_f2l:
+ case Bytecodes::_d2l: {
+ LIRItem value(x->value(), this);
+ LIR_Opr reg = rlock_result(x);
+ value.set_destroys_register(); // USE_KILL
+ value.load_item();
+ set_vreg_flag(reg, must_start_in_memory);
+ __ convert(x->op(), value.result(), reg);
+ break;
+ }
+ case Bytecodes::_f2i:
+ case Bytecodes::_d2i: {
+ LIRItem value(x->value(), this);
+ LIR_Opr reg = rlock_result(x);
+ value.set_destroys_register(); // USE_KILL
+ value.load_item();
+ // Convert l2i afterwards.
+ LIR_Opr tmp1 = new_register(T_LONG);
+ set_vreg_flag(tmp1, must_start_in_memory);
+ __ convert(x->op(), value.result(), tmp1);
+ __ convert(Bytecodes::_l2i, tmp1, reg);
+ break;
+ }
+
+ // Within same category: just register conversions.
+ case Bytecodes::_i2b:
+ case Bytecodes::_i2c:
+ case Bytecodes::_i2s:
+ case Bytecodes::_i2l:
+ case Bytecodes::_l2i:
+ case Bytecodes::_f2d:
+ case Bytecodes::_d2f: {
+ LIRItem value(x->value(), this);
+ LIR_Opr reg = rlock_result(x);
+ value.load_item();
+ __ convert(x->op(), value.result(), reg);
+ break;
+ }
+
+ default: ShouldNotReachHere();
+ }
+}
+
+
+void LIRGenerator::do_NewInstance(NewInstance* x) {
+ // This instruction can be deoptimized in the slow path.
+ const LIR_Opr reg = result_register_for(x->type());
+#ifndef PRODUCT
+ if (PrintNotLoaded && !x->klass()->is_loaded()) {
+ tty->print_cr(" ###class not loaded at new bci %d", x->printable_bci());
+ }
+#endif
+ CodeEmitInfo* info = state_for(x, x->state());
+ LIR_Opr klass_reg = FrameMap::R4_metadata_opr; // Used by slow path (NewInstanceStub).
+ LIR_Opr tmp1 = FrameMap::R5_oop_opr;
+ LIR_Opr tmp2 = FrameMap::R6_oop_opr;
+ LIR_Opr tmp3 = FrameMap::R7_oop_opr;
+ LIR_Opr tmp4 = FrameMap::R8_oop_opr;
+ new_instance(reg, x->klass(), x->is_unresolved(), tmp1, tmp2, tmp3, tmp4, klass_reg, info);
+
+ // Must prevent reordering of stores for object initialization
+ // with stores that publish the new object.
+ __ membar_storestore();
+ LIR_Opr result = rlock_result(x);
+ __ move(reg, result);
+}
+
+
+void LIRGenerator::do_NewTypeArray(NewTypeArray* x) {
+ // Evaluate state_for early since it may emit code.
+ CodeEmitInfo* info = state_for(x, x->state());
+
+ LIRItem length(x->length(), this);
+ length.load_item();
+
+ LIR_Opr reg = result_register_for(x->type());
+ LIR_Opr klass_reg = FrameMap::R4_metadata_opr; // Used by slow path (NewTypeArrayStub).
+ // We use R5 in order to get a temp effect. This reg is used in slow path (NewTypeArrayStub).
+ LIR_Opr tmp1 = FrameMap::R5_oop_opr;
+ LIR_Opr tmp2 = FrameMap::R6_oop_opr;
+ LIR_Opr tmp3 = FrameMap::R7_oop_opr;
+ LIR_Opr tmp4 = FrameMap::R8_oop_opr;
+ LIR_Opr len = length.result();
+ BasicType elem_type = x->elt_type();
+
+ __ metadata2reg(ciTypeArrayKlass::make(elem_type)->constant_encoding(), klass_reg);
+
+ CodeStub* slow_path = new NewTypeArrayStub(klass_reg, len, reg, info);
+ __ allocate_array(reg, len, tmp1, tmp2, tmp3, tmp4, elem_type, klass_reg, slow_path);
+
+ // Must prevent reordering of stores for object initialization
+ // with stores that publish the new object.
+ __ membar_storestore();
+ LIR_Opr result = rlock_result(x);
+ __ move(reg, result);
+}
+
+
+void LIRGenerator::do_NewObjectArray(NewObjectArray* x) {
+ // Evaluate state_for early since it may emit code.
+ CodeEmitInfo* info = state_for(x, x->state());
+ // In case of patching (i.e., object class is not yet loaded),
+ // we need to reexecute the instruction and therefore provide
+ // the state before the parameters have been consumed.
+ CodeEmitInfo* patching_info = NULL;
+ if (!x->klass()->is_loaded() || PatchALot) {
+ patching_info = state_for(x, x->state_before());
+ }
+
+ LIRItem length(x->length(), this);
+ length.load_item();
+
+ const LIR_Opr reg = result_register_for(x->type());
+ LIR_Opr klass_reg = FrameMap::R4_metadata_opr; // Used by slow path (NewObjectArrayStub).
+ // We use R5 in order to get a temp effect. This reg is used in slow path (NewObjectArrayStub).
+ LIR_Opr tmp1 = FrameMap::R5_oop_opr;
+ LIR_Opr tmp2 = FrameMap::R6_oop_opr;
+ LIR_Opr tmp3 = FrameMap::R7_oop_opr;
+ LIR_Opr tmp4 = FrameMap::R8_oop_opr;
+ LIR_Opr len = length.result();
+
+ CodeStub* slow_path = new NewObjectArrayStub(klass_reg, len, reg, info);
+ ciMetadata* obj = ciObjArrayKlass::make(x->klass());
+ if (obj == ciEnv::unloaded_ciobjarrayklass()) {
+ BAILOUT("encountered unloaded_ciobjarrayklass due to out of memory error");
+ }
+ klass2reg_with_patching(klass_reg, obj, patching_info);
+ __ allocate_array(reg, len, tmp1, tmp2, tmp3, tmp4, T_OBJECT, klass_reg, slow_path);
+
+ // Must prevent reordering of stores for object initialization
+ // with stores that publish the new object.
+ __ membar_storestore();
+ LIR_Opr result = rlock_result(x);
+ __ move(reg, result);
+}
+
+
+void LIRGenerator::do_NewMultiArray(NewMultiArray* x) {
+ Values* dims = x->dims();
+ int i = dims->length();
+ LIRItemList* items = new LIRItemList(dims->length(), NULL);
+ while (i-- > 0) {
+ LIRItem* size = new LIRItem(dims->at(i), this);
+ items->at_put(i, size);
+ }
+
+ // Evaluate state_for early since it may emit code.
+ CodeEmitInfo* patching_info = NULL;
+ if (!x->klass()->is_loaded() || PatchALot) {
+ patching_info = state_for(x, x->state_before());
+
+ // Cannot re-use same xhandlers for multiple CodeEmitInfos, so
+ // clone all handlers (NOTE: Usually this is handled transparently
+ // by the CodeEmitInfo cloning logic in CodeStub constructors but
+ // is done explicitly here because a stub isn't being used).
+ x->set_exception_handlers(new XHandlers(x->exception_handlers()));
+ }
+ CodeEmitInfo* info = state_for(x, x->state());
+
+ i = dims->length();
+ while (i-- > 0) {
+ LIRItem* size = items->at(i);
+ size->load_nonconstant();
+ // FrameMap::_reserved_argument_area_size includes the dimensions
+ // varargs, because it's initialized to hir()->max_stack() when the
+ // FrameMap is created.
+ store_stack_parameter(size->result(), in_ByteSize(i*sizeof(jint) + FrameMap::first_available_sp_in_frame));
+ }
+
+ const LIR_Opr klass_reg = FrameMap::R4_metadata_opr; // Used by slow path.
+ klass2reg_with_patching(klass_reg, x->klass(), patching_info);
+
+ LIR_Opr rank = FrameMap::R5_opr; // Used by slow path.
+ __ move(LIR_OprFact::intConst(x->rank()), rank);
+
+ LIR_Opr varargs = FrameMap::as_pointer_opr(R6); // Used by slow path.
+ __ leal(LIR_OprFact::address(new LIR_Address(FrameMap::SP_opr, FrameMap::first_available_sp_in_frame, T_INT)),
+ varargs);
+
+ // Note: This instruction can be deoptimized in the slow path.
+ LIR_OprList* args = new LIR_OprList(3);
+ args->append(klass_reg);
+ args->append(rank);
+ args->append(varargs);
+ const LIR_Opr reg = result_register_for(x->type());
+ __ call_runtime(Runtime1::entry_for(Runtime1::new_multi_array_id),
+ LIR_OprFact::illegalOpr,
+ reg, args, info);
+
+ // Must prevent reordering of stores for object initialization
+ // with stores that publish the new object.
+ __ membar_storestore();
+ LIR_Opr result = rlock_result(x);
+ __ move(reg, result);
+}
+
+
+void LIRGenerator::do_BlockBegin(BlockBegin* x) {
+ // nothing to do for now
+}
+
+
+void LIRGenerator::do_CheckCast(CheckCast* x) {
+ LIRItem obj(x->obj(), this);
+ CodeEmitInfo* patching_info = NULL;
+ if (!x->klass()->is_loaded() || (PatchALot && !x->is_incompatible_class_change_check())) {
+ // Must do this before locking the destination register as
+ // an oop register, and before the obj is loaded (so x->obj()->item()
+ // is valid for creating a debug info location).
+ patching_info = state_for(x, x->state_before());
+ }
+ obj.load_item();
+ LIR_Opr out_reg = rlock_result(x);
+ CodeStub* stub;
+ CodeEmitInfo* info_for_exception = state_for(x);
+
+ if (x->is_incompatible_class_change_check()) {
+ assert(patching_info == NULL, "can't patch this");
+ stub = new SimpleExceptionStub(Runtime1::throw_incompatible_class_change_error_id,
+ LIR_OprFact::illegalOpr, info_for_exception);
+ } else {
+ stub = new SimpleExceptionStub(Runtime1::throw_class_cast_exception_id, obj.result(), info_for_exception);
+ }
+ // Following registers are used by slow_subtype_check:
+ LIR_Opr tmp1 = FrameMap::R4_oop_opr; // super_klass
+ LIR_Opr tmp2 = FrameMap::R5_oop_opr; // sub_klass
+ LIR_Opr tmp3 = FrameMap::R6_oop_opr; // temp
+ __ checkcast(out_reg, obj.result(), x->klass(), tmp1, tmp2, tmp3,
+ x->direct_compare(), info_for_exception, patching_info, stub,
+ x->profiled_method(), x->profiled_bci());
+}
+
+
+void LIRGenerator::do_InstanceOf(InstanceOf* x) {
+ LIRItem obj(x->obj(), this);
+ CodeEmitInfo* patching_info = NULL;
+ if (!x->klass()->is_loaded() || PatchALot) {
+ patching_info = state_for(x, x->state_before());
+ }
+ // Ensure the result register is not the input register because the
+ // result is initialized before the patching safepoint.
+ obj.load_item();
+ LIR_Opr out_reg = rlock_result(x);
+ // Following registers are used by slow_subtype_check:
+ LIR_Opr tmp1 = FrameMap::R4_oop_opr; // super_klass
+ LIR_Opr tmp2 = FrameMap::R5_oop_opr; // sub_klass
+ LIR_Opr tmp3 = FrameMap::R6_oop_opr; // temp
+ __ instanceof(out_reg, obj.result(), x->klass(), tmp1, tmp2, tmp3,
+ x->direct_compare(), patching_info,
+ x->profiled_method(), x->profiled_bci());
+}
+
+
+void LIRGenerator::do_If(If* x) {
+ assert(x->number_of_sux() == 2, "inconsistency");
+ ValueTag tag = x->x()->type()->tag();
+ LIRItem xitem(x->x(), this);
+ LIRItem yitem(x->y(), this);
+ LIRItem* xin = &xitem;
+ LIRItem* yin = &yitem;
+ If::Condition cond = x->cond();
+
+ LIR_Opr left = LIR_OprFact::illegalOpr;
+ LIR_Opr right = LIR_OprFact::illegalOpr;
+
+ xin->load_item();
+ left = xin->result();
+
+ if (yin->result()->is_constant() && yin->result()->type() == T_INT &&
+ Assembler::is_simm16(yin->result()->as_constant_ptr()->as_jint())) {
+ // Inline int constants which are small enough to be immediate operands.
+ right = LIR_OprFact::value_type(yin->value()->type());
+ } else if (tag == longTag && yin->is_constant() && yin->get_jlong_constant() == 0 &&
+ (cond == If::eql || cond == If::neq)) {
+ // Inline long zero.
+ right = LIR_OprFact::value_type(yin->value()->type());
+ } else if (tag == objectTag && yin->is_constant() && (yin->get_jobject_constant()->is_null_object())) {
+ right = LIR_OprFact::value_type(yin->value()->type());
+ } else {
+ yin->load_item();
+ right = yin->result();
+ }
+ set_no_result(x);
+
+ // Add safepoint before generating condition code so it can be recomputed.
+ if (x->is_safepoint()) {
+ // Increment backedge counter if needed.
+ increment_backedge_counter(state_for(x, x->state_before()), x->profiled_bci());
+ __ safepoint(safepoint_poll_register(), state_for(x, x->state_before()));
+ }
+
+ __ cmp(lir_cond(cond), left, right);
+ // Generate branch profiling. Profiling code doesn't kill flags.
+ profile_branch(x, cond);
+ move_to_phi(x->state());
+ if (x->x()->type()->is_float_kind()) {
+ __ branch(lir_cond(cond), right->type(), x->tsux(), x->usux());
+ } else {
+ __ branch(lir_cond(cond), right->type(), x->tsux());
+ }
+ assert(x->default_sux() == x->fsux(), "wrong destination above");
+ __ jump(x->default_sux());
+}
+
+
+LIR_Opr LIRGenerator::getThreadPointer() {
+ return FrameMap::as_pointer_opr(R16_thread);
+}
+
+
+void LIRGenerator::trace_block_entry(BlockBegin* block) {
+ LIR_Opr arg1 = FrameMap::R3_opr; // ARG1
+ __ move(LIR_OprFact::intConst(block->block_id()), arg1);
+ LIR_OprList* args = new LIR_OprList(1);
+ args->append(arg1);
+ address func = CAST_FROM_FN_PTR(address, Runtime1::trace_block_entry);
+ __ call_runtime_leaf(func, LIR_OprFact::illegalOpr, LIR_OprFact::illegalOpr, args);
+}
+
+
+void LIRGenerator::volatile_field_store(LIR_Opr value, LIR_Address* address,
+ CodeEmitInfo* info) {
+#ifdef _LP64
+ __ store(value, address, info);
+#else
+ Unimplemented();
+// __ volatile_store_mem_reg(value, address, info);
+#endif
+}
+
+void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result,
+ CodeEmitInfo* info) {
+#ifdef _LP64
+ __ load(address, result, info);
+#else
+ Unimplemented();
+// __ volatile_load_mem_reg(address, result, info);
+#endif
+}
+
+
+void LIRGenerator::put_Object_unsafe(LIR_Opr src, LIR_Opr offset, LIR_Opr data,
+ BasicType type, bool is_volatile) {
+ LIR_Opr base_op = src;
+ LIR_Opr index_op = offset;
+
+ bool is_obj = (type == T_ARRAY || type == T_OBJECT);
+#ifndef _LP64
+ if (is_volatile && type == T_LONG) {
+ __ volatile_store_unsafe_reg(data, src, offset, type, NULL, lir_patch_none);
+ } else
+#endif
+ {
+ if (type == T_BOOLEAN) {
+ type = T_BYTE;
+ }
+ LIR_Address* addr;
+ if (type == T_ARRAY || type == T_OBJECT) {
+ LIR_Opr tmp = new_pointer_register();
+ __ add(base_op, index_op, tmp);
+ addr = new LIR_Address(tmp, type);
+ } else {
+ addr = new LIR_Address(base_op, index_op, type);
+ }
+
+ if (is_obj) {
+ pre_barrier(LIR_OprFact::address(addr), LIR_OprFact::illegalOpr /* pre_val */,
+ true /* do_load */, false /* patch */, NULL);
+ // _bs->c1_write_barrier_pre(this, LIR_OprFact::address(addr));
+ }
+ __ move(data, addr);
+ if (is_obj) {
+ // This address is precise.
+ post_barrier(LIR_OprFact::address(addr), data);
+ }
+ }
+}
+
+
+void LIRGenerator::get_Object_unsafe(LIR_Opr dst, LIR_Opr src, LIR_Opr offset,
+ BasicType type, bool is_volatile) {
+#ifndef _LP64
+ if (is_volatile && type == T_LONG) {
+ __ volatile_load_unsafe_reg(src, offset, dst, type, NULL, lir_patch_none);
+ } else
+#endif
+ {
+ LIR_Address* addr = new LIR_Address(src, offset, type);
+ __ load(addr, dst);
+ }
+}
+
+
+void LIRGenerator::do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) {
+ BasicType type = x->basic_type();
+ LIRItem src(x->object(), this);
+ LIRItem off(x->offset(), this);
+ LIRItem value(x->value(), this);
+
+ src.load_item();
+ value.load_item();
+ off.load_nonconstant();
+
+ LIR_Opr dst = rlock_result(x, type);
+ LIR_Opr data = value.result();
+ bool is_obj = (type == T_ARRAY || type == T_OBJECT);
+
+ LIR_Opr tmp = FrameMap::R0_opr;
+ LIR_Opr ptr = new_pointer_register();
+ __ add(src.result(), off.result(), ptr);
+
+ if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
+ __ membar();
+ } else {
+ __ membar_release();
+ }
+
+ if (x->is_add()) {
+ __ xadd(ptr, data, dst, tmp);
+ } else {
+ const bool can_move_barrier = true; // TODO: port GraphKit::can_move_pre_barrier() from C2
+ if (!can_move_barrier && is_obj) {
+ // Do the pre-write barrier, if any.
+ pre_barrier(ptr, LIR_OprFact::illegalOpr /* pre_val */,
+ true /* do_load */, false /* patch */, NULL);
+ }
+ __ xchg(ptr, data, dst, tmp);
+ if (is_obj) {
+ // Seems to be a precise address.
+ post_barrier(ptr, data);
+ if (can_move_barrier) {
+ pre_barrier(LIR_OprFact::illegalOpr, dst /* pre_val */,
+ false /* do_load */, false /* patch */, NULL);
+ }
+ }
+ }
+
+ __ membar();
+}
+
+
+void LIRGenerator::do_update_CRC32(Intrinsic* x) {
+ assert(UseCRC32Intrinsics, "or should not be here");
+ LIR_Opr result = rlock_result(x);
+
+ switch (x->id()) {
+ case vmIntrinsics::_updateCRC32: {
+ LIRItem crc(x->argument_at(0), this);
+ LIRItem val(x->argument_at(1), this);
+ // Registers destroyed by update_crc32.
+ crc.set_destroys_register();
+ val.set_destroys_register();
+ crc.load_item();
+ val.load_item();
+ __ update_crc32(crc.result(), val.result(), result);
+ break;
+ }
+ case vmIntrinsics::_updateBytesCRC32:
+ case vmIntrinsics::_updateByteBufferCRC32: {
+ bool is_updateBytes = (x->id() == vmIntrinsics::_updateBytesCRC32);
+
+ LIRItem crc(x->argument_at(0), this);
+ LIRItem buf(x->argument_at(1), this);
+ LIRItem off(x->argument_at(2), this);
+ LIRItem len(x->argument_at(3), this);
+ buf.load_item();
+ off.load_nonconstant();
+
+ LIR_Opr index = off.result();
+ int offset = is_updateBytes ? arrayOopDesc::base_offset_in_bytes(T_BYTE) : 0;
+ if (off.result()->is_constant()) {
+ index = LIR_OprFact::illegalOpr;
+ offset += off.result()->as_jint();
+ }
+ LIR_Opr base_op = buf.result();
+ LIR_Address* a = NULL;
+
+ if (index->is_valid()) {
+ LIR_Opr tmp = new_register(T_LONG);
+ __ convert(Bytecodes::_i2l, index, tmp);
+ index = tmp;
+ __ add(index, LIR_OprFact::intptrConst(offset), index);
+ a = new LIR_Address(base_op, index, T_BYTE);
+ } else {
+ a = new LIR_Address(base_op, offset, T_BYTE);
+ }
+
+ BasicTypeList signature(3);
+ signature.append(T_INT);
+ signature.append(T_ADDRESS);
+ signature.append(T_INT);
+ CallingConvention* cc = frame_map()->c_calling_convention(&signature);
+ const LIR_Opr result_reg = result_register_for(x->type());
+
+ LIR_Opr arg1 = cc->at(0),
+ arg2 = cc->at(1),
+ arg3 = cc->at(2);
+
+ // CCallingConventionRequiresIntsAsLongs
+ crc.load_item_force(arg1); // We skip int->long conversion here, because CRC32 stub doesn't care about high bits.
+ __ leal(LIR_OprFact::address(a), arg2);
+ load_int_as_long(gen()->lir(), len, arg3);
+
+ __ call_runtime_leaf(StubRoutines::updateBytesCRC32(), LIR_OprFact::illegalOpr, result_reg, cc->args());
+ __ move(result_reg, result);
+ break;
+ }
+ default: {
+ ShouldNotReachHere();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/cpu/ppc/vm/c1_LinearScan_ppc.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012, 2015 SAP AG. 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 "c1/c1_Instruction.hpp"
+#include "c1/c1_LinearScan.hpp"
+#include "utilities/bitMap.inline.hpp"
+
+void LinearScan::allocate_fpu_stack() {
+ Unimplemented();
+ // No FPU stack on PPC
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/cpu/ppc/vm/c1_LinearScan_ppc.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012, 2015 SAP AG. 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.
+ *
+ */
+
+#ifndef CPU_PPC_VM_C1_LINEARSCAN_PPC_HPP
+#define CPU_PPC_VM_C1_LINEARSCAN_PPC_HPP
+
+inline bool LinearScan::is_processed_reg_num(int reg_num) {
+ assert(FrameMap::R0_opr->cpu_regnr() == FrameMap::last_cpu_reg() + 1, "wrong assumption below");
+ assert(FrameMap::R1_opr->cpu_regnr() == FrameMap::last_cpu_reg() + 2, "wrong assumption below");
+ assert(FrameMap::R13_opr->cpu_regnr() == FrameMap::last_cpu_reg() + 3, "wrong assumption below");
+ assert(FrameMap::R16_opr->cpu_regnr() == FrameMap::last_cpu_reg() + 4, "wrong assumption below");
+ assert(FrameMap::R29_opr->cpu_regnr() == FrameMap::last_cpu_reg() + 5, "wrong assumption below");
+ return reg_num <= FrameMap::last_cpu_reg() || reg_num >= pd_nof_cpu_regs_frame_map;
+}
+
+inline int LinearScan::num_physical_regs(BasicType type) {
+ return 1;
+}
+
+
+inline bool LinearScan::requires_adjacent_regs(BasicType type) {
+ return false;
+}
+
+inline bool LinearScan::is_caller_save(int assigned_reg) {
+ return true; // assigned_reg < pd_first_callee_saved_reg;
+}
+
+
+inline void LinearScan::pd_add_temps(LIR_Op* op) {
+ // No special case behaviours yet
+}
+
+
+inline bool LinearScanWalker::pd_init_regs_for_alloc(Interval* cur) {
+ if (allocator()->gen()->is_vreg_flag_set(cur->reg_num(), LIRGenerator::callee_saved)) {
+ assert(cur->type() != T_FLOAT && cur->type() != T_DOUBLE, "cpu regs only");
+ _first_reg = pd_first_callee_saved_reg;
+ _last_reg = pd_last_callee_saved_reg;
+ ShouldNotReachHere(); // Currently no callee saved regs.
+ return true;
+ } else if (cur->type() == T_INT || cur->type() == T_LONG || cur->type() == T_OBJECT ||
+ cur->type() == T_ADDRESS || cur->type() == T_METADATA) {
+ _first_reg = pd_first_cpu_reg;
+ _last_reg = pd_last_cpu_reg;
+ return true;
+ }
+ return false;
+}
+
+#endif // CPU_PPC_VM_C1_LINEARSCAN_PPC_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/cpu/ppc/vm/c1_MacroAssembler_ppc.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -0,0 +1,486 @@
+/*
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012, 2015 SAP AG. 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 "c1/c1_MacroAssembler.hpp"
+#include "c1/c1_Runtime1.hpp"
+#include "classfile/systemDictionary.hpp"
+#include "gc/shared/collectedHeap.hpp"
+#include "interpreter/interpreter.hpp"
+#include "oops/arrayOop.hpp"
+#include "oops/markOop.hpp"
+#include "runtime/basicLock.hpp"
+#include "runtime/biasedLocking.hpp"
+#include "runtime/os.hpp"
+#include "runtime/stubRoutines.hpp"
+#include "runtime/sharedRuntime.hpp"
+
+
+void C1_MacroAssembler::inline_cache_check(Register receiver, Register iCache) {
+ const Register temp_reg = R12_scratch2;
+ verify_oop(receiver);
+ load_klass(temp_reg, receiver);
+ if (TrapBasedICMissChecks) {
+ trap_ic_miss_check(temp_reg, iCache);
+ } else {
+ Label L;
+ cmpd(CCR0, temp_reg, iCache);
+ beq(CCR0, L);
+ //load_const_optimized(temp_reg, SharedRuntime::get_ic_miss_stub(), R0);
+ calculate_address_from_global_toc(temp_reg, SharedRuntime::get_ic_miss_stub(), true, true, false);
+ mtctr(temp_reg);
+ bctr();
+ align(32, 12);
+ bind(L);
+ }
+}
+
+
+void C1_MacroAssembler::explicit_null_check(Register base) {
+ Unimplemented();
+}
+
+
+void C1_MacroAssembler::build_frame(int frame_size_in_bytes, int bang_size_in_bytes) {
+ assert(bang_size_in_bytes >= frame_size_in_bytes, "stack bang size incorrect");
+ // Make sure there is enough stack space for this method's activation.
+ generate_stack_overflow_check(bang_size_in_bytes);
+
+ // Create the frame.
+ const Register return_pc = R0;
+
+ mflr(return_pc);
+ // Get callers sp.
+ std(return_pc, _abi(lr), R1_SP); // SP->lr = return_pc
+ push_frame(frame_size_in_bytes, R0); // SP -= frame_size_in_bytes
+}
+
+
+void C1_MacroAssembler::unverified_entry(Register receiver, Register ic_klass) {
+ Unimplemented(); // Currently unused.
+ //if (C1Breakpoint) illtrap();
+ //inline_cache_check(receiver, ic_klass);
+}
+
+
+void C1_MacroAssembler::verified_entry() {
+ if (C1Breakpoint) illtrap();
+ // build frame
+}
+
+
+void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox, Register Rscratch, Label& slow_case) {
+ assert_different_registers(Rmark, Roop, Rbox, Rscratch);
+
+ Label done, cas_failed, slow_int;
+
+ // The following move must be the first instruction of emitted since debug
+ // information may be generated for it.
+ // Load object header.
+ ld(Rmark, oopDesc::mark_offset_in_bytes(), Roop);
+
+ verify_oop(Roop);
+
+ // Save object being locked into the BasicObjectLock...
+ std(Roop, BasicObjectLock::obj_offset_in_bytes(), Rbox);
+
+ if (UseBiasedLocking) {
+ biased_locking_enter(CCR0, Roop, Rmark, Rscratch, R0, done, &slow_int);
+ }
+
+ // ... and mark it unlocked.
+ ori(Rmark, Rmark, markOopDesc::unlocked_value);
+
+ // Save unlocked object header into the displaced header location on the stack.
+ std(Rmark, BasicLock::displaced_header_offset_in_bytes(), Rbox);
+
+ // Compare object markOop with Rmark and if equal exchange Rscratch with object markOop.
+ assert(oopDesc::mark_offset_in_bytes() == 0, "cas must take a zero displacement");
+ cmpxchgd(/*flag=*/CCR0,
+ /*current_value=*/Rscratch,
+ /*compare_value=*/Rmark,
+ /*exchange_value=*/Rbox,
+ /*where=*/Roop/*+0==mark_offset_in_bytes*/,
+ MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq,
+ MacroAssembler::cmpxchgx_hint_acquire_lock(),
+ noreg,
+ &cas_failed,
+ /*check without membar and ldarx first*/true);
+ // If compare/exchange succeeded we found an unlocked object and we now have locked it
+ // hence we are done.
+ b(done);
+
+ bind(slow_int);
+ b(slow_case); // far
+
+ bind(cas_failed);
+ // We did not find an unlocked object so see if this is a recursive case.
+ sub(Rscratch, Rscratch, R1_SP);
+ load_const_optimized(R0, (~(os::vm_page_size()-1) | markOopDesc::lock_mask_in_place));
+ and_(R0/*==0?*/, Rscratch, R0);
+ std(R0/*==0, perhaps*/, BasicLock::displaced_header_offset_in_bytes(), Rbox);
+ bne(CCR0, slow_int);
+
+ bind(done);
+}
+
+
+void C1_MacroAssembler::unlock_object(Register Rmark, Register Roop, Register Rbox, Label& slow_case) {
+ assert_different_registers(Rmark, Roop, Rbox);
+
+ Label slow_int, done;
+
+ Address mark_addr(Roop, oopDesc::mark_offset_in_bytes());
+ assert(mark_addr.disp() == 0, "cas must take a zero displacement");
+
+ if (UseBiasedLocking) {
+ // Load the object out of the BasicObjectLock.
+ ld(Roop, BasicObjectLock::obj_offset_in_bytes(), Rbox);
+ verify_oop(Roop);
+ biased_locking_exit(CCR0, Roop, R0, done);
+ }
+ // Test first it it is a fast recursive unlock.
+ ld(Rmark, BasicLock::displaced_header_offset_in_bytes(), Rbox);
+ cmpdi(CCR0, Rmark, 0);
+ beq(CCR0, done);
+ if (!UseBiasedLocking) {
+ // Load object.
+ ld(Roop, BasicObjectLock::obj_offset_in_bytes(), Rbox);
+ verify_oop(Roop);
+ }
+
+ // Check if it is still a light weight lock, this is is true if we see
+ // the stack address of the basicLock in the markOop of the object.
+ cmpxchgd(/*flag=*/CCR0,
+ /*current_value=*/R0,
+ /*compare_value=*/Rbox,
+ /*exchange_value=*/Rmark,
+ /*where=*/Roop,
+ MacroAssembler::MemBarRel,
+ MacroAssembler::cmpxchgx_hint_release_lock(),
+ noreg,
+ &slow_int);
+ b(done);
+ bind(slow_int);
+ b(slow_case); // far
+
+ // Done
+ bind(done);
+}
+
+
+void C1_MacroAssembler::try_allocate(
+ Register obj, // result: pointer to object after successful allocation
+ Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
+ int con_size_in_bytes, // object size in bytes if known at compile time
+ Register t1, // temp register, must be global register for incr_allocated_bytes
+ Register t2, // temp register
+ Label& slow_case // continuation point if fast allocation fails
+) {
+ if (UseTLAB) {
+ tlab_allocate(obj, var_size_in_bytes, con_size_in_bytes, t1, slow_case);
+ } else {
+ eden_allocate(obj, var_size_in_bytes, con_size_in_bytes, t1, t2, slow_case);
+ RegisterOrConstant size_in_bytes = var_size_in_bytes->is_valid()
+ ? RegisterOrConstant(var_size_in_bytes)
+ : RegisterOrConstant(con_size_in_bytes);
+ incr_allocated_bytes(size_in_bytes, t1, t2);
+ }
+}
+
+
+void C1_MacroAssembler::initialize_header(Register obj, Register klass, Register len, Register t1, Register t2) {
+ assert_different_registers(obj, klass, len, t1, t2);
+ if (UseBiasedLocking && !len->is_valid()) {
+ ld(t1, in_bytes(Klass::prototype_header_offset()), klass);
+ } else {
+ load_const_optimized(t1, (intx)markOopDesc::prototype());
+ }
+ std(t1, oopDesc::mark_offset_in_bytes(), obj);
+ store_klass(obj, klass);
+ if (len->is_valid()) {
+ stw(len, arrayOopDesc::length_offset_in_bytes(), obj);
+ } else if (UseCompressedClassPointers) {
+ // Otherwise length is in the class gap.
+ store_klass_gap(obj);
+ }
+}
+
+
+void C1_MacroAssembler::initialize_body(Register base, Register index) {
+ assert_different_registers(base, index);
+ srdi(index, index, LogBytesPerWord);
+ clear_memory_doubleword(base, index);
+}
+
+void C1_MacroAssembler::initialize_body(Register obj, Register tmp1, Register tmp2,
+ int obj_size_in_bytes, int hdr_size_in_bytes) {
+ const int index = (obj_size_in_bytes - hdr_size_in_bytes) / HeapWordSize;
+
+ const int cl_size = VM_Version::L1_data_cache_line_size(),
+ cl_dwords = cl_size>>3,
+ cl_dw_addr_bits = exact_log2(cl_dwords);
+
+ const Register tmp = R0,
+ base_ptr = tmp1,
+ cnt_dwords = tmp2;
+
+ if (index <= 6) {
+ // Use explicit NULL stores.
+ if (index > 0) { li(tmp, 0); }
+ for (int i = 0; i < index; ++i) { std(tmp, hdr_size_in_bytes + i * HeapWordSize, obj); }
+
+ } else if (index < (2<<cl_dw_addr_bits)-1) {
+ // simple loop
+ Label loop;
+
+ li(cnt_dwords, index);
+ addi(base_ptr, obj, hdr_size_in_bytes); // Compute address of first element.
+ li(tmp, 0);
+ mtctr(cnt_dwords); // Load counter.
+ bind(loop);
+ std(tmp, 0, base_ptr); // Clear 8byte aligned block.
+ addi(base_ptr, base_ptr, 8);
+ bdnz(loop);
+
+ } else {
+ // like clear_memory_doubleword
+ Label startloop, fast, fastloop, restloop, done;
+
+ addi(base_ptr, obj, hdr_size_in_bytes); // Compute address of first element.
+ load_const_optimized(cnt_dwords, index);
+ rldicl_(tmp, base_ptr, 64-3, 64-cl_dw_addr_bits); // Extract dword offset within first cache line.
+ beq(CCR0, fast); // Already 128byte aligned.
+
+ subfic(tmp, tmp, cl_dwords);
+ mtctr(tmp); // Set ctr to hit 128byte boundary (0<ctr<cl_dwords).
+ subf(cnt_dwords, tmp, cnt_dwords); // rest.
+ li(tmp, 0);
+
+ bind(startloop); // Clear at the beginning to reach 128byte boundary.
+ std(tmp, 0, base_ptr); // Clear 8byte aligned block.
+ addi(base_ptr, base_ptr, 8);
+ bdnz(startloop);
+
+ bind(fast); // Clear 128byte blocks.
+ srdi(tmp, cnt_dwords, cl_dw_addr_bits); // Loop count for 128byte loop (>0).
+ andi(cnt_dwords, cnt_dwords, cl_dwords-1); // Rest in dwords.
+ mtctr(tmp); // Load counter.
+
+ bind(fastloop);
+ dcbz(base_ptr); // Clear 128byte aligned block.
+ addi(base_ptr, base_ptr, cl_size);
+ bdnz(fastloop);
+
+ cmpdi(CCR0, cnt_dwords, 0); // size 0?
+ beq(CCR0, done); // rest == 0
+ li(tmp, 0);
+ mtctr(cnt_dwords); // Load counter.
+
+ bind(restloop); // Clear rest.
+ std(tmp, 0, base_ptr); // Clear 8byte aligned block.
+ addi(base_ptr, base_ptr, 8);
+ bdnz(restloop);
+
+ bind(done);
+ }
+}
+
+void C1_MacroAssembler::allocate_object(
+ Register obj, // result: pointer to object after successful allocation
+ Register t1, // temp register
+ Register t2, // temp register
+ Register t3, // temp register
+ int hdr_size, // object header size in words
+ int obj_size, // object size in words
+ Register klass, // object klass
+ Label& slow_case // continuation point if fast allocation fails
+) {
+ assert_different_registers(obj, t1, t2, t3, klass);
+
+ // allocate space & initialize header
+ if (!is_simm16(obj_size * wordSize)) {
+ // Would need to use extra register to load
+ // object size => go the slow case for now.
+ b(slow_case);
+ return;
+ }
+ try_allocate(obj, noreg, obj_size * wordSize, t2, t3, slow_case);
+
+ initialize_object(obj, klass, noreg, obj_size * HeapWordSize, t1, t2);
+}
+
+void C1_MacroAssembler::initialize_object(
+ Register obj, // result: pointer to object after successful allocation
+ Register klass, // object klass
+ Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
+ int con_size_in_bytes, // object size in bytes if known at compile time
+ Register t1, // temp register
+ Register t2 // temp register
+ ) {
+ const int hdr_size_in_bytes = instanceOopDesc::header_size() * HeapWordSize;
+
+ initialize_header(obj, klass, noreg, t1, t2);
+
+#ifdef ASSERT
+ {
+ lwz(t1, in_bytes(Klass::layout_helper_offset()), klass);
+ if (var_size_in_bytes != noreg) {
+ cmpw(CCR0, t1, var_size_in_bytes);
+ } else {
+ cmpwi(CCR0, t1, con_size_in_bytes);
+ }
+ asm_assert_eq("bad size in initialize_object", 0x753);
+ }
+#endif
+
+ // Initialize body.
+ if (var_size_in_bytes != noreg) {
+ // Use a loop.
+ addi(t1, obj, hdr_size_in_bytes); // Compute address of first element.
+ addi(t2, var_size_in_bytes, -hdr_size_in_bytes); // Compute size of body.
+ initialize_body(t1, t2);
+ } else if (con_size_in_bytes > hdr_size_in_bytes) {
+ // Use a loop.
+ initialize_body(obj, t1, t2, con_size_in_bytes, hdr_size_in_bytes);
+ }
+
+ if (CURRENT_ENV->dtrace_alloc_probes()) {
+ Unimplemented();
+// assert(obj == O0, "must be");
+// call(CAST_FROM_FN_PTR(address, Runtime1::entry_for(Runtime1::dtrace_object_alloc_id)),
+// relocInfo::runtime_call_type);
+ }
+
+ verify_oop(obj);
+}
+
+
+void C1_MacroAssembler::allocate_array(
+ Register obj, // result: pointer to array after successful allocation
+ Register len, // array length
+ Register t1, // temp register
+ Register t2, // temp register
+ Register t3, // temp register
+ int hdr_size, // object header size in words
+ int elt_size, // element size in bytes
+ Register klass, // object klass
+ Label& slow_case // continuation point if fast allocation fails
+) {
+ assert_different_registers(obj, len, t1, t2, t3, klass);
+
+ // Determine alignment mask.
+ assert(!(BytesPerWord & 1), "must be a multiple of 2 for masking code to work");
+ int log2_elt_size = exact_log2(elt_size);
+
+ // Check for negative or excessive length.
+ size_t max_length = max_array_allocation_length >> log2_elt_size;
+ if (UseTLAB) {
+ size_t max_tlab = align_size_up(ThreadLocalAllocBuffer::max_size() >> log2_elt_size, 64*K);
+ if (max_tlab < max_length) { max_length = max_tlab; }
+ }
+ load_const_optimized(t1, max_length);
+ cmpld(CCR0, len, t1);
+ bc_far_optimized(Assembler::bcondCRbiIs1, bi0(CCR0, Assembler::greater), slow_case);
+
+ // compute array size
+ // note: If 0 <= len <= max_length, len*elt_size + header + alignment is
+ // smaller or equal to the largest integer; also, since top is always
+ // aligned, we can do the alignment here instead of at the end address
+ // computation.
+ const Register arr_size = t1;
+ Register arr_len_in_bytes = len;
+ if (elt_size != 1) {
+ sldi(t1, len, log2_elt_size);
+ arr_len_in_bytes = t1;
+ }
+ addi(arr_size, arr_len_in_bytes, hdr_size * wordSize + MinObjAlignmentInBytesMask); // Add space for header & alignment.
+ clrrdi(arr_size, arr_size, LogMinObjAlignmentInBytes); // Align array size.
+
+ // Allocate space & initialize header.
+ if (UseTLAB) {
+ tlab_allocate(obj, arr_size, 0, t2, slow_case);
+ } else {
+ eden_allocate(obj, arr_size, 0, t2, t3, slow_case);
+ }
+ initialize_header(obj, klass, len, t2, t3);
+
+ // Initialize body.
+ const Register base = t2;
+ const Register index = t3;
+ addi(base, obj, hdr_size * wordSize); // compute address of first element
+ addi(index, arr_size, -(hdr_size * wordSize)); // compute index = number of bytes to clear
+ initialize_body(base, index);
+
+ if (CURRENT_ENV->dtrace_alloc_probes()) {
+ Unimplemented();
+ //assert(obj == O0, "must be");
+ //call(CAST_FROM_FN_PTR(address, Runtime1::entry_for(Runtime1::dtrace_object_alloc_id)),
+ // relocInfo::runtime_call_type);
+ }
+
+ verify_oop(obj);
+}
+
+
+#ifndef PRODUCT
+
+void C1_MacroAssembler::verify_stack_oop(int stack_offset) {
+ verify_oop_addr((RegisterOrConstant)(stack_offset + STACK_BIAS), R1_SP, "broken oop in stack slot");
+}
+
+void C1_MacroAssembler::verify_not_null_oop(Register r) {
+ Label not_null;
+ cmpdi(CCR0, r, 0);
+ bne(CCR0, not_null);
+ stop("non-null oop required");
+ bind(not_null);
+ if (!VerifyOops) return;
+ verify_oop(r);
+}
+
+#endif // PRODUCT
+
+void C1_MacroAssembler::null_check(Register r, Label* Lnull) {
+ if (TrapBasedNullChecks) { // SIGTRAP based
+ trap_null_check(r);
+ } else { // explicit
+ //const address exception_entry = Runtime1::entry_for(Runtime1::throw_null_pointer_exception_id);
+ assert(Lnull != NULL, "must have Label for explicit check");
+ cmpdi(CCR0, r, 0);
+ bc_far_optimized(Assembler::bcondCRbiIs1, bi0(CCR0, Assembler::equal), *Lnull);
+ }
+}
+
+address C1_MacroAssembler::call_c_with_frame_resize(address dest, int frame_resize) {
+ if (frame_resize) { resize_frame(-frame_resize, R0); }
+#if defined(ABI_ELFv2)
+ address return_pc = call_c(dest, relocInfo::runtime_call_type);
+#else
+ address return_pc = call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, dest), relocInfo::runtime_call_type);
+#endif
+ if (frame_resize) { resize_frame(frame_resize, R0); }
+ return return_pc;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/cpu/ppc/vm/c1_MacroAssembler_ppc.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012, 2015 SAP AG. 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.
+ *
+ */
+
+#ifndef CPU_PPC_VM_C1_MACROASSEMBLER_PPC_HPP
+#define CPU_PPC_VM_C1_MACROASSEMBLER_PPC_HPP
+
+ void pd_init() { /* nothing to do */ }
+
+ public:
+ void try_allocate(
+ Register obj, // result: pointer to object after successful allocation
+ Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
+ int con_size_in_bytes, // object size in bytes if known at compile time
+ Register t1, // temp register
+ Register t2, // temp register
+ Label& slow_case // continuation point if fast allocation fails
+ );
+
+ void initialize_header(Register obj, Register klass, Register len, Register t1, Register t2);
+ void initialize_body(Register base, Register index);
+ void initialize_body(Register obj, Register tmp1, Register tmp2, int obj_size_in_bytes, int hdr_size_in_bytes);
+
+ // locking/unlocking
+ void lock_object (Register Rmark, Register Roop, Register Rbox, Register Rscratch, Label& slow_case);
+ void unlock_object(Register Rmark, Register Roop, Register Rbox, Label& slow_case);
+
+ void initialize_object(
+ Register obj, // result: pointer to object after successful allocation
+ Register klass, // object klass
+ Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
+ int con_size_in_bytes, // object size in bytes if known at compile time
+ Register t1, // temp register
+ Register t2 // temp register
+ );
+
+ // Allocation of fixed-size objects
+ // (Can also be used to allocate fixed-size arrays, by setting
+ // hdr_size correctly and storing the array length afterwards.)
+ void allocate_object(
+ Register obj, // result: pointer to object after successful allocation
+ Register t1, // temp register
+ Register t2, // temp register
+ Register t3, // temp register
+ int hdr_size, // object header size in words
+ int obj_size, // object size in words
+ Register klass, // object klass
+ Label& slow_case // continuation point if fast allocation fails
+ );
+
+ enum {
+ max_array_allocation_length = 0x40000000 // ppc friendly value, requires lis only
+ };
+
+ // Allocation of arrays
+ void allocate_array(
+ Register obj, // result: pointer to array after successful allocation
+ Register len, // array length
+ Register t1, // temp register
+ Register t2, // temp register
+ Register t3, // temp register
+ int hdr_size, // object header size in words
+ int elt_size, // element size in bytes
+ Register klass, // object klass
+ Label& slow_case // continuation point if fast allocation fails
+ );
+
+ void null_check(Register r, Label *Lnull = NULL);
+
+ address call_c_with_frame_resize(address dest, int frame_resize);
+
+#endif // CPU_PPC_VM_C1_MACROASSEMBLER_PPC_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/cpu/ppc/vm/c1_Runtime1_ppc.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -0,0 +1,1020 @@
+/*
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012, 2015 SAP AG. 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 "c1/c1_Defs.hpp"
+#include "c1/c1_MacroAssembler.hpp"
+#include "c1/c1_Runtime1.hpp"
+#include "interpreter/interpreter.hpp"
+#include "nativeInst_ppc.hpp"
+#include "oops/compiledICHolder.hpp"
+#include "oops/oop.inline.hpp"
+#include "prims/jvmtiExport.hpp"
+#include "register_ppc.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/signature.hpp"
+#include "runtime/vframeArray.hpp"
+#include "utilities/macros.hpp"
+#include "vmreg_ppc.inline.hpp"
+#if INCLUDE_ALL_GCS
+#include "gc/g1/g1SATBCardTableModRefBS.hpp"
+#endif
+
+// Implementation of StubAssembler
+
+int StubAssembler::call_RT(Register oop_result1, Register metadata_result,
+ address entry_point, int number_of_arguments) {
+ set_num_rt_args(0); // Nothing on stack
+ assert(!(oop_result1->is_valid() || metadata_result->is_valid()) ||
+ oop_result1 != metadata_result, "registers must be different");
+
+ // Currently no stack banging. We assume that there are enough
+ // StackShadowPages (which have been banged in generate_stack_overflow_check)
+ // for the stub frame and the runtime frames.
+
+ set_last_Java_frame(R1_SP, noreg);
+
+ // ARG1 must hold thread address.
+ mr(R3_ARG1, R16_thread);
+
+ address return_pc = call_c_with_frame_resize(entry_point, /*No resize, we have a C compatible frame.*/0);
+
+ reset_last_Java_frame();
+
+ // Check for pending exceptions.
+ {
+ ld(R0, in_bytes(Thread::pending_exception_offset()), R16_thread);
+ cmpdi(CCR0, R0, 0);
+
+ // This used to conditionally jump to forward_exception however it is
+ // possible if we relocate that the branch will not reach. So we must jump
+ // around so we can always reach.
+
+ Label ok;
+ beq(CCR0, ok);
+
+ // Make sure that the vm_results are cleared.
+ if (oop_result1->is_valid() || metadata_result->is_valid()) {
+ li(R0, 0);
+ if (oop_result1->is_valid()) {
+ std(R0, in_bytes(JavaThread::vm_result_offset()), R16_thread);
+ }
+ if (metadata_result->is_valid()) {
+ std(R0, in_bytes(JavaThread::vm_result_2_offset()), R16_thread);
+ }
+ }
+
+ if (frame_size() == no_frame_size) {
+ ShouldNotReachHere(); // We always have a frame size.
+ //pop_frame(); // pop the stub frame
+ //ld(R0, _abi(lr), R1_SP);
+ //mtlr(R0);
+ //load_const_optimized(R0, StubRoutines::forward_exception_entry());
+ //mtctr(R0);
+ //bctr();
+ } else if (_stub_id == Runtime1::forward_exception_id) {
+ should_not_reach_here();
+ } else {
+ // keep stub frame for next call_RT
+ //load_const_optimized(R0, Runtime1::entry_for(Runtime1::forward_exception_id));
+ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(Runtime1::entry_for(Runtime1::forward_exception_id)));
+ mtctr(R0);
+ bctr();
+ }
+
+ bind(ok);
+ }
+
+ // Get oop results if there are any and reset the values in the thread.
+ if (oop_result1->is_valid()) {
+ get_vm_result(oop_result1);
+ }
+ if (metadata_result->is_valid()) {
+ get_vm_result_2(metadata_result);
+ }
+
+ return (int)(return_pc - code_section()->start());
+}
+
+
+int StubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1) {
+ mr_if_needed(R4_ARG2, arg1);
+ return call_RT(oop_result1, metadata_result, entry, 1);
+}
+
+
+int StubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2) {
+ mr_if_needed(R4_ARG2, arg1);
+ mr_if_needed(R5_ARG3, arg2); assert(arg2 != R4_ARG2, "smashed argument");
+ return call_RT(oop_result1, metadata_result, entry, 2);
+}
+
+
+int StubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2, Register arg3) {
+ mr_if_needed(R4_ARG2, arg1);
+ mr_if_needed(R5_ARG3, arg2); assert(arg2 != R4_ARG2, "smashed argument");
+ mr_if_needed(R6_ARG4, arg3); assert(arg3 != R4_ARG2 && arg3 != R5_ARG3, "smashed argument");
+ return call_RT(oop_result1, metadata_result, entry, 3);
+}
+
+
+// Implementation of Runtime1
+
+#define __ sasm->
+
+static int cpu_reg_save_offsets[FrameMap::nof_cpu_regs];
+static int fpu_reg_save_offsets[FrameMap::nof_fpu_regs];
+static int frame_size_in_bytes = -1;
+
+static OopMap* generate_oop_map(StubAssembler* sasm, bool save_fpu_registers) {
+ assert(frame_size_in_bytes > frame::abi_reg_args_size, "init");
+ sasm->set_frame_size(frame_size_in_bytes / BytesPerWord);
+ int frame_size_in_slots = frame_size_in_bytes / sizeof(jint);
+ OopMap* oop_map = new OopMap(frame_size_in_slots, 0);
+
+ int i;
+ for (i = 0; i < FrameMap::nof_cpu_regs; i++) {
+ Register r = as_Register(i);
+ if (FrameMap::reg_needs_save(r)) {
+ int sp_offset = cpu_reg_save_offsets[i];
+ oop_map->set_callee_saved(VMRegImpl::stack2reg(sp_offset>>2), r->as_VMReg());
+ oop_map->set_callee_saved(VMRegImpl::stack2reg((sp_offset>>2) + 1), r->as_VMReg()->next());
+ }
+ }
+
+ if (save_fpu_registers) {
+ for (i = 0; i < FrameMap::nof_fpu_regs; i++) {
+ FloatRegister r = as_FloatRegister(i);
+ int sp_offset = fpu_reg_save_offsets[i];
+ oop_map->set_callee_saved(VMRegImpl::stack2reg(sp_offset>>2), r->as_VMReg());
+ oop_map->set_callee_saved(VMRegImpl::stack2reg((sp_offset>>2) + 1), r->as_VMReg()->next());
+ }
+ }
+
+ return oop_map;
+}
+
+static OopMap* save_live_registers(StubAssembler* sasm, bool save_fpu_registers = true,
+ Register ret_pc = noreg, int stack_preserve = 0) {
+ if (ret_pc == noreg) {
+ ret_pc = R0;
+ __ mflr(ret_pc);
+ }
+ __ std(ret_pc, _abi(lr), R1_SP); // C code needs pc in C1 method.
+ __ push_frame(frame_size_in_bytes + stack_preserve, R0);
+
+ // Record volatile registers as callee-save values in an OopMap so
+ // their save locations will be propagated to the caller frame's
+ // RegisterMap during StackFrameStream construction (needed for
+ // deoptimization; see compiledVFrame::create_stack_value).
+ // OopMap frame sizes are in c2 stack slot sizes (sizeof(jint)).
+
+ int i;
+ for (i = 0; i < FrameMap::nof_cpu_regs; i++) {
+ Register r = as_Register(i);
+ if (FrameMap::reg_needs_save(r)) {
+ int sp_offset = cpu_reg_save_offsets[i];
+ __ std(r, sp_offset + STACK_BIAS, R1_SP);
+ }
+ }
+
+ if (save_fpu_registers) {
+ for (i = 0; i < FrameMap::nof_fpu_regs; i++) {
+ FloatRegister r = as_FloatRegister(i);
+ int sp_offset = fpu_reg_save_offsets[i];
+ __ stfd(r, sp_offset + STACK_BIAS, R1_SP);
+ }
+ }
+
+ return generate_oop_map(sasm, save_fpu_registers);
+}
+
+static void restore_live_registers(StubAssembler* sasm, Register result1, Register result2,
+ bool restore_fpu_registers = true) {
+ for (int i = 0; i < FrameMap::nof_cpu_regs; i++) {
+ Register r = as_Register(i);
+ if (FrameMap::reg_needs_save(r) && r != result1 && r != result2) {
+ int sp_offset = cpu_reg_save_offsets[i];
+ __ ld(r, sp_offset + STACK_BIAS, R1_SP);
+ }
+ }
+
+ if (restore_fpu_registers) {
+ for (int i = 0; i < FrameMap::nof_fpu_regs; i++) {
+ FloatRegister r = as_FloatRegister(i);
+ int sp_offset = fpu_reg_save_offsets[i];
+ __ lfd(r, sp_offset + STACK_BIAS, R1_SP);
+ }
+ }
+
+ __ pop_frame();
+ __ ld(R0, _abi(lr), R1_SP);
+ __ mtlr(R0);
+}
+
+
+void Runtime1::initialize_pd() {
+ int i;
+ int sp_offset = frame::abi_reg_args_size;
+
+ for (i = 0; i < FrameMap::nof_cpu_regs; i++) {
+ Register r = as_Register(i);
+ if (FrameMap::reg_needs_save(r)) {
+ cpu_reg_save_offsets[i] = sp_offset;
+ sp_offset += BytesPerWord;
+ }
+ }
+
+ for (i = 0; i < FrameMap::nof_fpu_regs; i++) {
+ fpu_reg_save_offsets[i] = sp_offset;
+ sp_offset += BytesPerWord;
+ }
+ frame_size_in_bytes = align_size_up(sp_offset, frame::alignment_in_bytes);
+}
+
+
+OopMapSet* Runtime1::generate_exception_throw(StubAssembler* sasm, address target, bool has_argument) {
+ // Make a frame and preserve the caller's caller-save registers.
+ OopMap* oop_map = save_live_registers(sasm);
+
+ int call_offset;
+ if (!has_argument) {
+ call_offset = __ call_RT(noreg, noreg, target);
+ } else {
+ call_offset = __ call_RT(noreg, noreg, target, R4_ARG2);
+ }
+ OopMapSet* oop_maps = new OopMapSet();
+ oop_maps->add_gc_map(call_offset, oop_map);
+
+ __ should_not_reach_here();
+ return oop_maps;
+}
+
+static OopMapSet* generate_exception_throw_with_stack_parms(StubAssembler* sasm, address target,
+ int stack_parms) {
+ // Make a frame and preserve the caller's caller-save registers.
+ const int parm_size_in_bytes = align_size_up(stack_parms << LogBytesPerWord, frame::alignment_in_bytes);
+ const int padding = parm_size_in_bytes - (stack_parms << LogBytesPerWord);
+ OopMap* oop_map = save_live_registers(sasm, true, noreg, parm_size_in_bytes);
+
+ int call_offset = 0;
+ switch (stack_parms) {
+ case 3:
+ __ ld(R6_ARG4, frame_size_in_bytes + padding + 16, R1_SP);
+ case 2:
+ __ ld(R5_ARG3, frame_size_in_bytes + padding + 8, R1_SP);
+ case 1:
+ __ ld(R4_ARG2, frame_size_in_bytes + padding + 0, R1_SP);
+ call_offset = __ call_RT(noreg, noreg, target);
+ break;
+ default: Unimplemented(); break;
+ }
+ OopMapSet* oop_maps = new OopMapSet();
+ oop_maps->add_gc_map(call_offset, oop_map);
+
+ __ should_not_reach_here();
+ return oop_maps;
+}
+
+
+OopMapSet* Runtime1::generate_stub_call(StubAssembler* sasm, Register result, address target,
+ Register arg1, Register arg2, Register arg3) {
+ // Make a frame and preserve the caller's caller-save registers.
+ OopMap* oop_map = save_live_registers(sasm);
+
+ int call_offset;
+ if (arg1 == noreg) {
+ call_offset = __ call_RT(result, noreg, target);
+ } else if (arg2 == noreg) {
+ call_offset = __ call_RT(result, noreg, target, arg1);
+ } else if (arg3 == noreg) {
+ call_offset = __ call_RT(result, noreg, target, arg1, arg2);
+ } else {
+ call_offset = __ call_RT(result, noreg, target, arg1, arg2, arg3);
+ }
+ OopMapSet* oop_maps = new OopMapSet();
+ oop_maps->add_gc_map(call_offset, oop_map);
+
+ restore_live_registers(sasm, result, noreg);
+ __ blr();
+ return oop_maps;
+}
+
+static OopMapSet* stub_call_with_stack_parms(StubAssembler* sasm, Register result, address target,
+ int stack_parms, bool do_return = true) {
+ // Make a frame and preserve the caller's caller-save registers.
+ const int parm_size_in_bytes = align_size_up(stack_parms << LogBytesPerWord, frame::alignment_in_bytes);
+ const int padding = parm_size_in_bytes - (stack_parms << LogBytesPerWord);
+ OopMap* oop_map = save_live_registers(sasm, true, noreg, parm_size_in_bytes);
+
+ int call_offset = 0;
+ switch (stack_parms) {
+ case 3:
+ __ ld(R6_ARG4, frame_size_in_bytes + padding + 16, R1_SP);
+ case 2:
+ __ ld(R5_ARG3, frame_size_in_bytes + padding + 8, R1_SP);
+ case 1:
+ __ ld(R4_ARG2, frame_size_in_bytes + padding + 0, R1_SP);
+ call_offset = __ call_RT(result, noreg, target);
+ break;
+ default: Unimplemented(); break;
+ }
+ OopMapSet* oop_maps = new OopMapSet();
+ oop_maps->add_gc_map(call_offset, oop_map);
+
+ restore_live_registers(sasm, result, noreg);
+ if (do_return) __ blr();
+ return oop_maps;
+}
+
+
+OopMapSet* Runtime1::generate_patching(StubAssembler* sasm, address target) {
+ // Make a frame and preserve the caller's caller-save registers.
+ OopMap* oop_map = save_live_registers(sasm);
+
+ // Call the runtime patching routine, returns non-zero if nmethod got deopted.
+ int call_offset = __ call_RT(noreg, noreg, target);
+ OopMapSet* oop_maps = new OopMapSet();
+ oop_maps->add_gc_map(call_offset, oop_map);
+ __ cmpdi(CCR0, R3_RET, 0);
+
+ // Re-execute the patched instruction or, if the nmethod was deoptmized,
+ // return to the deoptimization handler entry that will cause re-execution
+ // of the current bytecode.
+ DeoptimizationBlob* deopt_blob = SharedRuntime::deopt_blob();
+ assert(deopt_blob != NULL, "deoptimization blob must have been created");
+
+ // Return to the deoptimization handler entry for unpacking and rexecute.
+ // If we simply returned the we'd deopt as if any call we patched had just
+ // returned.
+
+ restore_live_registers(sasm, noreg, noreg);
+ // Return if patching routine returned 0.
+ __ bclr(Assembler::bcondCRbiIs1, Assembler::bi0(CCR0, Assembler::equal), Assembler::bhintbhBCLRisReturn);
+
+ address stub = deopt_blob->unpack_with_reexecution();
+ //__ load_const_optimized(R0, stub);
+ __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
+ __ mtctr(R0);
+ __ bctr();
+
+ return oop_maps;
+}
+
+OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
+ OopMapSet* oop_maps = NULL;
+
+ // For better readability.
+ const bool must_gc_arguments = true;
+ const bool dont_gc_arguments = false;
+
+ // Stub code & info for the different stubs.
+ switch (id) {
+ case forward_exception_id:
+ {
+ oop_maps = generate_handle_exception(id, sasm);
+ }
+ break;
+
+ case new_instance_id:
+ case fast_new_instance_id:
+ case fast_new_instance_init_check_id:
+ {
+ if (id == new_instance_id) {
+ __ set_info("new_instance", dont_gc_arguments);
+ } else if (id == fast_new_instance_id) {
+ __ set_info("fast new_instance", dont_gc_arguments);
+ } else {
+ assert(id == fast_new_instance_init_check_id, "bad StubID");
+ __ set_info("fast new_instance init check", dont_gc_arguments);
+ }
+ // We don't support eden allocation.
+// if ((id == fast_new_instance_id || id == fast_new_instance_init_check_id) &&
+// UseTLAB && FastTLABRefill) {
+// if (id == fast_new_instance_init_check_id) {
+// // make sure the klass is initialized
+// __ lbz(R0, in_bytes(InstanceKlass::init_state_offset()), R3_ARG1);
+// __ cmpwi(CCR0, R0, InstanceKlass::fully_initialized);
+// __ bne(CCR0, slow_path);
+// }
+//#ifdef ASSERT
+// // assert object can be fast path allocated
+// {
+// Label ok, not_ok;
+// __ lwz(R0, in_bytes(Klass::layout_helper_offset()), R3_ARG1);
+// // make sure it's an instance (LH > 0)
+// __ cmpwi(CCR0, R0, 0);
+// __ ble(CCR0, not_ok);
+// __ testbitdi(CCR0, R0, R0, Klass::_lh_instance_slow_path_bit);
+// __ beq(CCR0, ok);
+//
+// __ bind(not_ok);
+// __ stop("assert(can be fast path allocated)");
+// __ bind(ok);
+// }
+//#endif // ASSERT
+// // We don't support eden allocation.
+// __ bind(slow_path);
+// }
+ oop_maps = generate_stub_call(sasm, R3_RET, CAST_FROM_FN_PTR(address, new_instance), R4_ARG2);
+ }
+ break;
+
+ case counter_overflow_id:
+ // Bci and method are on stack.
+ oop_maps = stub_call_with_stack_parms(sasm, noreg, CAST_FROM_FN_PTR(address, counter_overflow), 2);
+ break;
+
+ case new_type_array_id:
+ case new_object_array_id:
+ {
+ if (id == new_type_array_id) {
+ __ set_info("new_type_array", dont_gc_arguments);
+ } else {
+ __ set_info("new_object_array", dont_gc_arguments);
+ }
+
+#ifdef ASSERT
+ // Assert object type is really an array of the proper kind.
+ {
+ int tag = (id == new_type_array_id) ? Klass::_lh_array_tag_type_value : Klass::_lh_array_tag_obj_value;
+ Label ok;
+ __ lwz(R0, in_bytes(Klass::layout_helper_offset()), R4_ARG2);
+ __ srawi(R0, R0, Klass::_lh_array_tag_shift);
+ __ cmpwi(CCR0, R0, tag);
+ __ beq(CCR0, ok);
+ __ stop("assert(is an array klass)");
+ __ should_not_reach_here();
+ __ bind(ok);
+ }
+#endif // ASSERT
+
+ // We don't support eden allocation.
+
+ if (id == new_type_array_id) {
+ oop_maps = generate_stub_call(sasm, R3_RET, CAST_FROM_FN_PTR(address, new_type_array), R4_ARG2, R5_ARG3);
+ } else {
+ oop_maps = generate_stub_call(sasm, R3_RET, CAST_FROM_FN_PTR(address, new_object_array), R4_ARG2, R5_ARG3);
+ }
+ }
+ break;
+
+ case new_multi_array_id:
+ {
+ // R4: klass
+ // R5: rank
+ // R6: address of 1st dimension
+ __ set_info("new_multi_array", dont_gc_arguments);
+ oop_maps = generate_stub_call(sasm, R3_RET, CAST_FROM_FN_PTR(address, new_multi_array), R4_ARG2, R5_ARG3, R6_ARG4);
+ }
+ break;
+
+ case register_finalizer_id:
+ {
+ __ set_info("register_finalizer", dont_gc_arguments);
+ // This code is called via rt_call. Hence, caller-save registers have been saved.
+ Register t = R11_scratch1;
+
+ // Load the klass and check the has finalizer flag.
+ __ load_klass(t, R3_ARG1);
+ __ lwz(t, in_bytes(Klass::access_flags_offset()), t);
+ __ testbitdi(CCR0, R0, t, exact_log2(JVM_ACC_HAS_FINALIZER));
+ // Return if has_finalizer bit == 0 (CR0.eq).
+ __ bclr(Assembler::bcondCRbiIs1, Assembler::bi0(CCR0, Assembler::equal), Assembler::bhintbhBCLRisReturn);
+
+ __ mflr(R0);
+ __ std(R0, _abi(lr), R1_SP);
+ __ push_frame(frame::abi_reg_args_size, R0); // Empty dummy frame (no callee-save regs).
+ sasm->set_frame_size(frame::abi_reg_args_size / BytesPerWord);
+ OopMap* oop_map = new OopMap(frame::abi_reg_args_size / sizeof(jint), 0);
+ int call_offset = __ call_RT(noreg, noreg,
+ CAST_FROM_FN_PTR(address, SharedRuntime::register_finalizer), R3_ARG1);
+ oop_maps = new OopMapSet();
+ oop_maps->add_gc_map(call_offset, oop_map);
+
+ __ pop_frame();
+ __ ld(R0, _abi(lr), R1_SP);
+ __ mtlr(R0);
+ __ blr();
+ }
+ break;
+
+ case throw_range_check_failed_id:
+ {
+ __ set_info("range_check_failed", dont_gc_arguments); // Arguments will be discarded.
+ __ std(R0, -8, R1_SP); // Pass index on stack.
+ oop_maps = generate_exception_throw_with_stack_parms(sasm, CAST_FROM_FN_PTR(address, throw_range_check_exception), 1);
+ }
+ break;
+
+ case throw_index_exception_id:
+ {
+ __ set_info("index_range_check_failed", dont_gc_arguments); // Arguments will be discarded.
+ oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_index_exception), true);
+ }
+ break;
+
+ case throw_div0_exception_id:
+ {
+ __ set_info("throw_div0_exception", dont_gc_arguments);
+ oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_div0_exception), false);
+ }
+ break;
+
+ case throw_null_pointer_exception_id:
+ {
+ __ set_info("throw_null_pointer_exception", dont_gc_arguments);
+ oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_null_pointer_exception), false);
+ }
+ break;
+
+ case handle_exception_nofpu_id:
+ case handle_exception_id:
+ {
+ __ set_info("handle_exception", dont_gc_arguments);
+ oop_maps = generate_handle_exception(id, sasm);
+ }
+ break;
+
+ case handle_exception_from_callee_id:
+ {
+ __ set_info("handle_exception_from_callee", dont_gc_arguments);
+ oop_maps = generate_handle_exception(id, sasm);
+ }
+ break;
+
+ case unwind_exception_id:
+ {
+ const Register Rexception = R3 /*LIRGenerator::exceptionOopOpr()*/,
+ Rexception_pc = R4 /*LIRGenerator::exceptionPcOpr()*/,
+ Rexception_save = R31, Rcaller_sp = R30;
+ __ set_info("unwind_exception", dont_gc_arguments);
+
+ __ ld(Rcaller_sp, 0, R1_SP);
+ __ push_frame_reg_args(0, R0); // dummy frame for C call
+ __ mr(Rexception_save, Rexception); // save over C call
+ __ ld(Rexception_pc, _abi(lr), Rcaller_sp); // return pc
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), R16_thread, Rexception_pc);
+ __ verify_not_null_oop(Rexception_save);
+ __ mtctr(R3_RET);
+ __ ld(Rexception_pc, _abi(lr), Rcaller_sp); // return pc
+ __ mr(R1_SP, Rcaller_sp); // Pop both frames at once.
+ __ mr(Rexception, Rexception_save); // restore
+ __ mtlr(Rexception_pc);
+ __ bctr();
+ }
+ break;
+
+ case throw_array_store_exception_id:
+ {
+ __ set_info("throw_array_store_exception", dont_gc_arguments);
+ oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_array_store_exception), true);
+ }
+ break;
+
+ case throw_class_cast_exception_id:
+ {
+ __ set_info("throw_class_cast_exception", dont_gc_arguments);
+ oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_class_cast_exception), true);
+ }
+ break;
+
+ case throw_incompatible_class_change_error_id:
+ {
+ __ set_info("throw_incompatible_class_cast_exception", dont_gc_arguments);
+ oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_incompatible_class_change_error), false);
+ }
+ break;
+
+ case slow_subtype_check_id:
+ { // Support for uint StubRoutine::partial_subtype_check( Klass sub, Klass super );
+ const Register sub_klass = R5,
+ super_klass = R4,
+ temp1_reg = R6,
+ temp2_reg = R0;
+ __ check_klass_subtype_slow_path(sub_klass, super_klass, temp1_reg, temp2_reg); // returns with CR0.eq if successful
+ __ crandc(CCR0, Assembler::equal, CCR0, Assembler::equal); // failed: CR0.ne
+ __ blr();
+ }
+ break;
+
+ case monitorenter_nofpu_id:
+ case monitorenter_id:
+ {
+ __ set_info("monitorenter", dont_gc_arguments);
+
+ int save_fpu_registers = (id == monitorenter_id);
+ // Make a frame and preserve the caller's caller-save registers.
+ OopMap* oop_map = save_live_registers(sasm, save_fpu_registers);
+
+ int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, monitorenter), R4_ARG2, R5_ARG3);
+
+ oop_maps = new OopMapSet();
+ oop_maps->add_gc_map(call_offset, oop_map);
+
+ restore_live_registers(sasm, noreg, noreg, save_fpu_registers);
+ __ blr();
+ }
+ break;
+
+ case monitorexit_nofpu_id:
+ case monitorexit_id:
+ {
+ // note: Really a leaf routine but must setup last java sp
+ // => use call_RT for now (speed can be improved by
+ // doing last java sp setup manually).
+ __ set_info("monitorexit", dont_gc_arguments);
+
+ int save_fpu_registers = (id == monitorexit_id);
+ // Make a frame and preserve the caller's caller-save registers.
+ OopMap* oop_map = save_live_registers(sasm, save_fpu_registers);
+
+ int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, monitorexit), R4_ARG2);
+
+ oop_maps = new OopMapSet();
+ oop_maps->add_gc_map(call_offset, oop_map);
+
+ restore_live_registers(sasm, noreg, noreg, save_fpu_registers);
+ __ blr();
+ }
+ break;
+
+ case deoptimize_id:
+ {
+ __ set_info("deoptimize", dont_gc_arguments);
+ __ std(R0, -8, R1_SP); // Pass trap_request on stack.
+ oop_maps = stub_call_with_stack_parms(sasm, noreg, CAST_FROM_FN_PTR(address, deoptimize), 1, /*do_return*/ false);
+
+ DeoptimizationBlob* deopt_blob = SharedRuntime::deopt_blob();
+ assert(deopt_blob != NULL, "deoptimization blob must have been created");
+ address stub = deopt_blob->unpack_with_reexecution();
+ //__ load_const_optimized(R0, stub);
+ __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
+ __ mtctr(R0);
+ __ bctr();
+ }
+ break;
+
+ case access_field_patching_id:
+ {
+ __ set_info("access_field_patching", dont_gc_arguments);
+ oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, access_field_patching));
+ }
+ break;
+
+ case load_klass_patching_id:
+ {
+ __ set_info("load_klass_patching", dont_gc_arguments);
+ oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_klass_patching));
+ }
+ break;
+
+ case load_mirror_patching_id:
+ {
+ __ set_info("load_mirror_patching", dont_gc_arguments);
+ oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_mirror_patching));
+ }
+ break;
+
+ case load_appendix_patching_id:
+ {
+ __ set_info("load_appendix_patching", dont_gc_arguments);
+ oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_appendix_patching));
+ }
+ break;
+
+ case dtrace_object_alloc_id:
+ { // O0: object
+ __ unimplemented("stub dtrace_object_alloc_id");
+ __ set_info("dtrace_object_alloc", dont_gc_arguments);
+// // We can't gc here so skip the oopmap but make sure that all
+// // the live registers get saved.
+// save_live_registers(sasm);
+//
+// __ save_thread(L7_thread_cache);
+// __ call(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_object_alloc),
+// relocInfo::runtime_call_type);
+// __ delayed()->mov(I0, O0);
+// __ restore_thread(L7_thread_cache);
+//
+// restore_live_registers(sasm);
+// __ ret();
+// __ delayed()->restore();
+ }
+ break;
+
+#if INCLUDE_ALL_GCS
+ case g1_pre_barrier_slow_id:
+ {
+ BarrierSet* bs = Universe::heap()->barrier_set();
+ if (bs->kind() != BarrierSet::G1SATBCTLogging) {
+ goto unimplemented_entry;
+ }
+
+ __ set_info("g1_pre_barrier_slow_id", dont_gc_arguments);
+
+ // Using stack slots: pre_val (pre-pushed), spill tmp, spill tmp2.
+ const int stack_slots = 3;
+ Register pre_val = R0; // previous value of memory
+ Register tmp = R14;
+ Register tmp2 = R15;
+
+ Label refill, restart;
+ int satb_q_index_byte_offset =
+ in_bytes(JavaThread::satb_mark_queue_offset() +
+ SATBMarkQueue::byte_offset_of_index());
+ int satb_q_buf_byte_offset =
+ in_bytes(JavaThread::satb_mark_queue_offset() +
+ SATBMarkQueue::byte_offset_of_buf());
+
+ // Spill
+ __ std(tmp, -16, R1_SP);
+ __ std(tmp2, -24, R1_SP);
+
+ __ bind(restart);
+ // Load the index into the SATB buffer. SATBMarkQueue::_index is a
+ // size_t so ld_ptr is appropriate.
+ __ ld(tmp, satb_q_index_byte_offset, R16_thread);
+
+ // index == 0?
+ __ cmpdi(CCR0, tmp, 0);
+ __ beq(CCR0, refill);
+
+ __ ld(tmp2, satb_q_buf_byte_offset, R16_thread);
+ __ ld(pre_val, -8, R1_SP); // Load from stack.
+ __ addi(tmp, tmp, -oopSize);
+
+ __ std(tmp, satb_q_index_byte_offset, R16_thread);
+ __ stdx(pre_val, tmp2, tmp); // [_buf + index] := <address_of_card>
+
+ // Restore temp registers and return-from-leaf.
+ __ ld(tmp2, -24, R1_SP);
+ __ ld(tmp, -16, R1_SP);
+ __ blr();
+
+ __ bind(refill);
+ const int nbytes_save = (MacroAssembler::num_volatile_regs + stack_slots) * BytesPerWord;
+ __ save_volatile_gprs(R1_SP, -nbytes_save); // except R0
+ __ mflr(R0);
+ __ std(R0, _abi(lr), R1_SP);
+ __ push_frame_reg_args(nbytes_save, R0); // dummy frame for C call
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SATBMarkQueueSet::handle_zero_index_for_thread), R16_thread);
+ __ pop_frame();
+ __ ld(R0, _abi(lr), R1_SP);
+ __ mtlr(R0);
+ __ restore_volatile_gprs(R1_SP, -nbytes_save); // except R0
+ __ b(restart);
+ }
+ break;
+
+ case g1_post_barrier_slow_id:
+ {
+ BarrierSet* bs = Universe::heap()->barrier_set();
+ if (bs->kind() != BarrierSet::G1SATBCTLogging) {
+ goto unimplemented_entry;
+ }
+
+ __ set_info("g1_post_barrier_slow_id", dont_gc_arguments);
+
+ // Using stack slots: spill addr, spill tmp2
+ const int stack_slots = 2;
+ Register tmp = R0;
+ Register addr = R14;
+ Register tmp2 = R15;
+ jbyte* byte_map_base = ((CardTableModRefBS*)bs)->byte_map_base;
+
+ Label restart, refill, ret;
+
+ // Spill
+ __ std(addr, -8, R1_SP);
+ __ std(tmp2, -16, R1_SP);
+
+ __ srdi(addr, R0, CardTableModRefBS::card_shift); // Addr is passed in R0.
+ __ load_const_optimized(/*cardtable*/ tmp2, byte_map_base, tmp);
+ __ add(addr, tmp2, addr);
+ __ lbz(tmp, 0, addr); // tmp := [addr + cardtable]
+
+ // Return if young card.
+ __ cmpwi(CCR0, tmp, G1SATBCardTableModRefBS::g1_young_card_val());
+ __ beq(CCR0, ret);
+
+ // Return if sequential consistent value is already dirty.
+ __ membar(Assembler::StoreLoad);
+ __ lbz(tmp, 0, addr); // tmp := [addr + cardtable]
+
+ __ cmpwi(CCR0, tmp, G1SATBCardTableModRefBS::dirty_card_val());
+ __ beq(CCR0, ret);
+
+ // Not dirty.
+
+ // First, dirty it.
+ __ li(tmp, G1SATBCardTableModRefBS::dirty_card_val());
+ __ stb(tmp, 0, addr);
+
+ int dirty_card_q_index_byte_offset =
+ in_bytes(JavaThread::dirty_card_queue_offset() +
+ DirtyCardQueue::byte_offset_of_index());
+ int dirty_card_q_buf_byte_offset =
+ in_bytes(JavaThread::dirty_card_queue_offset() +
+ DirtyCardQueue::byte_offset_of_buf());
+
+ __ bind(restart);
+
+ // Get the index into the update buffer. DirtyCardQueue::_index is
+ // a size_t so ld_ptr is appropriate here.
+ __ ld(tmp2, dirty_card_q_index_byte_offset, R16_thread);
+
+ // index == 0?
+ __ cmpdi(CCR0, tmp2, 0);
+ __ beq(CCR0, refill);
+
+ __ ld(tmp, dirty_card_q_buf_byte_offset, R16_thread);
+ __ addi(tmp2, tmp2, -oopSize);
+
+ __ std(tmp2, dirty_card_q_index_byte_offset, R16_thread);
+ __ add(tmp2, tmp, tmp2);
+ __ std(addr, 0, tmp2); // [_buf + index] := <address_of_card>
+
+ // Restore temp registers and return-from-leaf.
+ __ bind(ret);
+ __ ld(tmp2, -16, R1_SP);
+ __ ld(addr, -8, R1_SP);
+ __ blr();
+
+ __ bind(refill);
+ const int nbytes_save = (MacroAssembler::num_volatile_regs + stack_slots) * BytesPerWord;
+ __ save_volatile_gprs(R1_SP, -nbytes_save); // except R0
+ __ mflr(R0);
+ __ std(R0, _abi(lr), R1_SP);
+ __ push_frame_reg_args(nbytes_save, R0); // dummy frame for C call
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, DirtyCardQueueSet::handle_zero_index_for_thread), R16_thread);
+ __ pop_frame();
+ __ ld(R0, _abi(lr), R1_SP);
+ __ mtlr(R0);
+ __ restore_volatile_gprs(R1_SP, -nbytes_save); // except R0
+ __ b(restart);
+ }
+ break;
+#endif // INCLUDE_ALL_GCS
+
+ case predicate_failed_trap_id:
+ {
+ __ set_info("predicate_failed_trap", dont_gc_arguments);
+ OopMap* oop_map = save_live_registers(sasm);
+
+ int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, predicate_failed_trap));
+
+ oop_maps = new OopMapSet();
+ oop_maps->add_gc_map(call_offset, oop_map);
+
+ DeoptimizationBlob* deopt_blob = SharedRuntime::deopt_blob();
+ assert(deopt_blob != NULL, "deoptimization blob must have been created");
+ restore_live_registers(sasm, noreg, noreg);
+
+ address stub = deopt_blob->unpack_with_reexecution();
+ //__ load_const_optimized(R0, stub);
+ __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
+ __ mtctr(R0);
+ __ bctr();
+ }
+ break;
+
+ default:
+ unimplemented_entry:
+ {
+ __ set_info("unimplemented entry", dont_gc_arguments);
+ __ mflr(R0);
+ __ std(R0, _abi(lr), R1_SP);
+ __ push_frame(frame::abi_reg_args_size, R0); // empty dummy frame
+ sasm->set_frame_size(frame::abi_reg_args_size / BytesPerWord);
+ OopMap* oop_map = new OopMap(frame::abi_reg_args_size / sizeof(jint), 0);
+
+ __ load_const_optimized(R4_ARG2, (int)id);
+ int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), R4_ARG2);
+
+ oop_maps = new OopMapSet();
+ oop_maps->add_gc_map(call_offset, oop_map);
+ __ should_not_reach_here();
+ }
+ break;
+ }
+ return oop_maps;
+}
+
+
+OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler* sasm) {
+ __ block_comment("generate_handle_exception");
+
+ // Save registers, if required.
+ OopMapSet* oop_maps = new OopMapSet();
+ OopMap* oop_map = NULL;
+ const Register Rexception = R3 /*LIRGenerator::exceptionOopOpr()*/,
+ Rexception_pc = R4 /*LIRGenerator::exceptionPcOpr()*/;
+
+ switch (id) {
+ case forward_exception_id:
+ // We're handling an exception in the context of a compiled frame.
+ // The registers have been saved in the standard places. Perform
+ // an exception lookup in the caller and dispatch to the handler
+ // if found. Otherwise unwind and dispatch to the callers
+ // exception handler.
+ oop_map = generate_oop_map(sasm, true);
+ // Transfer the pending exception to the exception_oop.
+ // Also load the PC which is typically at SP + frame_size_in_bytes + _abi(lr),
+ // but we support additional slots in the frame for parameter passing.
+ __ ld(Rexception_pc, 0, R1_SP);
+ __ ld(Rexception, in_bytes(JavaThread::pending_exception_offset()), R16_thread);
+ __ li(R0, 0);
+ __ ld(Rexception_pc, _abi(lr), Rexception_pc);
+ __ std(R0, in_bytes(JavaThread::pending_exception_offset()), R16_thread);
+ break;
+ case handle_exception_nofpu_id:
+ case handle_exception_id:
+ // At this point all registers MAY be live.
+ oop_map = save_live_registers(sasm, id != handle_exception_nofpu_id, Rexception_pc);
+ break;
+ case handle_exception_from_callee_id:
+ // At this point all registers except exception oop and exception pc are dead.
+ oop_map = new OopMap(frame_size_in_bytes / sizeof(jint), 0);
+ sasm->set_frame_size(frame_size_in_bytes / BytesPerWord);
+ __ std(Rexception_pc, _abi(lr), R1_SP);
+ __ push_frame(frame_size_in_bytes, R0);
+ break;
+ default: ShouldNotReachHere();
+ }
+
+ __ verify_not_null_oop(Rexception);
+
+#ifdef ASSERT
+ // Check that fields in JavaThread for exception oop and issuing pc are
+ // empty before writing to them.
+ __ ld(R0, in_bytes(JavaThread::exception_oop_offset()), R16_thread);
+ __ cmpdi(CCR0, R0, 0);
+ __ asm_assert_eq("exception oop already set", 0x963);
+ __ ld(R0, in_bytes(JavaThread::exception_pc_offset() ), R16_thread);
+ __ cmpdi(CCR0, R0, 0);
+ __ asm_assert_eq("exception pc already set", 0x962);
+#endif
+
+ // Save the exception and issuing pc in the thread.
+ __ std(Rexception, in_bytes(JavaThread::exception_oop_offset()), R16_thread);
+ __ std(Rexception_pc, in_bytes(JavaThread::exception_pc_offset() ), R16_thread);
+
+ int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, exception_handler_for_pc));
+ oop_maps->add_gc_map(call_offset, oop_map);
+
+ __ mtctr(R3_RET);
+
+ // Note: if nmethod has been deoptimized then regardless of
+ // whether it had a handler or not we will deoptimize
+ // by entering the deopt blob with a pending exception.
+
+ // Restore the registers that were saved at the beginning, remove
+ // the frame and jump to the exception handler.
+ switch (id) {
+ case forward_exception_id:
+ case handle_exception_nofpu_id:
+ case handle_exception_id:
+ restore_live_registers(sasm, noreg, noreg, id != handle_exception_nofpu_id);
+ __ bctr();
+ break;
+ case handle_exception_from_callee_id: {
+ __ pop_frame();
+ __ ld(Rexception_pc, _abi(lr), R1_SP);
+ __ mtlr(Rexception_pc);
+ __ bctr();
+ break;
+ }
+ default: ShouldNotReachHere();
+ }
+
+ return oop_maps;
+}
+
+const char *Runtime1::pd_name_for_address(address entry) {
+ return "<unknown function>";
+}
+
+#undef __
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/cpu/ppc/vm/c1_globals_ppc.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012, 2015 SAP AG. 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.
+ *
+ */
+
+#ifndef CPU_PPC_VM_C1_GLOBALS_PPC_HPP
+#define CPU_PPC_VM_C1_GLOBALS_PPC_HPP
+
+#include "utilities/globalDefinitions.hpp"
+#include "utilities/macros.hpp"
+
+// Sets the default values for platform dependent flags used by the client compiler.
+// (see c1_globals.hpp)
+
+#ifndef TIERED
+define_pd_global(bool, BackgroundCompilation, true );
+define_pd_global(bool, CICompileOSR, true );
+define_pd_global(bool, InlineIntrinsics, true );
+define_pd_global(bool, PreferInterpreterNativeStubs, false);
+define_pd_global(bool, ProfileTraps, false);
+define_pd_global(bool, UseOnStackReplacement, true );
+define_pd_global(bool, TieredCompilation, false);
+define_pd_global(intx, CompileThreshold, 1000 );
+
+define_pd_global(intx, OnStackReplacePercentage, 1400 );
+define_pd_global(bool, UseTLAB, true );
+define_pd_global(bool, ProfileInterpreter, false);
+define_pd_global(intx, FreqInlineSize, 325 );
+define_pd_global(bool, ResizeTLAB, true );
+define_pd_global(intx, ReservedCodeCacheSize, 32*M );
+define_pd_global(intx, CodeCacheExpansionSize, 32*K );
+define_pd_global(uintx,CodeCacheMinBlockLength, 1);
+define_pd_global(uintx,MetaspaceSize, 12*M );
+define_pd_global(bool, NeverActAsServerClassMachine, true );
+define_pd_global(intx, NewSizeThreadIncrease, 16*K );
+define_pd_global(uint64_t,MaxRAM, 1ULL*G);
+define_pd_global(intx, InitialCodeCacheSize, 160*K);
+#endif // !TIERED
+
+define_pd_global(bool, UseTypeProfile, false);
+define_pd_global(bool, RoundFPResults, false);
+
+define_pd_global(bool, LIRFillDelaySlots, false);
+define_pd_global(bool, OptimizeSinglePrecision, false);
+define_pd_global(bool, CSEArrayLength, true );
+define_pd_global(bool, TwoOperandLIRForm, false);
+
+#endif // CPU_PPC_VM_C1_GLOBALS_PPC_HPP
--- a/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -39,7 +39,7 @@
define_pd_global(bool, ProfileTraps, true);
define_pd_global(bool, UseOnStackReplacement, true);
define_pd_global(bool, ProfileInterpreter, true);
-define_pd_global(bool, TieredCompilation, false);
+define_pd_global(bool, TieredCompilation, true);
define_pd_global(intx, CompileThreshold, 10000);
define_pd_global(intx, OnStackReplacePercentage, 140);
--- a/hotspot/src/cpu/ppc/vm/c2_init_ppc.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/c2_init_ppc.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012, 2013 SAP AG. All rights reserved.
+ * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012, 2015 SAP AG. 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
@@ -45,4 +45,8 @@
FLAG_SET_ERGO(bool, InsertEndGroupPPC64, true);
}
}
+
+ if (!VM_Version::has_isel() && FLAG_IS_DEFAULT(ConditionalMoveLimit)) {
+ FLAG_SET_ERGO(intx, ConditionalMoveLimit, 0);
+ }
}
--- a/hotspot/src/cpu/ppc/vm/compiledIC_ppc.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/compiledIC_ppc.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -1,5 +1,6 @@
/*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012, 2015 SAP AG. 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
@@ -129,13 +130,20 @@
// - call
__ calculate_address_from_global_toc(reg_scratch, __ method_toc());
AddressLiteral ic = __ allocate_metadata_address((Metadata *)NULL);
- __ load_const_from_method_toc(as_Register(Matcher::inline_cache_reg_encode()), ic, reg_scratch);
+ bool success = __ load_const_from_method_toc(as_Register(Matcher::inline_cache_reg_encode()),
+ ic, reg_scratch, /*fixed_size*/ true);
+ if (!success) {
+ return NULL; // CodeCache is full
+ }
if (ReoptimizeCallSequences) {
__ b64_patchable((address)-1, relocInfo::none);
} else {
AddressLiteral a((address)-1);
- __ load_const_from_method_toc(reg_scratch, a, reg_scratch);
+ success = __ load_const_from_method_toc(reg_scratch, a, reg_scratch, /*fixed_size*/ true);
+ if (!success) {
+ return NULL; // CodeCache is full
+ }
__ mtctr(reg_scratch);
__ bctr();
}
@@ -153,6 +161,7 @@
return stub;
#else
ShouldNotReachHere();
+ return NULL;
#endif
}
#undef __
--- a/hotspot/src/cpu/ppc/vm/frame_ppc.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/frame_ppc.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012, 2014 SAP AG. All rights reserved.
+ * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012, 2015 SAP AG. 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
@@ -271,39 +271,6 @@
}
#endif
-void frame::adjust_unextended_sp() {
- // If we are returning to a compiled MethodHandle call site, the
- // saved_fp will in fact be a saved value of the unextended SP. The
- // simplest way to tell whether we are returning to such a call site
- // is as follows:
-
- if (is_compiled_frame() && false /*is_at_mh_callsite()*/) { // TODO PPC port
- // If the sender PC is a deoptimization point, get the original
- // PC. For MethodHandle call site the unextended_sp is stored in
- // saved_fp.
- _unextended_sp = _fp - _cb->frame_size();
-
-#ifdef ASSERT
- nmethod *sender_nm = _cb->as_nmethod_or_null();
- assert(sender_nm && *_sp == *_unextended_sp, "backlink changed");
-
- intptr_t* sp = _unextended_sp; // check if stack can be walked from here
- for (int x = 0; x < 5; ++x) { // check up to a couple of backlinks
- intptr_t* prev_sp = *(intptr_t**)sp;
- if (prev_sp == 0) break; // end of stack
- assert(prev_sp>sp, "broken stack");
- sp = prev_sp;
- }
-
- if (sender_nm->is_deopt_mh_entry(_pc)) { // checks for deoptimization
- address original_pc = sender_nm->get_original_pc(this);
- assert(sender_nm->insts_contains(original_pc), "original PC must be in nmethod");
- assert(sender_nm->is_method_handle_return(original_pc), "must be");
- }
-#endif
- }
-}
-
intptr_t *frame::initial_deoptimization_info() {
// unused... but returns fp() to minimize changes introduced by 7087445
return fp();
--- a/hotspot/src/cpu/ppc/vm/frame_ppc.hpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/frame_ppc.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012, 2014 SAP AG. All rights reserved.
+ * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012, 2015 SAP AG. 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
@@ -465,7 +465,6 @@
// The frame's stack pointer before it has been extended by a c2i adapter;
// needed by deoptimization
intptr_t* _unextended_sp;
- void adjust_unextended_sp();
public:
--- a/hotspot/src/cpu/ppc/vm/frame_ppc.inline.hpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/frame_ppc.inline.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -39,9 +39,6 @@
_pc = pc; // Must be set for get_deopt_original_pc()
_fp = (intptr_t*)own_abi()->callers_sp;
- // Use _fp - frame_size, needs to be done between _cb and _pc initialization
- // and get_deopt_original_pc.
- adjust_unextended_sp();
address original_pc = nmethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
--- a/hotspot/src/cpu/ppc/vm/globalDefinitions_ppc.hpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/globalDefinitions_ppc.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -36,4 +36,7 @@
// The PPC CPUs are NOT multiple-copy-atomic.
#define CPU_NOT_MULTIPLE_COPY_ATOMIC
+// The expected size in bytes of a cache line, used to pad data structures.
+#define DEFAULT_CACHE_LINE_SIZE 128
+
#endif // CPU_PPC_VM_GLOBALDEFINITIONS_PPC_HPP
--- a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -93,9 +93,9 @@
// own dispatch. The dispatch address in R24_dispatch_addr is used for the
// dispatch.
void InterpreterMacroAssembler::dispatch_epilog(TosState state, int bcp_incr) {
+ if (bcp_incr) { addi(R14_bcp, R14_bcp, bcp_incr); }
mtctr(R24_dispatch_addr);
- addi(R14_bcp, R14_bcp, bcp_incr);
- bctr();
+ bcctr(bcondAlways, 0, bhintbhBCCTRisNotPredictable);
}
void InterpreterMacroAssembler::check_and_handle_popframe(Register scratch_reg) {
@@ -212,9 +212,6 @@
unimplemented("dispatch_Lbyte_code: verify"); // See Sparc Implementation to implement this
}
-#ifdef FAST_DISPATCH
- unimplemented("dispatch_Lbyte_code FAST_DISPATCH");
-#else
assert_different_registers(bytecode, R11_scratch1);
// Calc dispatch table address.
@@ -225,8 +222,7 @@
// Jump off!
mtctr(R11_scratch1);
- bctr();
-#endif
+ bcctr(bcondAlways, 0, bhintbhBCCTRisNotPredictable);
}
void InterpreterMacroAssembler::load_receiver(Register Rparam_count, Register Rrecv_dst) {
@@ -546,8 +542,8 @@
sldi(RsxtIndex, RsxtIndex, index_shift);
blt(CCR0, LnotOOR);
// Index should be in R17_tos, array should be in R4_ARG2.
- mr(R17_tos, Rindex);
- mr(R4_ARG2, Rarray);
+ mr_if_needed(R17_tos, Rindex);
+ mr_if_needed(R4_ARG2, Rarray);
load_dispatch_table(Rtmp, (address*)Interpreter::_throw_ArrayIndexOutOfBoundsException_entry);
mtctr(Rtmp);
bctr();
@@ -842,7 +838,6 @@
// Must fence, otherwise, preceding store(s) may float below cmpxchg.
// CmpxchgX sets CCR0 to cmpX(current, displaced).
- fence(); // TODO: replace by MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq ?
cmpxchgd(/*flag=*/CCR0,
/*current_value=*/current_header,
/*compare_value=*/displaced_header, /*exchange_value=*/monitor,
@@ -850,7 +845,8 @@
MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq,
MacroAssembler::cmpxchgx_hint_acquire_lock(),
noreg,
- &cas_failed);
+ &cas_failed,
+ /*check without membar and ldarx first*/true);
// If the compare-and-exchange succeeded, then we found an unlocked
// object and we have now locked it.
@@ -868,9 +864,7 @@
sub(current_header, current_header, R1_SP);
assert(os::vm_page_size() > 0xfff, "page size too small - change the constant");
- load_const_optimized(tmp,
- (address) (~(os::vm_page_size()-1) |
- markOopDesc::lock_mask_in_place));
+ load_const_optimized(tmp, ~(os::vm_page_size()-1) | markOopDesc::lock_mask_in_place);
and_(R0/*==0?*/, current_header, tmp);
// If condition is true we are done and hence we can store 0 in the displaced
@@ -1107,6 +1101,7 @@
}
void InterpreterMacroAssembler::test_invocation_counter_for_mdp(Register invocation_count,
+ Register method_counters,
Register Rscratch,
Label &profile_continue) {
assert(ProfileInterpreter, "must be profiling interpreter");
@@ -1115,12 +1110,11 @@
Label done;
// If no method data exists, and the counter is high enough, make one.
- int ipl_offs = load_const_optimized(Rscratch, &InvocationCounter::InterpreterProfileLimit, R0, true);
- lwz(Rscratch, ipl_offs, Rscratch);
+ lwz(Rscratch, in_bytes(MethodCounters::interpreter_profile_limit_offset()), method_counters);
cmpdi(CCR0, R28_mdx, 0);
// Test to see if we should create a method data oop.
- cmpd(CCR1, Rscratch /* InterpreterProfileLimit */, invocation_count);
+ cmpd(CCR1, Rscratch, invocation_count);
bne(CCR0, done);
bge(CCR1, profile_continue);
@@ -1133,15 +1127,15 @@
bind(done);
}
-void InterpreterMacroAssembler::test_backedge_count_for_osr(Register backedge_count, Register branch_bcp, Register Rtmp) {
- assert_different_registers(backedge_count, Rtmp, branch_bcp);
+void InterpreterMacroAssembler::test_backedge_count_for_osr(Register backedge_count, Register method_counters,
+ Register target_bcp, Register disp, Register Rtmp) {
+ assert_different_registers(backedge_count, target_bcp, disp, Rtmp, R4_ARG2);
assert(UseOnStackReplacement,"Must UseOnStackReplacement to test_backedge_count_for_osr");
Label did_not_overflow;
Label overflow_with_error;
- int ibbl_offs = load_const_optimized(Rtmp, &InvocationCounter::InterpreterBackwardBranchLimit, R0, true);
- lwz(Rtmp, ibbl_offs, Rtmp);
+ lwz(Rtmp, in_bytes(MethodCounters::interpreter_backward_branch_limit_offset()), method_counters);
cmpw(CCR0, backedge_count, Rtmp);
blt(CCR0, did_not_overflow);
@@ -1153,17 +1147,15 @@
// the overflow function is called only once every overflow_frequency.
if (ProfileInterpreter) {
const int overflow_frequency = 1024;
- li(Rtmp, overflow_frequency-1);
- andr(Rtmp, Rtmp, backedge_count);
- cmpwi(CCR0, Rtmp, 0);
+ andi_(Rtmp, backedge_count, overflow_frequency-1);
bne(CCR0, did_not_overflow);
}
// Overflow in loop, pass branch bytecode.
- call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), branch_bcp, true);
+ subf(R4_ARG2, disp, target_bcp); // Compute branch bytecode (previous bcp).
+ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), R4_ARG2, true);
// Was an OSR adapter generated?
- // O0 = osr nmethod
cmpdi(CCR0, R3_RET, 0);
beq(CCR0, overflow_with_error);
@@ -1324,7 +1316,7 @@
assert_different_registers(Rdst, Rtmp1);
const Register invocation_counter = Rtmp1;
const Register counter = Rdst;
- // TODO ppc port assert(4 == InvocationCounter::sz_counter(), "unexpected field size.");
+ // TODO: PPC port: assert(4 == InvocationCounter::sz_counter(), "unexpected field size.");
// Load backedge counter.
lwz(counter, in_bytes(MethodCounters::backedge_counter_offset()) +
@@ -1337,8 +1329,7 @@
addi(counter, counter, InvocationCounter::count_increment);
// Mask the invocation counter.
- li(Rscratch, InvocationCounter::count_mask_value);
- andr(invocation_counter, invocation_counter, Rscratch);
+ andi(invocation_counter, invocation_counter, InvocationCounter::count_mask_value);
// Store new counter value.
stw(counter, in_bytes(MethodCounters::backedge_counter_offset()) +
@@ -1817,15 +1808,13 @@
test_method_data_pointer(profile_continue);
if (MethodData::profile_return_jsr292_only()) {
- assert(Method::intrinsic_id_size_in_bytes() == 2, "assuming Method::_intrinsic_id is u2");
-
// If we don't profile all invoke bytecodes we must make sure
// it's a bytecode we indeed profile. We can't go back to the
// begining of the ProfileData we intend to update to check its
// type because we're right after it and we don't known its
// length.
lbz(tmp1, 0, R14_bcp);
- lhz(tmp2, Method::intrinsic_id_offset_in_bytes(), R19_method);
+ lbz(tmp2, Method::intrinsic_id_offset_in_bytes(), R19_method);
cmpwi(CCR0, tmp1, Bytecodes::_invokedynamic);
cmpwi(CCR1, tmp1, Bytecodes::_invokehandle);
cror(CCR0, Assembler::equal, CCR1, Assembler::equal);
@@ -2207,9 +2196,7 @@
// Load the backedge counter.
lwz(backedge_count, be_counter_offset, Rcounters); // is unsigned int
// Mask the backedge counter.
- Register tmp = invocation_count;
- li(tmp, InvocationCounter::count_mask_value);
- andr(backedge_count, tmp, backedge_count); // Cannot use andi, need sign extension of count_mask_value.
+ andi(backedge_count, backedge_count, InvocationCounter::count_mask_value);
// Load the invocation counter.
lwz(invocation_count, inv_counter_offset, Rcounters); // is unsigned int
@@ -2266,7 +2253,7 @@
bne(CCR0, test);
address fd = CAST_FROM_FN_PTR(address, verify_return_address);
- const int nbytes_save = 11*8; // volatile gprs except R0
+ const int nbytes_save = MacroAssembler::num_volatile_regs * 8;
save_volatile_gprs(R1_SP, -nbytes_save); // except R0
save_LR_CR(Rtmp); // Save in old frame.
push_frame_reg_args(nbytes_save, Rtmp);
--- a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -203,7 +203,7 @@
void restore_interpreter_state(Register scratch, bool bcp_and_mdx_only = false);
void increment_backedge_counter(const Register Rcounters, Register Rtmp, Register Rtmp2, Register Rscratch);
- void test_backedge_count_for_osr(Register backedge_count, Register branch_bcp, Register Rtmp);
+ void test_backedge_count_for_osr(Register backedge_count, Register method_counters, Register target_bcp, Register disp, Register Rtmp);
void record_static_call_in_profile(Register Rentry, Register Rtmp);
void record_receiver_call_in_profile(Register Rklass, Register Rentry, Register Rtmp);
@@ -222,7 +222,7 @@
void set_method_data_pointer_for_bcp();
void test_method_data_pointer(Label& zero_continue);
void verify_method_data_pointer();
- void test_invocation_counter_for_mdp(Register invocation_count, Register Rscratch, Label &profile_continue);
+ void test_invocation_counter_for_mdp(Register invocation_count, Register method_counters, Register Rscratch, Label &profile_continue);
void set_mdp_data_at(int constant, Register value);
--- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -30,6 +30,7 @@
#include "gc/shared/collectedHeap.inline.hpp"
#include "interpreter/interpreter.hpp"
#include "memory/resourceArea.hpp"
+#include "nativeInst_ppc.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/biasedLocking.hpp"
#include "runtime/icache.hpp"
@@ -114,7 +115,7 @@
}
if (hi16) {
- addis(dst, R29, MacroAssembler::largeoffset_si16_si16_hi(offset));
+ addis(dst, R29_TOC, MacroAssembler::largeoffset_si16_si16_hi(offset));
}
if (lo16) {
if (add_relocation) {
@@ -256,7 +257,9 @@
}
#endif // _LP64
-void MacroAssembler::load_const_from_method_toc(Register dst, AddressLiteral& a, Register toc) {
+// Returns true if successful.
+bool MacroAssembler::load_const_from_method_toc(Register dst, AddressLiteral& a,
+ Register toc, bool fixed_size) {
int toc_offset = 0;
// Use RelocationHolder::none for the constant pool entry, otherwise
// we will end up with a failing NativeCall::verify(x) where x is
@@ -264,11 +267,13 @@
// FIXME: We should insert relocation information for oops at the constant
// pool entries instead of inserting it at the loads; patching of a constant
// pool entry should be less expensive.
- address oop_address = address_constant((address)a.value(), RelocationHolder::none);
+ address const_address = address_constant((address)a.value(), RelocationHolder::none);
+ if (const_address == NULL) { return false; } // allocation failure
// Relocate at the pc of the load.
relocate(a.rspec());
- toc_offset = (int)(oop_address - code()->consts()->start());
- ld_largeoffset_unchecked(dst, toc_offset, toc, true);
+ toc_offset = (int)(const_address - code()->consts()->start());
+ ld_largeoffset_unchecked(dst, toc_offset, toc, fixed_size);
+ return true;
}
bool MacroAssembler::is_load_const_from_method_toc_at(address a) {
@@ -446,6 +451,15 @@
assert(dest.is_bound() || target_pc == b_pc, "postcondition");
}
+// 1 or 2 instructions
+void MacroAssembler::bc_far_optimized(int boint, int biint, Label& dest) {
+ if (dest.is_bound() && is_within_range_of_bcxx(target(dest), pc())) {
+ bc(boint, biint, dest);
+ } else {
+ bc_far(boint, biint, dest, MacroAssembler::bc_far_optimize_on_relocate);
+ }
+}
+
bool MacroAssembler::is_bc_far_at(address instruction_addr) {
return is_bc_far_variant1_at(instruction_addr) ||
is_bc_far_variant2_at(instruction_addr) ||
@@ -496,7 +510,7 @@
// variant 1, the 1st instruction contains the destination address:
//
// bcxx DEST
- // endgroup
+ // nop
//
const int instruction_1 = *(int*)(instruction_addr);
boint = inv_bo_field(instruction_1);
@@ -523,10 +537,10 @@
// variant 1:
//
// bcxx DEST
- // endgroup
+ // nop
//
masm.bc(boint, biint, dest);
- masm.endgroup();
+ masm.nop();
} else {
// variant 2:
//
@@ -810,7 +824,22 @@
std(R9, offset, dst); offset += 8;
std(R10, offset, dst); offset += 8;
std(R11, offset, dst); offset += 8;
- std(R12, offset, dst);
+ std(R12, offset, dst); offset += 8;
+
+ stfd(F0, offset, dst); offset += 8;
+ stfd(F1, offset, dst); offset += 8;
+ stfd(F2, offset, dst); offset += 8;
+ stfd(F3, offset, dst); offset += 8;
+ stfd(F4, offset, dst); offset += 8;
+ stfd(F5, offset, dst); offset += 8;
+ stfd(F6, offset, dst); offset += 8;
+ stfd(F7, offset, dst); offset += 8;
+ stfd(F8, offset, dst); offset += 8;
+ stfd(F9, offset, dst); offset += 8;
+ stfd(F10, offset, dst); offset += 8;
+ stfd(F11, offset, dst); offset += 8;
+ stfd(F12, offset, dst); offset += 8;
+ stfd(F13, offset, dst);
}
// For verify_oops.
@@ -825,7 +854,22 @@
ld(R9, offset, src); offset += 8;
ld(R10, offset, src); offset += 8;
ld(R11, offset, src); offset += 8;
- ld(R12, offset, src);
+ ld(R12, offset, src); offset += 8;
+
+ lfd(F0, offset, src); offset += 8;
+ lfd(F1, offset, src); offset += 8;
+ lfd(F2, offset, src); offset += 8;
+ lfd(F3, offset, src); offset += 8;
+ lfd(F4, offset, src); offset += 8;
+ lfd(F5, offset, src); offset += 8;
+ lfd(F6, offset, src); offset += 8;
+ lfd(F7, offset, src); offset += 8;
+ lfd(F8, offset, src); offset += 8;
+ lfd(F9, offset, src); offset += 8;
+ lfd(F10, offset, src); offset += 8;
+ lfd(F11, offset, src); offset += 8;
+ lfd(F12, offset, src); offset += 8;
+ lfd(F13, offset, src);
}
void MacroAssembler::save_LR_CR(Register tmp) {
@@ -908,7 +952,7 @@
if (is_simm(-offset, 16)) {
stdu(R1_SP, -offset, R1_SP);
} else {
- load_const(tmp, -offset);
+ load_const_optimized(tmp, -offset);
stdux(R1_SP, R1_SP, tmp);
}
}
@@ -1090,20 +1134,21 @@
assert(fd->entry() != NULL, "function must be linked");
AddressLiteral fd_entry(fd->entry());
- load_const_from_method_toc(R11, fd_entry, toc);
+ bool success = load_const_from_method_toc(R11, fd_entry, toc, /*fixed_size*/ true);
mtctr(R11);
if (fd->env() == NULL) {
li(R11, 0);
nop();
} else {
AddressLiteral fd_env(fd->env());
- load_const_from_method_toc(R11, fd_env, toc);
+ success = success && load_const_from_method_toc(R11, fd_env, toc, /*fixed_size*/ true);
}
AddressLiteral fd_toc(fd->toc());
- load_toc_from_toc(R2_TOC, fd_toc, toc);
- // R2_TOC is killed.
+ // Set R2_TOC (load from toc)
+ success = success && load_const_from_method_toc(R2_TOC, fd_toc, toc, /*fixed_size*/ true);
bctrl();
_last_calls_return_pc = pc();
+ if (!success) { return NULL; }
} else {
// It's a friend function, load the entry point and don't care about
// toc and env. Use an optimizable call instruction, but ensure the
@@ -1367,11 +1412,6 @@
bool preset_result_reg = (int_flag_success != dest_current_value && int_flag_success != compare_value &&
int_flag_success != exchange_value && int_flag_success != addr_base);
- // release/fence semantics
- if (semantics & MemBarRel) {
- release();
- }
-
if (use_result_reg && preset_result_reg) {
li(int_flag_success, 0); // preset (assume cas failed)
}
@@ -1383,6 +1423,11 @@
bne(flag, failed);
}
+ // release/fence semantics
+ if (semantics & MemBarRel) {
+ release();
+ }
+
// atomic emulation loop
bind(retry);
@@ -1462,11 +1507,6 @@
int_flag_success!=exchange_value && int_flag_success!=addr_base);
assert(int_flag_success == noreg || failed_ext == NULL, "cannot have both");
- // release/fence semantics
- if (semantics & MemBarRel) {
- release();
- }
-
if (use_result_reg && preset_result_reg) {
li(int_flag_success, 0); // preset (assume cas failed)
}
@@ -1478,6 +1518,11 @@
bne(flag, failed);
}
+ // release/fence semantics
+ if (semantics & MemBarRel) {
+ release();
+ }
+
// atomic emulation loop
bind(retry);
@@ -1501,8 +1546,6 @@
li(int_flag_success, 1);
}
- // POWER6 doesn't need isync in CAS.
- // Always emit isync to be on the safe side.
if (semantics & MemBarFenceAfter) {
fence();
} else if (semantics & MemBarAcq) {
@@ -1627,13 +1670,14 @@
}
/////////////////////////////////////////// subtype checking ////////////////////////////////////////////
-
void MacroAssembler::check_klass_subtype_fast_path(Register sub_klass,
Register super_klass,
Register temp1_reg,
Register temp2_reg,
- Label& L_success,
- Label& L_failure) {
+ Label* L_success,
+ Label* L_failure,
+ Label* L_slow_path,
+ RegisterOrConstant super_check_offset) {
const Register check_cache_offset = temp1_reg;
const Register cached_super = temp2_reg;
@@ -1643,6 +1687,18 @@
int sco_offset = in_bytes(Klass::super_check_offset_offset());
int sc_offset = in_bytes(Klass::secondary_super_cache_offset());
+ bool must_load_sco = (super_check_offset.constant_or_zero() == -1);
+ bool need_slow_path = (must_load_sco || super_check_offset.constant_or_zero() == sco_offset);
+
+ Label L_fallthrough;
+ int label_nulls = 0;
+ if (L_success == NULL) { L_success = &L_fallthrough; label_nulls++; }
+ if (L_failure == NULL) { L_failure = &L_fallthrough; label_nulls++; }
+ if (L_slow_path == NULL) { L_slow_path = &L_fallthrough; label_nulls++; }
+ assert(label_nulls <= 1 ||
+ (L_slow_path == &L_fallthrough && label_nulls <= 2 && !need_slow_path),
+ "at most one NULL in the batch, usually");
+
// If the pointers are equal, we are done (e.g., String[] elements).
// This self-check enables sharing of secondary supertype arrays among
// non-primary types such as array-of-interface. Otherwise, each such
@@ -1651,15 +1707,20 @@
// type checks are in fact trivially successful in this manner,
// so we get a nicely predicted branch right at the start of the check.
cmpd(CCR0, sub_klass, super_klass);
- beq(CCR0, L_success);
+ beq(CCR0, *L_success);
// Check the supertype display:
+ if (must_load_sco) {
+ // The super check offset is always positive...
lwz(check_cache_offset, sco_offset, super_klass);
+ super_check_offset = RegisterOrConstant(check_cache_offset);
+ // super_check_offset is register.
+ assert_different_registers(sub_klass, super_klass, cached_super, super_check_offset.as_register());
+ }
// The loaded value is the offset from KlassOopDesc.
- ldx(cached_super, check_cache_offset, sub_klass);
+ ld(cached_super, super_check_offset, sub_klass);
cmpd(CCR0, cached_super, super_klass);
- beq(CCR0, L_success);
// This check has worked decisively for primary supers.
// Secondary supers are sought in the super_cache ('super_cache_addr').
@@ -1672,9 +1733,39 @@
// So if it was a primary super, we can just fail immediately.
// Otherwise, it's the slow path for us (no success at this point).
- cmpwi(CCR0, check_cache_offset, sc_offset);
- bne(CCR0, L_failure);
- // bind(slow_path); // fallthru
+#define FINAL_JUMP(label) if (&(label) != &L_fallthrough) { b(label); }
+
+ if (super_check_offset.is_register()) {
+ beq(CCR0, *L_success);
+ cmpwi(CCR0, super_check_offset.as_register(), sc_offset);
+ if (L_failure == &L_fallthrough) {
+ beq(CCR0, *L_slow_path);
+ } else {
+ bne(CCR0, *L_failure);
+ FINAL_JUMP(*L_slow_path);
+ }
+ } else {
+ if (super_check_offset.as_constant() == sc_offset) {
+ // Need a slow path; fast failure is impossible.
+ if (L_slow_path == &L_fallthrough) {
+ beq(CCR0, *L_success);
+ } else {
+ bne(CCR0, *L_slow_path);
+ FINAL_JUMP(*L_success);
+ }
+ } else {
+ // No slow path; it's a fast decision.
+ if (L_failure == &L_fallthrough) {
+ beq(CCR0, *L_success);
+ } else {
+ bne(CCR0, *L_failure);
+ FINAL_JUMP(*L_success);
+ }
+ }
+ }
+
+ bind(L_fallthrough);
+#undef FINAL_JUMP
}
void MacroAssembler::check_klass_subtype_slow_path(Register sub_klass,
@@ -1698,7 +1789,7 @@
ld(array_ptr, source_offset, sub_klass);
- //assert(4 == arrayOopDesc::length_length_in_bytes(), "precondition violated.");
+ // TODO: PPC port: assert(4 == arrayOopDesc::length_length_in_bytes(), "precondition violated.");
lwz(temp, length_offset, array_ptr);
cmpwi(CCR0, temp, 0);
beq(CCR0, result_reg!=noreg ? failure : fallthru); // length 0
@@ -1719,8 +1810,9 @@
bind(hit);
std(super_klass, target_offset, sub_klass); // save result to cache
- if (result_reg != noreg) li(result_reg, 0); // load zero result (indicates a hit)
- if (L_success != NULL) b(*L_success);
+ if (result_reg != noreg) { li(result_reg, 0); } // load zero result (indicates a hit)
+ if (L_success != NULL) { b(*L_success); }
+ else if (result_reg == noreg) { blr(); } // return with CR0.eq if neither label nor result reg provided
bind(fallthru);
}
@@ -1732,7 +1824,7 @@
Register temp2_reg,
Label& L_success) {
Label L_failure;
- check_klass_subtype_fast_path(sub_klass, super_klass, temp1_reg, temp2_reg, L_success, L_failure);
+ check_klass_subtype_fast_path(sub_klass, super_klass, temp1_reg, temp2_reg, &L_success, &L_failure);
check_klass_subtype_slow_path(sub_klass, super_klass, temp1_reg, temp2_reg, &L_success);
bind(L_failure); // Fallthru if not successful.
}
@@ -1765,6 +1857,7 @@
}
}
+// Supports temp2_reg = R0.
void MacroAssembler::biased_locking_enter(ConditionRegister cr_reg, Register obj_reg,
Register mark_reg, Register temp_reg,
Register temp2_reg, Label& done, Label* slow_case) {
@@ -1788,10 +1881,10 @@
"biased locking makes assumptions about bit layout");
if (PrintBiasedLockingStatistics) {
- load_const(temp_reg, (address) BiasedLocking::total_entry_count_addr(), temp2_reg);
- lwz(temp2_reg, 0, temp_reg);
- addi(temp2_reg, temp2_reg, 1);
- stw(temp2_reg, 0, temp_reg);
+ load_const(temp2_reg, (address) BiasedLocking::total_entry_count_addr(), temp_reg);
+ lwzx(temp_reg, temp2_reg);
+ addi(temp_reg, temp_reg, 1);
+ stwx(temp_reg, temp2_reg);
}
andi(temp_reg, mark_reg, markOopDesc::biased_lock_mask_in_place);
@@ -1809,10 +1902,10 @@
if (PrintBiasedLockingStatistics) {
Label l;
bne(cr_reg, l);
- load_const(mark_reg, (address) BiasedLocking::biased_lock_entry_count_addr());
- lwz(temp2_reg, 0, mark_reg);
- addi(temp2_reg, temp2_reg, 1);
- stw(temp2_reg, 0, mark_reg);
+ load_const(temp2_reg, (address) BiasedLocking::biased_lock_entry_count_addr());
+ lwzx(mark_reg, temp2_reg);
+ addi(mark_reg, mark_reg, 1);
+ stwx(mark_reg, temp2_reg);
// restore mark_reg
ld(mark_reg, oopDesc::mark_offset_in_bytes(), obj_reg);
bind(l);
@@ -1878,10 +1971,10 @@
// need to revoke that bias. The revocation will occur in the
// interpreter runtime in the slow case.
if (PrintBiasedLockingStatistics) {
- load_const(temp_reg, (address) BiasedLocking::anonymously_biased_lock_entry_count_addr(), temp2_reg);
- lwz(temp2_reg, 0, temp_reg);
- addi(temp2_reg, temp2_reg, 1);
- stw(temp2_reg, 0, temp_reg);
+ load_const(temp2_reg, (address) BiasedLocking::anonymously_biased_lock_entry_count_addr(), temp_reg);
+ lwzx(temp_reg, temp2_reg);
+ addi(temp_reg, temp_reg, 1);
+ stwx(temp_reg, temp2_reg);
}
b(done);
@@ -1892,15 +1985,14 @@
// value as the comparison value when doing the cas to acquire the
// bias in the current epoch. In other words, we allow transfer of
// the bias from one thread to another directly in this situation.
- andi(temp_reg, mark_reg, markOopDesc::age_mask_in_place);
- orr(temp_reg, R16_thread, temp_reg);
- load_klass(temp2_reg, obj_reg);
- ld(temp2_reg, in_bytes(Klass::prototype_header_offset()), temp2_reg);
- orr(temp_reg, temp_reg, temp2_reg);
+ load_klass(temp_reg, obj_reg);
+ andi(temp2_reg, mark_reg, markOopDesc::age_mask_in_place);
+ orr(temp2_reg, R16_thread, temp2_reg);
+ ld(temp_reg, in_bytes(Klass::prototype_header_offset()), temp_reg);
+ orr(temp_reg, temp2_reg, temp_reg);
assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0");
- // CmpxchgX sets cr_reg to cmpX(temp2_reg, mark_reg).
cmpxchgd(/*flag=*/cr_reg, /*current_value=*/temp2_reg,
/*compare_value=*/mark_reg, /*exchange_value=*/temp_reg,
/*where=*/obj_reg,
@@ -1913,10 +2005,10 @@
// need to revoke that bias. The revocation will occur in the
// interpreter runtime in the slow case.
if (PrintBiasedLockingStatistics) {
- load_const(temp_reg, (address) BiasedLocking::rebiased_lock_entry_count_addr(), temp2_reg);
- lwz(temp2_reg, 0, temp_reg);
- addi(temp2_reg, temp2_reg, 1);
- stw(temp2_reg, 0, temp_reg);
+ load_const(temp2_reg, (address) BiasedLocking::rebiased_lock_entry_count_addr(), temp_reg);
+ lwzx(temp_reg, temp2_reg);
+ addi(temp_reg, temp_reg, 1);
+ stwx(temp_reg, temp2_reg);
}
b(done);
@@ -1952,10 +2044,10 @@
if (PrintBiasedLockingStatistics) {
Label l;
bne(cr_reg, l);
- load_const(temp_reg, (address) BiasedLocking::revoked_lock_entry_count_addr(), temp2_reg);
- lwz(temp2_reg, 0, temp_reg);
- addi(temp2_reg, temp2_reg, 1);
- stw(temp2_reg, 0, temp_reg);
+ load_const(temp2_reg, (address) BiasedLocking::revoked_lock_entry_count_addr(), temp_reg);
+ lwzx(temp_reg, temp2_reg);
+ addi(temp_reg, temp_reg, 1);
+ stwx(temp_reg, temp2_reg);
bind(l);
}
@@ -1977,6 +2069,109 @@
beq(cr_reg, done);
}
+// allocation (for C1)
+void MacroAssembler::eden_allocate(
+ Register obj, // result: pointer to object after successful allocation
+ Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
+ int con_size_in_bytes, // object size in bytes if known at compile time
+ Register t1, // temp register
+ Register t2, // temp register
+ Label& slow_case // continuation point if fast allocation fails
+) {
+ b(slow_case);
+}
+
+void MacroAssembler::tlab_allocate(
+ Register obj, // result: pointer to object after successful allocation
+ Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
+ int con_size_in_bytes, // object size in bytes if known at compile time
+ Register t1, // temp register
+ Label& slow_case // continuation point if fast allocation fails
+) {
+ // make sure arguments make sense
+ assert_different_registers(obj, var_size_in_bytes, t1);
+ assert(0 <= con_size_in_bytes && is_simm13(con_size_in_bytes), "illegal object size");
+ assert((con_size_in_bytes & MinObjAlignmentInBytesMask) == 0, "object size is not multiple of alignment");
+
+ const Register new_top = t1;
+ //verify_tlab(); not implemented
+
+ ld(obj, in_bytes(JavaThread::tlab_top_offset()), R16_thread);
+ ld(R0, in_bytes(JavaThread::tlab_end_offset()), R16_thread);
+ if (var_size_in_bytes == noreg) {
+ addi(new_top, obj, con_size_in_bytes);
+ } else {
+ add(new_top, obj, var_size_in_bytes);
+ }
+ cmpld(CCR0, new_top, R0);
+ bc_far_optimized(Assembler::bcondCRbiIs1, bi0(CCR0, Assembler::greater), slow_case);
+
+#ifdef ASSERT
+ // make sure new free pointer is properly aligned
+ {
+ Label L;
+ andi_(R0, new_top, MinObjAlignmentInBytesMask);
+ beq(CCR0, L);
+ stop("updated TLAB free is not properly aligned", 0x934);
+ bind(L);
+ }
+#endif // ASSERT
+
+ // update the tlab top pointer
+ std(new_top, in_bytes(JavaThread::tlab_top_offset()), R16_thread);
+ //verify_tlab(); not implemented
+}
+void MacroAssembler::tlab_refill(Label& retry_tlab, Label& try_eden, Label& slow_case) {
+ unimplemented("tlab_refill");
+}
+void MacroAssembler::incr_allocated_bytes(RegisterOrConstant size_in_bytes, Register t1, Register t2) {
+ unimplemented("incr_allocated_bytes");
+}
+
+address MacroAssembler::emit_trampoline_stub(int destination_toc_offset,
+ int insts_call_instruction_offset, Register Rtoc) {
+ // Start the stub.
+ address stub = start_a_stub(64);
+ if (stub == NULL) { return NULL; } // CodeCache full: bail out
+
+ // Create a trampoline stub relocation which relates this trampoline stub
+ // with the call instruction at insts_call_instruction_offset in the
+ // instructions code-section.
+ relocate(trampoline_stub_Relocation::spec(code()->insts()->start() + insts_call_instruction_offset));
+ const int stub_start_offset = offset();
+
+ // For java_to_interp stubs we use R11_scratch1 as scratch register
+ // and in call trampoline stubs we use R12_scratch2. This way we
+ // can distinguish them (see is_NativeCallTrampolineStub_at()).
+ Register reg_scratch = R12_scratch2;
+
+ // Now, create the trampoline stub's code:
+ // - load the TOC
+ // - load the call target from the constant pool
+ // - call
+ if (Rtoc == noreg) {
+ calculate_address_from_global_toc(reg_scratch, method_toc());
+ Rtoc = reg_scratch;
+ }
+
+ ld_largeoffset_unchecked(reg_scratch, destination_toc_offset, Rtoc, false);
+ mtctr(reg_scratch);
+ bctr();
+
+ const address stub_start_addr = addr_at(stub_start_offset);
+
+ // Assert that the encoded destination_toc_offset can be identified and that it is correct.
+ assert(destination_toc_offset == NativeCallTrampolineStub_at(stub_start_addr)->destination_toc_offset(),
+ "encoded offset into the constant pool must match");
+ // Trampoline_stub_size should be good.
+ assert((uint)(offset() - stub_start_offset) <= trampoline_stub_size, "should be good size");
+ assert(is_NativeCallTrampolineStub_at(stub_start_addr), "doesn't look like a trampoline");
+
+ // End the stub.
+ end_a_stub();
+ return stub;
+}
+
// TM on PPC64.
void MacroAssembler::atomic_inc_ptr(Register addr, Register result, int simm16) {
Label retry;
@@ -2387,17 +2582,16 @@
// Must fence, otherwise, preceding store(s) may float below cmpxchg.
// Compare object markOop with mark and if equal exchange scratch1 with object markOop.
- // CmpxchgX sets cr_reg to cmpX(current, displaced).
- membar(Assembler::StoreStore);
cmpxchgd(/*flag=*/flag,
/*current_value=*/current_header,
/*compare_value=*/displaced_header,
/*exchange_value=*/box,
/*where=*/oop,
- MacroAssembler::MemBarAcq,
+ MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq,
MacroAssembler::cmpxchgx_hint_acquire_lock(),
noreg,
- &cas_failed);
+ &cas_failed,
+ /*check without membar and ldarx first*/true);
assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0");
// If the compare-and-exchange succeeded, then we found an unlocked
@@ -2410,8 +2604,7 @@
// Check if the owner is self by comparing the value in the markOop of object
// (current_header) with the stack pointer.
sub(current_header, current_header, R1_SP);
- load_const_optimized(temp, (address) (~(os::vm_page_size()-1) |
- markOopDesc::lock_mask_in_place));
+ load_const_optimized(temp, ~(os::vm_page_size()-1) | markOopDesc::lock_mask_in_place);
and_(R0/*==0?*/, current_header, temp);
// If condition is true we are cont and hence we can store 0 as the
@@ -2437,8 +2630,6 @@
// Try to CAS m->owner from NULL to current thread.
addi(temp, displaced_header, ObjectMonitor::owner_offset_in_bytes()-markOopDesc::monitor_value);
- li(displaced_header, 0);
- // CmpxchgX sets flag to cmpX(current, displaced).
cmpxchgd(/*flag=*/flag,
/*current_value=*/current_header,
/*compare_value=*/(intptr_t)0,
@@ -2928,31 +3119,12 @@
}
}
-void MacroAssembler::load_klass_with_trap_null_check(Register dst, Register src) {
- if (!os::zero_page_read_protected()) {
- if (TrapBasedNullChecks) {
- trap_null_check(src);
- }
- }
- load_klass(dst, src);
-}
-
-void MacroAssembler::reinit_heapbase(Register d, Register tmp) {
- if (Universe::heap() != NULL) {
- load_const_optimized(R30, Universe::narrow_ptrs_base(), tmp);
- } else {
- // Heap not yet allocated. Load indirectly.
- int simm16_offset = load_const_optimized(R30, Universe::narrow_ptrs_base_addr(), tmp, true);
- ld(R30, simm16_offset, R30);
- }
-}
-
// Clear Array
// Kills both input registers. tmp == R0 is allowed.
void MacroAssembler::clear_memory_doubleword(Register base_ptr, Register cnt_dwords, Register tmp) {
// Procedure for large arrays (uses data cache block zero instruction).
Label startloop, fast, fastloop, small_rest, restloop, done;
- const int cl_size = VM_Version::get_cache_line_size(),
+ const int cl_size = VM_Version::L1_data_cache_line_size(),
cl_dwords = cl_size>>3,
cl_dw_addr_bits = exact_log2(cl_dwords),
dcbz_min = 1; // Min count of dcbz executions, needs to be >0.
@@ -4025,7 +4197,7 @@
bind(L_check_1);
addi(idx, idx, 0x2);
- andi_(idx, idx, 0x1) ;
+ andi_(idx, idx, 0x1);
addic_(idx, idx, -1);
blt(CCR0, L_post_third_loop_done);
@@ -4255,17 +4427,42 @@
address/* FunctionDescriptor** */fd = StubRoutines::verify_oop_subroutine_entry_address();
const Register tmp = R11; // Will be preserved.
- const int nbytes_save = 11*8; // Volatile gprs except R0.
+ const int nbytes_save = MacroAssembler::num_volatile_regs * 8;
save_volatile_gprs(R1_SP, -nbytes_save); // except R0
- if (oop == tmp) mr(R4_ARG2, oop);
+ mr_if_needed(R4_ARG2, oop);
save_LR_CR(tmp); // save in old frame
push_frame_reg_args(nbytes_save, tmp);
// load FunctionDescriptor** / entry_address *
load_const_optimized(tmp, fd, R0);
// load FunctionDescriptor* / entry_address
ld(tmp, 0, tmp);
- if (oop != tmp) mr_if_needed(R4_ARG2, oop);
+ load_const_optimized(R3_ARG1, (address)msg, R0);
+ // Call destination for its side effect.
+ call_c(tmp);
+
+ pop_frame();
+ restore_LR_CR(tmp);
+ restore_volatile_gprs(R1_SP, -nbytes_save); // except R0
+}
+
+void MacroAssembler::verify_oop_addr(RegisterOrConstant offs, Register base, const char* msg) {
+ if (!VerifyOops) {
+ return;
+ }
+
+ address/* FunctionDescriptor** */fd = StubRoutines::verify_oop_subroutine_entry_address();
+ const Register tmp = R11; // Will be preserved.
+ const int nbytes_save = MacroAssembler::num_volatile_regs * 8;
+ save_volatile_gprs(R1_SP, -nbytes_save); // except R0
+
+ ld(R4_ARG2, offs, base);
+ save_LR_CR(tmp); // save in old frame
+ push_frame_reg_args(nbytes_save, tmp);
+ // load FunctionDescriptor** / entry_address *
+ load_const_optimized(tmp, fd, R0);
+ // load FunctionDescriptor* / entry_address
+ ld(tmp, 0, tmp);
load_const_optimized(R3_ARG1, (address)msg, R0);
// Call destination for its side effect.
call_c(tmp);
--- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -119,11 +119,8 @@
// Emits an oop const to the constant pool, loads the constant, and
// sets a relocation info with address current_pc.
- void load_const_from_method_toc(Register dst, AddressLiteral& a, Register toc);
- void load_toc_from_toc(Register dst, AddressLiteral& a, Register toc) {
- assert(dst == R2_TOC, "base register must be TOC");
- load_const_from_method_toc(dst, a, toc);
- }
+ // Returns true if successful.
+ bool load_const_from_method_toc(Register dst, AddressLiteral& a, Register toc, bool fixed_size = false);
static bool is_load_const_from_method_toc_at(address a);
static int get_offset_of_load_const_from_method_toc_at(address a);
@@ -174,6 +171,7 @@
// optimize: flag for telling the conditional far branch to optimize
// itself when relocated.
void bc_far(int boint, int biint, Label& dest, int optimize);
+ void bc_far_optimized(int boint, int biint, Label& dest); // 1 or 2 instructions
// Relocation of conditional far branches.
static bool is_bc_far_at(address instruction_addr);
static address get_dest_of_bc_far_at(address instruction_addr);
@@ -262,6 +260,7 @@
// some ABI-related functions
void save_nonvolatile_gprs( Register dst_base, int offset);
void restore_nonvolatile_gprs(Register src_base, int offset);
+ enum { num_volatile_regs = 11 + 14 }; // GPR + FPR
void save_volatile_gprs( Register dst_base, int offset);
void restore_volatile_gprs(Register src_base, int offset);
void save_LR_CR( Register tmp); // tmp contains LR on return.
@@ -461,8 +460,10 @@
Register super_klass,
Register temp1_reg,
Register temp2_reg,
- Label& L_success,
- Label& L_failure);
+ Label* L_success,
+ Label* L_failure,
+ Label* L_slow_path = NULL, // default fall through
+ RegisterOrConstant super_check_offset = RegisterOrConstant(-1));
// The rest of the type check; must be wired to a corresponding fast path.
// It does not repeat the fast path logic, so don't use it standalone.
@@ -507,6 +508,28 @@
// biased locking exit case failed.
void biased_locking_exit(ConditionRegister cr_reg, Register mark_addr, Register temp_reg, Label& done);
+ // allocation (for C1)
+ void eden_allocate(
+ Register obj, // result: pointer to object after successful allocation
+ Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
+ int con_size_in_bytes, // object size in bytes if known at compile time
+ Register t1, // temp register
+ Register t2, // temp register
+ Label& slow_case // continuation point if fast allocation fails
+ );
+ void tlab_allocate(
+ Register obj, // result: pointer to object after successful allocation
+ Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
+ int con_size_in_bytes, // object size in bytes if known at compile time
+ Register t1, // temp register
+ Label& slow_case // continuation point if fast allocation fails
+ );
+ void tlab_refill(Label& retry_tlab, Label& try_eden, Label& slow_case);
+ void incr_allocated_bytes(RegisterOrConstant size_in_bytes, Register t1, Register t2);
+
+ enum { trampoline_stub_size = 6 * 4 };
+ address emit_trampoline_stub(int destination_toc_offset, int insts_call_instruction_offset, Register Rtoc = noreg);
+
void atomic_inc_ptr(Register addr, Register result, int simm16 = 1);
void atomic_ori_int(Register addr, Register result, int uimm16);
@@ -597,9 +620,7 @@
// Implicit or explicit null check, jumps to static address exception_entry.
inline void null_check_throw(Register a, int offset, Register temp_reg, address exception_entry);
-
- // Check accessed object for null. Use SIGTRAP-based null checks on AIX.
- inline void load_with_trap_null_check(Register d, int si16, Register s1);
+ inline void null_check(Register a, int offset, Label *Lis_null); // implicit only if Lis_null not provided
// Load heap oop and decompress. Loaded oop may not be null.
// Specify tmp to save one cycle.
@@ -619,20 +640,17 @@
inline Register decode_heap_oop_not_null(Register d, Register src = noreg);
// Null allowed.
+ inline Register encode_heap_oop(Register d, Register src); // Prefer null check in GC barrier!
inline void decode_heap_oop(Register d);
// Load/Store klass oop from klass field. Compress.
void load_klass(Register dst, Register src);
- void load_klass_with_trap_null_check(Register dst, Register src);
void store_klass(Register dst_oop, Register klass, Register tmp = R0);
void store_klass_gap(Register dst_oop, Register val = noreg); // Will store 0 if val not specified.
static int instr_size_for_decode_klass_not_null();
void decode_klass_not_null(Register dst, Register src = noreg);
Register encode_klass_not_null(Register dst, Register src = noreg);
- // Load common heap base into register.
- void reinit_heapbase(Register d, Register tmp = noreg);
-
// SIGTRAP-based range checks for arrays.
inline void trap_range_check_l(Register a, Register b);
inline void trap_range_check_l(Register a, int si16);
@@ -750,6 +768,7 @@
// Emit code to verify that reg contains a valid oop if +VerifyOops is set.
void verify_oop(Register reg, const char* s = "broken oop");
+ void verify_oop_addr(RegisterOrConstant offs, Register base, const char* s = "contains broken oop");
// TODO: verify method and klass metadata (compare against vptr?)
void _verify_method_ptr(Register reg, const char * msg, const char * file, int line) {}
--- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -70,9 +70,11 @@
}
inline void MacroAssembler::membar(int bits) {
- // TODO: use elemental_membar(bits) for Power 8 and disable optimization of acquire-release
- // (Matcher::post_membar_release where we use PPC64_ONLY(xop == Op_MemBarRelease ||))
- if (bits & StoreLoad) sync(); else lwsync();
+ // Comment: Usage of elemental_membar(bits) is not recommended for Power 8.
+ // If elemental_membar(bits) is used, disable optimization of acquire-release
+ // (Matcher::post_membar_release where we use PPC64_ONLY(xop == Op_MemBarRelease ||))!
+ if (bits & StoreLoad) { sync(); }
+ else if (bits) { lwsync(); }
}
inline void MacroAssembler::release() { membar(LoadStore | StoreStore); }
inline void MacroAssembler::acquire() { membar(LoadLoad | LoadStore); }
@@ -86,7 +88,7 @@
// Offset of given address to the global TOC.
inline int MacroAssembler::offset_to_global_toc(const address addr) {
intptr_t offset = (intptr_t)addr - (intptr_t)MacroAssembler::global_toc();
- assert(Assembler::is_simm((long)offset, 31) && offset >= 0, "must be in range");
+ assert(Assembler::is_uimm((long)offset, 31), "must be in range");
return (int)offset;
}
@@ -98,7 +100,7 @@
// Offset of given address to current method's TOC.
inline int MacroAssembler::offset_to_method_toc(address addr) {
intptr_t offset = (intptr_t)addr - (intptr_t)method_toc();
- assert(is_simm((long)offset, 31) && offset >= 0, "must be in range");
+ assert(Assembler::is_uimm((long)offset, 31), "must be in range");
return (int)offset;
}
@@ -190,13 +192,13 @@
// Variant 1, the 1st instruction contains the destination address:
//
// bcxx DEST
- // endgroup
+ // nop
//
const int instruction_1 = *(int*)(instruction_addr);
const int instruction_2 = *(int*)(instruction_addr + 4);
return is_bcxx(instruction_1) &&
(inv_bd_field(instruction_1, (intptr_t)instruction_addr) != (intptr_t)(instruction_addr + 2*4)) &&
- is_endgroup(instruction_2);
+ is_nop(instruction_2);
}
// Relocation of conditional far branches.
@@ -302,13 +304,17 @@
}
}
-inline void MacroAssembler::load_with_trap_null_check(Register d, int si16, Register s1) {
- if (!os::zero_page_read_protected()) {
+inline void MacroAssembler::null_check(Register a, int offset, Label *Lis_null) {
+ if (!ImplicitNullChecks || needs_explicit_null_check(offset) || !os::zero_page_read_protected()) {
if (TrapBasedNullChecks) {
- trap_null_check(s1);
+ assert(UseSIGTRAP, "sanity");
+ trap_null_check(a);
+ } else if (Lis_null){
+ Label ok;
+ cmpdi(CCR0, a, 0);
+ beq(CCR0, *Lis_null);
}
}
- ld(d, si16, s1);
}
inline void MacroAssembler::load_heap_oop_not_null(Register d, RegisterOrConstant offs, Register s1, Register tmp) {
@@ -365,6 +371,26 @@
return current; // Encoded oop is in this register.
}
+inline Register MacroAssembler::encode_heap_oop(Register d, Register src) {
+ if (Universe::narrow_oop_base() != NULL) {
+ if (VM_Version::has_isel()) {
+ cmpdi(CCR0, src, 0);
+ Register co = encode_heap_oop_not_null(d, src);
+ assert(co == d, "sanity");
+ isel_0(d, CCR0, Assembler::equal);
+ } else {
+ Label isNull;
+ or_(d, src, src); // move and compare 0
+ beq(CCR0, isNull);
+ encode_heap_oop_not_null(d, src);
+ bind(isNull);
+ }
+ return d;
+ } else {
+ return encode_heap_oop_not_null(d, src);
+ }
+}
+
inline Register MacroAssembler::decode_heap_oop_not_null(Register d, Register src) {
if (Universe::narrow_oop_base_disjoint() && src != noreg && src != d &&
Universe::narrow_oop_shift() != 0) {
--- a/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -1,6 +1,6 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012, 2014 SAP AG. All rights reserved.
+ * Copyright 2012, 2015 SAP AG. 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
@@ -504,8 +504,7 @@
frame cur_frame = os::current_frame();
// Robust search of trace_calling_frame (independant of inlining).
- // Assumes saved_regs comes from a pusha in the trace_calling_frame.
- assert(cur_frame.sp() < saved_regs, "registers not saved on stack ?");
+ assert(cur_frame.sp() <= saved_regs, "registers not saved on stack ?");
frame trace_calling_frame = os::get_sender_for_C_frame(&cur_frame);
while (trace_calling_frame.fp() < saved_regs) {
trace_calling_frame = os::get_sender_for_C_frame(&trace_calling_frame);
@@ -539,7 +538,7 @@
BLOCK_COMMENT("trace_method_handle {");
const Register tmp = R11; // Will be preserved.
- const int nbytes_save = 11*8; // volatile gprs except R0
+ const int nbytes_save = MacroAssembler::num_volatile_regs * 8;
__ save_volatile_gprs(R1_SP, -nbytes_save); // except R0
__ save_LR_CR(tmp); // save in old frame
--- a/hotspot/src/cpu/ppc/vm/nativeInst_ppc.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/nativeInst_ppc.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012, 2014 SAP AG. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012, 2015 SAP AG. 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
@@ -65,13 +65,17 @@
address destination = Assembler::bxx_destination(addr);
// Do we use a trampoline stub for this call?
- CodeBlob* cb = CodeCache::find_blob_unsafe(addr); // Else we get assertion if nmethod is zombie.
- assert(cb && cb->is_nmethod(), "sanity");
- nmethod *nm = (nmethod *)cb;
- if (nm->stub_contains(destination) && is_NativeCallTrampolineStub_at(destination)) {
- // Yes we do, so get the destination from the trampoline stub.
- const address trampoline_stub_addr = destination;
- destination = NativeCallTrampolineStub_at(trampoline_stub_addr)->destination(nm);
+ // Trampoline stubs are located behind the main code.
+ if (destination > addr) {
+ // Filter out recursive method invocation (call to verified/unverified entry point).
+ CodeBlob* cb = CodeCache::find_blob_unsafe(addr); // Else we get assertion if nmethod is zombie.
+ assert(cb && cb->is_nmethod(), "sanity");
+ nmethod *nm = (nmethod *)cb;
+ if (nm->stub_contains(destination) && is_NativeCallTrampolineStub_at(destination)) {
+ // Yes we do, so get the destination from the trampoline stub.
+ const address trampoline_stub_addr = destination;
+ destination = NativeCallTrampolineStub_at(trampoline_stub_addr)->destination(nm);
+ }
}
return destination;
@@ -267,7 +271,7 @@
oop_addr = r->oop_addr();
*oop_addr = cast_to_oop(data);
} else {
- assert(oop_addr == r->oop_addr(), "must be only one set-oop here") ;
+ assert(oop_addr == r->oop_addr(), "must be only one set-oop here");
}
}
if (iter.type() == relocInfo::metadata_type) {
@@ -351,6 +355,27 @@
}
#endif // ASSERT
+
+void NativeGeneralJump::insert_unconditional(address code_pos, address entry) {
+ CodeBuffer cb(code_pos, BytesPerInstWord + 1);
+ MacroAssembler* a = new MacroAssembler(&cb);
+ a->b(entry);
+ ICache::ppc64_flush_icache_bytes(code_pos, NativeGeneralJump::instruction_size);
+}
+
+// MT-safe patching of a jmp instruction.
+void NativeGeneralJump::replace_mt_safe(address instr_addr, address code_buffer) {
+ // Bytes beyond offset NativeGeneralJump::instruction_size are copied by caller.
+
+ // Finally patch out the jump.
+ volatile juint *jump_addr = (volatile juint*)instr_addr;
+ // Release not needed because caller uses invalidate_range after copying the remaining bytes.
+ //OrderAccess::release_store(jump_addr, *((juint*)code_buffer));
+ *jump_addr = *((juint*)code_buffer); // atomically store code over branch instruction
+ ICache::ppc64_flush_icache_bytes(instr_addr, NativeGeneralJump::instruction_size);
+}
+
+
//-------------------------------------------------------------------
// Call trampoline stubs.
@@ -364,10 +389,12 @@
//
address NativeCallTrampolineStub::encoded_destination_addr() const {
- address instruction_addr = addr_at(2 * BytesPerInstWord);
- assert(MacroAssembler::is_ld_largeoffset(instruction_addr),
- "must be a ld with large offset (from the constant pool)");
-
+ address instruction_addr = addr_at(0 * BytesPerInstWord);
+ if (!MacroAssembler::is_ld_largeoffset(instruction_addr)) {
+ instruction_addr = addr_at(2 * BytesPerInstWord);
+ assert(MacroAssembler::is_ld_largeoffset(instruction_addr),
+ "must be a ld with large offset (from the constant pool)");
+ }
return instruction_addr;
}
--- a/hotspot/src/cpu/ppc/vm/nativeInst_ppc.hpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/nativeInst_ppc.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012, 2013 SAP AG. All rights reserved.
+ * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012, 2015 SAP AG. 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
@@ -50,6 +50,8 @@
friend class Relocation;
public:
+ bool is_jump() { return Assembler::is_b(long_at(0)); } // See NativeGeneralJump.
+
bool is_sigtrap_ic_miss_check() {
assert(UseSIGTRAP, "precondition");
return MacroAssembler::is_trap_ic_miss_check(long_at(0));
@@ -235,8 +237,8 @@
return call;
}
-// An interface for accessing/manipulating native set_oop imm, reg instructions.
-// (used to manipulate inlined data references, etc.)
+// An interface for accessing/manipulating native set_oop imm, reg instructions
+// (used to manipulate inlined data references, etc.).
class NativeMovConstReg: public NativeInstruction {
public:
@@ -384,10 +386,21 @@
void set_destination(address new_destination);
};
+// Note: Other stubs must not begin with this pattern.
inline bool is_NativeCallTrampolineStub_at(address address) {
int first_instr = *(int*)address;
- return Assembler::is_addis(first_instr) &&
- (Register)(intptr_t)Assembler::inv_rt_field(first_instr) == R12_scratch2;
+ // calculate_address_from_global_toc and long form of ld_largeoffset_unchecked begin with addis with target R12
+ if (Assembler::is_addis(first_instr) &&
+ (Register)(intptr_t)Assembler::inv_rt_field(first_instr) == R12_scratch2) return true;
+
+ // short form of ld_largeoffset_unchecked is ld which is followed by mtctr
+ int second_instr = *((int*)address + 1);
+ if (Assembler::is_ld(first_instr) &&
+ (Register)(intptr_t)Assembler::inv_rt_field(first_instr) == R12_scratch2 &&
+ Assembler::is_mtctr(second_instr) &&
+ (Register)(intptr_t)Assembler::inv_rs_field(second_instr) == R12_scratch2) return true;
+
+ return false;
}
inline NativeCallTrampolineStub* NativeCallTrampolineStub_at(address address) {
@@ -395,4 +408,102 @@
return (NativeCallTrampolineStub*)address;
}
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------------------------
+// N a t i v e G e n e r a l J u m p
+//-------------------------------------
+
+// Despite the name, handles only simple branches.
+class NativeGeneralJump;
+inline NativeGeneralJump* nativeGeneralJump_at(address address);
+
+// Currently only implemented as single unconditional branch.
+class NativeGeneralJump: public NativeInstruction {
+ public:
+
+ enum PPC64_specific_constants {
+ instruction_size = 4
+ };
+
+ address instruction_address() const { return addr_at(0); }
+
+ // Creation.
+ friend inline NativeGeneralJump* nativeGeneralJump_at(address addr) {
+ NativeGeneralJump* jump = (NativeGeneralJump*)(addr);
+ DEBUG_ONLY( jump->verify(); )
+ return jump;
+ }
+
+ // Insertion of native general jump instruction.
+ static void insert_unconditional(address code_pos, address entry);
+
+ address jump_destination() const {
+ DEBUG_ONLY( verify(); )
+ return addr_at(0) + Assembler::inv_li_field(long_at(0));
+ }
+
+ void set_jump_destination(address dest) {
+ DEBUG_ONLY( verify(); )
+ insert_unconditional(addr_at(0), dest);
+ }
+
+ static void replace_mt_safe(address instr_addr, address code_buffer);
+
+ void verify() const { guarantee(Assembler::is_b(long_at(0)), "invalid NativeGeneralJump"); }
+};
+
+// An interface for accessing/manipulating native load int (load_const32).
+class NativeMovRegMem;
+inline NativeMovRegMem* nativeMovRegMem_at(address address);
+class NativeMovRegMem: public NativeInstruction {
+ public:
+
+ enum PPC64_specific_constants {
+ instruction_size = 8
+ };
+
+ address instruction_address() const { return addr_at(0); }
+
+ intptr_t offset() const {
+#ifdef VM_LITTLE_ENDIAN
+ short *hi_ptr = (short*)(addr_at(0));
+ short *lo_ptr = (short*)(addr_at(4));
+#else
+ short *hi_ptr = (short*)(addr_at(0) + 2);
+ short *lo_ptr = (short*)(addr_at(4) + 2);
+#endif
+ return ((*hi_ptr) << 16) | ((*lo_ptr) & 0xFFFF);
+ }
+
+ void set_offset(intptr_t x) {
+#ifdef VM_LITTLE_ENDIAN
+ short *hi_ptr = (short*)(addr_at(0));
+ short *lo_ptr = (short*)(addr_at(4));
+#else
+ short *hi_ptr = (short*)(addr_at(0) + 2);
+ short *lo_ptr = (short*)(addr_at(4) + 2);
+#endif
+ *hi_ptr = x >> 16;
+ *lo_ptr = x & 0xFFFF;
+ ICache::ppc64_flush_icache_bytes(addr_at(0), NativeMovRegMem::instruction_size);
+ }
+
+ void add_offset_in_bytes(intptr_t radd_offset) {
+ set_offset(offset() + radd_offset);
+ }
+
+ void verify() const {
+ guarantee(Assembler::is_lis(long_at(0)), "load_const32 1st instr");
+ guarantee(Assembler::is_ori(long_at(4)), "load_const32 2nd instr");
+ }
+
+ private:
+ friend inline NativeMovRegMem* nativeMovRegMem_at(address address) {
+ NativeMovRegMem* test = (NativeMovRegMem*)address;
+ DEBUG_ONLY( test->verify(); )
+ return test;
+ }
+};
+
#endif // CPU_PPC_VM_NATIVEINST_PPC_HPP
--- a/hotspot/src/cpu/ppc/vm/ppc.ad Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/ppc.ad Fri Dec 04 23:50:05 2015 +0000
@@ -698,7 +698,7 @@
// ----------------------------
reg_class flt_reg(
-/*F0*/ // scratch
+ F0,
F1,
F2,
F3,
@@ -735,7 +735,7 @@
// Double precision float registers have virtual `high halves' that
// are needed by the allocator.
reg_class dbl_reg(
-/*F0, F0_H*/ // scratch
+ F0, F0_H,
F1, F1_H,
F2, F2_H,
F3, F3_H,
@@ -1040,8 +1040,6 @@
//---< Used for optimization in Compile::Shorten_branches >---
//--------------------------------------------------------------
-const uint trampoline_stub_size = 6 * BytesPerInstWord;
-
class CallStubImpl {
public:
@@ -1053,7 +1051,7 @@
// This doesn't need to be accurate to the byte, but it
// must be larger than or equal to the real size of the stub.
static uint size_call_trampoline() {
- return trampoline_stub_size;
+ return MacroAssembler::trampoline_stub_size;
}
// number of relocations needed by a call trampoline stub
@@ -1079,46 +1077,10 @@
// branch via CTR (LR/link still points to the call-site above)
void CallStubImpl::emit_trampoline_stub(MacroAssembler &_masm, int destination_toc_offset, int insts_call_instruction_offset) {
- // Start the stub.
- address stub = __ start_a_stub(Compile::MAX_stubs_size/2);
+ address stub = __ emit_trampoline_stub(destination_toc_offset, insts_call_instruction_offset);
if (stub == NULL) {
- ciEnv::current()->record_failure("CodeCache is full");
- return;
+ ciEnv::current()->record_out_of_memory_failure();
}
-
- // For java_to_interp stubs we use R11_scratch1 as scratch register
- // and in call trampoline stubs we use R12_scratch2. This way we
- // can distinguish them (see is_NativeCallTrampolineStub_at()).
- Register reg_scratch = R12_scratch2;
-
- // Create a trampoline stub relocation which relates this trampoline stub
- // with the call instruction at insts_call_instruction_offset in the
- // instructions code-section.
- __ relocate(trampoline_stub_Relocation::spec(__ code()->insts()->start() + insts_call_instruction_offset));
- const int stub_start_offset = __ offset();
-
- // Now, create the trampoline stub's code:
- // - load the TOC
- // - load the call target from the constant pool
- // - call
- __ calculate_address_from_global_toc(reg_scratch, __ method_toc());
- __ ld_largeoffset_unchecked(reg_scratch, destination_toc_offset, reg_scratch, false);
- __ mtctr(reg_scratch);
- __ bctr();
-
- const address stub_start_addr = __ addr_at(stub_start_offset);
-
- // FIXME: Assert that the trampoline stub can be identified and patched.
-
- // Assert that the encoded destination_toc_offset can be identified and that it is correct.
- assert(destination_toc_offset == NativeCallTrampolineStub_at(stub_start_addr)->destination_toc_offset(),
- "encoded offset into the constant pool must match");
- // Trampoline_stub_size should be good.
- assert((uint)(__ offset() - stub_start_offset) <= trampoline_stub_size, "should be good size");
- assert(is_NativeCallTrampolineStub_at(stub_start_addr), "doesn't look like a trampoline");
-
- // End the stub.
- __ end_a_stub();
}
//=============================================================================
@@ -1156,6 +1118,10 @@
if (!Compile::current()->in_scratch_emit_size()) {
// Put the entry point as a constant into the constant pool.
const address entry_point_toc_addr = __ address_constant(entry_point, RelocationHolder::none);
+ if (entry_point_toc_addr == NULL) {
+ ciEnv::current()->record_out_of_memory_failure();
+ return offsets;
+ }
const int entry_point_toc_offset = __ offset_to_method_toc(entry_point_toc_addr);
// Emit the trampoline stub which will be related to the branch-and-link below.
@@ -2474,6 +2440,10 @@
// Create a non-oop constant, no relocation needed.
// If it is an IC, it has a virtual_call_Relocation.
const_toc_addr = __ long_constant((jlong)$src$$constant);
+ if (const_toc_addr == NULL) {
+ ciEnv::current()->record_out_of_memory_failure();
+ return;
+ }
// Get the constant's TOC offset.
toc_offset = __ offset_to_method_toc(const_toc_addr);
@@ -2495,6 +2465,10 @@
// Create a non-oop constant, no relocation needed.
// If it is an IC, it has a virtual_call_Relocation.
const_toc_addr = __ long_constant((jlong)$src$$constant);
+ if (const_toc_addr == NULL) {
+ ciEnv::current()->record_out_of_memory_failure();
+ return;
+ }
// Get the constant's TOC offset.
const int toc_offset = __ offset_to_method_toc(const_toc_addr);
@@ -2631,6 +2605,10 @@
const_toc_addr = __ long_constant((jlong)$src$$constant);
}
+ if (const_toc_addr == NULL) {
+ ciEnv::current()->record_out_of_memory_failure();
+ return;
+ }
// Get the constant's TOC offset.
toc_offset = __ offset_to_method_toc(const_toc_addr);
}
@@ -2660,6 +2638,10 @@
const_toc_addr = __ long_constant((jlong)$src$$constant);
}
+ if (const_toc_addr == NULL) {
+ ciEnv::current()->record_out_of_memory_failure();
+ return;
+ }
// Get the constant's TOC offset.
const int toc_offset = __ offset_to_method_toc(const_toc_addr);
// Store the toc offset of the constant.
@@ -3408,13 +3390,19 @@
// Put the entry point as a constant into the constant pool.
const address entry_point_toc_addr = __ address_constant(entry_point, RelocationHolder::none);
+ if (entry_point_toc_addr == NULL) {
+ ciEnv::current()->record_out_of_memory_failure();
+ return;
+ }
const int entry_point_toc_offset = __ offset_to_method_toc(entry_point_toc_addr);
+
// Emit the trampoline stub which will be related to the branch-and-link below.
CallStubImpl::emit_trampoline_stub(_masm, entry_point_toc_offset, start_offset);
if (ciEnv::current()->failing()) { return; } // Code cache may be full.
- __ relocate(_optimized_virtual ?
- relocInfo::opt_virtual_call_type : relocInfo::static_call_type);
+ int method_index = resolved_method_index(cbuf);
+ __ relocate(_optimized_virtual ? opt_virtual_call_Relocate::spec(method_index)
+ : static_call_Relocate::spec(method_index));
}
// The real call.
@@ -3433,76 +3421,6 @@
}
%}
- // Emit a method handle call.
- //
- // Method handle calls from compiled to compiled are going thru a
- // c2i -> i2c adapter, extending the frame for their arguments. The
- // caller however, returns directly to the compiled callee, that has
- // to cope with the extended frame. We restore the original frame by
- // loading the callers sp and adding the calculated framesize.
- enc_class enc_java_handle_call(method meth) %{
- // TODO: PPC port $archOpcode(ppc64Opcode_compound);
-
- MacroAssembler _masm(&cbuf);
- address entry_point = (address)$meth$$method;
-
- // Remember the offset not the address.
- const int start_offset = __ offset();
- // The trampoline stub.
- if (!ra_->C->in_scratch_emit_size()) {
- // No entry point given, use the current pc.
- // Make sure branch fits into
- if (entry_point == 0) entry_point = __ pc();
-
- // Put the entry point as a constant into the constant pool.
- const address entry_point_toc_addr = __ address_constant(entry_point, RelocationHolder::none);
- const int entry_point_toc_offset = __ offset_to_method_toc(entry_point_toc_addr);
-
- // Emit the trampoline stub which will be related to the branch-and-link below.
- CallStubImpl::emit_trampoline_stub(_masm, entry_point_toc_offset, start_offset);
- if (ra_->C->env()->failing()) { return; } // Code cache may be full.
- assert(_optimized_virtual, "methodHandle call should be a virtual call");
- __ relocate(relocInfo::opt_virtual_call_type);
- }
-
- // The real call.
- // Note: At this point we do not have the address of the trampoline
- // stub, and the entry point might be too far away for bl, so __ pc()
- // serves as dummy and the bl will be patched later.
- cbuf.set_insts_mark();
- __ bl(__ pc()); // Emits a relocation.
-
- assert(_method, "execute next statement conditionally");
- // The stub for call to interpreter.
- address stub = CompiledStaticCall::emit_to_interp_stub(cbuf);
- if (stub == NULL) {
- ciEnv::current()->record_failure("CodeCache is full");
- return;
- }
-
- // Restore original sp.
- __ ld(R11_scratch1, 0, R1_SP); // Load caller sp.
- const long framesize = ra_->C->frame_slots() << LogBytesPerInt;
- unsigned int bytes = (unsigned int)framesize;
- long offset = Assembler::align_addr(bytes, frame::alignment_in_bytes);
- if (Assembler::is_simm(-offset, 16)) {
- __ addi(R1_SP, R11_scratch1, -offset);
- } else {
- __ load_const_optimized(R12_scratch2, -offset);
- __ add(R1_SP, R11_scratch1, R12_scratch2);
- }
-#ifdef ASSERT
- __ ld(R12_scratch2, 0, R1_SP); // Load from unextended_sp.
- __ cmpd(CCR0, R11_scratch1, R12_scratch2);
- __ asm_assert_eq("backlink changed", 0x8000);
-#endif
- // If fails should store backlink before unextending.
-
- if (ra_->C->env()->failing()) {
- return;
- }
- %}
-
// Second node of expanded dynamic call - the call.
enc_class enc_java_dynamic_call_sched(method meth) %{
// TODO: PPC port $archOpcode(ppc64Opcode_bl);
@@ -3513,6 +3431,10 @@
// Create a call trampoline stub for the given method.
const address entry_point = !($meth$$method) ? 0 : (address)$meth$$method;
const address entry_point_const = __ address_constant(entry_point, RelocationHolder::none);
+ if (entry_point_const == NULL) {
+ ciEnv::current()->record_out_of_memory_failure();
+ return;
+ }
const int entry_point_const_toc_offset = __ offset_to_method_toc(entry_point_const);
CallStubImpl::emit_trampoline_stub(_masm, entry_point_const_toc_offset, __ offset());
if (ra_->C->env()->failing()) { return; } // Code cache may be full.
@@ -3530,8 +3452,8 @@
const address virtual_call_oop_addr = __ addr_at(virtual_call_oop_addr_offset);
assert(MacroAssembler::is_load_const_from_method_toc_at(virtual_call_oop_addr),
"should be load from TOC");
-
- __ relocate(virtual_call_Relocation::spec(virtual_call_oop_addr));
+ int method_index = resolved_method_index(cbuf);
+ __ relocate(virtual_call_Relocation::spec(virtual_call_oop_addr, method_index));
}
// At this point I do not have the address of the trampoline stub,
@@ -3620,7 +3542,11 @@
address virtual_call_meta_addr = __ pc();
// Load a clear inline cache.
AddressLiteral empty_ic((address) Universe::non_oop_word());
- __ load_const_from_method_toc(ic_reg, empty_ic, Rtoc);
+ bool success = __ load_const_from_method_toc(ic_reg, empty_ic, Rtoc, /*fixed_size*/ true);
+ if (!success) {
+ ciEnv::current()->record_out_of_memory_failure();
+ return;
+ }
// CALL to fixup routine. Fixup routine uses ScopeDesc info
// to determine who we intended to call.
__ relocate(virtual_call_Relocation::spec(virtual_call_meta_addr));
@@ -3676,7 +3602,11 @@
__ calculate_address_from_global_toc(Rtoc, __ method_toc());
// Put entry, env, toc into the constant pool, this needs up to 3 constant
// pool entries; call_c_using_toc will optimize the call.
- __ call_c_using_toc(fd, relocInfo::runtime_call_type, Rtoc);
+ bool success = __ call_c_using_toc(fd, relocInfo::runtime_call_type, Rtoc);
+ if (!success) {
+ ciEnv::current()->record_out_of_memory_failure();
+ return;
+ }
#endif
// Check the ret_addr_offset.
@@ -6263,6 +6193,10 @@
ins_encode %{
// TODO: PPC port $archOpcode(ppc64Opcode_lfs);
address float_address = __ float_constant($src$$constant);
+ if (float_address == NULL) {
+ ciEnv::current()->record_out_of_memory_failure();
+ return;
+ }
__ lfs($dst$$FloatRegister, __ offset_to_method_toc(float_address), $toc$$Register);
%}
ins_pipe(pipe_class_memory);
@@ -6284,6 +6218,10 @@
FloatRegister Rdst = $dst$$FloatRegister;
Register Rtoc = $toc$$Register;
address float_address = __ float_constant($src$$constant);
+ if (float_address == NULL) {
+ ciEnv::current()->record_out_of_memory_failure();
+ return;
+ }
int offset = __ offset_to_method_toc(float_address);
int hi = (offset + (1<<15))>>16;
int lo = offset - hi * (1<<16);
@@ -6318,7 +6256,12 @@
size(4);
ins_encode %{
// TODO: PPC port $archOpcode(ppc64Opcode_lfd);
- int offset = __ offset_to_method_toc(__ double_constant($src$$constant));
+ address float_address = __ double_constant($src$$constant);
+ if (float_address == NULL) {
+ ciEnv::current()->record_out_of_memory_failure();
+ return;
+ }
+ int offset = __ offset_to_method_toc(float_address);
__ lfd($dst$$FloatRegister, offset, $toc$$Register);
%}
ins_pipe(pipe_class_memory);
@@ -6340,7 +6283,11 @@
FloatRegister Rdst = $dst$$FloatRegister;
Register Rtoc = $toc$$Register;
address float_address = __ double_constant($src$$constant);
- int offset = __ offset_to_method_toc(float_address);
+ if (float_address == NULL) {
+ ciEnv::current()->record_out_of_memory_failure();
+ return;
+ }
+ int offset = __ offset_to_method_toc(float_address);
int hi = (offset + (1<<15))>>16;
int lo = offset - hi * (1<<16);
@@ -11790,7 +11737,6 @@
instruct CallStaticJavaDirect(method meth) %{
match(CallStaticJava);
effect(USE meth);
- predicate(!((CallStaticJavaNode*)n)->is_method_handle_invoke());
ins_cost(CALL_COST);
ins_num_consts(3 /* up to 3 patchable constants: inline cache, 2 call targets. */);
@@ -11801,20 +11747,6 @@
ins_pipe(pipe_class_call);
%}
-// Schedulable version of call static node.
-instruct CallStaticJavaDirectHandle(method meth) %{
- match(CallStaticJava);
- effect(USE meth);
- predicate(((CallStaticJavaNode*)n)->is_method_handle_invoke());
- ins_cost(CALL_COST);
-
- ins_num_consts(3 /* up to 3 patchable constants: inline cache, 2 call targets. */);
-
- format %{ "CALL,static $meth \t// ==> " %}
- ins_encode( enc_java_handle_call(meth) );
- ins_pipe(pipe_class_call);
-%}
-
// Call Java Dynamic Instruction
// Used by postalloc expand of CallDynamicJavaDirectSchedEx (actual call).
--- a/hotspot/src/cpu/ppc/vm/register_ppc.hpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/register_ppc.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -627,6 +627,9 @@
REGISTER_DECLARATION(Register, R28_mdx, R28);
#endif // CC_INTERP
+REGISTER_DECLARATION(Register, R19_inline_cache_reg, R19);
+REGISTER_DECLARATION(Register, R29_TOC, R29);
+
#ifndef DONT_USE_REGISTER_DEFINES
#define R21_tmp1 AS_REGISTER(Register, R21)
#define R22_tmp2 AS_REGISTER(Register, R22)
@@ -648,6 +651,9 @@
#define R28_mdx AS_REGISTER(Register, R28)
#endif
+#define R19_inline_cache_reg AS_REGISTER(Register, R19)
+#define R29_TOC AS_REGISTER(Register, R29)
+
#define CCR4_is_synced AS_REGISTER(ConditionRegister, CCR4)
#endif
--- a/hotspot/src/cpu/ppc/vm/relocInfo_ppc.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/relocInfo_ppc.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -84,13 +84,11 @@
NativeConditionalFarBranch* branch = NativeConditionalFarBranch_at(inst_loc);
return branch->branch_destination();
} else {
- // There are two instructions at the beginning of a stub, therefore we
- // load at orig_addr + 8.
orig_addr = nativeCall_at(inst_loc)->get_trampoline();
if (orig_addr == NULL) {
return (address) -1;
} else {
- return (address) nativeMovConstReg_at(orig_addr + 8)->data();
+ return ((NativeCallTrampolineStub*)orig_addr)->destination();
}
}
}
--- a/hotspot/src/cpu/ppc/vm/runtime_ppc.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/runtime_ppc.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012, 2014 SAP AG. All rights reserved.
+ * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012, 2015 SAP AG. 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
@@ -45,16 +45,6 @@
#ifdef COMPILER2
-// SP adjustment (must use unextended SP) for method handle call sites
-// during exception handling.
-static intptr_t adjust_SP_for_methodhandle_callsite(JavaThread *thread) {
- RegisterMap map(thread, false);
- // The frame constructor will do the correction for us (see frame::adjust_unextended_SP).
- frame mh_caller_frame = thread->last_frame().sender(&map);
- assert(mh_caller_frame.is_compiled_frame(), "Only may reach here for compiled MH call sites");
- return (intptr_t) mh_caller_frame.unextended_sp();
-}
-
//------------------------------generate_exception_blob---------------------------
// Creates exception blob at the end.
// Using exception blob, this code is jumped from a compiled method.
@@ -129,17 +119,10 @@
OopMapSet* oop_maps = new OopMapSet();
oop_maps->add_gc_map(calls_return_pc - start, map);
- // Get unextended_sp for method handle call sites.
- Label mh_callsite, mh_done; // Use a 2nd c call if it's a method handle call site.
- __ lwa(R4_ARG2, in_bytes(JavaThread::is_method_handle_return_offset()), R16_thread);
- __ cmpwi(CCR0, R4_ARG2, 0);
- __ bne(CCR0, mh_callsite);
-
__ mtctr(R3_RET); // Move address of exception handler to SR_CTR.
__ reset_last_Java_frame();
__ pop_frame();
- __ bind(mh_done);
// We have a handler in register SR_CTR (could be deopt blob).
// Get the exception oop.
@@ -161,25 +144,6 @@
__ mtlr(R4_ARG2);
__ bctr();
-
- // Same as above, but also set sp to unextended_sp.
- __ bind(mh_callsite);
- __ mr(R31, R3_RET); // Save branch address.
- __ mr(R3_ARG1, R16_thread);
-#if defined(ABI_ELFv2)
- __ call_c((address) adjust_SP_for_methodhandle_callsite, relocInfo::none);
-#else
- __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, adjust_SP_for_methodhandle_callsite), relocInfo::none);
-#endif
- // Returns unextended_sp in R3_RET.
-
- __ mtctr(R31); // Move address of exception handler to SR_CTR.
- __ reset_last_Java_frame();
-
- __ mr(R1_SP, R3_RET); // Set sp to unextended_sp.
- __ b(mh_done);
-
-
// Make sure all code is generated.
masm->flush();
--- a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -62,7 +62,7 @@
// Support different return pc locations.
enum ReturnPCLocation {
return_pc_is_lr,
- return_pc_is_r4,
+ return_pc_is_pre_saved,
return_pc_is_thread_saved_exception_pc
};
@@ -241,16 +241,17 @@
__ mfcr(R31);
__ std(R31, _abi(cr), R1_SP);
switch (return_pc_location) {
- case return_pc_is_lr: __ mflr(R31); break;
- case return_pc_is_r4: __ mr(R31, R4); break;
- case return_pc_is_thread_saved_exception_pc:
- __ ld(R31, thread_(saved_exception_pc)); break;
+ case return_pc_is_lr: __ mflr(R31); break;
+ case return_pc_is_pre_saved: assert(return_pc_adjustment == 0, "unsupported"); break;
+ case return_pc_is_thread_saved_exception_pc: __ ld(R31, thread_(saved_exception_pc)); break;
default: ShouldNotReachHere();
}
- if (return_pc_adjustment != 0) {
- __ addi(R31, R31, return_pc_adjustment);
+ if (return_pc_location != return_pc_is_pre_saved) {
+ if (return_pc_adjustment != 0) {
+ __ addi(R31, R31, return_pc_adjustment);
+ }
+ __ std(R31, _abi(lr), R1_SP);
}
- __ std(R31, _abi(lr), R1_SP);
// push a new frame
__ push_frame(frame_size_in_bytes, R31);
@@ -646,7 +647,7 @@
return round_to(stk, 2);
}
-#ifdef COMPILER2
+#if defined(COMPILER1) || defined(COMPILER2)
// Calling convention for calling C code.
int SharedRuntime::c_calling_convention(const BasicType *sig_bt,
VMRegPair *regs,
@@ -2576,7 +2577,7 @@
#endif
}
-#ifdef COMPILER2
+#if defined(COMPILER1) || defined(COMPILER2)
// Frame generation for deopt and uncommon trap blobs.
static void push_skeleton_frame(MacroAssembler* masm, bool deopt,
/* Read */
@@ -2734,7 +2735,7 @@
const address start = __ pc();
-#ifdef COMPILER2
+#if defined(COMPILER1) || defined(COMPILER2)
// --------------------------------------------------------------------------
// Prolog for non exception case!
@@ -2783,28 +2784,43 @@
BLOCK_COMMENT("Prolog for exception case");
- // The RegisterSaves doesn't need to adjust the return pc for this situation.
- const int return_pc_adjustment_exception = 0;
-
- // Push the "unpack frame".
- // Save everything in sight.
- assert(R4 == R4_ARG2, "exception pc must be in r4");
- RegisterSaver::push_frame_reg_args_and_save_live_registers(masm,
- &first_frame_size_in_bytes,
- /*generate_oop_map=*/ false,
- return_pc_adjustment_exception,
- RegisterSaver::return_pc_is_r4);
-
- // Deopt during an exception. Save exec mode for unpack_frames.
- __ li(exec_mode_reg, Deoptimization::Unpack_exception);
-
// Store exception oop and pc in thread (location known to GC).
// This is needed since the call to "fetch_unroll_info()" may safepoint.
__ std(R3_ARG1, in_bytes(JavaThread::exception_oop_offset()), R16_thread);
__ std(R4_ARG2, in_bytes(JavaThread::exception_pc_offset()), R16_thread);
+ __ std(R4_ARG2, _abi(lr), R1_SP);
+
+ // Vanilla deoptimization with an exception pending in exception_oop.
+ int exception_in_tls_offset = __ pc() - start;
+
+ // Push the "unpack frame".
+ // Save everything in sight.
+ RegisterSaver::push_frame_reg_args_and_save_live_registers(masm,
+ &first_frame_size_in_bytes,
+ /*generate_oop_map=*/ false,
+ /*return_pc_adjustment_exception=*/ 0,
+ RegisterSaver::return_pc_is_pre_saved);
+
+ // Deopt during an exception. Save exec mode for unpack_frames.
+ __ li(exec_mode_reg, Deoptimization::Unpack_exception);
// fall through
+ int reexecute_offset = 0;
+#ifdef COMPILER1
+ __ b(exec_mode_initialized);
+
+ // Reexecute entry, similar to c2 uncommon trap
+ reexecute_offset = __ pc() - start;
+
+ RegisterSaver::push_frame_reg_args_and_save_live_registers(masm,
+ &first_frame_size_in_bytes,
+ /*generate_oop_map=*/ false,
+ /*return_pc_adjustment_reexecute=*/ 0,
+ RegisterSaver::return_pc_is_pre_saved);
+ __ li(exec_mode_reg, Deoptimization::Unpack_reexecute);
+#endif
+
// --------------------------------------------------------------------------
__ BIND(exec_mode_initialized);
@@ -2918,7 +2934,9 @@
int exception_offset = __ pc() - start;
#endif // COMPILER2
- _deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, 0, first_frame_size_in_bytes / wordSize);
+ _deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset,
+ reexecute_offset, first_frame_size_in_bytes / wordSize);
+ _deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset);
}
#ifdef COMPILER2
--- a/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -48,6 +48,12 @@
#define BLOCK_COMMENT(str) __ block_comment(str)
#endif
+#if defined(ABI_ELFv2)
+#define STUB_ENTRY(name) StubRoutines::name()
+#else
+#define STUB_ENTRY(name) ((FunctionDescriptor*)StubRoutines::name())->entry()
+#endif
+
class StubGenerator: public StubCodeGenerator {
private:
@@ -259,8 +265,7 @@
//
// global toc register
- __ load_const(R29, MacroAssembler::global_toc(), R11_scratch1);
-
+ __ load_const_optimized(R29_TOC, MacroAssembler::global_toc(), R11_scratch1);
// Remember the senderSP so we interpreter can pop c2i arguments off of the stack
// when called via a c2i.
@@ -619,14 +624,17 @@
// Kills:
// nothing
//
- void gen_write_ref_array_pre_barrier(Register from, Register to, Register count, bool dest_uninitialized, Register Rtmp1) {
+ void gen_write_ref_array_pre_barrier(Register from, Register to, Register count, bool dest_uninitialized, Register Rtmp1,
+ Register preserve1 = noreg, Register preserve2 = noreg) {
BarrierSet* const bs = Universe::heap()->barrier_set();
switch (bs->kind()) {
case BarrierSet::G1SATBCTLogging:
// With G1, don't generate the call if we statically know that the target in uninitialized
if (!dest_uninitialized) {
- const int spill_slots = 4 * wordSize;
- const int frame_size = frame::abi_reg_args_size + spill_slots;
+ int spill_slots = 3;
+ if (preserve1 != noreg) { spill_slots++; }
+ if (preserve2 != noreg) { spill_slots++; }
+ const int frame_size = align_size_up(frame::abi_reg_args_size + spill_slots * BytesPerWord, frame::alignment_in_bytes);
Label filtered;
// Is marking active?
@@ -640,17 +648,23 @@
__ beq(CCR0, filtered);
__ save_LR_CR(R0);
- __ push_frame_reg_args(spill_slots, R0);
- __ std(from, frame_size - 1 * wordSize, R1_SP);
- __ std(to, frame_size - 2 * wordSize, R1_SP);
- __ std(count, frame_size - 3 * wordSize, R1_SP);
+ __ push_frame(frame_size, R0);
+ int slot_nr = 0;
+ __ std(from, frame_size - (++slot_nr) * wordSize, R1_SP);
+ __ std(to, frame_size - (++slot_nr) * wordSize, R1_SP);
+ __ std(count, frame_size - (++slot_nr) * wordSize, R1_SP);
+ if (preserve1 != noreg) { __ std(preserve1, frame_size - (++slot_nr) * wordSize, R1_SP); }
+ if (preserve2 != noreg) { __ std(preserve2, frame_size - (++slot_nr) * wordSize, R1_SP); }
__ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_pre), to, count);
- __ ld(from, frame_size - 1 * wordSize, R1_SP);
- __ ld(to, frame_size - 2 * wordSize, R1_SP);
- __ ld(count, frame_size - 3 * wordSize, R1_SP);
- __ pop_frame();
+ slot_nr = 0;
+ __ ld(from, frame_size - (++slot_nr) * wordSize, R1_SP);
+ __ ld(to, frame_size - (++slot_nr) * wordSize, R1_SP);
+ __ ld(count, frame_size - (++slot_nr) * wordSize, R1_SP);
+ if (preserve1 != noreg) { __ ld(preserve1, frame_size - (++slot_nr) * wordSize, R1_SP); }
+ if (preserve2 != noreg) { __ ld(preserve2, frame_size - (++slot_nr) * wordSize, R1_SP); }
+ __ addi(R1_SP, R1_SP, frame_size); // pop_frame()
__ restore_LR_CR(R0);
__ bind(filtered);
@@ -674,27 +688,22 @@
//
// The input registers and R0 are overwritten.
//
- void gen_write_ref_array_post_barrier(Register addr, Register count, Register tmp, bool branchToEnd) {
+ void gen_write_ref_array_post_barrier(Register addr, Register count, Register tmp, Register preserve = noreg) {
BarrierSet* const bs = Universe::heap()->barrier_set();
switch (bs->kind()) {
case BarrierSet::G1SATBCTLogging:
{
- if (branchToEnd) {
- __ save_LR_CR(R0);
- // We need this frame only to spill LR.
- __ push_frame_reg_args(0, R0);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_post), addr, count);
- __ pop_frame();
- __ restore_LR_CR(R0);
- } else {
- // Tail call: fake call from stub caller by branching without linking.
- address entry_point = (address)CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_post);
- __ mr_if_needed(R3_ARG1, addr);
- __ mr_if_needed(R4_ARG2, count);
- __ load_const(R11, entry_point, R0);
- __ call_c_and_return_to_caller(R11);
- }
+ int spill_slots = (preserve != noreg) ? 1 : 0;
+ const int frame_size = align_size_up(frame::abi_reg_args_size + spill_slots * BytesPerWord, frame::alignment_in_bytes);
+
+ __ save_LR_CR(R0);
+ __ push_frame(frame_size, R0);
+ if (preserve != noreg) { __ std(preserve, frame_size - 1 * wordSize, R1_SP); }
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_post), addr, count);
+ if (preserve != noreg) { __ ld(preserve, frame_size - 1 * wordSize, R1_SP); }
+ __ addi(R1_SP, R1_SP, frame_size); // pop_frame();
+ __ restore_LR_CR(R0);
}
break;
case BarrierSet::CardTableForRS:
@@ -729,12 +738,9 @@
__ addi(addr, addr, 1);
__ bdnz(Lstore_loop);
__ bind(Lskip_loop);
-
- if (!branchToEnd) __ blr();
}
break;
case BarrierSet::ModRef:
- if (!branchToEnd) __ blr();
break;
default:
ShouldNotReachHere();
@@ -763,8 +769,10 @@
// Procedure for large arrays (uses data cache block zero instruction).
Label dwloop, fast, fastloop, restloop, lastdword, done;
- int cl_size=VM_Version::get_cache_line_size(), cl_dwords=cl_size>>3, cl_dwordaddr_bits=exact_log2(cl_dwords);
- int min_dcbz=2; // Needs to be positive, apply dcbz only to at least min_dcbz cache lines.
+ int cl_size = VM_Version::L1_data_cache_line_size();
+ int cl_dwords = cl_size >> 3;
+ int cl_dwordaddr_bits = exact_log2(cl_dwords);
+ int min_dcbz = 2; // Needs to be positive, apply dcbz only to at least min_dcbz cache lines.
// Clear up to 128byte boundary if long enough, dword_cnt=(16-(base>>3))%16.
__ dcbtst(base_ptr_reg); // Indicate write access to first cache line ...
@@ -1081,7 +1089,6 @@
Register tmp1 = R6_ARG4;
Register tmp2 = R7_ARG5;
- Label l_overlap;
#ifdef ASSERT
__ srdi_(tmp2, R5_ARG3, 31);
__ asm_assert_eq("missing zero extend", 0xAFFE);
@@ -1091,19 +1098,11 @@
__ sldi(tmp2, R5_ARG3, log2_elem_size); // size in bytes
__ cmpld(CCR0, R3_ARG1, R4_ARG2); // Use unsigned comparison!
__ cmpld(CCR1, tmp1, tmp2);
- __ crand(CCR0, Assembler::less, CCR1, Assembler::less);
- __ blt(CCR0, l_overlap); // Src before dst and distance smaller than size.
-
- // need to copy forwards
- if (__ is_within_range_of_b(no_overlap_target, __ pc())) {
- __ b(no_overlap_target);
- } else {
- __ load_const(tmp1, no_overlap_target, tmp2);
- __ mtctr(tmp1);
- __ bctr();
- }
-
- __ bind(l_overlap);
+ __ crnand(CCR0, Assembler::less, CCR1, Assembler::less);
+ // Overlaps if Src before dst and distance smaller than size.
+ // Branch to forward copy routine otherwise (within range of 32kB).
+ __ bc(Assembler::bcondCRbiIs1, Assembler::bi0(CCR0, Assembler::less), no_overlap_target);
+
// need to copy backwards
}
@@ -1248,6 +1247,7 @@
}
__ bind(l_4);
+ __ li(R3_RET, 0); // return 0
__ blr();
return start;
@@ -1269,15 +1269,9 @@
Register tmp2 = R7_ARG5;
Register tmp3 = R8_ARG6;
-#if defined(ABI_ELFv2)
address nooverlap_target = aligned ?
- StubRoutines::arrayof_jbyte_disjoint_arraycopy() :
- StubRoutines::jbyte_disjoint_arraycopy();
-#else
- address nooverlap_target = aligned ?
- ((FunctionDescriptor*)StubRoutines::arrayof_jbyte_disjoint_arraycopy())->entry() :
- ((FunctionDescriptor*)StubRoutines::jbyte_disjoint_arraycopy())->entry();
-#endif
+ STUB_ENTRY(arrayof_jbyte_disjoint_arraycopy) :
+ STUB_ENTRY(jbyte_disjoint_arraycopy);
array_overlap_test(nooverlap_target, 0);
// Do reverse copy. We assume the case of actual overlap is rare enough
@@ -1292,6 +1286,7 @@
__ lbzx(tmp1, R3_ARG1, R5_ARG3);
__ bge(CCR0, l_1);
+ __ li(R3_RET, 0); // return 0
__ blr();
return start;
@@ -1474,6 +1469,7 @@
__ bdnz(l_5);
}
__ bind(l_4);
+ __ li(R3_RET, 0); // return 0
__ blr();
return start;
@@ -1495,15 +1491,9 @@
Register tmp2 = R7_ARG5;
Register tmp3 = R8_ARG6;
-#if defined(ABI_ELFv2)
address nooverlap_target = aligned ?
- StubRoutines::arrayof_jshort_disjoint_arraycopy() :
- StubRoutines::jshort_disjoint_arraycopy();
-#else
- address nooverlap_target = aligned ?
- ((FunctionDescriptor*)StubRoutines::arrayof_jshort_disjoint_arraycopy())->entry() :
- ((FunctionDescriptor*)StubRoutines::jshort_disjoint_arraycopy())->entry();
-#endif
+ STUB_ENTRY(arrayof_jshort_disjoint_arraycopy) :
+ STUB_ENTRY(jshort_disjoint_arraycopy);
array_overlap_test(nooverlap_target, 1);
@@ -1517,6 +1507,7 @@
__ lhzx(tmp2, R3_ARG1, tmp1);
__ bge(CCR0, l_1);
+ __ li(R3_RET, 0); // return 0
__ blr();
return start;
@@ -1620,6 +1611,7 @@
StubCodeMark mark(this, "StubRoutines", name);
address start = __ function_entry();
generate_disjoint_int_copy_core(aligned);
+ __ li(R3_RET, 0); // return 0
__ blr();
return start;
}
@@ -1704,20 +1696,15 @@
StubCodeMark mark(this, "StubRoutines", name);
address start = __ function_entry();
-#if defined(ABI_ELFv2)
address nooverlap_target = aligned ?
- StubRoutines::arrayof_jint_disjoint_arraycopy() :
- StubRoutines::jint_disjoint_arraycopy();
-#else
- address nooverlap_target = aligned ?
- ((FunctionDescriptor*)StubRoutines::arrayof_jint_disjoint_arraycopy())->entry() :
- ((FunctionDescriptor*)StubRoutines::jint_disjoint_arraycopy())->entry();
-#endif
+ STUB_ENTRY(arrayof_jint_disjoint_arraycopy) :
+ STUB_ENTRY(jint_disjoint_arraycopy);
array_overlap_test(nooverlap_target, 2);
generate_conjoint_int_copy_core(aligned);
+ __ li(R3_RET, 0); // return 0
__ blr();
return start;
@@ -1796,6 +1783,7 @@
StubCodeMark mark(this, "StubRoutines", name);
address start = __ function_entry();
generate_disjoint_long_copy_core(aligned);
+ __ li(R3_RET, 0); // return 0
__ blr();
return start;
@@ -1878,19 +1866,14 @@
StubCodeMark mark(this, "StubRoutines", name);
address start = __ function_entry();
-#if defined(ABI_ELFv2)
address nooverlap_target = aligned ?
- StubRoutines::arrayof_jlong_disjoint_arraycopy() :
- StubRoutines::jlong_disjoint_arraycopy();
-#else
- address nooverlap_target = aligned ?
- ((FunctionDescriptor*)StubRoutines::arrayof_jlong_disjoint_arraycopy())->entry() :
- ((FunctionDescriptor*)StubRoutines::jlong_disjoint_arraycopy())->entry();
-#endif
+ STUB_ENTRY(arrayof_jlong_disjoint_arraycopy) :
+ STUB_ENTRY(jlong_disjoint_arraycopy);
array_overlap_test(nooverlap_target, 3);
generate_conjoint_long_copy_core(aligned);
+ __ li(R3_RET, 0); // return 0
__ blr();
return start;
@@ -1910,15 +1893,9 @@
address start = __ function_entry();
-#if defined(ABI_ELFv2)
address nooverlap_target = aligned ?
- StubRoutines::arrayof_oop_disjoint_arraycopy() :
- StubRoutines::oop_disjoint_arraycopy();
-#else
- address nooverlap_target = aligned ?
- ((FunctionDescriptor*)StubRoutines::arrayof_oop_disjoint_arraycopy())->entry() :
- ((FunctionDescriptor*)StubRoutines::oop_disjoint_arraycopy())->entry();
-#endif
+ STUB_ENTRY(arrayof_oop_disjoint_arraycopy) :
+ STUB_ENTRY(oop_disjoint_arraycopy);
gen_write_ref_array_pre_barrier(R3_ARG1, R4_ARG2, R5_ARG3, dest_uninitialized, R9_ARG7);
@@ -1934,7 +1911,9 @@
generate_conjoint_long_copy_core(aligned);
}
- gen_write_ref_array_post_barrier(R9_ARG7, R10_ARG8, R11_scratch1, /*branchToEnd*/ false);
+ gen_write_ref_array_post_barrier(R9_ARG7, R10_ARG8, R11_scratch1);
+ __ li(R3_RET, 0); // return 0
+ __ blr();
return start;
}
@@ -1964,11 +1943,460 @@
generate_disjoint_long_copy_core(aligned);
}
- gen_write_ref_array_post_barrier(R9_ARG7, R10_ARG8, R11_scratch1, /*branchToEnd*/ false);
+ gen_write_ref_array_post_barrier(R9_ARG7, R10_ARG8, R11_scratch1);
+ __ li(R3_RET, 0); // return 0
+ __ blr();
+
+ return start;
+ }
+
+
+ // Helper for generating a dynamic type check.
+ // Smashes only the given temp registers.
+ void generate_type_check(Register sub_klass,
+ Register super_check_offset,
+ Register super_klass,
+ Register temp,
+ Label& L_success) {
+ assert_different_registers(sub_klass, super_check_offset, super_klass);
+
+ BLOCK_COMMENT("type_check:");
+
+ Label L_miss;
+
+ __ check_klass_subtype_fast_path(sub_klass, super_klass, temp, R0, &L_success, &L_miss, NULL,
+ super_check_offset);
+ __ check_klass_subtype_slow_path(sub_klass, super_klass, temp, R0, &L_success, NULL);
+
+ // Fall through on failure!
+ __ bind(L_miss);
+ }
+
+
+ // Generate stub for checked oop copy.
+ //
+ // Arguments for generated stub:
+ // from: R3
+ // to: R4
+ // count: R5 treated as signed
+ // ckoff: R6 (super_check_offset)
+ // ckval: R7 (super_klass)
+ // ret: R3 zero for success; (-1^K) where K is partial transfer count
+ //
+ address generate_checkcast_copy(const char *name, bool dest_uninitialized) {
+
+ const Register R3_from = R3_ARG1; // source array address
+ const Register R4_to = R4_ARG2; // destination array address
+ const Register R5_count = R5_ARG3; // elements count
+ const Register R6_ckoff = R6_ARG4; // super_check_offset
+ const Register R7_ckval = R7_ARG5; // super_klass
+
+ const Register R8_offset = R8_ARG6; // loop var, with stride wordSize
+ const Register R9_remain = R9_ARG7; // loop var, with stride -1
+ const Register R10_oop = R10_ARG8; // actual oop copied
+ const Register R11_klass = R11_scratch1; // oop._klass
+ const Register R12_tmp = R12_scratch2;
+
+ const Register R2_minus1 = R2;
+
+ //__ align(CodeEntryAlignment);
+ StubCodeMark mark(this, "StubRoutines", name);
+ address start = __ function_entry();
+
+ // TODO: Assert that int is 64 bit sign extended and arrays are not conjoint.
+
+ gen_write_ref_array_pre_barrier(R3_from, R4_to, R5_count, dest_uninitialized, R12_tmp, /* preserve: */ R6_ckoff, R7_ckval);
+
+ //inc_counter_np(SharedRuntime::_checkcast_array_copy_ctr, R12_tmp, R3_RET);
+
+ Label load_element, store_element, store_null, success, do_card_marks;
+ __ or_(R9_remain, R5_count, R5_count); // Initialize loop index, and test it.
+ __ li(R8_offset, 0); // Offset from start of arrays.
+ __ li(R2_minus1, -1);
+ __ bne(CCR0, load_element);
+
+ // Empty array: Nothing to do.
+ __ li(R3_RET, 0); // Return 0 on (trivial) success.
+ __ blr();
+
+ // ======== begin loop ========
+ // (Entry is load_element.)
+ __ align(OptoLoopAlignment);
+ __ bind(store_element);
+ if (UseCompressedOops) {
+ __ encode_heap_oop_not_null(R10_oop);
+ __ bind(store_null);
+ __ stw(R10_oop, R8_offset, R4_to);
+ } else {
+ __ bind(store_null);
+ __ std(R10_oop, R8_offset, R4_to);
+ }
+
+ __ addi(R8_offset, R8_offset, heapOopSize); // Step to next offset.
+ __ add_(R9_remain, R2_minus1, R9_remain); // Decrement the count.
+ __ beq(CCR0, success);
+
+ // ======== loop entry is here ========
+ __ bind(load_element);
+ __ load_heap_oop(R10_oop, R8_offset, R3_from, &store_null); // Load the oop.
+
+ __ load_klass(R11_klass, R10_oop); // Query the object klass.
+
+ generate_type_check(R11_klass, R6_ckoff, R7_ckval, R12_tmp,
+ // Branch to this on success:
+ store_element);
+ // ======== end loop ========
+
+ // It was a real error; we must depend on the caller to finish the job.
+ // Register R9_remain has number of *remaining* oops, R5_count number of *total* oops.
+ // Emit GC store barriers for the oops we have copied (R5_count minus R9_remain),
+ // and report their number to the caller.
+ __ subf_(R5_count, R9_remain, R5_count);
+ __ nand(R3_RET, R5_count, R5_count); // report (-1^K) to caller
+ __ bne(CCR0, do_card_marks);
+ __ blr();
+
+ __ bind(success);
+ __ li(R3_RET, 0);
+
+ __ bind(do_card_marks);
+ // Store check on R4_to[0..R5_count-1].
+ gen_write_ref_array_post_barrier(R4_to, R5_count, R12_tmp, /* preserve: */ R3_RET);
+ __ blr();
+ return start;
+ }
+
+
+ // Generate 'unsafe' array copy stub.
+ // Though just as safe as the other stubs, it takes an unscaled
+ // size_t argument instead of an element count.
+ //
+ // Arguments for generated stub:
+ // from: R3
+ // to: R4
+ // count: R5 byte count, treated as ssize_t, can be zero
+ //
+ // Examines the alignment of the operands and dispatches
+ // to a long, int, short, or byte copy loop.
+ //
+ address generate_unsafe_copy(const char* name,
+ address byte_copy_entry,
+ address short_copy_entry,
+ address int_copy_entry,
+ address long_copy_entry) {
+
+ const Register R3_from = R3_ARG1; // source array address
+ const Register R4_to = R4_ARG2; // destination array address
+ const Register R5_count = R5_ARG3; // elements count (as long on PPC64)
+
+ const Register R6_bits = R6_ARG4; // test copy of low bits
+ const Register R7_tmp = R7_ARG5;
+
+ //__ align(CodeEntryAlignment);
+ StubCodeMark mark(this, "StubRoutines", name);
+ address start = __ function_entry();
+
+ // Bump this on entry, not on exit:
+ //inc_counter_np(SharedRuntime::_unsafe_array_copy_ctr, R6_bits, R7_tmp);
+
+ Label short_copy, int_copy, long_copy;
+
+ __ orr(R6_bits, R3_from, R4_to);
+ __ orr(R6_bits, R6_bits, R5_count);
+ __ andi_(R0, R6_bits, (BytesPerLong-1));
+ __ beq(CCR0, long_copy);
+
+ __ andi_(R0, R6_bits, (BytesPerInt-1));
+ __ beq(CCR0, int_copy);
+
+ __ andi_(R0, R6_bits, (BytesPerShort-1));
+ __ beq(CCR0, short_copy);
+
+ // byte_copy:
+ __ b(byte_copy_entry);
+
+ __ bind(short_copy);
+ __ srwi(R5_count, R5_count, LogBytesPerShort);
+ __ b(short_copy_entry);
+
+ __ bind(int_copy);
+ __ srwi(R5_count, R5_count, LogBytesPerInt);
+ __ b(int_copy_entry);
+
+ __ bind(long_copy);
+ __ srwi(R5_count, R5_count, LogBytesPerLong);
+ __ b(long_copy_entry);
return start;
}
+
+ // Perform range checks on the proposed arraycopy.
+ // Kills the two temps, but nothing else.
+ // Also, clean the sign bits of src_pos and dst_pos.
+ void arraycopy_range_checks(Register src, // source array oop
+ Register src_pos, // source position
+ Register dst, // destination array oop
+ Register dst_pos, // destination position
+ Register length, // length of copy
+ Register temp1, Register temp2,
+ Label& L_failed) {
+ BLOCK_COMMENT("arraycopy_range_checks:");
+
+ const Register array_length = temp1; // scratch
+ const Register end_pos = temp2; // scratch
+
+ // if (src_pos + length > arrayOop(src)->length() ) FAIL;
+ __ lwa(array_length, arrayOopDesc::length_offset_in_bytes(), src);
+ __ add(end_pos, src_pos, length); // src_pos + length
+ __ cmpd(CCR0, end_pos, array_length);
+ __ bgt(CCR0, L_failed);
+
+ // if (dst_pos + length > arrayOop(dst)->length() ) FAIL;
+ __ lwa(array_length, arrayOopDesc::length_offset_in_bytes(), dst);
+ __ add(end_pos, dst_pos, length); // src_pos + length
+ __ cmpd(CCR0, end_pos, array_length);
+ __ bgt(CCR0, L_failed);
+
+ BLOCK_COMMENT("arraycopy_range_checks done");
+ }
+
+
+ //
+ // Generate generic array copy stubs
+ //
+ // Input:
+ // R3 - src oop
+ // R4 - src_pos
+ // R5 - dst oop
+ // R6 - dst_pos
+ // R7 - element count
+ //
+ // Output:
+ // R3 == 0 - success
+ // R3 == -1 - need to call System.arraycopy
+ //
+ address generate_generic_copy(const char *name,
+ address entry_jbyte_arraycopy,
+ address entry_jshort_arraycopy,
+ address entry_jint_arraycopy,
+ address entry_oop_arraycopy,
+ address entry_disjoint_oop_arraycopy,
+ address entry_jlong_arraycopy,
+ address entry_checkcast_arraycopy) {
+ Label L_failed, L_objArray;
+
+ // Input registers
+ const Register src = R3_ARG1; // source array oop
+ const Register src_pos = R4_ARG2; // source position
+ const Register dst = R5_ARG3; // destination array oop
+ const Register dst_pos = R6_ARG4; // destination position
+ const Register length = R7_ARG5; // elements count
+
+ // registers used as temp
+ const Register src_klass = R8_ARG6; // source array klass
+ const Register dst_klass = R9_ARG7; // destination array klass
+ const Register lh = R10_ARG8; // layout handler
+ const Register temp = R2;
+
+ //__ align(CodeEntryAlignment);
+ StubCodeMark mark(this, "StubRoutines", name);
+ address start = __ function_entry();
+
+ // Bump this on entry, not on exit:
+ //inc_counter_np(SharedRuntime::_generic_array_copy_ctr, lh, temp);
+
+ // In principle, the int arguments could be dirty.
+
+ //-----------------------------------------------------------------------
+ // Assembler stubs will be used for this call to arraycopy
+ // if the following conditions are met:
+ //
+ // (1) src and dst must not be null.
+ // (2) src_pos must not be negative.
+ // (3) dst_pos must not be negative.
+ // (4) length must not be negative.
+ // (5) src klass and dst klass should be the same and not NULL.
+ // (6) src and dst should be arrays.
+ // (7) src_pos + length must not exceed length of src.
+ // (8) dst_pos + length must not exceed length of dst.
+ BLOCK_COMMENT("arraycopy initial argument checks");
+
+ __ cmpdi(CCR1, src, 0); // if (src == NULL) return -1;
+ __ extsw_(src_pos, src_pos); // if (src_pos < 0) return -1;
+ __ cmpdi(CCR5, dst, 0); // if (dst == NULL) return -1;
+ __ cror(CCR1, Assembler::equal, CCR0, Assembler::less);
+ __ extsw_(dst_pos, dst_pos); // if (src_pos < 0) return -1;
+ __ cror(CCR5, Assembler::equal, CCR0, Assembler::less);
+ __ extsw_(length, length); // if (length < 0) return -1;
+ __ cror(CCR1, Assembler::equal, CCR5, Assembler::equal);
+ __ cror(CCR1, Assembler::equal, CCR0, Assembler::less);
+ __ beq(CCR1, L_failed);
+
+ BLOCK_COMMENT("arraycopy argument klass checks");
+ __ load_klass(src_klass, src);
+ __ load_klass(dst_klass, dst);
+
+ // Load layout helper
+ //
+ // |array_tag| | header_size | element_type | |log2_element_size|
+ // 32 30 24 16 8 2 0
+ //
+ // array_tag: typeArray = 0x3, objArray = 0x2, non-array = 0x0
+ //
+
+ int lh_offset = in_bytes(Klass::layout_helper_offset());
+
+ // Load 32-bits signed value. Use br() instruction with it to check icc.
+ __ lwz(lh, lh_offset, src_klass);
+
+ // Handle objArrays completely differently...
+ jint objArray_lh = Klass::array_layout_helper(T_OBJECT);
+ __ load_const_optimized(temp, objArray_lh, R0);
+ __ cmpw(CCR0, lh, temp);
+ __ beq(CCR0, L_objArray);
+
+ __ cmpd(CCR5, src_klass, dst_klass); // if (src->klass() != dst->klass()) return -1;
+ __ cmpwi(CCR6, lh, Klass::_lh_neutral_value); // if (!src->is_Array()) return -1;
+
+ __ crnand(CCR5, Assembler::equal, CCR6, Assembler::less);
+ __ beq(CCR5, L_failed);
+
+ // At this point, it is known to be a typeArray (array_tag 0x3).
+#ifdef ASSERT
+ { Label L;
+ jint lh_prim_tag_in_place = (Klass::_lh_array_tag_type_value << Klass::_lh_array_tag_shift);
+ __ load_const_optimized(temp, lh_prim_tag_in_place, R0);
+ __ cmpw(CCR0, lh, temp);
+ __ bge(CCR0, L);
+ __ stop("must be a primitive array");
+ __ bind(L);
+ }
+#endif
+
+ arraycopy_range_checks(src, src_pos, dst, dst_pos, length,
+ temp, dst_klass, L_failed);
+
+ // TypeArrayKlass
+ //
+ // src_addr = (src + array_header_in_bytes()) + (src_pos << log2elemsize);
+ // dst_addr = (dst + array_header_in_bytes()) + (dst_pos << log2elemsize);
+ //
+
+ const Register offset = dst_klass; // array offset
+ const Register elsize = src_klass; // log2 element size
+
+ __ rldicl(offset, lh, 64 - Klass::_lh_header_size_shift, 64 - exact_log2(Klass::_lh_header_size_mask + 1));
+ __ andi(elsize, lh, Klass::_lh_log2_element_size_mask);
+ __ add(src, offset, src); // src array offset
+ __ add(dst, offset, dst); // dst array offset
+
+ // Next registers should be set before the jump to corresponding stub.
+ const Register from = R3_ARG1; // source array address
+ const Register to = R4_ARG2; // destination array address
+ const Register count = R5_ARG3; // elements count
+
+ // 'from', 'to', 'count' registers should be set in this order
+ // since they are the same as 'src', 'src_pos', 'dst'.
+
+ BLOCK_COMMENT("scale indexes to element size");
+ __ sld(src_pos, src_pos, elsize);
+ __ sld(dst_pos, dst_pos, elsize);
+ __ add(from, src_pos, src); // src_addr
+ __ add(to, dst_pos, dst); // dst_addr
+ __ mr(count, length); // length
+
+ BLOCK_COMMENT("choose copy loop based on element size");
+ // Using conditional branches with range 32kB.
+ const int bo = Assembler::bcondCRbiIs1, bi = Assembler::bi0(CCR0, Assembler::equal);
+ __ cmpwi(CCR0, elsize, 0);
+ __ bc(bo, bi, entry_jbyte_arraycopy);
+ __ cmpwi(CCR0, elsize, LogBytesPerShort);
+ __ bc(bo, bi, entry_jshort_arraycopy);
+ __ cmpwi(CCR0, elsize, LogBytesPerInt);
+ __ bc(bo, bi, entry_jint_arraycopy);
+#ifdef ASSERT
+ { Label L;
+ __ cmpwi(CCR0, elsize, LogBytesPerLong);
+ __ beq(CCR0, L);
+ __ stop("must be long copy, but elsize is wrong");
+ __ bind(L);
+ }
+#endif
+ __ b(entry_jlong_arraycopy);
+
+ // ObjArrayKlass
+ __ bind(L_objArray);
+ // live at this point: src_klass, dst_klass, src[_pos], dst[_pos], length
+
+ Label L_disjoint_plain_copy, L_checkcast_copy;
+ // test array classes for subtyping
+ __ cmpd(CCR0, src_klass, dst_klass); // usual case is exact equality
+ __ bne(CCR0, L_checkcast_copy);
+
+ // Identically typed arrays can be copied without element-wise checks.
+ arraycopy_range_checks(src, src_pos, dst, dst_pos, length,
+ temp, lh, L_failed);
+
+ __ addi(src, src, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); //src offset
+ __ addi(dst, dst, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); //dst offset
+ __ sldi(src_pos, src_pos, LogBytesPerHeapOop);
+ __ sldi(dst_pos, dst_pos, LogBytesPerHeapOop);
+ __ add(from, src_pos, src); // src_addr
+ __ add(to, dst_pos, dst); // dst_addr
+ __ mr(count, length); // length
+ __ b(entry_oop_arraycopy);
+
+ __ bind(L_checkcast_copy);
+ // live at this point: src_klass, dst_klass
+ {
+ // Before looking at dst.length, make sure dst is also an objArray.
+ __ lwz(temp, lh_offset, dst_klass);
+ __ cmpw(CCR0, lh, temp);
+ __ bne(CCR0, L_failed);
+
+ // It is safe to examine both src.length and dst.length.
+ arraycopy_range_checks(src, src_pos, dst, dst_pos, length,
+ temp, lh, L_failed);
+
+ // Marshal the base address arguments now, freeing registers.
+ __ addi(src, src, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); //src offset
+ __ addi(dst, dst, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); //dst offset
+ __ sldi(src_pos, src_pos, LogBytesPerHeapOop);
+ __ sldi(dst_pos, dst_pos, LogBytesPerHeapOop);
+ __ add(from, src_pos, src); // src_addr
+ __ add(to, dst_pos, dst); // dst_addr
+ __ mr(count, length); // length
+
+ Register sco_temp = R6_ARG4; // This register is free now.
+ assert_different_registers(from, to, count, sco_temp,
+ dst_klass, src_klass);
+
+ // Generate the type check.
+ int sco_offset = in_bytes(Klass::super_check_offset_offset());
+ __ lwz(sco_temp, sco_offset, dst_klass);
+ generate_type_check(src_klass, sco_temp, dst_klass,
+ temp, L_disjoint_plain_copy);
+
+ // Fetch destination element klass from the ObjArrayKlass header.
+ int ek_offset = in_bytes(ObjArrayKlass::element_klass_offset());
+
+ // The checkcast_copy loop needs two extra arguments:
+ __ ld(R7_ARG5, ek_offset, dst_klass); // dest elem klass
+ __ lwz(R6_ARG4, sco_offset, R7_ARG5); // sco of elem klass
+ __ b(entry_checkcast_arraycopy);
+ }
+
+ __ bind(L_disjoint_plain_copy);
+ __ b(entry_disjoint_oop_arraycopy);
+
+ __ bind(L_failed);
+ __ li(R3_RET, -1); // return -1
+ __ blr();
+ return start;
+ }
+
+
void generate_arraycopy_stubs() {
// Note: the disjoint stubs must be generated first, some of
// the conjoint stubs use them.
@@ -2005,6 +2433,24 @@
StubRoutines::_arrayof_oop_arraycopy = generate_conjoint_oop_copy(true, "arrayof_oop_arraycopy", false);
StubRoutines::_arrayof_oop_arraycopy_uninit = generate_conjoint_oop_copy(true, "arrayof_oop_arraycopy", true);
+ // special/generic versions
+ StubRoutines::_checkcast_arraycopy = generate_checkcast_copy("checkcast_arraycopy", false);
+ StubRoutines::_checkcast_arraycopy_uninit = generate_checkcast_copy("checkcast_arraycopy_uninit", true);
+
+ StubRoutines::_unsafe_arraycopy = generate_unsafe_copy("unsafe_arraycopy",
+ STUB_ENTRY(jbyte_arraycopy),
+ STUB_ENTRY(jshort_arraycopy),
+ STUB_ENTRY(jint_arraycopy),
+ STUB_ENTRY(jlong_arraycopy));
+ StubRoutines::_generic_arraycopy = generate_generic_copy("generic_arraycopy",
+ STUB_ENTRY(jbyte_arraycopy),
+ STUB_ENTRY(jshort_arraycopy),
+ STUB_ENTRY(jint_arraycopy),
+ STUB_ENTRY(oop_arraycopy),
+ STUB_ENTRY(oop_disjoint_arraycopy),
+ STUB_ENTRY(jlong_arraycopy),
+ STUB_ENTRY(checkcast_arraycopy));
+
// fill routines
StubRoutines::_jbyte_fill = generate_fill(T_BYTE, false, "jbyte_fill");
StubRoutines::_jshort_fill = generate_fill(T_SHORT, false, "jshort_fill");
--- a/hotspot/src/cpu/ppc/vm/stubRoutines_ppc_64.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/stubRoutines_ppc_64.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -34,7 +34,7 @@
// CRC32 Intrinsics.
void StubRoutines::ppc64::generate_load_crc_table_addr(MacroAssembler* masm, Register table) {
- __ load_const(table, StubRoutines::_crc_table_adr);
+ __ load_const_optimized(table, StubRoutines::_crc_table_adr, R0);
}
// CRC32 Intrinsics.
--- a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -255,34 +255,33 @@
if (TieredCompilation) {
const int increment = InvocationCounter::count_increment;
- const int mask = ((1 << Tier0InvokeNotifyFreqLog) - 1) << InvocationCounter::count_shift;
Label no_mdo;
if (ProfileInterpreter) {
- const Register Rmdo = Rscratch1;
+ const Register Rmdo = R3_counters;
// If no method data exists, go to profile_continue.
__ ld(Rmdo, in_bytes(Method::method_data_offset()), R19_method);
__ cmpdi(CCR0, Rmdo, 0);
__ beq(CCR0, no_mdo);
// Increment backedge counter in the MDO.
- const int mdo_bc_offs = in_bytes(MethodData::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset());
- __ lwz(Rscratch2, mdo_bc_offs, Rmdo);
+ const int mdo_ic_offs = in_bytes(MethodData::invocation_counter_offset()) + in_bytes(InvocationCounter::counter_offset());
+ __ lwz(Rscratch2, mdo_ic_offs, Rmdo);
+ __ lwz(Rscratch1, in_bytes(MethodData::invoke_mask_offset()), Rmdo);
__ addi(Rscratch2, Rscratch2, increment);
- __ stw(Rscratch2, mdo_bc_offs, Rmdo);
- __ load_const_optimized(Rscratch1, mask, R0);
+ __ stw(Rscratch2, mdo_ic_offs, Rmdo);
__ and_(Rscratch1, Rscratch2, Rscratch1);
__ bne(CCR0, done);
__ b(*overflow);
}
// Increment counter in MethodCounters*.
- const int mo_bc_offs = in_bytes(MethodCounters::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset());
+ const int mo_bc_offs = in_bytes(MethodCounters::invocation_counter_offset()) + in_bytes(InvocationCounter::counter_offset());
__ bind(no_mdo);
__ get_method_counters(R19_method, R3_counters, done);
__ lwz(Rscratch2, mo_bc_offs, R3_counters);
+ __ lwz(Rscratch1, in_bytes(MethodCounters::invoke_mask_offset()), R3_counters);
__ addi(Rscratch2, Rscratch2, increment);
__ stw(Rscratch2, mo_bc_offs, R3_counters);
- __ load_const_optimized(Rscratch1, mask, R0);
__ and_(Rscratch1, Rscratch2, Rscratch1);
__ beq(CCR0, *overflow);
@@ -303,8 +302,7 @@
// Check if we must create a method data obj.
if (ProfileInterpreter && profile_method != NULL) {
const Register profile_limit = Rscratch1;
- int pl_offs = __ load_const_optimized(profile_limit, &InvocationCounter::InterpreterProfileLimit, R0, true);
- __ lwz(profile_limit, pl_offs, profile_limit);
+ __ lwz(profile_limit, in_bytes(MethodCounters::interpreter_profile_limit_offset()), R3_counters);
// Test to see if we should create a method data oop.
__ cmpw(CCR0, Rsum_ivc_bec, profile_limit);
__ blt(CCR0, *profile_method_continue);
@@ -314,9 +312,7 @@
// Finally check for counter overflow.
if (overflow) {
const Register invocation_limit = Rscratch1;
- int il_offs = __ load_const_optimized(invocation_limit, &InvocationCounter::InterpreterInvocationLimit, R0, true);
- __ lwz(invocation_limit, il_offs, invocation_limit);
- assert(4 == sizeof(InvocationCounter::InterpreterInvocationLimit), "unexpected field size");
+ __ lwz(invocation_limit, in_bytes(MethodCounters::interpreter_invocation_limit_offset()), R3_counters);
__ cmpw(CCR0, Rsum_ivc_bec, invocation_limit);
__ bge(CCR0, *overflow);
}
@@ -1484,9 +1480,9 @@
intptr_t* locals_base = (caller->is_interpreted_frame()) ?
caller->interpreter_frame_esp() + caller_actual_parameters :
- caller->sp() + method->max_locals() - 1 + (frame::abi_minframe_size / Interpreter::stackElementSize) ;
+ caller->sp() + method->max_locals() - 1 + (frame::abi_minframe_size / Interpreter::stackElementSize);
- intptr_t* monitor_base = caller->sp() - frame::ijava_state_size / Interpreter::stackElementSize ;
+ intptr_t* monitor_base = caller->sp() - frame::ijava_state_size / Interpreter::stackElementSize;
intptr_t* monitor = monitor_base - (moncount * frame::interpreter_frame_monitor_size());
intptr_t* esp_base = monitor - 1;
intptr_t* esp = esp_base - tempcount - popframe_extra_args;
--- a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.hpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -37,5 +37,3 @@
const static int InterpreterCodeSize = 230*K;
#endif // CPU_PPC_VM_TEMPLATEINTERPRETER_PPC_HPP
-
-
--- a/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -1626,12 +1626,13 @@
// --------------------------------------------------------------------------
// Normal (non-jsr) branch handling
+ // Bump bytecode pointer by displacement (take the branch).
+ __ add(R14_bcp, Rdisp, R14_bcp); // Add to bc addr.
+
const bool increment_invocation_counter_for_backward_branches = UseCompiler && UseLoopCounter;
if (increment_invocation_counter_for_backward_branches) {
- //__ unimplemented("branch invocation counter");
-
Label Lforward;
- __ add(R14_bcp, Rdisp, R14_bcp); // Add to bc addr.
+ __ dispatch_prolog(vtos);
// Check branch direction.
__ cmpdi(CCR0, Rdisp, 0);
@@ -1642,7 +1643,6 @@
if (TieredCompilation) {
Label Lno_mdo, Loverflow;
const int increment = InvocationCounter::count_increment;
- const int mask = ((1 << Tier0BackedgeNotifyFreqLog) - 1) << InvocationCounter::count_shift;
if (ProfileInterpreter) {
Register Rmdo = Rscratch1;
@@ -1654,7 +1654,7 @@
// Increment backedge counter in the MDO.
const int mdo_bc_offs = in_bytes(MethodData::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset());
__ lwz(Rscratch2, mdo_bc_offs, Rmdo);
- __ load_const_optimized(Rscratch3, mask, R0);
+ __ lwz(Rscratch3, in_bytes(MethodData::backedge_mask_offset()), Rmdo);
__ addi(Rscratch2, Rscratch2, increment);
__ stw(Rscratch2, mdo_bc_offs, Rmdo);
__ and_(Rscratch3, Rscratch2, Rscratch3);
@@ -1666,19 +1666,19 @@
const int mo_bc_offs = in_bytes(MethodCounters::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset());
__ bind(Lno_mdo);
__ lwz(Rscratch2, mo_bc_offs, R4_counters);
- __ load_const_optimized(Rscratch3, mask, R0);
+ __ lwz(Rscratch3, in_bytes(MethodCounters::backedge_mask_offset()), R4_counters);
__ addi(Rscratch2, Rscratch2, increment);
- __ stw(Rscratch2, mo_bc_offs, R19_method);
+ __ stw(Rscratch2, mo_bc_offs, R4_counters);
__ and_(Rscratch3, Rscratch2, Rscratch3);
__ bne(CCR0, Lforward);
__ bind(Loverflow);
// Notify point for loop, pass branch bytecode.
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), R14_bcp, true);
+ __ subf(R4_ARG2, Rdisp, R14_bcp); // Compute branch bytecode (previous bcp).
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), R4_ARG2, true);
// Was an OSR adapter generated?
- // O0 = osr nmethod
__ cmpdi(CCR0, R3_RET, 0);
__ beq(CCR0, Lforward);
@@ -1714,27 +1714,23 @@
__ increment_backedge_counter(R4_counters, invoke_ctr, Rscratch2, Rscratch3);
if (ProfileInterpreter) {
- __ test_invocation_counter_for_mdp(invoke_ctr, Rscratch2, Lforward);
+ __ test_invocation_counter_for_mdp(invoke_ctr, R4_counters, Rscratch2, Lforward);
if (UseOnStackReplacement) {
- __ test_backedge_count_for_osr(bumped_count, R14_bcp, Rscratch2);
+ __ test_backedge_count_for_osr(bumped_count, R4_counters, R14_bcp, Rdisp, Rscratch2);
}
} else {
if (UseOnStackReplacement) {
- __ test_backedge_count_for_osr(invoke_ctr, R14_bcp, Rscratch2);
+ __ test_backedge_count_for_osr(invoke_ctr, R4_counters, R14_bcp, Rdisp, Rscratch2);
}
}
}
__ bind(Lforward);
+ __ dispatch_epilog(vtos);
} else {
- // Bump bytecode pointer by displacement (take the branch).
- __ add(R14_bcp, Rdisp, R14_bcp); // Add to bc addr.
+ __ dispatch_next(vtos);
}
- // Continue with bytecode @ target.
- // %%%%% Like Intel, could speed things up by moving bytecode fetch to code above,
- // %%%%% and changing dispatch_next to dispatch_only.
- __ dispatch_next(vtos);
}
// Helper function for if_cmp* methods below.
--- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -38,7 +38,6 @@
# include <sys/sysinfo.h>
int VM_Version::_features = VM_Version::unknown_m;
-int VM_Version::_measured_cache_line_size = 32; // pessimistic init value
const char* VM_Version::_features_str = "";
bool VM_Version::_is_determine_features_test_running = false;
@@ -56,7 +55,7 @@
// If PowerArchitecturePPC64 hasn't been specified explicitly determine from features.
if (FLAG_IS_DEFAULT(PowerArchitecturePPC64)) {
- if (VM_Version::has_lqarx()) {
+ if (VM_Version::has_tcheck() && VM_Version::has_lqarx()) {
FLAG_SET_ERGO(uintx, PowerArchitecturePPC64, 8);
} else if (VM_Version::has_popcntw()) {
FLAG_SET_ERGO(uintx, PowerArchitecturePPC64, 7);
@@ -68,10 +67,19 @@
FLAG_SET_ERGO(uintx, PowerArchitecturePPC64, 0);
}
}
- guarantee(PowerArchitecturePPC64 == 0 || PowerArchitecturePPC64 == 5 ||
- PowerArchitecturePPC64 == 6 || PowerArchitecturePPC64 == 7 ||
- PowerArchitecturePPC64 == 8,
- "PowerArchitecturePPC64 should be 0, 5, 6, 7, or 8");
+
+ bool PowerArchitecturePPC64_ok = false;
+ switch (PowerArchitecturePPC64) {
+ case 8: if (!VM_Version::has_tcheck() ) break;
+ if (!VM_Version::has_lqarx() ) break;
+ case 7: if (!VM_Version::has_popcntw()) break;
+ case 6: if (!VM_Version::has_cmpb() ) break;
+ case 5: if (!VM_Version::has_popcntb()) break;
+ case 0: PowerArchitecturePPC64_ok = true; break;
+ default: break;
+ }
+ guarantee(PowerArchitecturePPC64_ok, "PowerArchitecturePPC64 cannot be set to "
+ UINTX_FORMAT " on this machine", PowerArchitecturePPC64);
// Power 8: Configure Data Stream Control Register.
if (PowerArchitecturePPC64 >= 8) {
@@ -132,9 +140,15 @@
// and 'atomic long memory ops' (see Unsafe_GetLongVolatile).
_supports_cx8 = true;
+ // Used by C1.
+ _supports_atomic_getset4 = true;
+ _supports_atomic_getadd4 = true;
+ _supports_atomic_getset8 = true;
+ _supports_atomic_getadd8 = true;
+
UseSSE = 0; // Only on x86 and x64
- intx cache_line_size = _measured_cache_line_size;
+ intx cache_line_size = L1_data_cache_line_size();
if (FLAG_IS_DEFAULT(AllocatePrefetchStyle)) AllocatePrefetchStyle = 1;
@@ -261,11 +275,9 @@
}
}
- // This machine does not allow unaligned memory accesses
- if (UseUnalignedAccesses) {
- if (!FLAG_IS_DEFAULT(UseUnalignedAccesses))
- warning("Unaligned memory access is not available on this CPU");
- FLAG_SET_DEFAULT(UseUnalignedAccesses, false);
+ // This machine allows unaligned memory accesses
+ if (FLAG_IS_DEFAULT(UseUnalignedAccesses)) {
+ FLAG_SET_DEFAULT(UseUnalignedAccesses, true);
}
}
@@ -291,7 +303,7 @@
}
void VM_Version::print_features() {
- tty->print_cr("Version: %s cache_line_size = %d", cpu_features(), (int) get_cache_line_size());
+ tty->print_cr("Version: %s L1_data_cache_line_size=%d", cpu_features(), L1_data_cache_line_size());
}
#ifdef COMPILER2
@@ -592,7 +604,7 @@
int count = 0; // count zeroed bytes
for (int i = 0; i < BUFFER_SIZE; i++) if (test_area[i] == 0) count++;
guarantee(is_power_of_2(count), "cache line size needs to be a power of 2");
- _measured_cache_line_size = count;
+ _L1_data_cache_line_size = count;
// Execute code. Illegal instructions will be replaced by 0 in the signal handler.
VM_Version::_is_determine_features_test_running = true;
--- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -65,7 +65,6 @@
all_features_m = -1
};
static int _features;
- static int _measured_cache_line_size;
static const char* _features_str;
static bool _is_determine_features_test_running;
@@ -99,8 +98,6 @@
static const char* cpu_features() { return _features_str; }
- static int get_cache_line_size() { return _measured_cache_line_size; }
-
// Assembler testing
static void allow_all();
static void revert();
--- a/hotspot/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -76,7 +76,8 @@
// We might implicit NULL fault here.
address npe_addr = __ pc(); // npe = null pointer exception
- __ load_klass_with_trap_null_check(rcvr_klass, R3);
+ __ null_check(R3, oopDesc::klass_offset_in_bytes(), /*implicit only*/NULL);
+ __ load_klass(rcvr_klass, R3);
// Set method (in case of interpreted method), and destination address.
int entry_offset = InstanceKlass::vtable_start_offset() + vtable_index*vtableEntry::size();
@@ -111,8 +112,8 @@
// If the vtable entry is null, the method is abstract.
address ame_addr = __ pc(); // ame = abstract method error
-
- __ load_with_trap_null_check(R12_scratch2, in_bytes(Method::from_compiled_offset()), R19_method);
+ __ null_check(R19_method, in_bytes(Method::from_compiled_offset()), /*implicit only*/NULL);
+ __ ld(R12_scratch2, in_bytes(Method::from_compiled_offset()), R19_method);
__ mtctr(R12_scratch2);
__ bctr();
masm->flush();
@@ -158,7 +159,8 @@
// We might implicit NULL fault here.
address npe_addr = __ pc(); // npe = null pointer exception
- __ load_klass_with_trap_null_check(rcvr_klass, R3_ARG1);
+ __ null_check(R3_ARG1, oopDesc::klass_offset_in_bytes(), /*implicit only*/NULL);
+ __ load_klass(rcvr_klass, R3_ARG1);
BLOCK_COMMENT("Load start of itable entries into itable_entry.");
__ lwz(vtable_len, InstanceKlass::vtable_length_offset() * wordSize, rcvr_klass);
@@ -217,15 +219,7 @@
address ame_addr = __ pc(); // ame = abstract method error
// Must do an explicit check if implicit checks are disabled.
- assert(!MacroAssembler::needs_explicit_null_check(in_bytes(Method::from_compiled_offset())), "sanity");
- if (!ImplicitNullChecks || !os::zero_page_read_protected()) {
- if (TrapBasedNullChecks) {
- __ trap_null_check(R19_method);
- } else {
- __ cmpdi(CCR0, R19_method, 0);
- __ beq(CCR0, throw_icce);
- }
- }
+ __ null_check(R19_method, in_bytes(Method::from_compiled_offset()), &throw_icce);
__ ld(R12_scratch2, in_bytes(Method::from_compiled_offset()), R19_method);
__ mtctr(R12_scratch2);
__ bctr();
--- a/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -816,6 +816,8 @@
inline void call( address d, relocInfo::relocType rt = relocInfo::runtime_call_type );
inline void call( Label& L, relocInfo::relocType rt = relocInfo::runtime_call_type );
+ inline void call( address d, RelocationHolder const& rspec );
+
public:
// pp 150
--- a/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -76,6 +76,8 @@
inline void Assembler::call( address d, relocInfo::relocType rt ) { insert_nop_after_cbcond(); cti(); emit_data( op(call_op) | wdisp(intptr_t(d), intptr_t(pc()), 30), rt); has_delay_slot(); assert(rt != relocInfo::virtual_call_type, "must use virtual_call_Relocation::spec"); }
inline void Assembler::call( Label& L, relocInfo::relocType rt ) { insert_nop_after_cbcond(); call( target(L), rt); }
+inline void Assembler::call( address d, RelocationHolder const& rspec ) { insert_nop_after_cbcond(); cti(); emit_data( op(call_op) | wdisp(intptr_t(d), intptr_t(pc()), 30), rspec); has_delay_slot(); assert(rspec.type() != relocInfo::virtual_call_type, "must use virtual_call_Relocation::spec"); }
+
inline void Assembler::flush( Register s1, Register s2) { emit_int32( op(arith_op) | op3(flush_op3) | rs1(s1) | rs2(s2)); }
inline void Assembler::flush( Register s1, int simm13a) { emit_data( op(arith_op) | op3(flush_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
--- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -770,8 +770,8 @@
}
-void MacroAssembler::ic_call(address entry, bool emit_delay) {
- RelocationHolder rspec = virtual_call_Relocation::spec(pc());
+void MacroAssembler::ic_call(address entry, bool emit_delay, jint method_index) {
+ RelocationHolder rspec = virtual_call_Relocation::spec(pc(), method_index);
patchable_set((intptr_t)Universe::non_oop_word(), G5_inline_cache_reg);
relocate(rspec);
call(entry, relocInfo::none);
@@ -780,7 +780,6 @@
}
}
-
void MacroAssembler::card_table_write(jbyte* byte_map_base,
Register tmp, Register obj) {
#ifdef _LP64
--- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -729,7 +729,11 @@
// Check if the call target is out of wdisp30 range (relative to the code cache)
static inline bool is_far_target(address d);
inline void call( address d, relocInfo::relocType rt = relocInfo::runtime_call_type );
+ inline void call( address d, RelocationHolder const& rspec);
+
inline void call( Label& L, relocInfo::relocType rt = relocInfo::runtime_call_type );
+ inline void call( Label& L, RelocationHolder const& rspec);
+
inline void callr( Register s1, Register s2 );
inline void callr( Register s1, int simm13a, RelocationHolder const& rspec = RelocationHolder() );
@@ -1146,7 +1150,7 @@
void set_vm_result(Register oop_result);
// Emit the CompiledIC call idiom
- void ic_call(address entry, bool emit_delay = true);
+ void ic_call(address entry, bool emit_delay = true, jint method_index = 0);
// if call_VM_base was called with check_exceptions=false, then call
// check_and_forward_exception to handle exceptions when it is safe
--- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.inline.hpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.inline.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -298,6 +298,10 @@
// expense of relocation and if we overflow the displacement
// of the quick call instruction.
inline void MacroAssembler::call( address d, relocInfo::relocType rt ) {
+ MacroAssembler::call(d, Relocation::spec_simple(rt));
+}
+
+inline void MacroAssembler::call( address d, RelocationHolder const& rspec ) {
#ifdef _LP64
intptr_t disp;
// NULL is ok because it will be relocated later.
@@ -309,14 +313,14 @@
// Is this address within range of the call instruction?
// If not, use the expensive instruction sequence
if (is_far_target(d)) {
- relocate(rt);
+ relocate(rspec);
AddressLiteral dest(d);
jumpl_to(dest, O7, O7);
} else {
- Assembler::call(d, rt);
+ Assembler::call(d, rspec);
}
#else
- Assembler::call( d, rt );
+ Assembler::call( d, rspec );
#endif
}
--- a/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -131,8 +131,9 @@
void NativeCall::verify() {
NativeInstruction::verify();
// make sure code pattern is actually a call instruction
- if (!is_op(long_at(0), Assembler::call_op)) {
- fatal("not a call");
+ int x = long_at(0);
+ if (!is_op(x, Assembler::call_op)) {
+ fatal("not a call: 0x%x @ " INTPTR_FORMAT, x, p2i(instruction_address()));
}
}
--- a/hotspot/src/cpu/sparc/vm/sparc.ad Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/sparc/vm/sparc.ad Fri Dec 04 23:50:05 2015 +0000
@@ -1001,7 +1001,7 @@
#endif
}
-void emit_call_reloc(CodeBuffer &cbuf, intptr_t entry_point, relocInfo::relocType rtype, bool preserve_g2 = false) {
+void emit_call_reloc(CodeBuffer &cbuf, intptr_t entry_point, RelocationHolder const& rspec, bool preserve_g2 = false) {
// The method which records debug information at every safepoint
// expects the call to be the first instruction in the snippet as
// it creates a PcDesc structure which tracks the offset of a call
@@ -1023,7 +1023,7 @@
int startpos = __ offset();
#endif /* ASSERT */
- __ call((address)entry_point, rtype);
+ __ call((address)entry_point, rspec);
if (preserve_g2) __ delayed()->mov(G2, L7);
else __ delayed()->nop();
@@ -2593,8 +2593,7 @@
enc_class Java_To_Runtime (method meth) %{ // CALL Java_To_Runtime
// CALL directly to the runtime
// The user of this is responsible for ensuring that R_L7 is empty (killed).
- emit_call_reloc(cbuf, $meth$$method, relocInfo::runtime_call_type,
- /*preserve_g2=*/true);
+ emit_call_reloc(cbuf, $meth$$method, runtime_call_Relocation::spec(), /*preserve_g2=*/true);
%}
enc_class preserve_SP %{
@@ -2611,13 +2610,14 @@
// CALL to fixup routine. Fixup routine uses ScopeDesc info to determine
// who we intended to call.
if (!_method) {
- emit_call_reloc(cbuf, $meth$$method, relocInfo::runtime_call_type);
- } else if (_optimized_virtual) {
- emit_call_reloc(cbuf, $meth$$method, relocInfo::opt_virtual_call_type);
+ emit_call_reloc(cbuf, $meth$$method, runtime_call_Relocation::spec());
} else {
- emit_call_reloc(cbuf, $meth$$method, relocInfo::static_call_type);
- }
- if (_method) { // Emit stub for static call.
+ int method_index = resolved_method_index(cbuf);
+ RelocationHolder rspec = _optimized_virtual ? opt_virtual_call_Relocation::spec(method_index)
+ : static_call_Relocation::spec(method_index);
+ emit_call_reloc(cbuf, $meth$$method, rspec);
+
+ // Emit stub for static call.
address stub = CompiledStaticCall::emit_to_interp_stub(cbuf);
// Stub does not fit into scratch buffer if TraceJumps is enabled
if (stub == NULL && !(TraceJumps && Compile::current()->in_scratch_emit_size())) {
@@ -2638,7 +2638,7 @@
Register G5_ic_reg = reg_to_register_object(Matcher::inline_cache_reg_encode());
assert(G5_ic_reg == G5_inline_cache_reg, "G5_inline_cache_reg used in assemble_ic_buffer_code()");
assert(G5_ic_reg == G5_megamorphic_method, "G5_megamorphic_method used in megamorphic call stub");
- __ ic_call((address)$meth$$method);
+ __ ic_call((address)$meth$$method, /*emit_delay=*/true, resolved_method_index(cbuf));
} else {
assert(!UseInlineCaches, "expect vtable calls only if not using ICs");
// Just go thru the vtable
@@ -10069,10 +10069,10 @@
format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp" %}
ins_encode %{
__ string_compare($str1$$Register, $str2$$Register,
- $cnt1$$Register, $cnt2$$Register,
+ $cnt1$$Register, $cnt2$$Register,
$tmp$$Register, $tmp$$Register,
$result$$Register, StrIntrinsicNode::LL);
- %}
+ %}
ins_pipe(long_memory_op);
%}
@@ -10088,7 +10088,7 @@
$cnt1$$Register, $cnt2$$Register,
$tmp$$Register, $tmp$$Register,
$result$$Register, StrIntrinsicNode::UU);
- %}
+ %}
ins_pipe(long_memory_op);
%}
@@ -10104,7 +10104,7 @@
$cnt1$$Register, $cnt2$$Register,
$tmp1$$Register, $tmp2$$Register,
$result$$Register, StrIntrinsicNode::LU);
- %}
+ %}
ins_pipe(long_memory_op);
%}
@@ -10117,10 +10117,10 @@
format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp1,$tmp2" %}
ins_encode %{
__ string_compare($str2$$Register, $str1$$Register,
- $cnt2$$Register, $cnt1$$Register,
+ $cnt2$$Register, $cnt1$$Register,
$tmp1$$Register, $tmp2$$Register,
$result$$Register, StrIntrinsicNode::UL);
- %}
+ %}
ins_pipe(long_memory_op);
%}
--- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -2260,8 +2260,8 @@
}
}
-void MacroAssembler::ic_call(address entry) {
- RelocationHolder rh = virtual_call_Relocation::spec(pc());
+void MacroAssembler::ic_call(address entry, jint method_index) {
+ RelocationHolder rh = virtual_call_Relocation::spec(pc(), method_index);
movptr(rax, (intptr_t)Universe::non_oop_word());
call(AddressLiteral(entry, rh));
}
--- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -850,7 +850,7 @@
void call(AddressLiteral entry);
// Emit the CompiledIC call idiom
- void ic_call(address entry);
+ void ic_call(address entry, jint method_index = 0);
// Jumps
--- a/hotspot/src/cpu/x86/vm/x86_32.ad Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/x86/vm/x86_32.ad Fri Dec 04 23:50:05 2015 +0000
@@ -1898,17 +1898,18 @@
// who we intended to call.
cbuf.set_insts_mark();
$$$emit8$primary;
+
if (!_method) {
emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.insts_end()) - 4),
- runtime_call_Relocation::spec(), RELOC_IMM32 );
- } else if (_optimized_virtual) {
- emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.insts_end()) - 4),
- opt_virtual_call_Relocation::spec(), RELOC_IMM32 );
+ runtime_call_Relocation::spec(),
+ RELOC_IMM32);
} else {
+ int method_index = resolved_method_index(cbuf);
+ RelocationHolder rspec = _optimized_virtual ? opt_virtual_call_Relocation::spec(method_index)
+ : static_call_Relocation::spec(method_index);
emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.insts_end()) - 4),
- static_call_Relocation::spec(), RELOC_IMM32 );
- }
- if (_method) { // Emit stub for static call.
+ rspec, RELOC_DISP32);
+ // Emit stubs for static call.
address stub = CompiledStaticCall::emit_to_interp_stub(cbuf);
if (stub == NULL) {
ciEnv::current()->record_failure("CodeCache is full");
@@ -1919,7 +1920,7 @@
enc_class Java_Dynamic_Call (method meth) %{ // JAVA DYNAMIC CALL
MacroAssembler _masm(&cbuf);
- __ ic_call((address)$meth$$method);
+ __ ic_call((address)$meth$$method, resolved_method_index(cbuf));
%}
enc_class Java_Compiled_Call (method meth) %{ // JAVA COMPILED CALL
@@ -11504,7 +11505,7 @@
__ arrays_equals(false, $str1$$Register, $str2$$Register,
$cnt$$Register, $result$$Register, $tmp3$$Register,
$tmp1$$XMMRegister, $tmp2$$XMMRegister, false /* char */);
- %}
+ %}
ins_pipe( pipe_slow );
%}
--- a/hotspot/src/cpu/x86/vm/x86_64.ad Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/cpu/x86/vm/x86_64.ad Fri Dec 04 23:50:05 2015 +0000
@@ -2120,22 +2120,15 @@
$$$emit8$primary;
if (!_method) {
- emit_d32_reloc(cbuf,
- (int) ($meth$$method - ((intptr_t) cbuf.insts_end()) - 4),
+ emit_d32_reloc(cbuf, (int) ($meth$$method - ((intptr_t) cbuf.insts_end()) - 4),
runtime_call_Relocation::spec(),
RELOC_DISP32);
- } else if (_optimized_virtual) {
- emit_d32_reloc(cbuf,
- (int) ($meth$$method - ((intptr_t) cbuf.insts_end()) - 4),
- opt_virtual_call_Relocation::spec(),
- RELOC_DISP32);
} else {
- emit_d32_reloc(cbuf,
- (int) ($meth$$method - ((intptr_t) cbuf.insts_end()) - 4),
- static_call_Relocation::spec(),
- RELOC_DISP32);
- }
- if (_method) {
+ int method_index = resolved_method_index(cbuf);
+ RelocationHolder rspec = _optimized_virtual ? opt_virtual_call_Relocation::spec(method_index)
+ : static_call_Relocation::spec(method_index);
+ emit_d32_reloc(cbuf, (int) ($meth$$method - ((intptr_t) cbuf.insts_end()) - 4),
+ rspec, RELOC_DISP32);
// Emit stubs for static call.
address mark = cbuf.insts_mark();
address stub = CompiledStaticCall::emit_to_interp_stub(cbuf, mark);
@@ -2148,7 +2141,7 @@
enc_class Java_Dynamic_Call(method meth) %{
MacroAssembler _masm(&cbuf);
- __ ic_call((address)$meth$$method);
+ __ ic_call((address)$meth$$method, resolved_method_index(cbuf));
%}
enc_class Java_Compiled_Call(method meth)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/os/aix/vm/c1_globals_aix.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012, 2015 SAP AG. 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.
+ *
+ */
+
+#ifndef OS_AIX_VM_C1_GLOBALS_AIX_HPP
+#define OS_AIX_VM_C1_GLOBALS_AIX_HPP
+
+#include "utilities/globalDefinitions.hpp"
+#include "utilities/macros.hpp"
+
+//
+// Sets the default values for operating system dependent flags used by the
+// client compiler. (see c1_globals.hpp)
+//
+
+#endif // OS_AIX_VM_C1_GLOBALS_AIX_HPP
--- a/hotspot/src/share/vm/asm/codeBuffer.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/share/vm/asm/codeBuffer.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -305,6 +305,31 @@
}
}
+void CodeSection::relocate(address at, relocInfo::relocType rtype, int format, jint method_index) {
+ RelocationHolder rh;
+ switch (rtype) {
+ case relocInfo::none: return;
+ case relocInfo::opt_virtual_call_type: {
+ rh = opt_virtual_call_Relocation::spec(method_index);
+ break;
+ }
+ case relocInfo::static_call_type: {
+ rh = static_call_Relocation::spec(method_index);
+ break;
+ }
+ case relocInfo::virtual_call_type: {
+ assert(method_index == 0, "resolved method overriding is not supported");
+ rh = Relocation::spec_simple(rtype);
+ break;
+ }
+ default: {
+ rh = Relocation::spec_simple(rtype);
+ break;
+ }
+ }
+ relocate(at, rh, format);
+}
+
void CodeSection::relocate(address at, RelocationHolder const& spec, int format) {
Relocation* reloc = spec.reloc();
relocInfo::relocType rtype = (relocInfo::relocType) reloc->type();
--- a/hotspot/src/share/vm/asm/codeBuffer.hpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/share/vm/asm/codeBuffer.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -209,10 +209,7 @@
// Emit a relocation.
void relocate(address at, RelocationHolder const& rspec, int format = 0);
- void relocate(address at, relocInfo::relocType rtype, int format = 0) {
- if (rtype != relocInfo::none)
- relocate(at, Relocation::spec_simple(rtype), format);
- }
+ void relocate(address at, relocInfo::relocType rtype, int format = 0, jint method_index = 0);
// alignment requirement for starting offset
// Requirements are that the instruction area and the
--- a/hotspot/src/share/vm/ci/ciMethod.hpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/share/vm/ci/ciMethod.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -250,6 +250,12 @@
ciField* get_field_at_bci( int bci, bool &will_link);
ciMethod* get_method_at_bci(int bci, bool &will_link, ciSignature* *declared_signature);
+ ciMethod* get_method_at_bci(int bci) {
+ bool ignored_will_link;
+ ciSignature* ignored_declared_signature;
+ return get_method_at_bci(bci, ignored_will_link, &ignored_declared_signature);
+ }
+
// Given a certain calling environment, find the monomorphic target
// for the call. Return NULL if the call is not monomorphic in
// its calling environment.
--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -1054,6 +1054,11 @@
do_name( isCompileConstant_name, "isCompileConstant") \
do_alias( isCompileConstant_signature, object_boolean_signature) \
\
+ do_class(sun_hotspot_WhiteBox, "sun/hotspot/WhiteBox") \
+ do_intrinsic(_deoptimize, sun_hotspot_WhiteBox, deoptimize_name, deoptimize_signature, F_R) \
+ do_name( deoptimize_name, "deoptimize") \
+ do_alias( deoptimize_signature, void_method_signature) \
+ \
/* unsafe memory references (there are a lot of them...) */ \
do_signature(getObject_signature, "(Ljava/lang/Object;J)Ljava/lang/Object;") \
do_signature(putObject_signature, "(Ljava/lang/Object;JLjava/lang/Object;)V") \
--- a/hotspot/src/share/vm/code/compiledIC.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/share/vm/code/compiledIC.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -434,7 +434,7 @@
InlineCacheBuffer::create_transition_stub(this, info.cached_metadata(), info.entry());
} else {
if (is_optimized()) {
- set_ic_destination(info.entry());
+ set_ic_destination(info.entry());
} else {
set_ic_destination_and_value(info.entry(), info.cached_metadata());
}
--- a/hotspot/src/share/vm/code/nmethod.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/share/vm/code/nmethod.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -978,19 +978,23 @@
oop_maps()->print();
}
}
- if (PrintDebugInfo || CompilerOracle::has_option_string(_method, "PrintDebugInfo")) {
+ if (printmethod || PrintDebugInfo || CompilerOracle::has_option_string(_method, "PrintDebugInfo")) {
print_scopes();
}
- if (PrintRelocations || CompilerOracle::has_option_string(_method, "PrintRelocations")) {
+ if (printmethod || PrintRelocations || CompilerOracle::has_option_string(_method, "PrintRelocations")) {
print_relocations();
}
- if (PrintDependencies || CompilerOracle::has_option_string(_method, "PrintDependencies")) {
+ if (printmethod || PrintDependencies || CompilerOracle::has_option_string(_method, "PrintDependencies")) {
print_dependencies();
}
- if (PrintExceptionHandlers) {
+ if (printmethod || PrintExceptionHandlers) {
print_handler_table();
print_nul_chk_table();
}
+ if (printmethod) {
+ print_recorded_oops();
+ print_recorded_metadata();
+ }
if (xtty != NULL) {
xtty->tail("print_nmethod");
}
@@ -3013,6 +3017,26 @@
}
}
+void nmethod::print_recorded_oops() {
+ tty->print_cr("Recorded oops:");
+ for (int i = 0; i < oops_count(); i++) {
+ oop o = oop_at(i);
+ tty->print("#%3d: " INTPTR_FORMAT " ", i, p2i(o));
+ o->print_value();
+ tty->cr();
+ }
+}
+
+void nmethod::print_recorded_metadata() {
+ tty->print_cr("Recorded metadata:");
+ for (int i = 0; i < metadata_count(); i++) {
+ Metadata* m = metadata_at(i);
+ tty->print("#%3d: " INTPTR_FORMAT " ", i, p2i(m));
+ m->print_value_on_maybe_null(tty);
+ tty->cr();
+ }
+}
+
#endif // PRODUCT
const char* nmethod::reloc_string_for(u_char* begin, u_char* end) {
@@ -3053,9 +3077,39 @@
}
return st.as_string();
}
- case relocInfo::virtual_call_type: return "virtual_call";
- case relocInfo::opt_virtual_call_type: return "optimized virtual_call";
- case relocInfo::static_call_type: return "static_call";
+ case relocInfo::virtual_call_type: {
+ stringStream st;
+ st.print_raw("virtual_call");
+ virtual_call_Relocation* r = iter.virtual_call_reloc();
+ Method* m = r->method_value();
+ if (m != NULL) {
+ assert(m->is_method(), "");
+ m->print_short_name(&st);
+ }
+ return st.as_string();
+ }
+ case relocInfo::opt_virtual_call_type: {
+ stringStream st;
+ st.print_raw("optimized virtual_call");
+ opt_virtual_call_Relocation* r = iter.opt_virtual_call_reloc();
+ Method* m = r->method_value();
+ if (m != NULL) {
+ assert(m->is_method(), "");
+ m->print_short_name(&st);
+ }
+ return st.as_string();
+ }
+ case relocInfo::static_call_type: {
+ stringStream st;
+ st.print_raw("static_call");
+ static_call_Relocation* r = iter.static_call_reloc();
+ Method* m = r->method_value();
+ if (m != NULL) {
+ assert(m->is_method(), "");
+ m->print_short_name(&st);
+ }
+ return st.as_string();
+ }
case relocInfo::static_stub_type: return "static_stub";
case relocInfo::external_word_type: return "external_word";
case relocInfo::internal_word_type: return "internal_word";
@@ -3393,3 +3447,19 @@
return buf;
}
#endif
+
+Method* nmethod::attached_method(address call_instr) {
+ assert(code_contains(call_instr), "not part of the nmethod");
+ RelocIterator iter(this, call_instr, call_instr + 1);
+ while (iter.next()) {
+ if (iter.addr() == call_instr) {
+ switch(iter.type()) {
+ case relocInfo::static_call_type: return iter.static_call_reloc()->method_value();
+ case relocInfo::opt_virtual_call_type: return iter.opt_virtual_call_reloc()->method_value();
+ case relocInfo::virtual_call_type: return iter.virtual_call_reloc()->method_value();
+ }
+ }
+ }
+ return NULL; // not found
+}
+
--- a/hotspot/src/share/vm/code/nmethod.hpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/share/vm/code/nmethod.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -392,6 +392,9 @@
int handler_table_size() const { return handler_table_end() - handler_table_begin(); }
int nul_chk_table_size() const { return nul_chk_table_end() - nul_chk_table_begin(); }
+ int oops_count() const { assert(oops_size() % oopSize == 0, ""); return (oops_size() / oopSize) + 1; }
+ int metadata_count() const { assert(metadata_size() % wordSize == 0, ""); return (metadata_size() / wordSize) + 1; }
+
int total_size () const;
void dec_hotness_counter() { _hotness_counter--; }
@@ -491,7 +494,7 @@
oop oop_at(int index) const { return index == 0 ? (oop) NULL: *oop_addr_at(index); }
oop* oop_addr_at(int index) const { // for GC
// relocation indexes are biased by 1 (because 0 is reserved)
- assert(index > 0 && index <= oops_size(), "must be a valid non-zero index");
+ assert(index > 0 && index <= oops_count(), "must be a valid non-zero index");
assert(!_oops_are_stale, "oops are stale");
return &oops_begin()[index - 1];
}
@@ -501,13 +504,15 @@
Metadata* metadata_at(int index) const { return index == 0 ? NULL: *metadata_addr_at(index); }
Metadata** metadata_addr_at(int index) const { // for GC
// relocation indexes are biased by 1 (because 0 is reserved)
- assert(index > 0 && index <= metadata_size(), "must be a valid non-zero index");
+ assert(index > 0 && index <= metadata_count(), "must be a valid non-zero index");
return &metadata_begin()[index - 1];
}
void copy_values(GrowableArray<jobject>* oops);
void copy_values(GrowableArray<Metadata*>* metadata);
+ Method* attached_method(address call_pc);
+
// Relocation support
private:
void fix_oop_relocations(address begin, address end, bool initialize_immediates);
@@ -696,6 +701,8 @@
void print_calls(outputStream* st) PRODUCT_RETURN;
void print_handler_table() PRODUCT_RETURN;
void print_nul_chk_table() PRODUCT_RETURN;
+ void print_recorded_oops() PRODUCT_RETURN;
+ void print_recorded_metadata() PRODUCT_RETURN;
void print_nmethod(bool print_code);
// need to re-define this from CodeBlob else the overload hides it
--- a/hotspot/src/share/vm/code/relocInfo.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/share/vm/code/relocInfo.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -581,13 +581,14 @@
normalize_address(_cached_value, dest);
jint x0 = scaled_offset_null_special(_cached_value, point);
- p = pack_1_int_to(p, x0);
+ p = pack_2_ints_to(p, x0, _method_index);
dest->set_locs_end((relocInfo*) p);
}
void virtual_call_Relocation::unpack_data() {
- jint x0 = unpack_1_int();
+ jint x0 = 0;
+ unpack_2_ints(x0, _method_index);
address point = addr();
_cached_value = x0==0? NULL: address_from_scaled_offset(x0, point);
}
@@ -793,6 +794,12 @@
return _cached_value;
}
+Method* virtual_call_Relocation::method_value() {
+ Metadata* m = code()->metadata_at(_method_index);
+ assert(m != NULL || _method_index == 0, "should be non-null for non-zero index");
+ assert(m == NULL || m->is_method(), "not a method");
+ return (Method*)m;
+}
void virtual_call_Relocation::clear_inline_cache() {
// No stubs for ICs
@@ -803,6 +810,23 @@
}
+void opt_virtual_call_Relocation::pack_data_to(CodeSection* dest) {
+ short* p = (short*) dest->locs_end();
+ p = pack_1_int_to(p, _method_index);
+ dest->set_locs_end((relocInfo*) p);
+}
+
+void opt_virtual_call_Relocation::unpack_data() {
+ _method_index = unpack_1_int();
+}
+
+Method* opt_virtual_call_Relocation::method_value() {
+ Metadata* m = code()->metadata_at(_method_index);
+ assert(m != NULL || _method_index == 0, "should be non-null for non-zero index");
+ assert(m == NULL || m->is_method(), "not a method");
+ return (Method*)m;
+}
+
void opt_virtual_call_Relocation::clear_inline_cache() {
// No stubs for ICs
// Clean IC
@@ -827,6 +851,22 @@
return NULL;
}
+Method* static_call_Relocation::method_value() {
+ Metadata* m = code()->metadata_at(_method_index);
+ assert(m != NULL || _method_index == 0, "should be non-null for non-zero index");
+ assert(m == NULL || m->is_method(), "not a method");
+ return (Method*)m;
+}
+
+void static_call_Relocation::pack_data_to(CodeSection* dest) {
+ short* p = (short*) dest->locs_end();
+ p = pack_1_int_to(p, _method_index);
+ dest->set_locs_end((relocInfo*) p);
+}
+
+void static_call_Relocation::unpack_data() {
+ _method_index = unpack_1_int();
+}
void static_call_Relocation::clear_inline_cache() {
// Safe call site info
@@ -1014,6 +1054,12 @@
break;
}
case relocInfo::static_call_type:
+ {
+ static_call_Relocation* r = (static_call_Relocation*) reloc();
+ tty->print(" | [destination=" INTPTR_FORMAT " metadata=" INTPTR_FORMAT "]",
+ p2i(r->destination()), p2i(r->method_value()));
+ break;
+ }
case relocInfo::runtime_call_type:
{
CallRelocation* r = (CallRelocation*) reloc();
@@ -1023,8 +1069,8 @@
case relocInfo::virtual_call_type:
{
virtual_call_Relocation* r = (virtual_call_Relocation*) reloc();
- tty->print(" | [destination=" INTPTR_FORMAT " cached_value=" INTPTR_FORMAT "]",
- p2i(r->destination()), p2i(r->cached_value()));
+ tty->print(" | [destination=" INTPTR_FORMAT " cached_value=" INTPTR_FORMAT " metadata=" INTPTR_FORMAT "]",
+ p2i(r->destination()), p2i(r->cached_value()), p2i(r->method_value()));
break;
}
case relocInfo::static_stub_type:
@@ -1039,6 +1085,13 @@
tty->print(" | [trampoline owner=" INTPTR_FORMAT "]", p2i(r->owner()));
break;
}
+ case relocInfo::opt_virtual_call_type:
+ {
+ opt_virtual_call_Relocation* r = (opt_virtual_call_Relocation*) reloc();
+ tty->print(" | [destination=" INTPTR_FORMAT " metadata=" INTPTR_FORMAT "]",
+ p2i(r->destination()), p2i(r->method_value()));
+ break;
+ }
}
tty->cr();
}
--- a/hotspot/src/share/vm/code/relocInfo.hpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/share/vm/code/relocInfo.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -1044,27 +1044,31 @@
// "cached_value" points to the first associated set-oop.
// The oop_limit helps find the last associated set-oop.
// (See comments at the top of this file.)
- static RelocationHolder spec(address cached_value) {
+ static RelocationHolder spec(address cached_value, jint method_index = 0) {
RelocationHolder rh = newHolder();
- new(rh) virtual_call_Relocation(cached_value);
+ new(rh) virtual_call_Relocation(cached_value, method_index);
return rh;
}
- virtual_call_Relocation(address cached_value) {
+ private:
+ address _cached_value; // location of set-value instruction
+ jint _method_index; // resolved method for a Java call
+
+ virtual_call_Relocation(address cached_value, int method_index) {
_cached_value = cached_value;
+ _method_index = method_index;
assert(cached_value != NULL, "first oop address must be specified");
}
- private:
- address _cached_value; // location of set-value instruction
-
friend class RelocIterator;
virtual_call_Relocation() { }
-
public:
address cached_value();
+ int method_index() { return _method_index; }
+ Method* method_value();
+
// data is packed as scaled offsets in "2_ints" format: [f l] or [Ff Ll]
// oop_limit is set to 0 if the limit falls somewhere within the call.
// When unpacking, a zero oop_limit is taken to refer to the end of the call.
@@ -1080,17 +1084,29 @@
relocInfo::relocType type() { return relocInfo::opt_virtual_call_type; }
public:
- static RelocationHolder spec() {
+ static RelocationHolder spec(int method_index = 0) {
RelocationHolder rh = newHolder();
- new(rh) opt_virtual_call_Relocation();
+ new(rh) opt_virtual_call_Relocation(method_index);
return rh;
}
private:
+ jint _method_index; // resolved method for a Java call
+
+ opt_virtual_call_Relocation(int method_index) {
+ _method_index = method_index;
+ }
+
friend class RelocIterator;
- opt_virtual_call_Relocation() { }
+ opt_virtual_call_Relocation() {}
public:
+ int method_index() { return _method_index; }
+ Method* method_value();
+
+ void pack_data_to(CodeSection* dest);
+ void unpack_data();
+
void clear_inline_cache();
// find the matching static_stub
@@ -1102,17 +1118,29 @@
relocInfo::relocType type() { return relocInfo::static_call_type; }
public:
- static RelocationHolder spec() {
+ static RelocationHolder spec(int method_index = 0) {
RelocationHolder rh = newHolder();
- new(rh) static_call_Relocation();
+ new(rh) static_call_Relocation(method_index);
return rh;
}
private:
+ jint _method_index; // resolved method for a Java call
+
+ static_call_Relocation(int method_index) {
+ _method_index = method_index;
+ }
+
friend class RelocIterator;
- static_call_Relocation() { }
+ static_call_Relocation() {}
public:
+ int method_index() { return _method_index; }
+ Method* method_value();
+
+ void pack_data_to(CodeSection* dest);
+ void unpack_data();
+
void clear_inline_cache();
// find the matching static_stub
--- a/hotspot/src/share/vm/interpreter/linkResolver.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -1456,6 +1456,33 @@
return;
}
+void LinkResolver::resolve_invoke(CallInfo& result, Handle& recv,
+ const methodHandle& attached_method,
+ Bytecodes::Code byte, TRAPS) {
+ KlassHandle defc = attached_method->method_holder();
+ Symbol* name = attached_method->name();
+ Symbol* type = attached_method->signature();
+ LinkInfo link_info(defc, name, type, KlassHandle(), /*check_access=*/false);
+ switch(byte) {
+ case Bytecodes::_invokevirtual:
+ resolve_virtual_call(result, recv, recv->klass(), link_info,
+ /*check_null_and_abstract=*/true, CHECK);
+ break;
+ case Bytecodes::_invokeinterface:
+ resolve_interface_call(result, recv, recv->klass(), link_info,
+ /*check_null_and_abstract=*/true, CHECK);
+ break;
+ case Bytecodes::_invokestatic:
+ resolve_static_call(result, link_info, /*initialize_class=*/false, CHECK);
+ break;
+ case Bytecodes::_invokespecial:
+ resolve_special_call(result, link_info, CHECK);
+ break;
+ default:
+ fatal("bad call: %s", Bytecodes::name(byte));
+ }
+}
+
void LinkResolver::resolve_invokestatic(CallInfo& result, const constantPoolHandle& pool, int index, TRAPS) {
LinkInfo link_info(pool, index, CHECK);
resolve_static_call(result, link_info, /*initialize_class*/true, CHECK);
--- a/hotspot/src/share/vm/interpreter/linkResolver.hpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/share/vm/interpreter/linkResolver.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -295,6 +295,12 @@
static void resolve_invoke(CallInfo& result, Handle recv,
const constantPoolHandle& pool, int index,
Bytecodes::Code byte, TRAPS);
+
+ // runtime resolving from attached method
+ static void resolve_invoke(CallInfo& result, Handle& recv,
+ const methodHandle& attached_method,
+ Bytecodes::Code byte, TRAPS);
+
private:
static void trace_method_resolution(const char* prefix, KlassHandle klass,
KlassHandle resolved_klass,
--- a/hotspot/src/share/vm/opto/block.hpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/share/vm/opto/block.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -419,12 +419,12 @@
void global_code_motion();
// Schedule Nodes early in their basic blocks.
- bool schedule_early(VectorSet &visited, Node_List &roots);
+ bool schedule_early(VectorSet &visited, Node_Stack &roots);
// For each node, find the latest block it can be scheduled into
// and then select the cheapest block between the latest and earliest
// block to place the node.
- void schedule_late(VectorSet &visited, Node_List &stack);
+ void schedule_late(VectorSet &visited, Node_Stack &stack);
// Compute the (backwards) latency of a node from a single use
int latency_from_use(Node *n, const Node *def, Node *use);
@@ -433,7 +433,7 @@
void partial_latency_of_defs(Node *n);
// Compute the instruction global latency with a backwards walk
- void compute_latencies_backwards(VectorSet &visited, Node_List &stack);
+ void compute_latencies_backwards(VectorSet &visited, Node_Stack &stack);
// Pick a block between early and late that is a cheaper alternative
// to late. Helper for schedule_late.
--- a/hotspot/src/share/vm/opto/callGenerator.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/share/vm/opto/callGenerator.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -46,6 +46,11 @@
return TypeFunc::make(method());
}
+bool CallGenerator::is_inlined_mh_linker(JVMState* jvms, ciMethod* callee) {
+ ciMethod* symbolic_info = jvms->method()->get_method_at_bci(jvms->bci());
+ return symbolic_info->is_method_handle_intrinsic() && !callee->is_method_handle_intrinsic();
+}
+
//-----------------------------ParseGenerator---------------------------------
// Internal class which handles all direct bytecode traversal.
class ParseGenerator : public InlineCallGenerator {
@@ -137,6 +142,13 @@
}
CallStaticJavaNode *call = new CallStaticJavaNode(kit.C, tf(), target, method(), kit.bci());
+ if (is_inlined_mh_linker(jvms, method())) {
+ // To be able to issue a direct call and skip a call to MH.linkTo*/invokeBasic adapter,
+ // additional information about the method being invoked should be attached
+ // to the call site to make resolution logic work
+ // (see SharedRuntime::resolve_static_call_C).
+ call->set_override_symbolic_info(true);
+ }
_call_node = call; // Save the call node in case we need it later
if (!is_static) {
// Make an explicit receiver null_check as part of this call.
@@ -192,7 +204,10 @@
// the call instruction will have a seemingly deficient out-count.
// (The bailout says something misleading about an "infinite loop".)
if (kit.gvn().type(receiver)->higher_equal(TypePtr::NULL_PTR)) {
- kit.inc_sp(method()->arg_size()); // restore arguments
+ assert(Bytecodes::is_invoke(kit.java_bc()), "%d: %s", kit.java_bc(), Bytecodes::name(kit.java_bc()));
+ ciMethod* declared_method = kit.method()->get_method_at_bci(kit.bci());
+ int arg_size = declared_method->signature()->arg_size_for_bc(kit.java_bc());
+ kit.inc_sp(arg_size); // restore arguments
kit.uncommon_trap(Deoptimization::Reason_null_check,
Deoptimization::Action_none,
NULL, "null receiver");
@@ -226,6 +241,13 @@
address target = SharedRuntime::get_resolve_virtual_call_stub();
// Normal inline cache used for call
CallDynamicJavaNode *call = new CallDynamicJavaNode(tf(), target, method(), _vtable_index, kit.bci());
+ if (is_inlined_mh_linker(jvms, method())) {
+ // To be able to issue a direct call (optimized virtual or virtual)
+ // and skip a call to MH.linkTo*/invokeBasic adapter, additional information
+ // about the method being invoked should be attached to the call site to
+ // make resolution logic work (see SharedRuntime::resolve_{virtual,opt_virtual}_call_C).
+ call->set_override_symbolic_info(true);
+ }
kit.set_arguments_for_java_call(call);
kit.set_edges_for_java_call(call);
Node* ret = kit.set_results_for_java_call(call);
@@ -463,8 +485,8 @@
_attempt++;
}
- if (cg != NULL) {
- assert(!cg->is_late_inline() && cg->is_inline(), "we're doing late inlining");
+ if (cg != NULL && cg->is_inline()) {
+ assert(!cg->is_late_inline(), "we're doing late inlining");
_inline_cg = cg;
Compile::current()->dec_number_of_mh_late_inlines();
return true;
@@ -807,8 +829,7 @@
const int vtable_index = Method::invalid_vtable_index;
CallGenerator* cg = C->call_generator(target, vtable_index, false, jvms, true, PROB_ALWAYS, NULL, true, true);
assert(cg == NULL || !cg->is_late_inline() || cg->is_mh_late_inline(), "no late inline here");
- if (cg != NULL && cg->is_inline())
- return cg;
+ return cg;
} else {
const char* msg = "receiver not constant";
if (PrintInlining) C->print_inlining(callee, jvms->depth() - 1, jvms->bci(), msg);
@@ -829,7 +850,7 @@
const TypeOopPtr* oop_ptr = member_name->bottom_type()->is_oopptr();
ciMethod* target = oop_ptr->const_oop()->as_member_name()->get_vmtarget();
- // In lamda forms we erase signature types to avoid resolving issues
+ // In lambda forms we erase signature types to avoid resolving issues
// involving class loaders. When we optimize a method handle invoke
// to a direct call we must cast the receiver and arguments to its
// actual types.
@@ -882,10 +903,9 @@
// provide us with a type
speculative_receiver_type = (receiver_type != NULL) ? receiver_type->speculative_type() : NULL;
}
- CallGenerator* cg = C->call_generator(target, vtable_index, call_does_dispatch, jvms, true, PROB_ALWAYS, speculative_receiver_type, true, true);
+ CallGenerator* cg = C->call_generator(target, vtable_index, call_does_dispatch, jvms, /*allow_inline=*/true, PROB_ALWAYS, speculative_receiver_type, true, true);
assert(cg == NULL || !cg->is_late_inline() || cg->is_mh_late_inline(), "no late inline here");
- if (cg != NULL && cg->is_inline())
- return cg;
+ return cg;
} else {
const char* msg = "member_name not constant";
if (PrintInlining) C->print_inlining(callee, jvms->depth() - 1, jvms->bci(), msg);
--- a/hotspot/src/share/vm/opto/callGenerator.hpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/share/vm/opto/callGenerator.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -49,7 +49,7 @@
public:
// Accessors
- ciMethod* method() const { return _method; }
+ ciMethod* method() const { return _method; }
// is_inline: At least some code implementing the method is copied here.
virtual bool is_inline() const { return false; }
@@ -123,7 +123,6 @@
// How to generate vanilla out-of-line call sites:
static CallGenerator* for_direct_call(ciMethod* m, bool separate_io_projs = false); // static, special
static CallGenerator* for_virtual_call(ciMethod* m, int vtable_index); // virtual, interface
- static CallGenerator* for_dynamic_call(ciMethod* m); // invokedynamic
static CallGenerator* for_method_handle_call( JVMState* jvms, ciMethod* caller, ciMethod* callee, bool delayed_forbidden);
static CallGenerator* for_method_handle_inline(JVMState* jvms, ciMethod* caller, ciMethod* callee, bool& input_not_const);
@@ -170,6 +169,8 @@
C->print_inlining(callee, inline_level, bci, msg);
}
}
+
+ static bool is_inlined_mh_linker(JVMState* jvms, ciMethod* m);
};
--- a/hotspot/src/share/vm/opto/callnode.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/share/vm/opto/callnode.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -959,7 +959,8 @@
uint CallJavaNode::size_of() const { return sizeof(*this); }
uint CallJavaNode::cmp( const Node &n ) const {
CallJavaNode &call = (CallJavaNode&)n;
- return CallNode::cmp(call) && _method == call._method;
+ return CallNode::cmp(call) && _method == call._method &&
+ _override_symbolic_info == call._override_symbolic_info;
}
#ifndef PRODUCT
void CallJavaNode::dump_spec(outputStream *st) const {
--- a/hotspot/src/share/vm/opto/callnode.hpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/share/vm/opto/callnode.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -657,25 +657,29 @@
bool _optimized_virtual;
bool _method_handle_invoke;
- ciMethod* _method; // Method being direct called
+ bool _override_symbolic_info; // Override symbolic call site info from bytecode
+ ciMethod* _method; // Method being direct called
public:
const int _bci; // Byte Code Index of call byte code
CallJavaNode(const TypeFunc* tf , address addr, ciMethod* method, int bci)
: CallNode(tf, addr, TypePtr::BOTTOM),
_method(method), _bci(bci),
_optimized_virtual(false),
- _method_handle_invoke(false)
+ _method_handle_invoke(false),
+ _override_symbolic_info(false)
{
init_class_id(Class_CallJava);
}
virtual int Opcode() const;
- ciMethod* method() const { return _method; }
- void set_method(ciMethod *m) { _method = m; }
- void set_optimized_virtual(bool f) { _optimized_virtual = f; }
- bool is_optimized_virtual() const { return _optimized_virtual; }
- void set_method_handle_invoke(bool f) { _method_handle_invoke = f; }
- bool is_method_handle_invoke() const { return _method_handle_invoke; }
+ ciMethod* method() const { return _method; }
+ void set_method(ciMethod *m) { _method = m; }
+ void set_optimized_virtual(bool f) { _optimized_virtual = f; }
+ bool is_optimized_virtual() const { return _optimized_virtual; }
+ void set_method_handle_invoke(bool f) { _method_handle_invoke = f; }
+ bool is_method_handle_invoke() const { return _method_handle_invoke; }
+ void set_override_symbolic_info(bool f) { _override_symbolic_info = f; }
+ bool override_symbolic_info() const { return _override_symbolic_info; }
#ifndef PRODUCT
virtual void dump_spec(outputStream *st) const;
--- a/hotspot/src/share/vm/opto/doCall.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/share/vm/opto/doCall.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -393,6 +393,100 @@
return false;
}
+#ifdef ASSERT
+static bool check_type(ciType* t1, ciType* t2) {
+ // Either oop-oop or prim-prim pair.
+ if (t1->is_primitive_type() && t2->is_primitive_type()) {
+ return t1->size() == t2->size(); // argument sizes should match
+ } else {
+ return !t1->is_primitive_type() && !t2->is_primitive_type(); // oop-oop
+ }
+}
+
+static bool check_inlined_mh_linker_info(ciMethod* symbolic_info, ciMethod* resolved_method) {
+ assert(symbolic_info->is_method_handle_intrinsic(), "sanity");
+ assert(!resolved_method->is_method_handle_intrinsic(), "sanity");
+
+ if (!symbolic_info->is_loaded() || !resolved_method->is_loaded()) {
+ return true; // Don't compare unloaded methods.
+ }
+ // Linkers have appendix argument which is not passed to callee.
+ int has_appendix = MethodHandles::has_member_arg(symbolic_info->intrinsic_id()) ? 1 : 0;
+ if (symbolic_info->arg_size() != (resolved_method->arg_size() + has_appendix)) {
+ return false; // Total size of arguments on stack mismatch.
+ }
+ if (!check_type(symbolic_info->return_type(), resolved_method->return_type())) {
+ return false; // Return value size or type mismatch encountered.
+ }
+
+ switch (symbolic_info->intrinsic_id()) {
+ case vmIntrinsics::_linkToVirtual:
+ case vmIntrinsics::_linkToInterface:
+ case vmIntrinsics::_linkToSpecial: {
+ if (resolved_method->is_static()) return false;
+ break;
+ }
+ case vmIntrinsics::_linkToStatic: {
+ if (!resolved_method->is_static()) return false;
+ break;
+ }
+ }
+
+ ciSignature* symbolic_sig = symbolic_info->signature();
+ ciSignature* resolved_sig = resolved_method->signature();
+
+ if (symbolic_sig->count() + (symbolic_info->is_static() ? 0 : 1) !=
+ resolved_sig->count() + (resolved_method->is_static() ? 0 : 1) + has_appendix) {
+ return false; // Argument count mismatch
+ }
+
+ int sbase = 0, rbase = 0;
+ int arg_count = MIN2(symbolic_sig->count() - has_appendix, resolved_sig->count());
+ ciType* recv_type = NULL;
+ if (symbolic_info->is_static() && !resolved_method->is_static()) {
+ recv_type = symbolic_sig->type_at(0);
+ sbase = 1;
+ } else if (!symbolic_info->is_static() && resolved_method->is_static()) {
+ recv_type = resolved_sig->type_at(0);
+ rbase = 1;
+ }
+ if (recv_type != NULL && recv_type->is_primitive_type()) {
+ return false; // Receiver should be an oop.
+ }
+ for (int i = 0; i < arg_count; i++) {
+ if (!check_type(symbolic_sig->type_at(sbase + i), resolved_sig->type_at(rbase + i))) {
+ return false; // Argument size or type mismatch encountered.
+ }
+ }
+ return true;
+}
+
+static bool is_call_consistent_with_jvms(JVMState* jvms, CallGenerator* cg) {
+ ciMethod* symbolic_info = jvms->method()->get_method_at_bci(jvms->bci());
+ ciMethod* resolved_method = cg->method();
+
+ if (CallGenerator::is_inlined_mh_linker(jvms, resolved_method)) {
+ return check_inlined_mh_linker_info(symbolic_info, resolved_method);
+ } else {
+ // Method name & descriptor should stay the same.
+ return (symbolic_info->get_Method()->name() == resolved_method->get_Method()->name()) &&
+ (symbolic_info->get_Method()->signature() == resolved_method->get_Method()->signature());
+ }
+}
+
+static bool check_call_consistency(JVMState* jvms, CallGenerator* cg) {
+ if (!is_call_consistent_with_jvms(jvms, cg)) {
+ tty->print_cr("JVMS:");
+ jvms->dump();
+ tty->print_cr("Bytecode info:");
+ jvms->method()->get_method_at_bci(jvms->bci())->print(); tty->cr();
+ tty->print_cr("Resolved method:");
+ cg->method()->print(); tty->cr();
+ return false;
+ }
+ return true;
+}
+#endif // ASSERT
//------------------------------do_call----------------------------------------
// Handle your basic call. Inline if we can & want to, else just setup call.
@@ -571,6 +665,8 @@
set_jvms(new_jvms);
}
+ assert(check_call_consistency(jvms, cg), "inconsistent info");
+
if (!stopped()) {
// This was some sort of virtual call, which did a null check for us.
// Now we can assert receiver-not-null, on the normal return path.
--- a/hotspot/src/share/vm/opto/gcm.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/share/vm/opto/gcm.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -228,18 +228,19 @@
// Find the earliest Block any instruction can be placed in. Some instructions
// are pinned into Blocks. Unpinned instructions can appear in last block in
// which all their inputs occur.
-bool PhaseCFG::schedule_early(VectorSet &visited, Node_List &roots) {
+bool PhaseCFG::schedule_early(VectorSet &visited, Node_Stack &roots) {
// Allocate stack with enough space to avoid frequent realloc
- Node_Stack nstack(roots.Size() + 8);
+ Node_Stack nstack(roots.size() + 8);
// _root will be processed among C->top() inputs
- roots.push(C->top());
+ roots.push(C->top(), 0);
visited.set(C->top()->_idx);
while (roots.size() != 0) {
// Use local variables nstack_top_n & nstack_top_i to cache values
// on stack's top.
- Node* parent_node = roots.pop();
+ Node* parent_node = roots.node();
uint input_index = 0;
+ roots.pop();
while (true) {
if (input_index == 0) {
@@ -286,7 +287,7 @@
break;
} else if (!is_visited) {
// Visit this guy later, using worklist
- roots.push(in);
+ roots.push(in, 0);
}
}
@@ -791,23 +792,23 @@
public:
// Constructor for the iterator
- Node_Backward_Iterator(Node *root, VectorSet &visited, Node_List &stack, PhaseCFG &cfg);
+ Node_Backward_Iterator(Node *root, VectorSet &visited, Node_Stack &stack, PhaseCFG &cfg);
// Postincrement operator to iterate over the nodes
Node *next();
private:
VectorSet &_visited;
- Node_List &_stack;
+ Node_Stack &_stack;
PhaseCFG &_cfg;
};
// Constructor for the Node_Backward_Iterator
-Node_Backward_Iterator::Node_Backward_Iterator( Node *root, VectorSet &visited, Node_List &stack, PhaseCFG &cfg)
+Node_Backward_Iterator::Node_Backward_Iterator( Node *root, VectorSet &visited, Node_Stack &stack, PhaseCFG &cfg)
: _visited(visited), _stack(stack), _cfg(cfg) {
// The stack should contain exactly the root
stack.clear();
- stack.push(root);
+ stack.push(root, root->outcnt());
// Clear the visited bits
visited.Clear();
@@ -820,12 +821,14 @@
if ( !_stack.size() )
return NULL;
- // '_stack' is emulating a real _stack. The 'visit-all-users' loop has been
- // made stateless, so I do not need to record the index 'i' on my _stack.
- // Instead I visit all users each time, scanning for unvisited users.
// I visit unvisited not-anti-dependence users first, then anti-dependent
- // children next.
- Node *self = _stack.pop();
+ // children next. I iterate backwards to support removal of nodes.
+ // The stack holds states consisting of 3 values:
+ // current Def node, flag which indicates 1st/2nd pass, index of current out edge
+ Node *self = (Node*)(((uintptr_t)_stack.node()) & ~1);
+ bool iterate_anti_dep = (((uintptr_t)_stack.node()) & 1);
+ uint idx = MIN2(_stack.index(), self->outcnt()); // Support removal of nodes.
+ _stack.pop();
// I cycle here when I am entering a deeper level of recursion.
// The key variable 'self' was set prior to jumping here.
@@ -841,9 +844,9 @@
Node *unvisited = NULL; // Unvisited anti-dependent Node, if any
// Scan for unvisited nodes
- for (DUIterator_Fast imax, i = self->fast_outs(imax); i < imax; i++) {
+ while (idx > 0) {
// For all uses, schedule late
- Node* n = self->fast_out(i); // Use
+ Node* n = self->raw_out(--idx); // Use
// Skip already visited children
if ( _visited.test(n->_idx) )
@@ -863,19 +866,31 @@
unvisited = n; // Found unvisited
// Check for possible-anti-dependent
- if( !n->needs_anti_dependence_check() )
- break; // Not visited, not anti-dep; schedule it NOW
+ // 1st pass: No such nodes, 2nd pass: Only such nodes.
+ if (n->needs_anti_dependence_check() == iterate_anti_dep) {
+ unvisited = n; // Found unvisited
+ break;
+ }
}
// Did I find an unvisited not-anti-dependent Node?
- if ( !unvisited )
+ if (!unvisited) {
+ if (!iterate_anti_dep) {
+ // 2nd pass: Iterate over nodes which needs_anti_dependence_check.
+ iterate_anti_dep = true;
+ idx = self->outcnt();
+ continue;
+ }
break; // All done with children; post-visit 'self'
+ }
// Visit the unvisited Node. Contains the obvious push to
// indicate I'm entering a deeper level of recursion. I push the
// old state onto the _stack and set a new state and loop (recurse).
- _stack.push(self);
+ _stack.push((Node*)((uintptr_t)self | (uintptr_t)iterate_anti_dep), idx);
self = unvisited;
+ iterate_anti_dep = false;
+ idx = self->outcnt();
} // End recursion loop
return self;
@@ -883,7 +898,7 @@
//------------------------------ComputeLatenciesBackwards----------------------
// Compute the latency of all the instructions.
-void PhaseCFG::compute_latencies_backwards(VectorSet &visited, Node_List &stack) {
+void PhaseCFG::compute_latencies_backwards(VectorSet &visited, Node_Stack &stack) {
#ifndef PRODUCT
if (trace_opto_pipelining())
tty->print("\n#---- ComputeLatenciesBackwards ----\n");
@@ -1157,7 +1172,7 @@
// dominator tree of all USES of a value. Pick the block with the least
// loop nesting depth that is lowest in the dominator tree.
extern const char must_clone[];
-void PhaseCFG::schedule_late(VectorSet &visited, Node_List &stack) {
+void PhaseCFG::schedule_late(VectorSet &visited, Node_Stack &stack) {
#ifndef PRODUCT
if (trace_opto_pipelining())
tty->print("\n#---- schedule_late ----\n");
@@ -1313,9 +1328,7 @@
// instructions are pinned into Blocks. Unpinned instructions can
// appear in last block in which all their inputs occur.
visited.Clear();
- Node_List stack(arena);
- // Pre-grow the list
- stack.map((C->live_nodes() >> 1) + 16, NULL);
+ Node_Stack stack(arena, (C->live_nodes() >> 2) + 16); // pre-grow
if (!schedule_early(visited, stack)) {
// Bailout without retry
C->record_method_not_compilable("early schedule failed");
--- a/hotspot/src/share/vm/opto/library_call.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/share/vm/opto/library_call.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -315,6 +315,8 @@
bool inline_profileBoolean();
bool inline_isCompileConstant();
+
+ bool inline_deoptimize();
};
//---------------------------make_vm_intrinsic----------------------------
@@ -750,6 +752,9 @@
case vmIntrinsics::_hasNegatives:
return inline_hasNegatives();
+ case vmIntrinsics::_deoptimize:
+ return inline_deoptimize();
+
default:
// If you get here, it may be that someone has added a new intrinsic
// to the list in vmSymbols.hpp without implementing it here.
@@ -6574,3 +6579,12 @@
set_result(n->is_Con() ? intcon(1) : intcon(0));
return true;
}
+
+bool LibraryCallKit::inline_deoptimize() {
+ assert(WhiteBoxAPI, "");
+ PreserveReexecuteState preexecs(this);
+ jvms()->set_should_reexecute(false);
+ uncommon_trap(Deoptimization::Reason_intrinsic,
+ Deoptimization::Action_none);
+ return true;
+}
--- a/hotspot/src/share/vm/opto/machnode.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/share/vm/opto/machnode.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -707,7 +707,8 @@
uint MachCallJavaNode::size_of() const { return sizeof(*this); }
uint MachCallJavaNode::cmp( const Node &n ) const {
MachCallJavaNode &call = (MachCallJavaNode&)n;
- return MachCallNode::cmp(call) && _method->equals(call._method);
+ return MachCallNode::cmp(call) && _method->equals(call._method) &&
+ _override_symbolic_info == call._override_symbolic_info;
}
#ifndef PRODUCT
void MachCallJavaNode::dump_spec(outputStream *st) const {
--- a/hotspot/src/share/vm/opto/machnode.hpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/share/vm/opto/machnode.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -885,16 +885,28 @@
virtual uint cmp( const Node &n ) const;
virtual uint size_of() const; // Size is bigger
public:
- ciMethod* _method; // Method being direct called
- int _bci; // Byte Code index of call byte code
- bool _optimized_virtual; // Tells if node is a static call or an optimized virtual
- bool _method_handle_invoke; // Tells if the call has to preserve SP
- MachCallJavaNode() : MachCallNode() {
+ ciMethod* _method; // Method being direct called
+ bool _override_symbolic_info; // Override symbolic call site info from bytecode
+ int _bci; // Byte Code index of call byte code
+ bool _optimized_virtual; // Tells if node is a static call or an optimized virtual
+ bool _method_handle_invoke; // Tells if the call has to preserve SP
+ MachCallJavaNode() : MachCallNode(), _override_symbolic_info(false) {
init_class_id(Class_MachCallJava);
}
virtual const RegMask &in_RegMask(uint) const;
+ int resolved_method_index(CodeBuffer &cbuf) const {
+ if (_override_symbolic_info) {
+ // Attach corresponding Method* to the call site, so VM can use it during resolution
+ // instead of querying symbolic info from bytecode.
+ assert(_method != NULL, "method should be set");
+ assert(_method->constant_encoding()->is_method(), "should point to a Method");
+ return cbuf.oop_recorder()->find_index(_method->constant_encoding());
+ }
+ return 0; // Use symbolic info from bytecode (resolved_method == NULL).
+ }
+
#ifndef PRODUCT
virtual void dump_spec(outputStream *st) const;
#endif
--- a/hotspot/src/share/vm/opto/matcher.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/share/vm/opto/matcher.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -1201,6 +1201,7 @@
mcall_java->_optimized_virtual = call_java->is_optimized_virtual();
is_method_handle_invoke = call_java->is_method_handle_invoke();
mcall_java->_method_handle_invoke = is_method_handle_invoke;
+ mcall_java->_override_symbolic_info = call_java->override_symbolic_info();
if (is_method_handle_invoke) {
C->set_has_method_handle_invokes(true);
}
--- a/hotspot/src/share/vm/prims/methodHandles.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/share/vm/prims/methodHandles.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -358,6 +358,19 @@
return 0;
}
+Bytecodes::Code MethodHandles::signature_polymorphic_intrinsic_bytecode(vmIntrinsics::ID id) {
+ switch(id) {
+ case vmIntrinsics::_linkToVirtual: return Bytecodes::_invokevirtual;
+ case vmIntrinsics::_linkToInterface: return Bytecodes::_invokeinterface;
+ case vmIntrinsics::_linkToStatic: return Bytecodes::_invokestatic;
+ case vmIntrinsics::_linkToSpecial: return Bytecodes::_invokespecial;
+ case vmIntrinsics::_invokeBasic: return Bytecodes::_invokehandle;
+ default:
+ fatal("unexpected id: (%d) %s", (uint)id, vmIntrinsics::name_at(id));
+ return Bytecodes::_illegal;
+ }
+}
+
int MethodHandles::signature_polymorphic_intrinsic_ref_kind(vmIntrinsics::ID iid) {
switch (iid) {
case vmIntrinsics::_invokeBasic: return 0;
--- a/hotspot/src/share/vm/prims/methodHandles.hpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/share/vm/prims/methodHandles.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -91,6 +91,10 @@
iid <= vmIntrinsics::LAST_MH_SIG_POLY);
}
+ static bool is_signature_polymorphic_method(Method* m) {
+ return is_signature_polymorphic(m->intrinsic_id());
+ }
+
static bool is_signature_polymorphic_intrinsic(vmIntrinsics::ID iid) {
assert(is_signature_polymorphic(iid), "");
// Most sig-poly methods are intrinsics which do not require an
@@ -131,6 +135,8 @@
return signature_polymorphic_name_id(klass, name) != vmIntrinsics::_none;
}
+ static Bytecodes::Code signature_polymorphic_intrinsic_bytecode(vmIntrinsics::ID id);
+
static int get_named_constant(int which, Handle name_box, TRAPS);
public:
--- a/hotspot/src/share/vm/prims/whitebox.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/share/vm/prims/whitebox.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -1290,6 +1290,11 @@
return (jlong) ikh->constants();
WB_END
+WB_ENTRY(void, WB_ClearInlineCaches(JNIEnv* env, jobject wb))
+ VM_ClearICs clear_ics;
+ VMThread::execute(&clear_ics);
+WB_END
+
template <typename T>
static bool GetMethodOption(JavaThread* thread, JNIEnv* env, jobject method, jstring name, T* value) {
assert(value != NULL, "sanity");
@@ -1615,6 +1620,7 @@
(void*)&WB_GetMethodStringOption},
{CC"isShared", CC"(Ljava/lang/Object;)Z", (void*)&WB_IsShared },
{CC"areSharedStringsIgnored", CC"()Z", (void*)&WB_AreSharedStringsIgnored },
+ {CC"clearInlineCaches", CC"()V", (void*)&WB_ClearInlineCaches },
};
#undef CC
--- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp Fri Dec 04 23:50:05 2015 +0000
@@ -1070,6 +1070,21 @@
return find_callee_info_helper(thread, vfst, bc, callinfo, THREAD);
}
+methodHandle SharedRuntime::extract_attached_method(vframeStream& vfst) {
+ nmethod* caller_nm = vfst.nm();
+
+ nmethodLocker caller_lock(caller_nm);
+
+ address pc = vfst.frame_pc();
+ { // Get call instruction under lock because another thread may be busy patching it.
+ MutexLockerEx ml_patch(Patching_lock, Mutex::_no_safepoint_check_flag);
+ if (NativeCall::is_call_before(pc)) {
+ NativeCall* ncall = nativeCall_before(pc);
+ return caller_nm->attached_method(ncall->instruction_address());
+ }
+ }
+ return NULL;
+}
// Finds receiver, CallInfo (i.e. receiver method), and calling bytecode
// for a call current in progress, i.e., arguments has been pushed on stack
@@ -1087,15 +1102,37 @@
methodHandle caller(THREAD, vfst.method());
int bci = vfst.bci();
- // Find bytecode
Bytecode_invoke bytecode(caller, bci);
- bc = bytecode.invoke_code();
int bytecode_index = bytecode.index();
+ methodHandle attached_method = extract_attached_method(vfst);
+ if (attached_method.not_null()) {
+ methodHandle callee = bytecode.static_target(CHECK_NH);
+ vmIntrinsics::ID id = callee->intrinsic_id();
+ // When VM replaces MH.invokeBasic/linkTo* call with a direct/virtual call,
+ // it attaches statically resolved method to the call site.
+ if (MethodHandles::is_signature_polymorphic(id) &&
+ MethodHandles::is_signature_polymorphic_intrinsic(id)) {
+ bc = MethodHandles::signature_polymorphic_intrinsic_bytecode(id);
+
+ // Need to adjust invokehandle since inlining through signature-polymorphic
+ // method happened.
+ if (bc == Bytecodes::_invokehandle &&
+ !MethodHandles::is_signature_polymorphic_method(attached_method())) {
+ bc = attached_method->is_static() ? Bytecodes::_invokestatic
+ : Bytecodes::_invokevirtual;
+ }
+ }
+ } else {
+ bc = bytecode.invoke_code();
+ }
+
+ bool has_receiver = bc != Bytecodes::_invokestatic &&
+ bc != Bytecodes::_invokedynamic &&
+ bc != Bytecodes::_invokehandle;
+
// Find receiver for non-static call
- if (bc != Bytecodes::_invokestatic &&
- bc != Bytecodes::_invokedynamic &&
- bc != Bytecodes::_invokehandle) {
+ if (has_receiver) {
// This register map must be update since we need to find the receiver for
// compiled frames. The receiver might be in a register.
RegisterMap reg_map2(thread);
@@ -1103,10 +1140,13 @@
// Caller-frame is a compiled frame
frame callerFrame = stubFrame.sender(®_map2);
- methodHandle callee = bytecode.static_target(CHECK_(nullHandle));
- if (callee.is_null()) {
- THROW_(vmSymbols::java_lang_NoSuchMethodException(), nullHandle);
+ if (attached_method.is_null()) {
+ methodHandle callee = bytecode.static_target(CHECK_NH);
+ if (callee.is_null()) {
+ THROW_(vmSymbols::java_lang_NoSuchMethodException(), nullHandle);
+ }
}
+
// Retrieve from a compiled argument list
receiver = Handle(THREAD, callerFrame.retrieve_receiver(®_map2));
@@ -1115,26 +1155,35 @@
}
}
- // Resolve method. This is parameterized by bytecode.
- constantPoolHandle constants(THREAD, caller->constants());
assert(receiver.is_null() || receiver->is_oop(), "wrong receiver");
- LinkResolver::resolve_invoke(callinfo, receiver, constants, bytecode_index, bc, CHECK_(nullHandle));
+
+ // Resolve method
+ if (attached_method.not_null()) {
+ // Parameterized by attached method.
+ LinkResolver::resolve_invoke(callinfo, receiver, attached_method, bc, CHECK_NH);
+ } else {
+ // Parameterized by bytecode.
+ constantPoolHandle constants(THREAD, caller->constants());
+ LinkResolver::resolve_invoke(callinfo, receiver, constants, bytecode_index, bc, CHECK_NH);
+ }
#ifdef ASSERT
// Check that the receiver klass is of the right subtype and that it is initialized for virtual calls
- if (bc != Bytecodes::_invokestatic && bc != Bytecodes::_invokedynamic && bc != Bytecodes::_invokehandle) {
+ if (has_receiver) {
assert(receiver.not_null(), "should have thrown exception");
KlassHandle receiver_klass(THREAD, receiver->klass());
- Klass* rk = constants->klass_ref_at(bytecode_index, CHECK_(nullHandle));
- // klass is already loaded
+ Klass* rk = NULL;
+ if (attached_method.not_null()) {
+ // In case there's resolved method attached, use its holder during the check.
+ rk = attached_method->method_holder();
+ } else {
+ // Klass is already loaded.
+ constantPoolHandle constants(THREAD, caller->constants());
+ rk = constants->klass_ref_at(bytecode_index, CHECK_NH);
+ }
KlassHandle static_receiver_klass(THREAD, rk);
- // Method handle invokes might have been optimized to a direct call
- // so don't check for the receiver class.
- // FIXME this weakens the assert too much
methodHandle callee = callinfo.selected_method();
- assert(receiver_klass->is_subtype_of(static_receiver_klass()) ||
- callee->is_method_handle_intrinsic() ||
- callee->is_compiled_lambda_form(),
+ assert(receiver_klass->is_subtype_of(static_receiver_klass()),
"actual receiver must be subclass of static receiver klass");
if (receiver_klass->is_instance_klass()) {
if (InstanceKlass::cast(receiver_klass())->is_not_initialized()) {
@@ -1670,7 +1719,6 @@
inline_cache->set_to_clean();
}
}
-
}
methodHandle callee_method = find_callee_method(thread, CHECK_(methodHandle()));
--- a/hotspot/src/share/vm/runtime/sharedRuntime.hpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/share/vm/runtime/sharedRuntime.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -343,6 +343,8 @@
Bytecodes::Code& bc,
CallInfo& callinfo, TRAPS);
+ static methodHandle extract_attached_method(vframeStream& vfst);
+
static address clean_virtual_call_entry();
static address clean_opt_virtual_call_entry();
static address clean_static_call_entry();
--- a/hotspot/src/share/vm/runtime/vm_operations.hpp Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/src/share/vm/runtime/vm_operations.hpp Fri Dec 04 23:50:05 2015 +0000
@@ -30,6 +30,7 @@
#include "oops/oop.hpp"
#include "runtime/thread.hpp"
#include "utilities/top.hpp"
+#include "code/codeCache.hpp"
// The following classes are used for operations
// initiated by a Java thread but that must
@@ -44,6 +45,7 @@
template(ThreadDump) \
template(PrintThreads) \
template(FindDeadlocks) \
+ template(ClearICs) \
template(ForceSafepoint) \
template(ForceAsyncSafepoint) \
template(Deoptimize) \
@@ -230,6 +232,13 @@
}
};
+class VM_ClearICs: public VM_Operation {
+ public:
+ VM_ClearICs() {}
+ void doit() { CodeCache::clear_inline_caches(); }
+ VMOp_Type type() const { return VMOp_ClearICs; }
+};
+
// dummy vm op, evaluated just to force a safepoint
class VM_ForceSafepoint: public VM_Operation {
public:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/jsr292/NonInlinedCall/Agent.java Fri Dec 04 23:50:05 2015 +0000
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+import java.io.File;
+import java.io.PrintStream;
+import java.lang.instrument.Instrumentation;
+import java.util.Arrays;
+
+public class Agent {
+ public static void main(String[] args) throws Exception {
+ String jarName = args[0];
+ String className = args[1];
+ String manifestName = "manifest.mf";
+
+ System.out.println("Creating "+manifestName);
+ try (PrintStream out = new PrintStream(new File(manifestName))) {
+ out.println("Premain-Class: " + className);
+ out.println("Can-Redefine-Classes: true");
+ }
+ System.out.println("Building "+jarName);
+ String[] jarArgs = new String[] {"-cfm", jarName, manifestName };
+
+ System.out.println("Running jar " + Arrays.toString(jarArgs));
+ sun.tools.jar.Main jarTool = new sun.tools.jar.Main(System.out, System.err, "jar");
+ if (!jarTool.run(jarArgs)) {
+ throw new Error("jar failed: args=" + Arrays.toString(args));
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/jsr292/NonInlinedCall/GCTest.java Fri Dec 04 23:50:05 2015 +0000
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8072008
+ * @library /testlibrary /../../test/lib
+ * @build GCTest NonInlinedReinvoker
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ * java.lang.invoke.GCTest
+ * java.lang.invoke.GCTest$T
+ * java.lang.invoke.NonInlinedReinvoker
+ * jdk.test.lib.Asserts
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ * -Xbatch -XX:-TieredCompilation -XX:CICompilerCount=1
+ * java.lang.invoke.GCTest
+ */
+package java.lang.invoke;
+
+import sun.hotspot.WhiteBox;
+
+import java.lang.ref.*;
+import static jdk.test.lib.Asserts.*;
+
+public class GCTest {
+ static final MethodHandles.Lookup LOOKUP = MethodHandles.Lookup.IMPL_LOOKUP;
+
+ static class T {
+ static int f1() { return 0; }
+ static int f2() { return 1; }
+ }
+
+ static @Stable MethodHandle mh;
+ static PhantomReference<LambdaForm> lform;
+
+ static final ReferenceQueue<LambdaForm> rq = new ReferenceQueue<>();
+ static final WhiteBox WB = WhiteBox.getWhiteBox();
+
+ @DontInline
+ static int invokeBasic() {
+ try {
+ return (int) mh.invokeBasic();
+ } catch (Throwable e) {
+ throw new Error(e);
+ }
+ }
+
+ static void test(int expected) {
+ for (int i = 0; i < 20_000; i++) {
+ invokeBasic();
+ }
+ assertEquals(invokeBasic(), expected);
+ }
+
+ public static void main(String[] args) throws Exception {
+ mh = NonInlinedReinvoker.make(
+ LOOKUP.findStatic(T.class, "f1", MethodType.methodType(int.class)));
+
+ // Monitor LambdaForm GC
+ lform = new PhantomReference<>(mh.form, rq);
+
+ test(0);
+ WB.clearInlineCaches();
+ test(0);
+
+ mh = NonInlinedReinvoker.make(
+ LOOKUP.findStatic(T.class, "f2", MethodType.methodType(int.class)));
+
+ Reference<?> ref = null;
+ while (ref == null) {
+ WB.fullGC();
+ try {
+ ref = rq.remove(1000);
+ } catch (InterruptedException e) { /*ignore*/ }
+ }
+
+ test(1);
+ WB.clearInlineCaches();
+ test(1);
+
+ System.out.println("TEST PASSED");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java Fri Dec 04 23:50:05 2015 +0000
@@ -0,0 +1,218 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8072008
+ * @library /testlibrary /../../test/lib
+ * @build InvokeTest NonInlinedReinvoker
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ * java.lang.invoke.InvokeTest
+ * java.lang.invoke.InvokeTest$T
+ * java.lang.invoke.InvokeTest$P1
+ * java.lang.invoke.InvokeTest$P2
+ * java.lang.invoke.InvokeTest$I
+ * java.lang.invoke.NonInlinedReinvoker
+ * jdk.test.lib.Asserts
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ * -Xbatch -XX:-TieredCompilation -XX:CICompilerCount=1
+ * java.lang.invoke.InvokeTest
+ */
+package java.lang.invoke;
+
+import sun.hotspot.WhiteBox;
+import static jdk.test.lib.Asserts.*;
+
+public class InvokeTest {
+ static MethodHandles.Lookup LOOKUP = MethodHandles.Lookup.IMPL_LOOKUP;
+
+ static final MethodHandle virtualMH; // invokevirtual T.f1
+ static final MethodHandle staticMH; // invokestatic T.f2
+ static final MethodHandle intfMH; // invokeinterface I.f1
+ static final MethodHandle specialMH; // invokespecial T.f4 T
+ static final MethodHandle basicMH;
+
+ static final WhiteBox WB = WhiteBox.getWhiteBox();
+
+ static volatile boolean doDeopt = false;
+
+ static {
+ try {
+ MethodType mtype = MethodType.methodType(Class.class);
+
+ virtualMH = LOOKUP.findVirtual(T.class, "f1", mtype);
+ staticMH = LOOKUP.findStatic (T.class, "f2", mtype);
+ intfMH = LOOKUP.findVirtual(I.class, "f3", mtype);
+ specialMH = LOOKUP.findSpecial(T.class, "f4", mtype, T.class);
+ basicMH = NonInlinedReinvoker.make(staticMH);
+ } catch (Exception e) {
+ throw new Error(e);
+ }
+ }
+
+ static class T implements I {
+ @DontInline public Class<?> f1() { if (doDeopt) WB.deoptimize(); return T.class; }
+ @DontInline public static Class<?> f2() { if (doDeopt) WB.deoptimize(); return T.class; }
+ @DontInline private Class<?> f4() { if (doDeopt) WB.deoptimize(); return T.class; }
+ }
+
+ static class P1 extends T {
+ @DontInline public Class<?> f1() { if (doDeopt) WB.deoptimize(); return P1.class; }
+ @DontInline public Class<?> f3() { if (doDeopt) WB.deoptimize(); return P1.class; }
+ }
+
+ static class P2 extends T {
+ @DontInline public Class<?> f1() { if (doDeopt) WB.deoptimize(); return P2.class; }
+ @DontInline public Class<?> f3() { if (doDeopt) WB.deoptimize(); return P2.class; }
+ }
+
+ static interface I {
+ @DontInline default Class<?> f3() { if (doDeopt) WB.deoptimize(); return I.class; }
+ }
+
+ @DontInline
+ static void linkToVirtual(Object obj, Class<?> extecpted) {
+ try {
+ Class<?> cls = (Class<?>)virtualMH.invokeExact((T)obj);
+ assertEquals(cls, obj.getClass());
+ } catch (Throwable e) {
+ throw new Error(e);
+ }
+ }
+
+ @DontInline
+ static void linkToInterface(Object obj, Class<?> expected) {
+ try {
+ Class<?> cls = (Class<?>)intfMH.invokeExact((I)obj);
+ assertEquals(cls, expected);
+ } catch (Throwable e) {
+ throw new Error(e);
+ }
+ }
+
+ @DontInline
+ static void linkToStatic() {
+ try {
+ Class<?> cls = (Class<?>)staticMH.invokeExact();
+ assertEquals(cls, T.class);
+ } catch (Throwable e) {
+ throw new Error(e);
+ }
+ }
+
+ @DontInline
+ static void linkToSpecial(Object obj, Class<?> expected) {
+ try {
+ Class<?> cls = (Class<?>)specialMH.invokeExact((T)obj);
+ assertEquals(cls, expected);
+ } catch (Throwable e) {
+ throw new Error(e);
+ }
+ }
+
+ @DontInline
+ static void invokeBasic() {
+ try {
+ Class<?> cls = (Class<?>)basicMH.invokeBasic();
+ assertEquals(cls, T.class);
+ } catch (Throwable e) {
+ throw new Error(e);
+ }
+ }
+
+ static void run(Runnable r) {
+ for (int i = 0; i < 20_000; i++) {
+ r.run();
+ }
+
+ doDeopt = true;
+ r.run();
+ doDeopt = false;
+
+ WB.clearInlineCaches();
+
+ for (int i = 0; i < 20_000; i++) {
+ r.run();
+ }
+
+ doDeopt = true;
+ r.run();
+ doDeopt = false;
+ }
+
+ static void testVirtual() {
+ System.out.println("linkToVirtual");
+
+ // Monomorphic case (optimized virtual call)
+ run(() -> linkToVirtual(new T(), T.class));
+
+ // Megamorphic case (virtual call)
+ Object[] recv = new Object[] { new T(), new P1(), new P2() };
+ run(() -> {
+ for (Object r : recv) {
+ linkToVirtual(r, r.getClass());
+ }});
+ }
+
+ static void testInterface() {
+ System.out.println("linkToInterface");
+
+ // Monomorphic case (optimized virtual call)
+ run(() -> linkToInterface(new T(), I.class));
+
+ // Megamorphic case (virtual call)
+ Object[][] recv = new Object[][] {{new T(), I.class}, {new P1(), P1.class}, {new P2(), P2.class}};
+ run(() -> {
+ for (Object[] r : recv) {
+ linkToInterface(r[0], (Class<?>)r[1]);
+ }});
+ }
+
+ static void testSpecial() {
+ System.out.println("linkToSpecial");
+ // Monomorphic case (optimized virtual call)
+ run(() -> linkToSpecial(new T(), T.class));
+ }
+
+ static void testStatic() {
+ System.out.println("linkToStatic");
+ // static call
+ run(() -> linkToStatic());
+ }
+
+ static void testBasic() {
+ System.out.println("invokeBasic");
+ // static call
+ run(() -> invokeBasic());
+ }
+
+ public static void main(String[] args) {
+ testVirtual();
+ testInterface();
+ testSpecial();
+ testStatic();
+ testBasic();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/jsr292/NonInlinedCall/NonInlinedReinvoker.java Fri Dec 04 23:50:05 2015 +0000
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+package java.lang.invoke;
+
+class NonInlinedReinvoker extends DelegatingMethodHandle {
+ private final MethodHandle target;
+
+ private NonInlinedReinvoker(MethodHandle target, LambdaForm lf) {
+ super(target.type(), lf);
+ this.target = target;
+ }
+ @Override
+ protected MethodHandle getTarget() {
+ return target;
+ }
+
+ @Override
+ MethodHandle asTypeUncached(MethodType newType) {
+ return asTypeCache = target.asType(newType);
+ }
+
+ static MethodHandle make(MethodHandle target) {
+ LambdaForm lform = DelegatingMethodHandle.makeReinvokerForm(
+ target, -1, DelegatingMethodHandle.class, "reinvoker.dontInline",
+ /*forceInline=*/false, DelegatingMethodHandle.NF_getTarget, null);
+ return new NonInlinedReinvoker(target, lform);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/jsr292/NonInlinedCall/RedefineTest.java Fri Dec 04 23:50:05 2015 +0000
@@ -0,0 +1,157 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8072008
+ * @library /testlibrary /../../test/lib
+ * @build RedefineTest Agent
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ * java.lang.invoke.RedefineTest
+ * Agent
+ * jdk.test.lib.Asserts
+ * @run main Agent agent.jar java.lang.invoke.RedefineTest
+ * @run main/othervm -Xbootclasspath/a:. -javaagent:agent.jar
+ * -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ * -Xbatch -XX:-TieredCompilation -XX:CICompilerCount=1
+ * java.lang.invoke.RedefineTest
+ */
+package java.lang.invoke;
+
+import sun.hotspot.WhiteBox;
+import sun.misc.Unsafe;
+
+import jdk.internal.org.objectweb.asm.*;
+
+import java.lang.instrument.ClassDefinition;
+import java.lang.instrument.Instrumentation;
+
+import static jdk.internal.org.objectweb.asm.Opcodes.*;
+
+public class RedefineTest {
+ static final MethodHandles.Lookup LOOKUP = MethodHandles.Lookup.IMPL_LOOKUP;
+ static final Unsafe UNSAFE = Unsafe.getUnsafe();
+
+ static final String NAME = "java/lang/invoke/RedefineTest$T";
+
+ static Class<?> getClass(int r) {
+ byte[] classFile = getClassFile(r);
+ return UNSAFE.defineClass(NAME, classFile, 0, classFile.length, null, null);
+ }
+
+ /**
+ * Generates a class of the following shape:
+ * static class T {
+ * @DontInline public static int f() { return $r; }
+ * }
+ */
+ static byte[] getClassFile(int r) {
+ ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
+ MethodVisitor mv;
+ cw.visit(52, ACC_PUBLIC | ACC_SUPER, NAME, null, "java/lang/Object", null);
+ {
+ mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "f", "()I", null, null);
+ mv.visitAnnotation("Ljava/lang/invoke/DontInline;", true);
+ mv.visitCode();
+ mv.visitLdcInsn(r);
+ mv.visitInsn(IRETURN);
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+ cw.visitEnd();
+ return cw.toByteArray();
+ }
+
+ static final MethodHandle mh;
+ static final Class<?> CLS = getClass(0);
+ static {
+ try {
+ mh = LOOKUP.findStatic(CLS, "f", MethodType.methodType(int.class));
+ } catch (Exception e) {
+ throw new Error(e);
+ }
+ }
+
+ static final WhiteBox WB = WhiteBox.getWhiteBox();
+
+ @DontInline
+ static int invokeBasic() {
+ try {
+ return (int)mh.invokeExact();
+ } catch (Throwable e) {
+ throw new Error(e);
+ }
+ }
+
+ static Instrumentation instr;
+ public static void premain(String args, Instrumentation instr) {
+ RedefineTest.instr = instr;
+ }
+
+
+ public static void main(String[] args) throws Exception {
+ for (int i = 0; i < 20_000; i++) {
+ int r = invokeBasic();
+ if (r != 0) {
+ throw new Error(r + " != 0");
+ }
+ }
+ // WB.ensureCompiled();
+
+ redefine();
+
+ int exp = (instr != null) ? 1 : 0;
+
+ for (int i = 0; i < 20_000; i++) {
+ if (invokeBasic() != exp) {
+ throw new Error();
+ }
+ }
+
+ WB.clearInlineCaches();
+
+ for (int i = 0; i < 20_000; i++) {
+ if (invokeBasic() != exp) {
+ throw new Error();
+ }
+ }
+
+ // WB.ensureCompiled();
+ }
+
+ static void redefine() {
+ if (instr == null) {
+ System.out.println("NOT REDEFINED");
+ return;
+ }
+ ClassDefinition cd = new ClassDefinition(CLS, getClassFile(1));
+ try {
+ instr.redefineClasses(cd);
+ } catch (Exception e) {
+ throw new Error(e);
+ }
+ System.out.println("REDEFINED");
+ }
+}
--- a/hotspot/test/sanity/MismatchedWhiteBox/WhiteBox.java Fri Dec 04 13:36:10 2015 -0800
+++ b/hotspot/test/sanity/MismatchedWhiteBox/WhiteBox.java Fri Dec 04 23:50:05 2015 +0000
@@ -29,7 +29,7 @@
* @library /testlibrary
* @compile WhiteBox.java
* @run main ClassFileInstaller sun.hotspot.WhiteBox
- * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI sun.hotspot.WhiteBox
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-CheckIntrinsics sun.hotspot.WhiteBox
*/
package sun.hotspot;