Mercurial > hg > icedtea7-forest-aarch64 > hotspot
changeset 5428:4ab69c6e4c85 icedtea-2.6pre03
Merge with ppc-aix-port
line wrap: on
line diff
--- a/make/aix/Makefile Thu Apr 24 16:21:06 2014 +0100 +++ b/make/aix/Makefile Tue Apr 29 21:57:16 2014 +0100 @@ -67,6 +67,10 @@ FORCE_TIERED=1 endif endif +# C1 is not ported on ppc64, so we cannot build a tiered VM: +ifeq ($(ARCH),ppc64)) + FORCE_TIERED=0 +endif ifdef LP64 ifeq ("$(filter $(LP64_ARCH),$(BUILDARCH))","")
--- a/make/linux/Makefile Thu Apr 24 16:21:06 2014 +0100 +++ b/make/linux/Makefile Tue Apr 29 21:57:16 2014 +0100 @@ -66,6 +66,10 @@ FORCE_TIERED=1 endif endif +# C1 is not ported on ppc64, so we cannot build a tiered VM: +ifeq ($(ARCH),ppc64) + FORCE_TIERED=0 +endif ifdef LP64 ifeq ("$(filter $(LP64_ARCH),$(BUILDARCH))","") @@ -208,7 +212,7 @@ TARGETS_SHARK = $(addsuffix shark,$(TARGETS)) BUILDTREE_MAKE = $(GAMMADIR)/make/$(OSNAME)/makefiles/buildtree.make -BUILDTREE_VARS = GAMMADIR=$(GAMMADIR) OS_FAMILY=$(OSNAME) SRCARCH=$(SRCARCH) BUILDARCH=$(BUILDARCH) LIBARCH=$(LIBARCH) +BUILDTREE_VARS = GAMMADIR=$(GAMMADIR) OS_FAMILY=$(OSNAME) SRCARCH=$(SRCARCH) BUILDARCH=$(BUILDARCH) LIBARCH=$(LIBARCH) OPENJDK_TARGET_CPU_ENDIAN=$(OPENJDK_TARGET_CPU_ENDIAN) BUILDTREE_VARS += HOTSPOT_RELEASE_VERSION=$(HOTSPOT_RELEASE_VERSION) HOTSPOT_BUILD_VERSION=$(HOTSPOT_BUILD_VERSION) JRE_RELEASE_VERSION=$(JRE_RELEASE_VERSION) BUILDTREE_VARS += ENABLE_FULL_DEBUG_SYMBOLS=$(ENABLE_FULL_DEBUG_SYMBOLS) OBJCOPY=$(OBJCOPY) STRIP_POLICY=$(STRIP_POLICY) ZIP_DEBUGINFO_FILES=$(ZIP_DEBUGINFO_FILES) ZIPEXE=$(ZIPEXE)
--- a/make/linux/makefiles/buildtree.make Thu Apr 24 16:21:06 2014 +0100 +++ b/make/linux/makefiles/buildtree.make Tue Apr 29 21:57:16 2014 +0100 @@ -26,7 +26,7 @@ # Usage: # # $(MAKE) -f buildtree.make SRCARCH=srcarch BUILDARCH=buildarch LIBARCH=libarch -# GAMMADIR=dir OS_FAMILY=os VARIANT=variant +# GAMMADIR=dir OS_FAMILY=os VARIANT=variant OPENJDK_TARGET_CPU_ENDIAN=endianness # # The macros ARCH, GAMMADIR, OS_FAMILY and VARIANT must be defined in the # environment or on the command-line: @@ -40,7 +40,8 @@ # HOTSPOT_RELEASE_VERSION - <major>.<minor>-b<nn> (11.0-b07) # HOTSPOT_BUILD_VERSION - internal, internal-$(USER_RELEASE_SUFFIX) or empty # JRE_RELEASE_VERSION - <major>.<minor>.<micro> (1.7.0) -# +# OPENJDK_TARGET_CPU_ENDIAN - target endianness: 'big'/'little'. Used to differentiate +# the architecture flavor for PowerPC64 # Builds the directory trees with makefiles plus some convenience files in # each directory: # @@ -133,7 +134,8 @@ env.sh env.csh jdkpath.sh .dbxrc test_gamma BUILDTREE_VARS = GAMMADIR=$(GAMMADIR) OS_FAMILY=$(OS_FAMILY) \ - SRCARCH=$(SRCARCH) BUILDARCH=$(BUILDARCH) LIBARCH=$(LIBARCH) VARIANT=$(VARIANT) + SRCARCH=$(SRCARCH) BUILDARCH=$(BUILDARCH) LIBARCH=$(LIBARCH) VARIANT=$(VARIANT) \ + OPENJDK_TARGET_CPU_ENDIAN=$(OPENJDK_TARGET_CPU_ENDIAN) # Define variables to be set in flags.make. # Default values are set in make/defs.make. @@ -210,6 +212,7 @@ echo "HOTSPOT_VM_DISTRO = $(HOTSPOT_VM_DISTRO)"; \ echo "OPENJDK = $(OPENJDK)"; \ echo "ZERO_BUILD = $(ZERO_BUILD)"; \ + echo "OPENJDK_TARGET_CPU_ENDIAN = $(OPENJDK_TARGET_CPU_ENDIAN)"; \ echo; \ echo "# Used for platform dispatching"; \ echo "TARGET_DEFINES = -DTARGET_OS_FAMILY_\$$(Platform_os_family)"; \
--- a/make/linux/makefiles/defs.make Thu Apr 24 16:21:06 2014 +0100 +++ b/make/linux/makefiles/defs.make Tue Apr 29 21:57:16 2014 +0100 @@ -133,6 +133,18 @@ PLATFORM = linux-ppc64 VM_PLATFORM = linux_ppc64 HS_ARCH = ppc + OPENJDK_TARGET_CPU_ENDIAN = big +endif + +# PPC64LE +ifeq ($(ARCH), ppc64le) + ARCH_DATA_MODEL = 64 + MAKE_ARGS += LP64=1 + PLATFORM = linux-ppc64 + VM_PLATFORM = linux_ppc64 + HS_ARCH = ppc + OPENJDK_TARGET_CPU_ENDIAN = little + ARCH := ppc64 endif # determine if HotSpot is being built in JDK6 or earlier version
--- a/make/linux/makefiles/ppc64.make Thu Apr 24 16:21:06 2014 +0100 +++ b/make/linux/makefiles/ppc64.make Tue Apr 29 21:57:16 2014 +0100 @@ -23,33 +23,54 @@ # # -# produce 64 bits object files. -CFLAGS += -m64 - -# make c code know it is on a 64 bit platform. +# make c code know it is on a 64 bit platform. CFLAGS += -D_LP64=1 -# fixes `relocation truncated to fit' error for gcc 4.1. -CFLAGS += -mminimal-toc +ifeq ($(origin OPENJDK_TARGET_CPU_ENDIAN),undefined) + # This can happen during hotspot standalone build. Set endianness from + # uname. We assume build and target machines are the same. + OPENJDK_TARGET_CPU_ENDIAN:=$(if $(filter ppc64le,$(shell uname -m)),little,big) +endif -# finds use ppc64 instructions, but schedule for power5 -CFLAGS += -mcpu=powerpc64 -mtune=power5 -minsert-sched-nops=regroup_exact -mno-multiple -mno-string +ifeq ($(filter $(OPENJDK_TARGET_CPU_ENDIAN),big little),) + $(error OPENJDK_TARGET_CPU_ENDIAN value should be 'big' or 'little') +endif -# PPC uses safefetch stubs. -CFLAGS += -DSAFEFETCH_STUBS +ifeq ($(OPENJDK_TARGET_CPU_ENDIAN),big) + # produce 64 bits object files. + CFLAGS += -m64 -# let linker produce 64 bit lib. -LFLAGS_VM += -m64 + # fixes `relocation truncated to fit' error for gcc 4.1. + CFLAGS += -mminimal-toc + + # finds use ppc64 instructions, but schedule for power5 + CFLAGS += -mcpu=powerpc64 -mtune=power5 -minsert-sched-nops=regroup_exact -mno-multiple -mno-string + + # PPC uses safefetch stubs. + CFLAGS += -DSAFEFETCH_STUBS -# let linker find external 64 bit libs. -LFLAGS_VM += -L/lib64 + # let linker produce 64 bit lib. + LFLAGS_VM += -m64 -# specify lib format. -LFLAGS_VM += -Wl,-melf64ppc + # let linker find external 64 bit libs. + LFLAGS_VM += -L/lib64 + + # specify lib format. + LFLAGS_VM += -Wl,-melf64ppc -# also build launcher as 64 bit executable. -LAUNCHERFLAGS += -m64 -LAUNCHERFLAGS += -D_LP64=1 -AOUT_FLAGS += -m64 -AOUT_FLAGS += -L/lib64 -AOUT_FLAGS += -Wl,-melf64ppc + # also build launcher as 64 bit executable. + LAUNCHERFLAGS += -m64 + LAUNCHERFLAGS += -D_LP64=1 + AOUT_FLAGS += -m64 + AOUT_FLAGS += -L/lib64 + AOUT_FLAGS += -Wl,-melf64ppc +else + # Little endian machine uses ELFv2 ABI. + CFLAGS += -DVM_LITTLE_ENDIAN -DABI_ELFv2 + + # PPC uses safefetch stubs. TODO(asmundak): is this needed? + CFLAGS += -DSAFEFETCH_STUBS + + # Use Power8, this is the first CPU to support PPC64 LE with ELFv2 ABI. + CFLAGS += -mcpu=power7 -mtune=power8 -minsert-sched-nops=regroup_exact -mno-multiple -mno-string +endif
--- a/make/linux/platform_ppc Thu Apr 24 16:21:06 2014 +0100 +++ b/make/linux/platform_ppc Tue Apr 29 21:57:16 2014 +0100 @@ -2,11 +2,11 @@ arch = ppc -arch_model = ppc +arch_model = ppc_32 os_arch = linux_ppc -os_arch_model = linux_ppc +os_arch_model = linux_ppc_32 lib_arch = ppc @@ -14,4 +14,4 @@ gnu_dis_arch = ppc -sysdefs = -DLINUX -D_GNU_SOURCE -DPPC +sysdefs = -DLINUX -D_GNU_SOURCE -DPPC32
--- a/src/cpu/ppc/vm/assembler_ppc.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/cpu/ppc/vm/assembler_ppc.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 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 @@ -36,6 +36,7 @@ #include "runtime/os.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" +#include "utilities/macros.hpp" #ifndef SERIALGC #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" @@ -383,10 +384,10 @@ bool load_xa = (xa != 0) || (xb < 0); bool return_xd = false; - if (load_xa) lis(tmp, xa); - if (xc) lis(d, xc); + if (load_xa) { lis(tmp, xa); } + if (xc) { lis(d, xc); } if (load_xa) { - if (xb) ori(tmp, tmp, xb); // No addi, we support tmp == R0. + if (xb) { ori(tmp, tmp, (unsigned short)xb); } // No addi, we support tmp == R0. } else { li(tmp, xb); // non-negative } @@ -408,18 +409,18 @@ // opt 4: avoid adding 0 if (xa) { // Highest 16-bit needed? lis(d, xa); - if (xb) addi(d, d, xb); + if (xb) { addi(d, d, xb); } } else { li(d, xb); } sldi(d, d, 32); - if (xc) addis(d, d, xc); + if (xc) { addis(d, d, xc); } } // opt 5: Return offset to be inserted into following instruction. if (return_simm16_rest) return xd; - if (xd) addi(d, d, xd); + if (xd) { addi(d, d, xd); } return 0; }
--- a/src/cpu/ppc/vm/assembler_ppc.hpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/cpu/ppc/vm/assembler_ppc.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -127,6 +127,7 @@ } }; +#if !defined(ABI_ELFv2) // A ppc64 function descriptor. struct FunctionDescriptor VALUE_OBJ_CLASS_SPEC { private: @@ -164,6 +165,7 @@ _env = (address) 0xbad; } }; +#endif class Assembler : public AbstractAssembler { protected: @@ -1027,15 +1029,14 @@ } static void set_imm(int* instr, short s) { - short* p = ((short *)instr) + 1; - *p = s; + // imm is always in the lower 16 bits of the instruction, + // so this is endian-neutral. Same for the get_imm below. + uint32_t w = *(uint32_t *)instr; + *instr = (int)((w & ~0x0000FFFF) | (s & 0x0000FFFF)); } static int get_imm(address a, int instruction_number) { - short imm; - short *p =((short *)a)+2*instruction_number+1; - imm = *p; - return (int)imm; + return (short)((int *)a)[instruction_number]; } static inline int hi16_signed( int x) { return (int)(int16_t)(x >> 16); } @@ -1072,6 +1073,7 @@ // Emit an address. inline address emit_addr(const address addr = NULL); +#if !defined(ABI_ELFv2) // Emit a function descriptor with the specified entry point, TOC, // and ENV. If the entry point is NULL, the descriptor will point // just past the descriptor. @@ -1079,6 +1081,7 @@ inline address emit_fd(address entry = NULL, address toc = (address) FunctionDescriptor::friend_toc, address env = (address) FunctionDescriptor::friend_env); +#endif ///////////////////////////////////////////////////////////////////////////////////// // PPC instructions
--- a/src/cpu/ppc/vm/assembler_ppc.inline.hpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/cpu/ppc/vm/assembler_ppc.inline.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -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 2012, 2014 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 @@ -64,6 +64,7 @@ return start; } +#if !defined(ABI_ELFv2) // Emit a function descriptor with the specified entry point, TOC, and // ENV. If the entry point is NULL, the descriptor will point just // past the descriptor. @@ -82,6 +83,7 @@ return (address)fd; } +#endif // Issue an illegal instruction. 0 is guaranteed to be an illegal instruction. inline void Assembler::illtrap() { Assembler::emit_int32(0); }
--- a/src/cpu/ppc/vm/bytes_ppc.hpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/cpu/ppc/vm/bytes_ppc.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -35,6 +35,126 @@ // Can I count on address always being a pointer to an unsigned char? Yes. +#if defined(VM_LITTLE_ENDIAN) + + // Returns true, if the byte ordering used by Java is different from the native byte ordering + // of the underlying machine. For example, true for Intel x86, False, for Solaris on Sparc. + static inline bool is_Java_byte_ordering_different() { return true; } + + // Forward declarations of the compiler-dependent implementation + static inline u2 swap_u2(u2 x); + static inline u4 swap_u4(u4 x); + static inline u8 swap_u8(u8 x); + + static inline u2 get_native_u2(address p) { + return (intptr_t(p) & 1) == 0 + ? *(u2*)p + : ( u2(p[1]) << 8 ) + | ( u2(p[0]) ); + } + + static inline u4 get_native_u4(address p) { + switch (intptr_t(p) & 3) { + case 0: return *(u4*)p; + + case 2: return ( u4( ((u2*)p)[1] ) << 16 ) + | ( u4( ((u2*)p)[0] ) ); + + default: return ( u4(p[3]) << 24 ) + | ( u4(p[2]) << 16 ) + | ( u4(p[1]) << 8 ) + | u4(p[0]); + } + } + + static inline u8 get_native_u8(address p) { + switch (intptr_t(p) & 7) { + case 0: return *(u8*)p; + + case 4: return ( u8( ((u4*)p)[1] ) << 32 ) + | ( u8( ((u4*)p)[0] ) ); + + case 2: return ( u8( ((u2*)p)[3] ) << 48 ) + | ( u8( ((u2*)p)[2] ) << 32 ) + | ( u8( ((u2*)p)[1] ) << 16 ) + | ( u8( ((u2*)p)[0] ) ); + + default: return ( u8(p[7]) << 56 ) + | ( u8(p[6]) << 48 ) + | ( u8(p[5]) << 40 ) + | ( u8(p[4]) << 32 ) + | ( u8(p[3]) << 24 ) + | ( u8(p[2]) << 16 ) + | ( u8(p[1]) << 8 ) + | u8(p[0]); + } + } + + + + static inline void put_native_u2(address p, u2 x) { + if ( (intptr_t(p) & 1) == 0 ) *(u2*)p = x; + else { + p[1] = x >> 8; + p[0] = x; + } + } + + static inline void put_native_u4(address p, u4 x) { + switch ( intptr_t(p) & 3 ) { + case 0: *(u4*)p = x; + break; + + case 2: ((u2*)p)[1] = x >> 16; + ((u2*)p)[0] = x; + break; + + default: ((u1*)p)[3] = x >> 24; + ((u1*)p)[2] = x >> 16; + ((u1*)p)[1] = x >> 8; + ((u1*)p)[0] = x; + break; + } + } + + static inline void put_native_u8(address p, u8 x) { + switch ( intptr_t(p) & 7 ) { + case 0: *(u8*)p = x; + break; + + case 4: ((u4*)p)[1] = x >> 32; + ((u4*)p)[0] = x; + break; + + case 2: ((u2*)p)[3] = x >> 48; + ((u2*)p)[2] = x >> 32; + ((u2*)p)[1] = x >> 16; + ((u2*)p)[0] = x; + break; + + default: ((u1*)p)[7] = x >> 56; + ((u1*)p)[6] = x >> 48; + ((u1*)p)[5] = x >> 40; + ((u1*)p)[4] = x >> 32; + ((u1*)p)[3] = x >> 24; + ((u1*)p)[2] = x >> 16; + ((u1*)p)[1] = x >> 8; + ((u1*)p)[0] = x; + } + } + + // Efficient reading and writing of unaligned unsigned data in Java byte ordering (i.e. big-endian ordering) + // (no byte-order reversal is needed since Power CPUs are big-endian oriented). + static inline u2 get_Java_u2(address p) { return swap_u2(get_native_u2(p)); } + static inline u4 get_Java_u4(address p) { return swap_u4(get_native_u4(p)); } + static inline u8 get_Java_u8(address p) { return swap_u8(get_native_u8(p)); } + + static inline void put_Java_u2(address p, u2 x) { put_native_u2(p, swap_u2(x)); } + static inline void put_Java_u4(address p, u4 x) { put_native_u4(p, swap_u4(x)); } + static inline void put_Java_u8(address p, u8 x) { put_native_u8(p, swap_u8(x)); } + +#else // !defined(VM_LITTLE_ENDIAN) + // Returns true, if the byte ordering used by Java is different from the nativ byte ordering // of the underlying machine. For example, true for Intel x86, False, for Solaris on Sparc. static inline bool is_Java_byte_ordering_different() { return false; } @@ -150,6 +270,12 @@ static inline void put_Java_u2(address p, u2 x) { put_native_u2(p, x); } static inline void put_Java_u4(address p, u4 x) { put_native_u4(p, x); } static inline void put_Java_u8(address p, u8 x) { put_native_u8(p, x); } + +#endif // VM_LITTLE_ENDIAN }; +#if defined(TARGET_OS_ARCH_linux_ppc) +#include "bytes_linux_ppc.inline.hpp" +#endif + #endif // CPU_PPC_VM_BYTES_PPC_HPP
--- a/src/cpu/ppc/vm/compile_ppc.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/cpu/ppc/vm/compile_ppc.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -83,34 +83,8 @@ call->_in_rms[TypeFunc::ReturnAdr] = BITS64_REG_DYNAMIC_CALL_mask(); } m->set_req(TypeFunc::ReturnAdr, loadToc); - } else { - assert(0, "I removed need for this."); } } - - if (m->rule() == safePoint_poll_conPollAddr_rule) { - // The node loading the poll address must be added before register allocation. - // Else the register allocator can use rscratch2RegP (r12) for another value that - // must be live in the safepoint. - // If TEMP effects of adl would work with SafePoints, this code here could be - // avoided. A KILL effect is not sufficient. - MachSafePointNode *ms = m->as_MachSafePoint(); - if (!pdEnv->loadPoll) { - if (LoadPollAddressFromThread) { - Unimplemented(); - } else { - pdEnv->loadPoll = new (pdEnv->C) loadConPollAddrNode(); - pdEnv->loadPoll->add_req(NULL); - pdEnv->loadPoll->_opnds[0] = new (pdEnv->C) rscratch2RegPOper(); - pdEnv->loadPoll->_opnds[1] = new (pdEnv->C) immP_NMOper(TypePtr::NOTNULL); - } - } - ms->ins_req(m->oper_input_base(), pdEnv->loadPoll); - // We added a required edge, so we must adapt the jvms. - // As another node might use the same jvms, we must clone it first. - ms->_jvms = ms->_jvms->clone_deep(pdEnv->C); - fix_jvms(ms->_jvms, +1); - } } }
--- a/src/cpu/ppc/vm/cppInterpreter_ppc.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/cpu/ppc/vm/cppInterpreter_ppc.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -422,8 +422,8 @@ __ addi(max_stack, max_stack, methodOopDesc::extra_stack_entries()); } - // mem_stack_limit = thread->memory_stack_limit(); - __ ld(mem_stack_limit, thread_(memory_stack_limit)); + // mem_stack_limit = thread->stack_limit(); + __ ld(mem_stack_limit, thread_(stack_overflow_limit)); // Point locals at the first argument. Method's locals are the // parameters on top of caller's expression stack. @@ -1126,7 +1126,9 @@ // (outgoing C args), R3_ARG1 to R10_ARG8, and F1_ARG1 to // F13_ARG13. __ mr(R3_ARG1, R18_locals); +#if !defined(ABI_ELFv2) __ ld(signature_handler_fd, 0, signature_handler_fd); +#endif __ call_stub(signature_handler_fd); // reload method __ ld(R19_method, state_(_method)); @@ -1285,8 +1287,13 @@ // native result acrosss the call. No oop is present __ mr(R3_ARG1, R16_thread); +#if defined(ABI_ELFv2) + __ call_c(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans), + relocInfo::none); +#else __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, JavaThread::check_special_condition_for_native_trans), relocInfo::none); +#endif __ bind(sync_check_done); //============================================================================= @@ -1336,9 +1343,9 @@ // notify here, we'll drop it on the floor. __ notify_method_exit(true/*native method*/, - ilgl /*illegal state (not used for native methods)*/); - - + ilgl /*illegal state (not used for native methods)*/, + InterpreterMacroAssembler::NotifyJVMTI, + false /*check_exceptions*/); //============================================================================= // Handle exceptions @@ -1403,7 +1410,7 @@ // First, pop to caller's frame. __ pop_interpreter_frame(R11_scratch1, R12_scratch2, R21_tmp1 /* set to return pc */, R22_tmp2); - __ push_frame_abi112(0, R11_scratch1); + __ push_frame_reg_args(0, R11_scratch1); // Get the address of the exception handler. __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), R16_thread, @@ -2531,7 +2538,7 @@ __ mr(R4_ARG2, R3_ARG1); // ARG2 := ARG1 // Find the address of the "catch_exception" stub. - __ push_frame_abi112(0, R11_scratch1); + __ push_frame_reg_args(0, R11_scratch1); __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), R16_thread, R4_ARG2);
--- a/src/cpu/ppc/vm/frame_ppc.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/cpu/ppc/vm/frame_ppc.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -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 2012, 2014 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 @@ -42,10 +42,6 @@ #include "runtime/vframeArray.hpp" #endif -#ifndef CC_INTERP -#error "CC_INTERP must be defined on PPC64" -#endif - #ifdef ASSERT void RegisterMap::check_location_valid() { } @@ -89,7 +85,10 @@ frame frame::sender_for_interpreter_frame(RegisterMap *map) const { // Pass callers initial_caller_sp as unextended_sp. - return frame(sender_sp(), sender_pc(), (intptr_t*)((parent_ijava_frame_abi *)callers_abi())->initial_caller_sp); + return frame(sender_sp(), sender_pc(), + CC_INTERP_ONLY((intptr_t*)((parent_ijava_frame_abi *)callers_abi())->initial_caller_sp) + NOT_CC_INTERP((intptr_t*)get_ijava_state()->sender_sp) + ); } frame frame::sender_for_compiled_frame(RegisterMap *map) const { @@ -183,6 +182,9 @@ interpreterState istate = get_interpreterState(); address lresult = (address)istate + in_bytes(BytecodeInterpreter::native_lresult_offset()); address fresult = (address)istate + in_bytes(BytecodeInterpreter::native_fresult_offset()); +#else + address lresult = (address)&(get_ijava_state()->lresult); + address fresult = (address)&(get_ijava_state()->fresult); #endif switch (method->result_type()) { @@ -259,7 +261,21 @@ values.describe(frame_no, (intptr_t*)&(istate->_native_fresult), " native_fresult"); values.describe(frame_no, (intptr_t*)&(istate->_native_lresult), " native_lresult"); #else - Unimplemented(); +#define DESCRIBE_ADDRESS(name) \ + values.describe(frame_no, (intptr_t*)&(get_ijava_state()->name), #name); + + DESCRIBE_ADDRESS(method); + DESCRIBE_ADDRESS(locals); + DESCRIBE_ADDRESS(monitors); + DESCRIBE_ADDRESS(cpoolCache); + DESCRIBE_ADDRESS(bcp); + DESCRIBE_ADDRESS(esp); + DESCRIBE_ADDRESS(mdx); + DESCRIBE_ADDRESS(top_frame_sp); + DESCRIBE_ADDRESS(sender_sp); + DESCRIBE_ADDRESS(oop_tmp); + DESCRIBE_ADDRESS(lresult); + DESCRIBE_ADDRESS(fresult); #endif } }
--- a/src/cpu/ppc/vm/frame_ppc.hpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/cpu/ppc/vm/frame_ppc.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -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 2012, 2014 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 @@ -29,10 +29,6 @@ #include "runtime/synchronizer.hpp" #include "utilities/top.hpp" -#ifndef CC_INTERP -#error "CC_INTERP must be defined on PPC64" -#endif - // C frame layout on PPC-64. // // In this figure the stack grows upwards, while memory grows @@ -50,7 +46,7 @@ // [C_FRAME] // // C_FRAME: - // 0 [ABI_112] + // 0 [ABI_REG_ARGS] // 112 CARG_9: outgoing arg 9 (arg_1 ... arg_8 via gpr_3 ... gpr_{10}) // ... // 40+M*8 CARG_M: outgoing arg M (M is the maximum of outgoing args taken over all call sites in the procedure) @@ -77,7 +73,7 @@ // 32 reserved // 40 space for TOC (=R2) register for next call // - // ABI_112: + // ABI_REG_ARGS: // 0 [ABI_48] // 48 CARG_1: spill slot for outgoing arg 1. used by next callee. // ... ... @@ -95,23 +91,25 @@ log_2_of_alignment_in_bits = 7 }; - // ABI_48: - struct abi_48 { + // ABI_MINFRAME: + struct abi_minframe { uint64_t callers_sp; uint64_t cr; //_16 uint64_t lr; +#if !defined(ABI_ELFv2) uint64_t reserved1; //_16 uint64_t reserved2; +#endif uint64_t toc; //_16 // nothing to add here! // aligned to frame::alignment_in_bytes (16) }; enum { - abi_48_size = sizeof(abi_48) + abi_minframe_size = sizeof(abi_minframe) }; - struct abi_112 : abi_48 { + struct abi_reg_args : abi_minframe { uint64_t carg_1; uint64_t carg_2; //_16 uint64_t carg_3; @@ -124,13 +122,13 @@ }; enum { - abi_112_size = sizeof(abi_112) + abi_reg_args_size = sizeof(abi_reg_args) }; #define _abi(_component) \ - (offset_of(frame::abi_112, _component)) + (offset_of(frame::abi_reg_args, _component)) - struct abi_112_spill : abi_112 { + struct abi_reg_args_spill : abi_reg_args { // additional spill slots uint64_t spill_ret; uint64_t spill_fret; //_16 @@ -138,11 +136,11 @@ }; enum { - abi_112_spill_size = sizeof(abi_112_spill) + abi_reg_args_spill_size = sizeof(abi_reg_args_spill) }; - #define _abi_112_spill(_component) \ - (offset_of(frame::abi_112_spill, _component)) + #define _abi_reg_args_spill(_component) \ + (offset_of(frame::abi_reg_args_spill, _component)) // non-volatile GPRs: @@ -195,7 +193,85 @@ #define _spill_nonvolatiles_neg(_component) \ (int)(-frame::spill_nonvolatiles_size + offset_of(frame::spill_nonvolatiles, _component)) - // Frame layout for the Java interpreter on PPC64. + + +#ifndef CC_INTERP + // Frame layout for the Java template interpreter on PPC64. + // + // Diffs to the CC_INTERP are marked with 'X'. + // + // TOP_IJAVA_FRAME: + // + // 0 [TOP_IJAVA_FRAME_ABI] + // alignment (optional) + // [operand stack] + // [monitors] (optional) + // X[IJAVA_STATE] + // note: own locals are located in the caller frame. + // + // PARENT_IJAVA_FRAME: + // + // 0 [PARENT_IJAVA_FRAME_ABI] + // alignment (optional) + // [callee's Java result] + // [callee's locals w/o arguments] + // [outgoing arguments] + // [used part of operand stack w/o arguments] + // [monitors] (optional) + // X[IJAVA_STATE] + // + + struct parent_ijava_frame_abi : abi_minframe { + }; + + enum { + parent_ijava_frame_abi_size = sizeof(parent_ijava_frame_abi) + }; + +#define _parent_ijava_frame_abi(_component) \ + (offset_of(frame::parent_ijava_frame_abi, _component)) + + struct top_ijava_frame_abi : abi_reg_args { + }; + + enum { + top_ijava_frame_abi_size = sizeof(top_ijava_frame_abi) + }; + +#define _top_ijava_frame_abi(_component) \ + (offset_of(frame::top_ijava_frame_abi, _component)) + + struct ijava_state { +#ifdef ASSERT + uint64_t ijava_reserved; // Used for assertion. + uint64_t ijava_reserved2; // Inserted for alignment. +#endif + uint64_t method; + uint64_t locals; + uint64_t monitors; + uint64_t cpoolCache; + uint64_t bcp; + uint64_t esp; + uint64_t mdx; + uint64_t top_frame_sp; // Maybe define parent_frame_abi and move there. + uint64_t sender_sp; + // Slots only needed for native calls. Maybe better to move elsewhere. + uint64_t oop_tmp; + uint64_t lresult; + uint64_t fresult; + // Aligned to frame::alignment_in_bytes (16). + }; + + enum { + ijava_state_size = sizeof(ijava_state) + }; + +#define _ijava_state_neg(_component) \ + (int) (-frame::ijava_state_size + offset_of(frame::ijava_state, _component)) + +#else // CC_INTERP: + + // Frame layout for the Java C++ interpreter on PPC64. // // This frame layout provides a C-like frame for every Java frame. // @@ -242,7 +318,7 @@ // [ENTRY_FRAME_LOCALS] // // PARENT_IJAVA_FRAME_ABI: - // 0 [ABI_48] + // 0 [ABI_MINFRAME] // top_frame_sp // initial_caller_sp // @@ -258,7 +334,7 @@ // PARENT_IJAVA_FRAME_ABI - struct parent_ijava_frame_abi : abi_48 { + struct parent_ijava_frame_abi : abi_minframe { // SOE registers. // C2i adapters spill their top-frame stack-pointer here. uint64_t top_frame_sp; // carg_1 @@ -285,7 +361,7 @@ uint64_t carg_6_unused; //_16 carg_6 uint64_t carg_7_unused; // carg_7 // Use arg8 for storing frame_manager_lr. The size of - // top_ijava_frame_abi must match abi_112. + // top_ijava_frame_abi must match abi_reg_args. uint64_t frame_manager_lr; //_16 carg_8 // nothing to add here! // aligned to frame::alignment_in_bytes (16) @@ -298,6 +374,8 @@ #define _top_ijava_frame_abi(_component) \ (offset_of(frame::top_ijava_frame_abi, _component)) +#endif // CC_INTERP + // ENTRY_FRAME struct entry_frame_locals { @@ -395,8 +473,8 @@ intptr_t* fp() const { return _fp; } // Accessors for ABIs - inline abi_48* own_abi() const { return (abi_48*) _sp; } - inline abi_48* callers_abi() const { return (abi_48*) _fp; } + inline abi_minframe* own_abi() const { return (abi_minframe*) _sp; } + inline abi_minframe* callers_abi() const { return (abi_minframe*) _fp; } private: @@ -421,6 +499,14 @@ #ifdef CC_INTERP // Additional interface for interpreter frames: inline interpreterState get_interpreterState() const; +#else + inline ijava_state* get_ijava_state() const; + // Some convenient register frame setters/getters for deoptimization. + inline intptr_t* interpreter_frame_esp() const; + inline void interpreter_frame_set_cpcache(constantPoolCacheOop cp); + inline void interpreter_frame_set_esp(intptr_t* esp); + inline void interpreter_frame_set_top_frame_sp(intptr_t* top_frame_sp); + inline void interpreter_frame_set_sender_sp(intptr_t* sender_sp); #endif // CC_INTERP // Size of a monitor in bytes.
--- a/src/cpu/ppc/vm/frame_ppc.inline.hpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/cpu/ppc/vm/frame_ppc.inline.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -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 2012, 2014 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 @@ -26,10 +26,6 @@ #ifndef CPU_PPC_VM_FRAME_PPC_INLINE_HPP #define CPU_PPC_VM_FRAME_PPC_INLINE_HPP -#ifndef CC_INTERP -#error "CC_INTERP must be defined on PPC64" -#endif - // Inline functions for ppc64 frames: // Find codeblob and set deopt_state. @@ -199,6 +195,75 @@ interpreterState istate = get_interpreterState(); return &istate->_constants; } + +#else // !CC_INTERP + +// Template Interpreter frame value accessors. + +inline frame::ijava_state* frame::get_ijava_state() const { + return (ijava_state*) ((uintptr_t)fp() - ijava_state_size); +} + +inline intptr_t** frame::interpreter_frame_locals_addr() const { + return (intptr_t**) &(get_ijava_state()->locals); +} +inline intptr_t* frame::interpreter_frame_bcx_addr() const { + return (intptr_t*) &(get_ijava_state()->bcp); +} +inline intptr_t* frame::interpreter_frame_mdx_addr() const { + return (intptr_t*) &(get_ijava_state()->mdx); +} +// Pointer beyond the "oldest/deepest" BasicObjectLock on stack. +inline BasicObjectLock* frame::interpreter_frame_monitor_end() const { + return (BasicObjectLock *) get_ijava_state()->monitors; +} + +inline BasicObjectLock* frame::interpreter_frame_monitor_begin() const { + return (BasicObjectLock *) get_ijava_state(); +} + +// Return register stack slot addr at which currently interpreted methodOop is found. +inline methodOop* frame::interpreter_frame_method_addr() const { + return (methodOop*) &(get_ijava_state()->method); +} +inline constantPoolCacheOop* frame::interpreter_frame_cpoolcache_addr() const { + return (constantPoolCacheOop*) &(get_ijava_state()->cpoolCache); +} +inline constantPoolCacheOop* frame::interpreter_frame_cache_addr() const { + return (constantPoolCacheOop*) &(get_ijava_state()->cpoolCache); +} + +inline oop* frame::interpreter_frame_temp_oop_addr() const { + return (oop *) &(get_ijava_state()->oop_tmp); +} +inline intptr_t* frame::interpreter_frame_esp() const { + return (intptr_t*) get_ijava_state()->esp; +} + +// Convenient setters +inline void frame::interpreter_frame_set_monitor_end(BasicObjectLock* end) { get_ijava_state()->monitors = (intptr_t) end;} +inline void frame::interpreter_frame_set_cpcache(constantPoolCacheOop cp) { *frame::interpreter_frame_cpoolcache_addr() = cp; } +inline void frame::interpreter_frame_set_esp(intptr_t* esp) { get_ijava_state()->esp = (intptr_t) esp; } +inline void frame::interpreter_frame_set_top_frame_sp(intptr_t* top_frame_sp) { get_ijava_state()->top_frame_sp = (intptr_t) top_frame_sp; } +inline void frame::interpreter_frame_set_sender_sp(intptr_t* sender_sp) { get_ijava_state()->sender_sp = (intptr_t) sender_sp; } + +inline intptr_t* frame::interpreter_frame_expression_stack() const { + return (intptr_t*)interpreter_frame_monitor_end() - 1; +} + +inline jint frame::interpreter_frame_expression_stack_direction() { + return -1; +} + +// top of expression stack +inline intptr_t* frame::interpreter_frame_tos_address() const { + return ((intptr_t*) get_ijava_state()->esp) + Interpreter::stackElementWords; +} + +inline intptr_t* frame::interpreter_frame_tos_at(jint offset) const { + return &interpreter_frame_tos_address()[offset]; +} + #endif // CC_INTERP inline int frame::interpreter_frame_monitor_size() {
--- a/src/cpu/ppc/vm/interp_masm_ppc_64.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/cpu/ppc/vm/interp_masm_ppc_64.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -1,6 +1,6 @@ /* * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 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 @@ -28,6 +28,7 @@ #include "assembler_ppc.hpp" #include "interp_masm_ppc_64.hpp" #include "interpreter/interpreterRuntime.hpp" +#include "prims/jvmtiThreadState.hpp" #ifdef PRODUCT @@ -45,6 +46,693 @@ MacroAssembler::null_check_throw(a, offset, temp_reg, exception_entry); } +void InterpreterMacroAssembler::branch_to_entry(address entry, Register Rscratch) { + assert(entry, "Entry must have been generated by now"); + if (is_within_range_of_b(entry, pc())) { + b(entry); + } else { + load_const_optimized(Rscratch, entry, R0); + mtctr(Rscratch); + bctr(); + } +} + +#ifndef CC_INTERP + +void InterpreterMacroAssembler::dispatch_next(TosState state, int bcp_incr) { + Register bytecode = R12_scratch2; + if (bcp_incr != 0) { + lbzu(bytecode, bcp_incr, R14_bcp); + } else { + lbz(bytecode, 0, R14_bcp); + } + + dispatch_Lbyte_code(state, bytecode, Interpreter::dispatch_table(state)); +} + +void InterpreterMacroAssembler::dispatch_via(TosState state, address* table) { + // Load current bytecode. + Register bytecode = R12_scratch2; + lbz(bytecode, 0, R14_bcp); + dispatch_Lbyte_code(state, bytecode, table); +} + +// Dispatch code executed in the prolog of a bytecode which does not do it's +// own dispatch. The dispatch address is computed and placed in R24_dispatch_addr. +void InterpreterMacroAssembler::dispatch_prolog(TosState state, int bcp_incr) { + Register bytecode = R12_scratch2; + lbz(bytecode, bcp_incr, R14_bcp); + + load_dispatch_table(R24_dispatch_addr, Interpreter::dispatch_table(state)); + + sldi(bytecode, bytecode, LogBytesPerWord); + ldx(R24_dispatch_addr, R24_dispatch_addr, bytecode); +} + +// Dispatch code executed in the epilog of a bytecode which does not do it's +// own dispatch. The dispatch address in R24_dispatch_addr is used for the +// dispatch. +void InterpreterMacroAssembler::dispatch_epilog(TosState state, int bcp_incr) { + mtctr(R24_dispatch_addr); + addi(R14_bcp, R14_bcp, bcp_incr); + bctr(); +} + +void InterpreterMacroAssembler::check_and_handle_popframe(Register scratch_reg) { + assert(scratch_reg != R0, "can't use R0 as scratch_reg here"); + if (JvmtiExport::can_pop_frame()) { + Label L; + + // Check the "pending popframe condition" flag in the current thread. + lwz(scratch_reg, in_bytes(JavaThread::popframe_condition_offset()), R16_thread); + + // Initiate popframe handling only if it is not already being + // processed. If the flag has the popframe_processing bit set, it + // means that this code is called *during* popframe handling - we + // don't want to reenter. + andi_(R0, scratch_reg, JavaThread::popframe_pending_bit); + beq(CCR0, L); + + andi_(R0, scratch_reg, JavaThread::popframe_processing_bit); + bne(CCR0, L); + + // Call the Interpreter::remove_activation_preserving_args_entry() + // func to get the address of the same-named entrypoint in the + // generated interpreter code. + call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, + Interpreter::remove_activation_preserving_args_entry), + relocInfo::none); + + // Jump to Interpreter::_remove_activation_preserving_args_entry. + mtctr(R3_RET); + bctr(); + + align(32, 12); + bind(L); + } +} + +void InterpreterMacroAssembler::check_and_handle_earlyret(Register scratch_reg) { + const Register Rthr_state_addr = scratch_reg; + if (JvmtiExport::can_force_early_return()) { + Label Lno_early_ret; + ld(Rthr_state_addr, in_bytes(JavaThread::jvmti_thread_state_offset()), R16_thread); + cmpdi(CCR0, Rthr_state_addr, 0); + beq(CCR0, Lno_early_ret); + + lwz(R0, in_bytes(JvmtiThreadState::earlyret_state_offset()), Rthr_state_addr); + cmpwi(CCR0, R0, JvmtiThreadState::earlyret_pending); + bne(CCR0, Lno_early_ret); + + // Jump to Interpreter::_earlyret_entry. + lwz(R3_ARG1, in_bytes(JvmtiThreadState::earlyret_tos_offset()), Rthr_state_addr); + call_VM_leaf(CAST_FROM_FN_PTR(address, Interpreter::remove_activation_early_entry)); + mtlr(R3_RET); + blr(); + + align(32, 12); + bind(Lno_early_ret); + } +} + +void InterpreterMacroAssembler::load_earlyret_value(TosState state, Register Rscratch1) { + const Register RjvmtiState = Rscratch1; + const Register Rscratch2 = R0; + + ld(RjvmtiState, in_bytes(JavaThread::jvmti_thread_state_offset()), R16_thread); + li(Rscratch2, 0); + + switch (state) { + case atos: ld(R17_tos, in_bytes(JvmtiThreadState::earlyret_oop_offset()), RjvmtiState); + std(Rscratch2, in_bytes(JvmtiThreadState::earlyret_oop_offset()), RjvmtiState); + break; + case ltos: ld(R17_tos, in_bytes(JvmtiThreadState::earlyret_value_offset()), RjvmtiState); + break; + case btos: // fall through + case ctos: // fall through + case stos: // fall through + case itos: lwz(R17_tos, in_bytes(JvmtiThreadState::earlyret_value_offset()), RjvmtiState); + break; + case ftos: lfs(F15_ftos, in_bytes(JvmtiThreadState::earlyret_value_offset()), RjvmtiState); + break; + case dtos: lfd(F15_ftos, in_bytes(JvmtiThreadState::earlyret_value_offset()), RjvmtiState); + break; + case vtos: break; + default : ShouldNotReachHere(); + } + + // Clean up tos value in the jvmti thread state. + std(Rscratch2, in_bytes(JvmtiThreadState::earlyret_value_offset()), RjvmtiState); + // Set tos state field to illegal value. + li(Rscratch2, ilgl); + stw(Rscratch2, in_bytes(JvmtiThreadState::earlyret_tos_offset()), RjvmtiState); +} + +// Common code to dispatch and dispatch_only. +// Dispatch value in Lbyte_code and increment Lbcp. + +void InterpreterMacroAssembler::load_dispatch_table(Register dst, address* table) { + address table_base = (address)Interpreter::dispatch_table((TosState)0); + intptr_t table_offs = (intptr_t)table - (intptr_t)table_base; + if (is_simm16(table_offs)) { + addi(dst, R25_templateTableBase, (int)table_offs); + } else { + load_const_optimized(dst, table, R0); + } +} + +void InterpreterMacroAssembler::dispatch_Lbyte_code(TosState state, Register bytecode, address* table, bool verify) { + if (verify) { + 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. + load_dispatch_table(R11_scratch1, table); + + sldi(R12_scratch2, bytecode, LogBytesPerWord); + ldx(R11_scratch1, R11_scratch1, R12_scratch2); + + // Jump off! + mtctr(R11_scratch1); + bctr(); +#endif +} + +void InterpreterMacroAssembler::load_receiver(Register Rparam_count, Register Rrecv_dst) { + sldi(Rrecv_dst, Rparam_count, Interpreter::logStackElementSize); + ldx(Rrecv_dst, Rrecv_dst, R15_esp); +} + +// helpers for expression stack + +void InterpreterMacroAssembler::pop_i(Register r) { + lwzu(r, Interpreter::stackElementSize, R15_esp); +} + +void InterpreterMacroAssembler::pop_ptr(Register r) { + ldu(r, Interpreter::stackElementSize, R15_esp); +} + +void InterpreterMacroAssembler::pop_l(Register r) { + ld(r, Interpreter::stackElementSize, R15_esp); + addi(R15_esp, R15_esp, 2 * Interpreter::stackElementSize); +} + +void InterpreterMacroAssembler::pop_f(FloatRegister f) { + lfsu(f, Interpreter::stackElementSize, R15_esp); +} + +void InterpreterMacroAssembler::pop_d(FloatRegister f) { + lfd(f, Interpreter::stackElementSize, R15_esp); + addi(R15_esp, R15_esp, 2 * Interpreter::stackElementSize); +} + +void InterpreterMacroAssembler::push_i(Register r) { + stw(r, 0, R15_esp); + addi(R15_esp, R15_esp, - Interpreter::stackElementSize ); +} + +void InterpreterMacroAssembler::push_ptr(Register r) { + std(r, 0, R15_esp); + addi(R15_esp, R15_esp, - Interpreter::stackElementSize ); +} + +void InterpreterMacroAssembler::push_l(Register r) { + std(r, - Interpreter::stackElementSize, R15_esp); + addi(R15_esp, R15_esp, - 2 * Interpreter::stackElementSize ); +} + +void InterpreterMacroAssembler::push_f(FloatRegister f) { + stfs(f, 0, R15_esp); + addi(R15_esp, R15_esp, - Interpreter::stackElementSize ); +} + +void InterpreterMacroAssembler::push_d(FloatRegister f) { + stfd(f, - Interpreter::stackElementSize, R15_esp); + addi(R15_esp, R15_esp, - 2 * Interpreter::stackElementSize ); +} + +void InterpreterMacroAssembler::push_2ptrs(Register first, Register second) { + std(first, 0, R15_esp); + std(second, -Interpreter::stackElementSize, R15_esp); + addi(R15_esp, R15_esp, - 2 * Interpreter::stackElementSize ); +} + +void InterpreterMacroAssembler::push_l_pop_d(Register l, FloatRegister d) { + std(l, 0, R15_esp); + lfd(d, 0, R15_esp); +} + +void InterpreterMacroAssembler::push_d_pop_l(FloatRegister d, Register l) { + stfd(d, 0, R15_esp); + ld(l, 0, R15_esp); +} + +void InterpreterMacroAssembler::push(TosState state) { + switch (state) { + case atos: push_ptr(); break; + case btos: + case ctos: + case stos: + case itos: push_i(); break; + case ltos: push_l(); break; + case ftos: push_f(); break; + case dtos: push_d(); break; + case vtos: /* nothing to do */ break; + default : ShouldNotReachHere(); + } +} + +void InterpreterMacroAssembler::pop(TosState state) { + switch (state) { + case atos: pop_ptr(); break; + case btos: + case ctos: + case stos: + case itos: pop_i(); break; + case ltos: pop_l(); break; + case ftos: pop_f(); break; + case dtos: pop_d(); break; + case vtos: /* nothing to do */ break; + default : ShouldNotReachHere(); + } + verify_oop(R17_tos, state); +} + +void InterpreterMacroAssembler::empty_expression_stack() { + addi(R15_esp, R26_monitor, - Interpreter::stackElementSize); +} + +void InterpreterMacroAssembler::get_2_byte_integer_at_bcp(int bcp_offset, + Register Rdst, + signedOrNot is_signed) { + // Read Java big endian format. + if (is_signed == Signed) { + lha(Rdst, bcp_offset, R14_bcp); + } else { + lhz(Rdst, bcp_offset, R14_bcp); + } +#if 0 + assert(Rtmp != Rdst, "need separate temp register"); + Register Rfirst = Rtmp; + lbz(Rfirst, bcp_offset, R14_bcp); // first byte + lbz(Rdst, bcp_offset+1, R14_bcp); // second byte + + // Rdst = ((Rfirst<<8) & 0xFF00) | (Rdst &~ 0xFF00) + rldimi(/*RA=*/Rdst, /*RS=*/Rfirst, /*sh=*/8, /*mb=*/48); + if (is_signed == Signed) { + extsh(Rdst, Rdst); + } +#endif +} + +void InterpreterMacroAssembler::get_4_byte_integer_at_bcp(int bcp_offset, + Register Rdst, + signedOrNot is_signed) { + // Read Java big endian format. + if (bcp_offset & 3) { // Offset unaligned? + load_const_optimized(Rdst, bcp_offset); + if (is_signed == Signed) { + lwax(Rdst, R14_bcp, Rdst); + } else { + lwzx(Rdst, R14_bcp, Rdst); + } + } else { + if (is_signed == Signed) { + lwa(Rdst, bcp_offset, R14_bcp); + } else { + lwz(Rdst, bcp_offset, R14_bcp); + } + } +} + +// Load the constant pool cache index from the bytecode stream. +// +// Kills / writes: +// - Rdst, Rscratch +void InterpreterMacroAssembler::get_cache_index_at_bcp(Register Rdst, int bcp_offset, size_t index_size) { + assert(bcp_offset > 0, "bcp is still pointing to start of bytecode"); + if (index_size == sizeof(u2)) { + get_2_byte_integer_at_bcp(bcp_offset, Rdst, Unsigned); + } else if (index_size == sizeof(u4)) { + assert(EnableInvokeDynamic, "giant index used only for JSR 292"); + get_4_byte_integer_at_bcp(bcp_offset, Rdst, Signed); + assert(constantPoolCacheOopDesc::decode_secondary_index(~123) == 123, "else change next line"); + nand(Rdst, Rdst, Rdst); // convert to plain index + } else if (index_size == sizeof(u1)) { + lbz(Rdst, bcp_offset, R14_bcp); + } else { + ShouldNotReachHere(); + } + // Rdst now contains cp cache index. +} + +void InterpreterMacroAssembler::get_cache_and_index_at_bcp(Register cache, int bcp_offset, size_t index_size) { + get_cache_index_at_bcp(cache, bcp_offset, index_size); + sldi(cache, cache, exact_log2(in_words(ConstantPoolCacheEntry::size()) * BytesPerWord)); + add(cache, R27_constPoolCache, cache); +} +#if 0 +// Load object from cpool->resolved_references(index). +void InterpreterMacroAssembler::load_resolved_reference_at_index(Register result, Register index) { + assert_different_registers(result, index); + get_constant_pool(result); + + // Convert from field index to resolved_references() index and from + // word index to byte offset. Since this is a java object, it can be compressed. + Register tmp = index; // reuse + sldi(tmp, index, LogBytesPerHeapOop); + // Load pointer for resolved_references[] objArray. + ld(result, ConstantPool::resolved_references_offset_in_bytes(), result); + // JNIHandles::resolve(result) + ld(result, 0, result); +#ifdef ASSERT + Label index_ok; + lwa(R0, arrayOopDesc::length_offset_in_bytes(), result); + sldi(R0, R0, LogBytesPerHeapOop); + cmpd(CCR0, tmp, R0); + blt(CCR0, index_ok); + stop("resolved reference index out of bounds", 0x09256); + bind(index_ok); +#endif + // Add in the index. + add(result, tmp, result); + load_heap_oop(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT), result); +} +#endif + +// Generate a subtype check: branch to ok_is_subtype if sub_klass is +// a subtype of super_klass. Blows registers Rsub_klass, tmp1, tmp2. +void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass, Register Rsuper_klass, Register Rtmp1, + Register Rtmp2, Register Rtmp3, Label &ok_is_subtype) { + // Profile the not-null value's klass. + profile_typecheck(Rsub_klass, Rtmp1, Rtmp2); + check_klass_subtype(Rsub_klass, Rsuper_klass, Rtmp1, Rtmp2, ok_is_subtype); + profile_typecheck_failed(Rtmp1, Rtmp2); +} + +void InterpreterMacroAssembler::generate_stack_overflow_check_with_compare_and_throw(Register Rmem_frame_size, Register Rscratch1) { + Label done; + sub(Rmem_frame_size, R1_SP, Rmem_frame_size); + ld(Rscratch1, thread_(stack_overflow_limit)); + cmpld(CCR0/*is_stack_overflow*/, Rmem_frame_size, Rscratch1); + bgt(CCR0/*is_stack_overflow*/, done); + + // Load target address of the runtime stub. + assert(StubRoutines::throw_StackOverflowError_entry() != NULL, "generated in wrong order"); + load_const_optimized(Rscratch1, (StubRoutines::throw_StackOverflowError_entry()), R0); + mtctr(Rscratch1); + // Restore caller_sp. +#ifdef ASSERT + ld(Rscratch1, 0, R1_SP); + ld(R0, 0, R21_sender_SP); + cmpd(CCR0, R0, Rscratch1); + asm_assert_eq("backlink", 0x547); +#endif // ASSERT + mr(R1_SP, R21_sender_SP); + bctr(); + + align(32, 12); + bind(done); +} + +// Separate these two to allow for delay slot in middle. +// These are used to do a test and full jump to exception-throwing code. + +// Check that index is in range for array, then shift index by index_shift, +// and put arrayOop + shifted_index into res. +// Note: res is still shy of address by array offset into object. + +void InterpreterMacroAssembler::index_check_without_pop(Register Rarray, Register Rindex, int index_shift, Register Rtmp, Register Rres) { + // Check that index is in range for array, then shift index by index_shift, + // and put arrayOop + shifted_index into res. + // Note: res is still shy of address by array offset into object. + // Kills: + // - Rindex + // Writes: + // - Rres: Address that corresponds to the array index if check was successful. + verify_oop(Rarray); + const Register Rlength = R0; + const Register RsxtIndex = Rtmp; + Label LisNull, LnotOOR; + + // Array nullcheck + if (!ImplicitNullChecks) { + cmpdi(CCR0, Rarray, 0); + beq(CCR0, LisNull); + } else { + null_check_throw(Rarray, arrayOopDesc::length_offset_in_bytes(), /*temp*/RsxtIndex); + } + + // Rindex might contain garbage in upper bits (remember that we don't sign extend + // during integer arithmetic operations). So kill them and put value into same register + // where ArrayIndexOutOfBounds would expect the index in. + rldicl(RsxtIndex, Rindex, 0, 32); // zero extend 32 bit -> 64 bit + + // Index check + lwz(Rlength, arrayOopDesc::length_offset_in_bytes(), Rarray); + cmplw(CCR0, Rindex, Rlength); + sldi(RsxtIndex, RsxtIndex, index_shift); + blt(CCR0, LnotOOR); + load_dispatch_table(Rtmp, (address*)Interpreter::_throw_ArrayIndexOutOfBoundsException_entry); + mtctr(Rtmp); + bctr(); + + if (!ImplicitNullChecks) { + bind(LisNull); + load_dispatch_table(Rtmp, (address*)Interpreter::_throw_NullPointerException_entry); + mtctr(Rtmp); + bctr(); + } + + align(32, 16); + bind(LnotOOR); + + // Calc address + add(Rres, RsxtIndex, Rarray); +} + +void InterpreterMacroAssembler::index_check(Register array, Register index, int index_shift, Register tmp, Register res) { + // pop array + pop_ptr(array); + + // check array + index_check_without_pop(array, index, index_shift, tmp, res); +} + +void InterpreterMacroAssembler::get_const(Register Rdst) { + ld(Rdst, in_bytes(methodOopDesc::const_offset()), R19_method); +} + +void InterpreterMacroAssembler::get_constant_pool(Register Rdst) { + get_const(Rdst); + ld(Rdst, in_bytes(constMethodOopDesc::constants_offset()), Rdst); +} + +void InterpreterMacroAssembler::get_constant_pool_cache(Register Rdst) { + get_constant_pool(Rdst); + ld(Rdst, constantPoolOopDesc::cache_offset_in_bytes(), Rdst); +} + +void InterpreterMacroAssembler::get_cpool_and_tags(Register Rcpool, Register Rtags) { + get_constant_pool(Rcpool); + ld(Rtags, constantPoolOopDesc::tags_offset_in_bytes(), Rcpool); +} + +// Unlock if synchronized method. +// +// Unlock the receiver if this is a synchronized method. +// Unlock any Java monitors from synchronized blocks. +// +// If there are locked Java monitors +// If throw_monitor_exception +// throws IllegalMonitorStateException +// Else if install_monitor_exception +// installs IllegalMonitorStateException +// Else +// no error processing +void InterpreterMacroAssembler::unlock_if_synchronized_method(TosState state, + bool throw_monitor_exception, + bool install_monitor_exception) { + Label Lunlocked, Lno_unlock; + { + Register Rdo_not_unlock_flag = R11_scratch1; + Register Raccess_flags = R12_scratch2; + + // Check if synchronized method or unlocking prevented by + // JavaThread::do_not_unlock_if_synchronized flag. + lbz(Rdo_not_unlock_flag, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()), R16_thread); + lwz(Raccess_flags, in_bytes(methodOopDesc::access_flags_offset()), R19_method); + li(R0, 0); + stb(R0, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()), R16_thread); // reset flag + + push(state); + + // Skip if we don't have to unlock. + rldicl_(R0, Raccess_flags, 64-JVM_ACC_SYNCHRONIZED_BIT, 63); // Extract bit and compare to 0. + beq(CCR0, Lunlocked); + + cmpwi(CCR0, Rdo_not_unlock_flag, 0); + bne(CCR0, Lno_unlock); + } + + // Unlock + { + Register Rmonitor_base = R11_scratch1; + + Label Lunlock; + // If it's still locked, everything is ok, unlock it. + ld(Rmonitor_base, 0, R1_SP); + addi(Rmonitor_base, Rmonitor_base, - (frame::ijava_state_size + frame::interpreter_frame_monitor_size_in_bytes())); // Monitor base + + ld(R0, BasicObjectLock::obj_offset_in_bytes(), Rmonitor_base); + cmpdi(CCR0, R0, 0); + bne(CCR0, Lunlock); + + // If it's already unlocked, throw exception. + if (throw_monitor_exception) { + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_illegal_monitor_state_exception)); + should_not_reach_here(); + } else { + if (install_monitor_exception) { + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::new_illegal_monitor_state_exception)); + b(Lunlocked); + } + } + + bind(Lunlock); + unlock_object(Rmonitor_base); + } + + // Check that all other monitors are unlocked. Throw IllegelMonitorState exception if not. + bind(Lunlocked); + { + Label Lexception, Lrestart; + Register Rcurrent_obj_addr = R11_scratch1; + const int delta = frame::interpreter_frame_monitor_size_in_bytes(); + assert((delta & LongAlignmentMask) == 0, "sizeof BasicObjectLock must be even number of doublewords"); + + bind(Lrestart); + // Set up search loop: Calc num of iterations. + { + Register Riterations = R12_scratch2; + Register Rmonitor_base = Rcurrent_obj_addr; + ld(Rmonitor_base, 0, R1_SP); + addi(Rmonitor_base, Rmonitor_base, - frame::ijava_state_size); // Monitor base + + subf_(Riterations, R26_monitor, Rmonitor_base); + ble(CCR0, Lno_unlock); + + addi(Rcurrent_obj_addr, Rmonitor_base, BasicObjectLock::obj_offset_in_bytes() - frame::interpreter_frame_monitor_size_in_bytes()); + // Check if any monitor is on stack, bail out if not + srdi(Riterations, Riterations, exact_log2(delta)); + mtctr(Riterations); + } + + // The search loop: Look for locked monitors. + { + const Register Rcurrent_obj = R0; + Label Lloop; + + ld(Rcurrent_obj, 0, Rcurrent_obj_addr); + addi(Rcurrent_obj_addr, Rcurrent_obj_addr, -delta); + bind(Lloop); + + // Check if current entry is used. + cmpdi(CCR0, Rcurrent_obj, 0); + bne(CCR0, Lexception); + // Preload next iteration's compare value. + ld(Rcurrent_obj, 0, Rcurrent_obj_addr); + addi(Rcurrent_obj_addr, Rcurrent_obj_addr, -delta); + bdnz(Lloop); + } + // Fell through: Everything's unlocked => finish. + b(Lno_unlock); + + // An object is still locked => need to throw exception. + bind(Lexception); + if (throw_monitor_exception) { + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_illegal_monitor_state_exception)); + should_not_reach_here(); + } else { + // Stack unrolling. Unlock object and if requested, install illegal_monitor_exception. + // Unlock does not block, so don't have to worry about the frame. + Register Rmonitor_addr = R11_scratch1; + addi(Rmonitor_addr, Rcurrent_obj_addr, -BasicObjectLock::obj_offset_in_bytes() + delta); + unlock_object(Rmonitor_addr); + if (install_monitor_exception) { + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::new_illegal_monitor_state_exception)); + } + b(Lrestart); + } + } + + align(32, 12); + bind(Lno_unlock); + pop(state); +} + +// Support function for remove_activation & Co. +void InterpreterMacroAssembler::merge_frames(Register Rsender_sp, Register return_pc, Register Rscratch1, Register Rscratch2) { + // Pop interpreter frame. + ld(Rscratch1, 0, R1_SP); // *SP + ld(Rsender_sp, _ijava_state_neg(sender_sp), Rscratch1); // top_frame_sp + ld(Rscratch2, 0, Rscratch1); // **SP +#ifdef ASSERT + { + Label Lok; + ld(R0, _ijava_state_neg(ijava_reserved), Rscratch1); + cmpdi(CCR0, R0, 0x5afe); + beq(CCR0, Lok); + stop("frame corrupted (remove activation)", 0x5afe); + bind(Lok); + } +#endif + if (return_pc!=noreg) { + ld(return_pc, _abi(lr), Rscratch1); // LR + } + + // Merge top frames. + subf(Rscratch1, R1_SP, Rsender_sp); // top_frame_sp - SP + stdux(Rscratch2, R1_SP, Rscratch1); // atomically set *(SP = top_frame_sp) = **SP +} + +// Remove activation. +// +// Unlock the receiver if this is a synchronized method. +// Unlock any Java monitors from synchronized blocks. +// Remove the activation from the stack. +// +// If there are locked Java monitors +// If throw_monitor_exception +// throws IllegalMonitorStateException +// Else if install_monitor_exception +// installs IllegalMonitorStateException +// Else +// no error processing +void InterpreterMacroAssembler::remove_activation(TosState state, + bool throw_monitor_exception, + bool install_monitor_exception) { + unlock_if_synchronized_method(state, throw_monitor_exception, install_monitor_exception); + + // Save result (push state before jvmti call and pop it afterwards) and notify jvmti. + notify_method_exit(false, state, NotifyJVMTI, true); + + verify_oop(R17_tos, state); + verify_oop(R19_method); + verify_thread(); + + merge_frames(/*top_frame_sp*/ R21_sender_SP, /*return_pc*/ R0, R11_scratch1, R12_scratch2); + mtlr(R0); +} + +#endif // !CC_INTERP + // Lock object // // Registers alive @@ -55,7 +743,7 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { if (UseHeavyMonitors) { call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), - monitor, /*check_for_exceptions=*/true && CC_INTERP_ONLY(false)); + monitor, /*check_for_exceptions=*/true CC_INTERP_ONLY(&& false)); } else { // template code: // @@ -81,7 +769,6 @@ assert_different_registers(displaced_header, object_mark_addr, current_header, tmp); - // markOop displaced_header = obj->mark().set_unlocked(); // Load markOop from object into displaced_header. @@ -94,12 +781,11 @@ // Set displaced_header to be (markOop of object | UNLOCK_VALUE). ori(displaced_header, displaced_header, markOopDesc::unlocked_value); - // monitor->lock()->set_displaced_header(displaced_header); // Initialize the box (Must happen before we update the object mark!). std(displaced_header, BasicObjectLock::lock_offset_in_bytes() + - BasicLock::displaced_header_offset_in_bytes(), monitor); + BasicLock::displaced_header_offset_in_bytes(), monitor); // if (Atomic::cmpxchg_ptr(/*ex=*/monitor, /*addr*/obj->mark_addr(), /*cmp*/displaced_header) == displaced_header) { @@ -108,7 +794,7 @@ // 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 ? + membar(Assembler::StoreStore); cmpxchgd(/*flag=*/CCR0, /*current_value=*/current_header, /*compare_value=*/displaced_header, /*exchange_value=*/monitor, @@ -144,10 +830,9 @@ bne(CCR0, slow_case); release(); std(R0/*==0!*/, BasicObjectLock::lock_offset_in_bytes() + - BasicLock::displaced_header_offset_in_bytes(), monitor); + BasicLock::displaced_header_offset_in_bytes(), monitor); b(done); - // } else { // // Slow path. // InterpreterRuntime::monitorenter(THREAD, monitor); @@ -156,9 +841,9 @@ // slow case of monitor enter. bind(slow_case); call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), - monitor, /*check_for_exceptions=*/true && CC_INTERP_ONLY(false)); + monitor, /*check_for_exceptions=*/true CC_INTERP_ONLY(&& false)); // } - + align(32, 12); bind(done); } } @@ -170,16 +855,16 @@ // which must be initialized with the object to lock. // // Throw IllegalMonitorException if object is not locked by current thread. -void InterpreterMacroAssembler::unlock_object(Register monitor) { +void InterpreterMacroAssembler::unlock_object(Register monitor, bool check_for_exceptions) { if (UseHeavyMonitors) { call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), - monitor, /*check_for_exceptions=*/false); + monitor, check_for_exceptions CC_INTERP_ONLY(&& false)); } else { // template code: // // if ((displaced_header = monitor->displaced_header()) == NULL) { - // // Recursive unlock. Mark the monitor unlocked by setting the object field to NULL. + // // Recursive unlock. Mark the monitor unlocked by setting the object field to NULL. // monitor->set_obj(NULL); // } else if (Atomic::cmpxchg_ptr(displaced_header, obj->mark_addr(), monitor) == monitor) { // // We swapped the unlocked mark in displaced_header into the object's mark word. @@ -195,7 +880,6 @@ const Register current_header = R10_ARG8; Label free_slot; - Label no_recursive_unlock; Label slow_case; assert_different_registers(object, displaced_header, object_mark_addr, current_header); @@ -215,8 +899,6 @@ cmpdi(CCR0, displaced_header, 0); beq(CCR0, free_slot); // recursive unlock - bind(no_recursive_unlock); - // } else if (Atomic::cmpxchg_ptr(displaced_header, obj->mark_addr(), monitor) == monitor) { // // We swapped the unlocked mark in displaced_header into the object's mark word. // monitor->set_obj(NULL); @@ -224,7 +906,7 @@ // If we still have a lightweight lock, unlock the object and be done. // The object address from the monitor is in object. - if (!UseBiasedLocking) ld(object, BasicObjectLock::obj_offset_in_bytes(), monitor); + if (!UseBiasedLocking) { ld(object, BasicObjectLock::obj_offset_in_bytes(), monitor); } addi(object_mark_addr, object, oopDesc::mark_offset_in_bytes()); // We have the displaced header in displaced_header. If the lock is still @@ -249,23 +931,991 @@ // we need to get into the slow case. bind(slow_case); call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), - monitor, /*check_for_exceptions=*/false); + monitor, check_for_exceptions CC_INTERP_ONLY(&& false)); // } Label done; - b(done); // monitor register may be overwritten! runtime has already freed the slot + b(done); // Monitor register may be overwritten! Runtime has already freed the slot. - // exchange worked, do monitor->set_obj(NULL); + // Exchange worked, do monitor->set_obj(NULL); align(32, 12); bind(free_slot); li(R0, 0); - // SAPJVM RR 2009-11-30: must release earlier (see cmpxchgd above) - // release(); std(R0, BasicObjectLock::obj_offset_in_bytes(), monitor); bind(done); } } +#ifndef CC_INTERP + +// Load compiled (i2c) or interpreter entry when calling from interpreted and +// do the call. Centralized so that all interpreter calls will do the same actions. +// If jvmti single stepping is on for a thread we must not call compiled code. +// +// Input: +// - Rtarget_method: method to call +// - Rret_addr: return address +// - 2 scratch regs +// +void InterpreterMacroAssembler::call_from_interpreter(Register Rtarget_method, Register Rret_addr, Register Rscratch1, Register Rscratch2) { + assert_different_registers(Rscratch1, Rscratch2, Rtarget_method, Rret_addr); + // Assume we want to go compiled if available. + const Register Rtarget_addr = Rscratch1; + const Register Rinterp_only = Rscratch2; + + ld(Rtarget_addr, in_bytes(methodOopDesc::from_interpreted_offset()), Rtarget_method); + + if (JvmtiExport::can_post_interpreter_events()) { + lwz(Rinterp_only, in_bytes(JavaThread::interp_only_mode_offset()), R16_thread); + + // JVMTI events, such as single-stepping, are implemented partly by avoiding running + // compiled code in threads for which the event is enabled. Check here for + // interp_only_mode if these events CAN be enabled. + Label done; + verify_thread(); + cmpwi(CCR0, Rinterp_only, 0); + beq(CCR0, done); + ld(Rtarget_addr, in_bytes(methodOopDesc::interpreter_entry_offset()), Rtarget_method); + align(32, 12); + bind(done); + } + +#ifdef ASSERT + { + Label Lok; + cmpdi(CCR0, Rtarget_addr, 0); + bne(CCR0, Lok); + stop("null entry point"); + bind(Lok); + } +#endif // ASSERT + + mr(R21_sender_SP, R1_SP); + + // Calc a precise SP for the call. The SP value we calculated in + // generate_fixed_frame() is based on the max_stack() value, so we would waste stack space + // if esp is not max. Also, the i2c adapter extends the stack space without restoring + // our pre-calced value, so repeating calls via i2c would result in stack overflow. + // Since esp already points to an empty slot, we just have to sub 1 additional slot + // to meet the abi scratch requirements. + // The max_stack pointer will get restored by means of the GR_Lmax_stack local in + // the return entry of the interpreter. + addi(Rscratch2, R15_esp, Interpreter::stackElementSize - frame::abi_reg_args_size); + clrrdi(Rscratch2, Rscratch2, exact_log2(frame::alignment_in_bytes)); // round towards smaller address + resize_frame_absolute(Rscratch2, Rscratch2, R0); + + mr_if_needed(R19_method, Rtarget_method); + mtctr(Rtarget_addr); + mtlr(Rret_addr); + + save_interpreter_state(Rscratch2); +#ifdef ASSERT + ld(Rscratch1, _ijava_state_neg(top_frame_sp), Rscratch2); // Rscratch2 contains fp + cmpd(CCR0, R21_sender_SP, Rscratch1); + asm_assert_eq("top_frame_sp incorrect", 0x951); +#endif + + bctr(); +} + +// Set the method data pointer for the current bcp. +void InterpreterMacroAssembler::set_method_data_pointer_for_bcp() { + assert(ProfileInterpreter, "must be profiling interpreter"); + Label get_continue; + ld(R28_mdx, in_bytes(methodOopDesc::method_data_offset()), R19_method); + test_method_data_pointer(get_continue); + call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::bcp_to_di), R19_method, R14_bcp); + + addi(R28_mdx, R28_mdx, in_bytes(methodDataOopDesc::data_offset())); + add(R28_mdx, R28_mdx, R3_RET); + bind(get_continue); +} + +// Test ImethodDataPtr. If it is null, continue at the specified label. +void InterpreterMacroAssembler::test_method_data_pointer(Label& zero_continue) { + assert(ProfileInterpreter, "must be profiling interpreter"); + cmpdi(CCR0, R28_mdx, 0); + beq(CCR0, zero_continue); +} + +void InterpreterMacroAssembler::verify_method_data_pointer() { + assert(ProfileInterpreter, "must be profiling interpreter"); +#ifdef ASSERT + Label verify_continue; + test_method_data_pointer(verify_continue); + + // If the mdp is valid, it will point to a DataLayout header which is + // consistent with the bcp. The converse is highly probable also. + lhz(R11_scratch1, in_bytes(DataLayout::bci_offset()), R28_mdx); + ld(R12_scratch2, in_bytes(methodOopDesc::const_offset()), R19_method); + addi(R11_scratch1, R11_scratch1, in_bytes(constMethodOopDesc::codes_offset())); + add(R11_scratch1, R12_scratch2, R12_scratch2); + cmpd(CCR0, R11_scratch1, R14_bcp); + beq(CCR0, verify_continue); + + call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::verify_mdp), R19_method, R14_bcp, R28_mdx); + + bind(verify_continue); +#endif +} + +void InterpreterMacroAssembler::test_invocation_counter_for_mdp(Register invocation_count, + Register Rscratch, + Label &profile_continue) { + assert(ProfileInterpreter, "must be profiling interpreter"); + // Control will flow to "profile_continue" if the counter is less than the + // limit or if we call profile_method(). + 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); + + cmpdi(CCR0, R28_mdx, 0); + // Test to see if we should create a method data oop. + cmpd(CCR1, Rscratch /* InterpreterProfileLimit */, invocation_count); + bne(CCR0, done); + bge(CCR1, profile_continue); + + // Build it now. + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method)); + set_method_data_pointer_for_bcp(); + b(profile_continue); + + align(32, 12); + 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); + 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); + cmpw(CCR0, backedge_count, Rtmp); + + blt(CCR0, did_not_overflow); + + // When ProfileInterpreter is on, the backedge_count comes from the + // methodDataOop, which value does not get reset on the call to + // frequency_counter_overflow(). To avoid excessive calls to the overflow + // routine while the method is being compiled, add a second test to make sure + // 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); + 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); + + // Was an OSR adapter generated? + // O0 = osr nmethod + cmpdi(CCR0, R3_RET, 0); + beq(CCR0, overflow_with_error); + + // Has the nmethod been invalidated already? + lwz(Rtmp, nmethod::entry_bci_offset(), R3_RET); + cmpwi(CCR0, Rtmp, InvalidOSREntryBci); + beq(CCR0, overflow_with_error); + + // Migrate the interpreter frame off of the stack. + // We can use all registers because we will not return to interpreter from this point. + + // Save nmethod. + const Register osr_nmethod = R31; + mr(osr_nmethod, R3_RET); + set_top_ijava_frame_at_SP_as_last_Java_frame(R1_SP, R11_scratch1); + call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::OSR_migration_begin), R16_thread); + reset_last_Java_frame(); + // OSR buffer is in ARG1 + + // Remove the interpreter frame. + merge_frames(/*top_frame_sp*/ R21_sender_SP, /*return_pc*/ R0, R11_scratch1, R12_scratch2); + + // Jump to the osr code. + ld(R11_scratch1, nmethod::osr_entry_point_offset(), osr_nmethod); + mtlr(R0); + mtctr(R11_scratch1); + bctr(); + + align(32, 12); + bind(overflow_with_error); + bind(did_not_overflow); +} + +// Store a value at some constant offset from the method data pointer. +void InterpreterMacroAssembler::set_mdp_data_at(int constant, Register value) { + assert(ProfileInterpreter, "must be profiling interpreter"); + + std(value, constant, R28_mdx); +} + +// Increment the value at some constant offset from the method data pointer. +void InterpreterMacroAssembler::increment_mdp_data_at(int constant, + Register counter_addr, + Register Rbumped_count, + bool decrement) { + // Locate the counter at a fixed offset from the mdp: + addi(counter_addr, R28_mdx, constant); + increment_mdp_data_at(counter_addr, Rbumped_count, decrement); +} + +// Increment the value at some non-fixed (reg + constant) offset from +// the method data pointer. +void InterpreterMacroAssembler::increment_mdp_data_at(Register reg, + int constant, + Register scratch, + Register Rbumped_count, + bool decrement) { + // Add the constant to reg to get the offset. + add(scratch, R28_mdx, reg); + // Then calculate the counter address. + addi(scratch, scratch, constant); + increment_mdp_data_at(scratch, Rbumped_count, decrement); +} + +void InterpreterMacroAssembler::increment_mdp_data_at(Register counter_addr, + Register Rbumped_count, + bool decrement) { + assert(ProfileInterpreter, "must be profiling interpreter"); + + // Load the counter. + ld(Rbumped_count, 0, counter_addr); + + if (decrement) { + // Decrement the register. Set condition codes. + addi(Rbumped_count, Rbumped_count, - DataLayout::counter_increment); + // Store the decremented counter, if it is still negative. + std(Rbumped_count, 0, counter_addr); + // Note: add/sub overflow check are not ported, since 64 bit + // calculation should never overflow. + } else { + // Increment the register. Set carry flag. + addi(Rbumped_count, Rbumped_count, DataLayout::counter_increment); + // Store the incremented counter. + std(Rbumped_count, 0, counter_addr); + } +} + +// Set a flag value at the current method data pointer position. +void InterpreterMacroAssembler::set_mdp_flag_at(int flag_constant, + Register scratch) { + assert(ProfileInterpreter, "must be profiling interpreter"); + // Load the data header. + lbz(scratch, in_bytes(DataLayout::flags_offset()), R28_mdx); + // Set the flag. + ori(scratch, scratch, flag_constant); + // Store the modified header. + stb(scratch, in_bytes(DataLayout::flags_offset()), R28_mdx); +} + +// Test the location at some offset from the method data pointer. +// If it is not equal to value, branch to the not_equal_continue Label. +void InterpreterMacroAssembler::test_mdp_data_at(int offset, + Register value, + Label& not_equal_continue, + Register test_out) { + assert(ProfileInterpreter, "must be profiling interpreter"); + + ld(test_out, offset, R28_mdx); + cmpd(CCR0, value, test_out); + bne(CCR0, not_equal_continue); +} + +// Update the method data pointer by the displacement located at some fixed +// offset from the method data pointer. +void InterpreterMacroAssembler::update_mdp_by_offset(int offset_of_disp, + Register scratch) { + assert(ProfileInterpreter, "must be profiling interpreter"); + + ld(scratch, offset_of_disp, R28_mdx); + add(R28_mdx, scratch, R28_mdx); +} + +// Update the method data pointer by the displacement located at the +// offset (reg + offset_of_disp). +void InterpreterMacroAssembler::update_mdp_by_offset(Register reg, + int offset_of_disp, + Register scratch) { + assert(ProfileInterpreter, "must be profiling interpreter"); + + add(scratch, reg, R28_mdx); + ld(scratch, offset_of_disp, scratch); + add(R28_mdx, scratch, R28_mdx); +} + +// Update the method data pointer by a simple constant displacement. +void InterpreterMacroAssembler::update_mdp_by_constant(int constant) { + assert(ProfileInterpreter, "must be profiling interpreter"); + addi(R28_mdx, R28_mdx, constant); +} + +// Update the method data pointer for a _ret bytecode whose target +// was not among our cached targets. +void InterpreterMacroAssembler::update_mdp_for_ret(TosState state, + Register return_bci) { + assert(ProfileInterpreter, "must be profiling interpreter"); + push(state); + mr(R21_tmp1, return_bci); // Protect return_bci, in case it is volatile. + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::update_mdp_for_ret), return_bci); + mr(return_bci, R21_tmp1); + pop(state); +} + +// Increments the backedge counter. +// Returns backedge counter + invocation counter in Rdst. +void InterpreterMacroAssembler::increment_backedge_counter(const Register Rdst, + const Register Rtmp1, Register Rscratch) { + assert(UseCompiler, "incrementing must be useful"); + 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."); + + // Load backedge counter + lwz(counter, in_bytes(methodOopDesc::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset()), R19_method); + // Load invocation counter + lwz(invocation_counter, in_bytes(methodOopDesc::invocation_counter_offset()) + in_bytes(InvocationCounter::counter_offset()), R19_method); + + // Add the delta to the backedge counter. + addi(counter, counter, InvocationCounter::count_increment); + + // Mask the invocation counter. + li(Rscratch, InvocationCounter::count_mask_value); + andr(invocation_counter, invocation_counter, Rscratch); + + // Store new counter value. + stw(counter, in_bytes(methodOopDesc::backedge_counter_offset()) + + in_bytes(InvocationCounter::counter_offset()), R19_method); + // Return invocation counter + backedge counter. + add(counter, counter, invocation_counter); +} + +// Count a taken branch in the bytecodes. +void InterpreterMacroAssembler::profile_taken_branch(Register scratch, Register bumped_count) { + if (ProfileInterpreter) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(profile_continue); + + // We are taking a branch. Increment the taken count. + increment_mdp_data_at(in_bytes(JumpData::taken_offset()), scratch, bumped_count); + + // The method data pointer needs to be updated to reflect the new target. + update_mdp_by_offset(in_bytes(JumpData::displacement_offset()), scratch); + bind (profile_continue); + } +} + +// Count a not-taken branch in the bytecodes. +void InterpreterMacroAssembler::profile_not_taken_branch(Register scratch1, Register scratch2) { + if (ProfileInterpreter) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(profile_continue); + + // We are taking a branch. Increment the not taken count. + increment_mdp_data_at(in_bytes(BranchData::not_taken_offset()), scratch1, scratch2); + + // The method data pointer needs to be updated to correspond to the + // next bytecode. + update_mdp_by_constant(in_bytes(BranchData::branch_data_size())); + bind (profile_continue); + } +} + +// Count a non-virtual call in the bytecodes. +void InterpreterMacroAssembler::profile_call(Register scratch1, Register scratch2) { + if (ProfileInterpreter) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(profile_continue); + + // We are making a call. Increment the count. + increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch1, scratch2); + + // The method data pointer needs to be updated to reflect the new target. + update_mdp_by_constant(in_bytes(CounterData::counter_data_size())); + bind (profile_continue); + } +} + +// Count a final call in the bytecodes. +void InterpreterMacroAssembler::profile_final_call(Register scratch1, Register scratch2) { + if (ProfileInterpreter) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(profile_continue); + + // We are making a call. Increment the count. + increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch1, scratch2); + + // The method data pointer needs to be updated to reflect the new target. + update_mdp_by_constant(in_bytes(VirtualCallData::virtual_call_data_size())); + bind (profile_continue); + } +} + +// Count a virtual call in the bytecodes. +void InterpreterMacroAssembler::profile_virtual_call(Register Rreceiver, + Register Rscratch1, + Register Rscratch2, + bool receiver_can_be_null) { + if (!ProfileInterpreter) { return; } + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(profile_continue); + + Label skip_receiver_profile; + if (receiver_can_be_null) { + Label not_null; + cmpdi(CCR0, Rreceiver, 0); + bne(CCR0, not_null); + // We are making a call. Increment the count for null receiver. + increment_mdp_data_at(in_bytes(CounterData::count_offset()), Rscratch1, Rscratch2); + b(skip_receiver_profile); + bind(not_null); + } + + // Record the receiver type. + record_klass_in_profile(Rreceiver, Rscratch1, Rscratch2, true); + bind(skip_receiver_profile); + + // The method data pointer needs to be updated to reflect the new target. + update_mdp_by_constant(in_bytes(VirtualCallData::virtual_call_data_size())); + bind (profile_continue); +} + +void InterpreterMacroAssembler::profile_typecheck(Register Rklass, Register Rscratch1, Register Rscratch2) { + if (ProfileInterpreter) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(profile_continue); + + int mdp_delta = in_bytes(BitData::bit_data_size()); + if (TypeProfileCasts) { + mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size()); + + // Record the object type. + record_klass_in_profile(Rklass, Rscratch1, Rscratch2, false); + } + + // The method data pointer needs to be updated. + update_mdp_by_constant(mdp_delta); + + bind (profile_continue); + } +} + +void InterpreterMacroAssembler::profile_typecheck_failed(Register Rscratch1, Register Rscratch2) { + if (ProfileInterpreter && TypeProfileCasts) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(profile_continue); + + int count_offset = in_bytes(CounterData::count_offset()); + // Back up the address, since we have already bumped the mdp. + count_offset -= in_bytes(VirtualCallData::virtual_call_data_size()); + + // *Decrement* the counter. We expect to see zero or small negatives. + increment_mdp_data_at(count_offset, Rscratch1, Rscratch2, true); + + bind (profile_continue); + } +} + +// Count a ret in the bytecodes. +void InterpreterMacroAssembler::profile_ret(TosState state, Register return_bci, Register scratch1, Register scratch2) { + if (ProfileInterpreter) { + Label profile_continue; + uint row; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(profile_continue); + + // Update the total ret count. + increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch1, scratch2 ); + + for (row = 0; row < RetData::row_limit(); row++) { + Label next_test; + + // See if return_bci is equal to bci[n]: + test_mdp_data_at(in_bytes(RetData::bci_offset(row)), return_bci, next_test, scratch1); + + // return_bci is equal to bci[n]. Increment the count. + increment_mdp_data_at(in_bytes(RetData::bci_count_offset(row)), scratch1, scratch2); + + // The method data pointer needs to be updated to reflect the new target. + update_mdp_by_offset(in_bytes(RetData::bci_displacement_offset(row)), scratch1); + b(profile_continue); + bind(next_test); + } + + update_mdp_for_ret(state, return_bci); + + bind (profile_continue); + } +} + +// Count the default case of a switch construct. +void InterpreterMacroAssembler::profile_switch_default(Register scratch1, Register scratch2) { + if (ProfileInterpreter) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(profile_continue); + + // Update the default case count + increment_mdp_data_at(in_bytes(MultiBranchData::default_count_offset()), + scratch1, scratch2); + + // The method data pointer needs to be updated. + update_mdp_by_offset(in_bytes(MultiBranchData::default_displacement_offset()), + scratch1); + + bind (profile_continue); + } +} + +// Count the index'th case of a switch construct. +void InterpreterMacroAssembler::profile_switch_case(Register index, + Register scratch1, + Register scratch2, + Register scratch3) { + if (ProfileInterpreter) { + assert_different_registers(index, scratch1, scratch2, scratch3); + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(profile_continue); + + // Build the base (index * per_case_size_in_bytes()) + case_array_offset_in_bytes(). + li(scratch3, in_bytes(MultiBranchData::case_array_offset())); + + assert (in_bytes(MultiBranchData::per_case_size()) == 16, "so that shladd works"); + sldi(scratch1, index, exact_log2(in_bytes(MultiBranchData::per_case_size()))); + add(scratch1, scratch1, scratch3); + + // Update the case count. + increment_mdp_data_at(scratch1, in_bytes(MultiBranchData::relative_count_offset()), scratch2, scratch3); + + // The method data pointer needs to be updated. + update_mdp_by_offset(scratch1, in_bytes(MultiBranchData::relative_displacement_offset()), scratch2); + + bind (profile_continue); + } +} + +void InterpreterMacroAssembler::profile_null_seen(Register Rscratch1, Register Rscratch2) { + if (ProfileInterpreter) { + assert_different_registers(Rscratch1, Rscratch2); + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(profile_continue); + + set_mdp_flag_at(BitData::null_seen_byte_constant(), Rscratch1); + + // The method data pointer needs to be updated. + int mdp_delta = in_bytes(BitData::bit_data_size()); + if (TypeProfileCasts) { + mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size()); + } + update_mdp_by_constant(mdp_delta); + + bind (profile_continue); + } +} + +void InterpreterMacroAssembler::record_klass_in_profile(Register Rreceiver, + Register Rscratch1, Register Rscratch2, + bool is_virtual_call) { + assert(ProfileInterpreter, "must be profiling"); + assert_different_registers(Rreceiver, Rscratch1, Rscratch2); + + Label done; + record_klass_in_profile_helper(Rreceiver, Rscratch1, Rscratch2, 0, done, is_virtual_call); + bind (done); +} + +void InterpreterMacroAssembler::record_klass_in_profile_helper( + Register receiver, Register scratch1, Register scratch2, + int start_row, Label& done, bool is_virtual_call) { + if (TypeProfileWidth == 0) { + if (is_virtual_call) { + increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch1, scratch2); + } + return; + } + + int last_row = VirtualCallData::row_limit() - 1; + assert(start_row <= last_row, "must be work left to do"); + // Test this row for both the receiver and for null. + // Take any of three different outcomes: + // 1. found receiver => increment count and goto done + // 2. found null => keep looking for case 1, maybe allocate this cell + // 3. found something else => keep looking for cases 1 and 2 + // Case 3 is handled by a recursive call. + for (int row = start_row; row <= last_row; row++) { + Label next_test; + bool test_for_null_also = (row == start_row); + + // See if the receiver is receiver[n]. + int recvr_offset = in_bytes(VirtualCallData::receiver_offset(row)); + test_mdp_data_at(recvr_offset, receiver, next_test, scratch1); + // delayed()->tst(scratch); + + // The receiver is receiver[n]. Increment count[n]. + int count_offset = in_bytes(VirtualCallData::receiver_count_offset(row)); + increment_mdp_data_at(count_offset, scratch1, scratch2); + b(done); + bind(next_test); + + if (test_for_null_also) { + Label found_null; + // Failed the equality check on receiver[n]... Test for null. + if (start_row == last_row) { + // The only thing left to do is handle the null case. + if (is_virtual_call) { + // Scratch1 contains test_out from test_mdp_data_at. + cmpdi(CCR0, scratch1, 0); + beq(CCR0, found_null); + // Receiver did not match any saved receiver and there is no empty row for it. + // Increment total counter to indicate polymorphic case. + increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch1, scratch2); + b(done); + bind(found_null); + } else { + cmpdi(CCR0, scratch1, 0); + bne(CCR0, done); + } + break; + } + // Since null is rare, make it be the branch-taken case. + cmpdi(CCR0, scratch1, 0); + beq(CCR0, found_null); + + // Put all the "Case 3" tests here. + record_klass_in_profile_helper(receiver, scratch1, scratch2, start_row + 1, done, is_virtual_call); + + // Found a null. Keep searching for a matching receiver, + // but remember that this is an empty (unused) slot. + bind(found_null); + } + } + + // In the fall-through case, we found no matching receiver, but we + // observed the receiver[start_row] is NULL. + + // Fill in the receiver field and increment the count. + int recvr_offset = in_bytes(VirtualCallData::receiver_offset(start_row)); + set_mdp_data_at(recvr_offset, receiver); + int count_offset = in_bytes(VirtualCallData::receiver_count_offset(start_row)); + li(scratch1, DataLayout::counter_increment); + set_mdp_data_at(count_offset, scratch1); + if (start_row > 0) { + b(done); + } +} + +// Add a InterpMonitorElem to stack (see frame_sparc.hpp). +void InterpreterMacroAssembler::add_monitor_to_stack(bool stack_is_empty, Register Rtemp1, Register Rtemp2) { + + // Very-local scratch registers. + const Register esp = Rtemp1; + const Register slot = Rtemp2; + + // Extracted monitor_size. + int monitor_size = frame::interpreter_frame_monitor_size_in_bytes(); + assert(Assembler::is_aligned((unsigned int)monitor_size, + (unsigned int)frame::alignment_in_bytes), + "size of a monitor must respect alignment of SP"); + + resize_frame(-monitor_size, /*temp*/esp); // Allocate space for new monitor + std(R1_SP, _ijava_state_neg(top_frame_sp), esp); // esp contains fp + + // Shuffle expression stack down. Recall that stack_base points + // just above the new expression stack bottom. Old_tos and new_tos + // are used to scan thru the old and new expression stacks. + if (!stack_is_empty) { + Label copy_slot, copy_slot_finished; + const Register n_slots = slot; + + addi(esp, R15_esp, Interpreter::stackElementSize); // Point to first element (pre-pushed stack). + subf(n_slots, esp, R26_monitor); + srdi_(n_slots, n_slots, LogBytesPerWord); // Compute number of slots to copy. + assert(LogBytesPerWord == 3, "conflicts assembler instructions"); + beq(CCR0, copy_slot_finished); // Nothing to copy. + + mtctr(n_slots); + + // loop + bind(copy_slot); + ld(slot, 0, esp); // Move expression stack down. + std(slot, -monitor_size, esp); // distance = monitor_size + addi(esp, esp, BytesPerWord); + bdnz(copy_slot); + + bind(copy_slot_finished); + } + + addi(R15_esp, R15_esp, -monitor_size); + addi(R26_monitor, R26_monitor, -monitor_size); + + // Restart interpreter +} + +// ============================================================================ +// Java locals access + +// Load a local variable at index in Rindex into register Rdst_value. +// Also puts address of local into Rdst_address as a service. +// Kills: +// - Rdst_value +// - Rdst_address +void InterpreterMacroAssembler::load_local_int(Register Rdst_value, Register Rdst_address, Register Rindex) { + sldi(Rdst_address, Rindex, Interpreter::logStackElementSize); + subf(Rdst_address, Rdst_address, R18_locals); + lwz(Rdst_value, 0, Rdst_address); +} + +// Load a local variable at index in Rindex into register Rdst_value. +// Also puts address of local into Rdst_address as a service. +// Kills: +// - Rdst_value +// - Rdst_address +void InterpreterMacroAssembler::load_local_long(Register Rdst_value, Register Rdst_address, Register Rindex) { + sldi(Rdst_address, Rindex, Interpreter::logStackElementSize); + subf(Rdst_address, Rdst_address, R18_locals); + ld(Rdst_value, -8, Rdst_address); +} + +// Load a local variable at index in Rindex into register Rdst_value. +// Also puts address of local into Rdst_address as a service. +// Input: +// - Rindex: slot nr of local variable +// Kills: +// - Rdst_value +// - Rdst_address +void InterpreterMacroAssembler::load_local_ptr(Register Rdst_value, Register Rdst_address, Register Rindex) { + sldi(Rdst_address, Rindex, Interpreter::logStackElementSize); + subf(Rdst_address, Rdst_address, R18_locals); + ld(Rdst_value, 0, Rdst_address); +} + +// Load a local variable at index in Rindex into register Rdst_value. +// Also puts address of local into Rdst_address as a service. +// Kills: +// - Rdst_value +// - Rdst_address +void InterpreterMacroAssembler::load_local_float(FloatRegister Rdst_value, Register Rdst_address, Register Rindex) { + sldi(Rdst_address, Rindex, Interpreter::logStackElementSize); + subf(Rdst_address, Rdst_address, R18_locals); + lfs(Rdst_value, 0, Rdst_address); +} + +// Load a local variable at index in Rindex into register Rdst_value. +// Also puts address of local into Rdst_address as a service. +// Kills: +// - Rdst_value +// - Rdst_address +void InterpreterMacroAssembler::load_local_double(FloatRegister Rdst_value, Register Rdst_address, Register Rindex) { + sldi(Rdst_address, Rindex, Interpreter::logStackElementSize); + subf(Rdst_address, Rdst_address, R18_locals); + lfd(Rdst_value, -8, Rdst_address); +} + +// Store an int value at local variable slot Rindex. +// Kills: +// - Rindex +void InterpreterMacroAssembler::store_local_int(Register Rvalue, Register Rindex) { + sldi(Rindex, Rindex, Interpreter::logStackElementSize); + subf(Rindex, Rindex, R18_locals); + stw(Rvalue, 0, Rindex); +} + +// Store a long value at local variable slot Rindex. +// Kills: +// - Rindex +void InterpreterMacroAssembler::store_local_long(Register Rvalue, Register Rindex) { + sldi(Rindex, Rindex, Interpreter::logStackElementSize); + subf(Rindex, Rindex, R18_locals); + std(Rvalue, -8, Rindex); +} + +// Store an oop value at local variable slot Rindex. +// Kills: +// - Rindex +void InterpreterMacroAssembler::store_local_ptr(Register Rvalue, Register Rindex) { + sldi(Rindex, Rindex, Interpreter::logStackElementSize); + subf(Rindex, Rindex, R18_locals); + std(Rvalue, 0, Rindex); +} + +// Store an int value at local variable slot Rindex. +// Kills: +// - Rindex +void InterpreterMacroAssembler::store_local_float(FloatRegister Rvalue, Register Rindex) { + sldi(Rindex, Rindex, Interpreter::logStackElementSize); + subf(Rindex, Rindex, R18_locals); + stfs(Rvalue, 0, Rindex); +} + +// Store an int value at local variable slot Rindex. +// Kills: +// - Rindex +void InterpreterMacroAssembler::store_local_double(FloatRegister Rvalue, Register Rindex) { + sldi(Rindex, Rindex, Interpreter::logStackElementSize); + subf(Rindex, Rindex, R18_locals); + stfd(Rvalue, -8, Rindex); +} + +// Read pending exception from thread and jump to interpreter. +// Throw exception entry if one if pending. Fall through otherwise. +void InterpreterMacroAssembler::check_and_forward_exception(Register Rscratch1, Register Rscratch2) { + assert_different_registers(Rscratch1, Rscratch2, R3); + Register Rexception = Rscratch1; + Register Rtmp = Rscratch2; + Label Ldone; + // Get pending exception oop. + ld(Rexception, thread_(pending_exception)); + cmpdi(CCR0, Rexception, 0); + beq(CCR0, Ldone); + li(Rtmp, 0); + mr_if_needed(R3, Rexception); + std(Rtmp, thread_(pending_exception)); // Clear exception in thread + if (Interpreter::rethrow_exception_entry() != NULL) { + // Already got entry address. + load_dispatch_table(Rtmp, (address*)Interpreter::rethrow_exception_entry()); + } else { + // Dynamically load entry address. + int simm16_rest = load_const_optimized(Rtmp, &Interpreter::_rethrow_exception_entry, R0, true); + ld(Rtmp, simm16_rest, Rtmp); + } + mtctr(Rtmp); + save_interpreter_state(Rtmp); + bctr(); + + align(32, 12); + bind(Ldone); +} + +void InterpreterMacroAssembler::call_VM(Register oop_result, address entry_point, bool check_exceptions) { + save_interpreter_state(R11_scratch1); + + MacroAssembler::call_VM(oop_result, entry_point, false); + + restore_interpreter_state(R11_scratch1, /*bcp_and_mdx_only*/ true); + + check_and_handle_popframe(R11_scratch1); + check_and_handle_earlyret(R11_scratch1); + // Now check exceptions manually. + if (check_exceptions) { + check_and_forward_exception(R11_scratch1, R12_scratch2); + } +} + +void InterpreterMacroAssembler::call_VM(Register oop_result, address entry_point, Register arg_1, bool check_exceptions) { + // ARG1 is reserved for the thread. + mr_if_needed(R4_ARG2, arg_1); + call_VM(oop_result, entry_point, check_exceptions); +} + +void InterpreterMacroAssembler::call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, bool check_exceptions) { + // ARG1 is reserved for the thread. + mr_if_needed(R4_ARG2, arg_1); + assert(arg_2 != R4_ARG2, "smashed argument"); + mr_if_needed(R5_ARG3, arg_2); + call_VM(oop_result, entry_point, check_exceptions); +} + +void InterpreterMacroAssembler::call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, Register arg_3, bool check_exceptions) { + // ARG1 is reserved for the thread. + mr_if_needed(R4_ARG2, arg_1); + assert(arg_2 != R4_ARG2, "smashed argument"); + mr_if_needed(R5_ARG3, arg_2); + assert(arg_3 != R4_ARG2 && arg_3 != R5_ARG3, "smashed argument"); + mr_if_needed(R6_ARG4, arg_3); + call_VM(oop_result, entry_point, check_exceptions); +} + +void InterpreterMacroAssembler::save_interpreter_state(Register scratch) { + ld(scratch, 0, R1_SP); + std(R15_esp, _ijava_state_neg(esp), scratch); + std(R14_bcp, _ijava_state_neg(bcp), scratch); + std(R26_monitor, _ijava_state_neg(monitors), scratch); + if (ProfileInterpreter) { std(R28_mdx, _ijava_state_neg(mdx), scratch); } + // Other entries should be unchanged. +} + + +void InterpreterMacroAssembler::restore_interpreter_state(Register scratch, bool oops_only) { + ld(scratch, 0, R1_SP); + ld(R19_method, _ijava_state_neg(method), scratch); + ld(R27_constPoolCache, _ijava_state_neg(cpoolCache), scratch); + ld(R14_bcp, _ijava_state_neg(bcp), scratch); // related to method + ld(R28_mdx, _ijava_state_neg(mdx), scratch); // related to method + if (!oops_only) { // Following ones are stack addresses and don't require reload after GC. + ld(R18_locals, _ijava_state_neg(locals), scratch); + ld(R26_monitor, _ijava_state_neg(monitors), scratch); + ld(R15_esp, _ijava_state_neg(esp), scratch); + } +#ifdef ASSERT + { + Label Lok; + subf(R0, R1_SP, scratch); + cmpdi(CCR0, R0, frame::abi_reg_args_size + frame::ijava_state_size); + bge(CCR0, Lok); + stop("frame too small (restore istate)", 0x5432); + bind(Lok); + } + { + Label Lok; + ld(R0, _ijava_state_neg(ijava_reserved), scratch); + cmpdi(CCR0, R0, 0x5afe); + beq(CCR0, Lok); + stop("frame corrupted (restore istate)", 0x5afe); + bind(Lok); + } +#endif +} + +#endif // !CC_INTERP + +void InterpreterMacroAssembler::get_method_counters(Register method, + Register Rcounters, + Label& skip) { +#if 0 + BLOCK_COMMENT("Load and ev. allocate counter object {"); + Label has_counters; + ld(Rcounters, in_bytes(Method::method_counters_offset()), method); + cmpdi(CCR0, Rcounters, 0); + bne(CCR0, has_counters); + call_VM(noreg, CAST_FROM_FN_PTR(address, + InterpreterRuntime::build_method_counters), method, false); + ld(Rcounters, in_bytes(Method::method_counters_offset()), method); + cmpdi(CCR0, Rcounters, 0); + beq(CCR0, skip); // No MethodCounters, OutOfMemory. + BLOCK_COMMENT("} Load and ev. allocate counter object"); + + bind(has_counters); +#endif +} + void InterpreterMacroAssembler::increment_invocation_counter(Register Rtmp, Register Rtmp2) { assert(UseCompiler, "incrementing must be useful"); // Address inv_counter(Lmethod, 0, in_bytes(methodOopDesc::invocation_counter_offset() @@ -308,6 +1958,66 @@ if (state == atos) { MacroAssembler::verify_oop(reg); } } +#ifndef CC_INTERP +// Local helper function for the verify_oop_or_return_address macro. +static bool verify_return_address(methodOop m, int bci) { +#ifndef PRODUCT + address pc = (address)(m->constMethod()) + in_bytes(constMethodOopDesc::codes_offset()) + bci; + // Assume it is a valid return address if it is inside m and is preceded by a jsr. + if (!m->contains(pc)) return false; + address jsr_pc; + jsr_pc = pc - Bytecodes::length_for(Bytecodes::_jsr); + if (*jsr_pc == Bytecodes::_jsr && jsr_pc >= m->code_base()) return true; + jsr_pc = pc - Bytecodes::length_for(Bytecodes::_jsr_w); + if (*jsr_pc == Bytecodes::_jsr_w && jsr_pc >= m->code_base()) return true; +#endif // PRODUCT + return false; +} + +void InterpreterMacroAssembler::verify_FPU(int stack_depth, TosState state) { + if (VerifyFPU) { + unimplemented("verfiyFPU"); + } +} + +void InterpreterMacroAssembler::verify_oop_or_return_address(Register reg, Register Rtmp) { + if (!VerifyOops) return; + + // The VM documentation for the astore[_wide] bytecode allows + // the TOS to be not only an oop but also a return address. + Label test; + Label skip; + // See if it is an address (in the current method): + + const int log2_bytecode_size_limit = 16; + srdi_(Rtmp, reg, log2_bytecode_size_limit); + bne(CCR0, test); + + address fd = CAST_FROM_FN_PTR(address, verify_return_address); + unsigned int nbytes_save = 10*8; // 10 volatile gprs + + save_LR_CR(Rtmp); + push_frame_reg_args(nbytes_save, Rtmp); + save_volatile_gprs(R1_SP, 112); // except R0 + + load_const_optimized(Rtmp, fd, R0); + mr_if_needed(R4_ARG2, reg); + mr(R3_ARG1, R19_method); + call_c(Rtmp); // call C + + restore_volatile_gprs(R1_SP, 112); // except R0 + pop_frame(); + restore_LR_CR(Rtmp); + b(skip); + + // Perform a more elaborate out-of-line call. + // Not an address; verify it: + bind(test); + verify_oop(reg); + bind(skip); +} +#endif // !CC_INTERP + // Inline assembly for: // // if (thread is in interp_only_mode) { @@ -330,13 +2040,12 @@ cmpwi(CCR0, R0, 0); beq(CCR0, jvmti_post_done); call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_method_entry), - /*check_exceptions=*/false); + /*check_exceptions=*/true CC_INTERP_ONLY(&& false)); bind(jvmti_post_done); } } - // Inline assembly for: // // if (thread is in interp_only_mode) { @@ -352,26 +2061,33 @@ // // Native methods have their result stored in d_tmp and l_tmp. // Java methods have their result stored in the expression stack. -void InterpreterMacroAssembler::notify_method_exit(bool is_native_method, TosState state) { +void InterpreterMacroAssembler::notify_method_exit(bool is_native_method, TosState state, + NotifyMethodExitMode mode, bool check_exceptions) { // JVMTI // Whenever JVMTI puts a thread in interp_only_mode, method // entry/exit events are sent for that thread to track stack // depth. If it is possible to enter interp_only_mode we add // the code to check if the event should be sent. - if (JvmtiExport::can_post_interpreter_events()) { + if (mode == NotifyJVMTI && JvmtiExport::can_post_interpreter_events()) { Label jvmti_post_done; lwz(R0, in_bytes(JavaThread::interp_only_mode_offset()), R16_thread); cmpwi(CCR0, R0, 0); beq(CCR0, jvmti_post_done); + CC_INTERP_ONLY(assert(is_native_method && !check_exceptions, "must not push state")); + if (!is_native_method) push(state); // Expose tos to GC. call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_method_exit), - /*check_exceptions=*/false); + /*check_exceptions=*/check_exceptions); + if (!is_native_method) pop(state); align(32, 12); bind(jvmti_post_done); } + + // Dtrace support not implemented. } +#ifdef CC_INTERP // Convert the current TOP_IJAVA_FRAME into a PARENT_IJAVA_FRAME // (using parent_frame_resize) and push a new interpreter // TOP_IJAVA_FRAME (using frame_size). @@ -429,7 +2145,6 @@ std(R1_SP, _top_ijava_frame_abi(top_frame_sp), R1_SP); } -#ifdef CC_INTERP // Turn state's interpreter frame into the current TOP_IJAVA_FRAME. void InterpreterMacroAssembler::pop_interpreter_frame_to_state(Register state, Register tmp1, Register tmp2, Register tmp3) { assert_different_registers(R14_state, R15_prev_state, tmp1, tmp2, tmp3); @@ -458,7 +2173,6 @@ // Used for non-initial callers by unextended_sp(). std(R1_SP, _top_ijava_frame_abi(initial_caller_sp), R1_SP); } -#endif // CC_INTERP // Set SP to initial caller's sp, but before fix the back chain. void InterpreterMacroAssembler::resize_frame_to_initial_caller(Register tmp1, Register tmp2) { @@ -468,7 +2182,6 @@ mr(R1_SP, tmp1); // ... and resize to initial caller. } -#ifdef CC_INTERP // Pop the current interpreter state (without popping the correspoding // frame) and restore R14_state and R15_prev_state accordingly. // Use prev_state_may_be_0 to indicate whether prev_state may be 0
--- a/src/cpu/ppc/vm/interp_masm_ppc_64.hpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/cpu/ppc/vm/interp_masm_ppc_64.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -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 2012, 2014 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 @@ -29,7 +29,7 @@ #include "assembler_ppc.inline.hpp" #include "interpreter/invocationCounter.hpp" -// This file specializes the assembler with interpreter-specific macros +// This file specializes the assembler with interpreter-specific macros. class InterpreterMacroAssembler: public MacroAssembler { @@ -39,27 +39,236 @@ void null_check_throw(Register a, int offset, Register temp_reg); - // Handy address generation macros + void branch_to_entry(address entry, Register Rscratch); + + // Handy address generation macros. #define thread_(field_name) in_bytes(JavaThread::field_name ## _offset()), R16_thread #define method_(field_name) in_bytes(methodOopDesc::field_name ## _offset()), R19_method #ifdef CC_INTERP #define state_(field_name) in_bytes(byte_offset_of(BytecodeInterpreter, field_name)), R14_state #define prev_state_(field_name) in_bytes(byte_offset_of(BytecodeInterpreter, field_name)), R15_prev_state + void pop (TosState state) {}; // Not needed. + void push(TosState state) {}; // Not needed. #endif +#ifndef CC_INTERP + virtual void check_and_handle_popframe(Register java_thread); + virtual void check_and_handle_earlyret(Register java_thread); + + // Base routine for all dispatches. + void dispatch_base(TosState state, address* table); + + void load_earlyret_value(TosState state, Register Rscratch1); + + static const Address l_tmp; + static const Address d_tmp; + + // dispatch routines + void dispatch_next(TosState state, int step = 0); + void dispatch_via (TosState state, address* table); + void load_dispatch_table(Register dst, address* table); + void dispatch_Lbyte_code(TosState state, Register bytecode, address* table, bool verify = false); + + // Called by shared interpreter generator. + void dispatch_prolog(TosState state, int step = 0); + void dispatch_epilog(TosState state, int step = 0); + + // Super call_VM calls - correspond to MacroAssembler::call_VM(_leaf) calls. + void super_call_VM_leaf(Register thread_cache, address entry_point, Register arg_1); + void super_call_VM(Register thread_cache, Register oop_result, Register last_java_sp, + address entry_point, Register arg_1, Register arg_2, bool check_exception = true); + + // Generate a subtype check: branch to ok_is_subtype if sub_klass is + // a subtype of super_klass. Blows registers tmp1, tmp2 and tmp3. + void gen_subtype_check(Register sub_klass, Register super_klass, + Register tmp1, Register tmp2, Register tmp3, Label &ok_is_subtype); + + // Load object from cpool->resolved_references(index). + void load_resolved_reference_at_index(Register result, Register index); + + void generate_stack_overflow_check_with_compare_and_throw(Register Rmem_frame_size, Register Rscratch1); + void load_receiver(Register Rparam_count, Register Rrecv_dst); + + // helpers for expression stack + void pop_i( Register r = R17_tos); + void pop_ptr( Register r = R17_tos); + void pop_l( Register r = R17_tos); + void pop_f(FloatRegister f = F15_ftos); + void pop_d(FloatRegister f = F15_ftos ); + + void push_i( Register r = R17_tos); + void push_ptr( Register r = R17_tos); + void push_l( Register r = R17_tos); + void push_f(FloatRegister f = F15_ftos ); + void push_d(FloatRegister f = F15_ftos); + + void push_2ptrs(Register first, Register second); + + void push_l_pop_d(Register l = R17_tos, FloatRegister d = F15_ftos); + void push_d_pop_l(FloatRegister d = F15_ftos, Register l = R17_tos); + + void pop (TosState state); // transition vtos -> state + void push(TosState state); // transition state -> vtos + void empty_expression_stack(); // Resets both Lesp and SP. + + public: + // Load values from bytecode stream: + + enum signedOrNot { Signed, Unsigned }; + enum setCCOrNot { set_CC, dont_set_CC }; + + void get_2_byte_integer_at_bcp(int bcp_offset, + Register Rdst, + signedOrNot is_signed); + + void get_4_byte_integer_at_bcp(int bcp_offset, + Register Rdst, + signedOrNot is_signed = Unsigned); + + void get_cache_index_at_bcp(Register Rdst, int bcp_offset, size_t index_size); + + void get_cache_and_index_at_bcp(Register cache, int bcp_offset, size_t index_size = sizeof(u2)); + + + // common code + + void field_offset_at(int n, Register tmp, Register dest, Register base); + int field_offset_at(Register object, address bcp, int offset); + void fast_iaaccess(int n, address bcp); + void fast_iagetfield(address bcp); + void fast_iaputfield(address bcp, bool do_store_check); + + void index_check(Register array, Register index, int index_shift, Register tmp, Register res); + void index_check_without_pop(Register array, Register index, int index_shift, Register tmp, Register res); + + void get_const(Register Rdst); + void get_constant_pool(Register Rdst); + void get_constant_pool_cache(Register Rdst); + void get_cpool_and_tags(Register Rcpool, Register Rtags); + void is_a(Label& L); + + // Java Call Helpers + void call_from_interpreter(Register Rtarget_method, Register Rret_addr, Register Rscratch1, Register Rscratch2); + + // -------------------------------------------------- + + void unlock_if_synchronized_method(TosState state, bool throw_monitor_exception = true, + bool install_monitor_exception = true); + + // Removes the current activation (incl. unlocking of monitors). + // Additionally this code is used for earlyReturn in which case we + // want to skip throwing an exception and installing an exception. + void remove_activation(TosState state, + bool throw_monitor_exception = true, + bool install_monitor_exception = true); + void merge_frames(Register Rtop_frame_sp, Register return_pc, Register Rscratch1, Register Rscratch2); // merge top frames + + void add_monitor_to_stack(bool stack_is_empty, Register Rtemp1, Register Rtemp2); + + // Local variable access helpers + void load_local_int(Register Rdst_value, Register Rdst_address, Register Rindex); + void load_local_long(Register Rdst_value, Register Rdst_address, Register Rindex); + void load_local_ptr(Register Rdst_value, Register Rdst_address, Register Rindex); + void load_local_float(FloatRegister Rdst_value, Register Rdst_address, Register Rindex); + void load_local_double(FloatRegister Rdst_value, Register Rdst_address, Register Rindex); + void store_local_int(Register Rvalue, Register Rindex); + void store_local_long(Register Rvalue, Register Rindex); + void store_local_ptr(Register Rvalue, Register Rindex); + void store_local_float(FloatRegister Rvalue, Register Rindex); + void store_local_double(FloatRegister Rvalue, Register Rindex); + + // Call VM for std frames + // Special call VM versions that check for exceptions and forward exception + // via short cut (not via expensive forward exception stub). + void check_and_forward_exception(Register Rscratch1, Register Rscratch2); + void call_VM(Register oop_result, address entry_point, bool check_exceptions = true); + void call_VM(Register oop_result, address entry_point, Register arg_1, bool check_exceptions = true); + void call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, bool check_exceptions = true); + void call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, Register arg_3, bool check_exceptions = true); + // Should not be used: + void call_VM(Register oop_result, Register last_java_sp, address entry_point, bool check_exceptions = true) {ShouldNotReachHere();} + void call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, bool check_exceptions = true) {ShouldNotReachHere();} + void call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2, bool check_exceptions = true) {ShouldNotReachHere();} + void call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2, Register arg_3, bool check_exceptions = true) {ShouldNotReachHere();} + + Address first_local_in_stack(); + + enum LoadOrStore { load, store }; + void static_iload_or_store(int which_local, LoadOrStore direction, Register Rtmp); + void static_aload_or_store(int which_local, LoadOrStore direction, Register Rtmp); + void static_dload_or_store(int which_local, LoadOrStore direction); + + void save_interpreter_state(Register scratch); + void restore_interpreter_state(Register scratch, bool bcp_and_mdx_only = false); + + void increment_backedge_counter(Register Rtmp, Register Rtmp2, Register Rscratch); + void test_backedge_count_for_osr(Register backedge_count, Register branch_bcp, Register Rtmp); + + void record_static_call_in_profile(Register Rentry, Register Rtmp); + void record_receiver_call_in_profile(Register Rklass, Register Rentry, Register Rtmp); +#endif // !CC_INTERP + + void get_method_counters(Register method, Register Rcounters, Label& skip); void increment_invocation_counter(Register Rtmp, Register Rtmp2); // Object locking void lock_object (Register lock_reg, Register obj_reg); - void unlock_object(Register lock_reg); + void unlock_object(Register lock_reg, bool check_for_exceptions = true); + +#ifndef CC_INTERP + + // Interpreter profiling operations + 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 set_mdp_data_at(int constant, Register value); + + void increment_mdp_data_at(int constant, Register counter_addr, Register Rbumped_count, bool decrement = false); + + void increment_mdp_data_at(Register counter_addr, Register Rbumped_count, bool decrement = false); + void increment_mdp_data_at(Register reg, int constant, Register scratch, Register Rbumped_count, bool decrement = false); + + void set_mdp_flag_at(int flag_constant, Register scratch); + void test_mdp_data_at(int offset, Register value, Label& not_equal_continue, Register test_out); + + void update_mdp_by_offset(int offset_of_disp, Register scratch); + void update_mdp_by_offset(Register reg, int offset_of_disp, + Register scratch); + void update_mdp_by_constant(int constant); + void update_mdp_for_ret(TosState state, Register return_bci); + + void profile_taken_branch(Register scratch, Register bumped_count); + void profile_not_taken_branch(Register scratch1, Register scratch2); + void profile_call(Register scratch1, Register scratch2); + void profile_final_call(Register scratch1, Register scratch2); + void profile_virtual_call(Register Rreceiver, Register Rscratch1, Register Rscratch2, bool receiver_can_be_null); + void profile_typecheck(Register Rklass, Register Rscratch1, Register Rscratch2); + void profile_typecheck_failed(Register Rscratch1, Register Rscratch2); + void profile_ret(TosState state, Register return_bci, Register scratch1, Register scratch2); + void profile_switch_default(Register scratch1, Register scratch2); + void profile_switch_case(Register index, Register scratch1,Register scratch2, Register scratch3); + void profile_null_seen(Register Rscratch1, Register Rscratch2); + void record_klass_in_profile(Register receiver, Register scratch1, Register scratch2, bool is_virtual_call); + void record_klass_in_profile_helper(Register receiver, Register scratch1, Register scratch2, int start_row, Label& done, bool is_virtual_call); + +#endif // !CC_INTERP // Debugging void verify_oop(Register reg, TosState state = atos); // only if +VerifyOops && state == atos +#ifndef CC_INTERP + void verify_oop_or_return_address(Register reg, Register rtmp); // for astore + void verify_FPU(int stack_depth, TosState state = ftos); +#endif // !CC_INTERP - // support for jvmdi/jvmpi + typedef enum { NotifyJVMTI, SkipNotifyJVMTI } NotifyMethodExitMode; + + // Support for jvmdi/jvmpi. void notify_method_entry(); - void notify_method_exit(bool is_native_method, TosState state); + void notify_method_exit(bool is_native_method, TosState state, + NotifyMethodExitMode mode, bool check_exceptions); #ifdef CC_INTERP // Convert the current TOP_IJAVA_FRAME into a PARENT_IJAVA_FRAME
--- a/src/cpu/ppc/vm/interpreterRT_ppc.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/cpu/ppc/vm/interpreterRT_ppc.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -109,8 +109,10 @@ } void InterpreterRuntime::SignatureHandlerGenerator::generate(uint64_t fingerprint) { +#if !defined(ABI_ELFv2) // Emit fd for current codebuffer. Needs patching! __ emit_fd(); +#endif // Generate code to handle arguments. iterate(fingerprint); @@ -127,11 +129,13 @@ // Implementation of SignatureHandlerLibrary void SignatureHandlerLibrary::pd_set_handler(address handler) { +#if !defined(ABI_ELFv2) // patch fd here. FunctionDescriptor* fd = (FunctionDescriptor*) handler; fd->set_entry(handler + (int)sizeof(FunctionDescriptor)); assert(fd->toc() == (address)0xcafe, "need to adjust TOC here"); +#endif }
--- a/src/cpu/ppc/vm/interpreter_ppc.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/cpu/ppc/vm/interpreter_ppc.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2014 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,10 +50,6 @@ #include "c1/c1_Runtime1.hpp" #endif -#ifndef CC_INTERP -#error "CC_INTERP must be defined on PPC" -#endif - #define __ _masm-> #ifdef PRODUCT @@ -127,13 +123,13 @@ const Register target_sp = R28_tmp8; const FloatRegister floatSlot = F0; - address entry = __ emit_fd(); + address entry = __ function_entry(); __ save_LR_CR(R0); __ save_nonvolatile_gprs(R1_SP, _spill_nonvolatiles_neg(r14)); // We use target_sp for storing arguments in the C frame. __ mr(target_sp, R1_SP); - __ push_frame_abi112_nonvolatiles(0, R11_scratch1); + __ push_frame_reg_args_nonvolatiles(0, R11_scratch1); __ mr(arg_java, R3_ARG1); @@ -146,7 +142,8 @@ #ifdef CC_INTERP __ ld(R19_method, state_(_method)); #else - __ unimplemented("slow signature handler 1"); + __ ld(R19_method, 0, target_sp); + __ ld(R19_method, _ijava_state_neg(method), R19_method); #endif // Get the result handler. @@ -156,7 +153,8 @@ #ifdef CC_INTERP __ ld(R19_method, state_(_method)); #else - __ unimplemented("slow signature handler 2"); + __ ld(R19_method, 0, target_sp); + __ ld(R19_method, _ijava_state_neg(method), R19_method); #endif { @@ -452,7 +450,7 @@ // // Registers alive // R16_thread - JavaThread* - // R19_method - callee's methodOop (method to be invoked) + // R19_method - callee's method (method to be invoked) // R1_SP - SP prepared such that caller's outgoing args are near top // LR - return address to caller // @@ -473,7 +471,7 @@ // Push a new C frame and save LR. __ save_LR_CR(R0); - __ push_frame_abi112(0, R11_scratch1); + __ push_frame_reg_args(0, R11_scratch1); // This is not a leaf but we have a JavaFrameAnchor now and we will // check (create) exceptions afterward so this is ok. @@ -490,7 +488,12 @@ // Return to frame manager, it will handle the pending exception. __ blr(); #else - Unimplemented(); + // We don't know our caller, so jump to the general forward exception stub, + // which will also pop our full frame off. Satisfy the interface of + // SharedRuntime::generate_forward_exception() + __ load_const_optimized(R11_scratch1, StubRoutines::forward_exception_entry(), R0); + __ mtctr(R11_scratch1); + __ bctr(); #endif return entry; @@ -499,8 +502,9 @@ // Call an accessor method (assuming it is resolved, otherwise drop into // vanilla (slow path) entry. address InterpreterGenerator::generate_accessor_entry(void) { - if(!UseFastAccessorMethods && (!FLAG_IS_ERGO(UseFastAccessorMethods))) + if (!UseFastAccessorMethods && (!FLAG_IS_ERGO(UseFastAccessorMethods))) { return NULL; + } Label Lslow_path, Lacquire; @@ -585,10 +589,14 @@ // Load from branch table and dispatch (volatile case: one instruction ahead) __ sldi(Rflags, Rflags, LogBytesPerWord); __ cmpwi(CCR6, Rscratch, 1); // volatile? - __ sldi(Rscratch, Rscratch, exact_log2(BytesPerInstWord)); // volatile ? size of 1 instruction : 0 + if (true/*support_IRIW_for_not_multiple_copy_atomic_cpu*/) { + __ sldi(Rscratch, Rscratch, exact_log2(BytesPerInstWord)); // volatile ? size of 1 instruction : 0 + } __ ldx(Rbtable, Rbtable, Rflags); - __ subf(Rbtable, Rscratch, Rbtable); // point to volatile/non-volatile entry point + if (true/*support_IRIW_for_not_multiple_copy_atomic_cpu*/) { + __ subf(Rbtable, Rscratch, Rbtable); // point to volatile/non-volatile entry point + } __ mtctr(Rbtable); __ bctr(); @@ -604,7 +612,7 @@ } assert(all_uninitialized != all_initialized, "consistency"); // either or - __ sync(); // volatile entry point (one instruction before non-volatile_entry point) + __ fence(); // volatile entry point (one instruction before non-volatile_entry point) if (branch_table[vtos] == 0) branch_table[vtos] = __ pc(); // non-volatile_entry point if (branch_table[dtos] == 0) branch_table[dtos] = __ pc(); // non-volatile_entry point if (branch_table[ftos] == 0) branch_table[ftos] = __ pc(); // non-volatile_entry point @@ -613,7 +621,7 @@ if (branch_table[itos] == 0) { // generate only once __ align(32, 28, 28); // align load - __ sync(); // volatile entry point (one instruction before non-volatile_entry point) + __ fence(); // volatile entry point (one instruction before non-volatile_entry point) branch_table[itos] = __ pc(); // non-volatile_entry point __ lwax(R3_RET, Rclass_or_obj, Roffset); __ beq(CCR6, Lacquire); @@ -622,7 +630,7 @@ if (branch_table[ltos] == 0) { // generate only once __ align(32, 28, 28); // align load - __ sync(); // volatile entry point (one instruction before non-volatile_entry point) + __ fence(); // volatile entry point (one instruction before non-volatile_entry point) branch_table[ltos] = __ pc(); // non-volatile_entry point __ ldx(R3_RET, Rclass_or_obj, Roffset); __ beq(CCR6, Lacquire); @@ -631,7 +639,7 @@ if (branch_table[btos] == 0) { // generate only once __ align(32, 28, 28); // align load - __ sync(); // volatile entry point (one instruction before non-volatile_entry point) + __ fence(); // volatile entry point (one instruction before non-volatile_entry point) branch_table[btos] = __ pc(); // non-volatile_entry point __ lbzx(R3_RET, Rclass_or_obj, Roffset); __ extsb(R3_RET, R3_RET); @@ -641,7 +649,7 @@ if (branch_table[ctos] == 0) { // generate only once __ align(32, 28, 28); // align load - __ sync(); // volatile entry point (one instruction before non-volatile_entry point) + __ fence(); // volatile entry point (one instruction before non-volatile_entry point) branch_table[ctos] = __ pc(); // non-volatile_entry point __ lhzx(R3_RET, Rclass_or_obj, Roffset); __ beq(CCR6, Lacquire); @@ -650,7 +658,7 @@ if (branch_table[stos] == 0) { // generate only once __ align(32, 28, 28); // align load - __ sync(); // volatile entry point (one instruction before non-volatile_entry point) + __ fence(); // volatile entry point (one instruction before non-volatile_entry point) branch_table[stos] = __ pc(); // non-volatile_entry point __ lhax(R3_RET, Rclass_or_obj, Roffset); __ beq(CCR6, Lacquire); @@ -659,7 +667,7 @@ if (branch_table[atos] == 0) { // generate only once __ align(32, 28, 28); // align load - __ sync(); // volatile entry point (one instruction before non-volatile_entry point) + __ fence(); // volatile entry point (one instruction before non-volatile_entry point) branch_table[atos] = __ pc(); // non-volatile_entry point __ load_heap_oop(R3_RET, (RegisterOrConstant)Roffset, Rclass_or_obj); __ verify_oop(R3_RET); @@ -682,10 +690,7 @@ #endif __ bind(Lslow_path); - assert(Interpreter::entry_for_kind(Interpreter::zerolocals), "Normal entry must have been generated by now"); - __ load_const_optimized(Rscratch, Interpreter::entry_for_kind(Interpreter::zerolocals), R0); - __ mtctr(Rscratch); - __ bctr(); + __ branch_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals), Rscratch); __ flush(); return entry; @@ -772,10 +777,7 @@ // Generate regular method entry. __ bind(slow_path); - assert(Interpreter::entry_for_kind(Interpreter::zerolocals), "Normal entry must have been generated by now"); - __ load_const_optimized(R11_scratch1, Interpreter::entry_for_kind(Interpreter::zerolocals), R0); - __ mtctr(R11_scratch1); - __ bctr(); + __ branch_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals), R11_scratch1); __ flush(); return entry;
--- a/src/cpu/ppc/vm/interpreter_ppc.hpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/cpu/ppc/vm/interpreter_ppc.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -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 2012, 2014 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 @@ -28,15 +28,23 @@ public: - // Stack index relative to tos (which points at value) + // Stack index relative to tos (which points at value). static int expr_index_at(int i) { return stackElementWords * i; } - // Already negated by c++ interpreter + // Already negated by c++ interpreter. static int local_index_at(int i) { assert(i <= 0, "local direction already negated"); return stackElementWords * i; } +#ifndef CC_INTERP + // The offset in bytes to access a expression stack slot + // relative to the esp pointer. + static int expr_offset_in_bytes(int slot) { + return stackElementSize * slot + wordSize; + } +#endif + #endif // CPU_PPC_VM_INTERPRETER_PPC_PP
--- a/src/cpu/ppc/vm/javaFrameAnchor_ppc.hpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/cpu/ppc/vm/javaFrameAnchor_ppc.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -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 2012, 2014 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 @@ -26,10 +26,6 @@ #ifndef CPU_PPC_VM_JAVAFRAMEANCHOR_PPC_HPP #define CPU_PPC_VM_JAVAFRAMEANCHOR_PPC_HPP -#ifndef CC_INTERP -#error "CC_INTERP must be defined on PPC64" -#endif - public: // Each arch must define reset, save, restore // These are used by objects that only care about:
--- a/src/cpu/ppc/vm/macroAssembler_ppc.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/cpu/ppc/vm/macroAssembler_ppc.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 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 @@ -573,7 +573,13 @@ "can't identify emitted call"); } else { // variant 1: - +#if defined(ABI_ELFv2) + nop(); + calculate_address_from_global_toc(R12, dest, true, true, false); + mtctr(R12); + nop(); + nop(); +#else mr(R0, R11); // spill R11 -> R0. // Load the destination address into CTR, @@ -583,6 +589,7 @@ mtctr(R11); mr(R11, R0); // spill R11 <- R0. nop(); +#endif // do the call/jump if (link) { @@ -891,16 +898,16 @@ } } -// Push a frame of size `bytes' plus abi112 on top. -void MacroAssembler::push_frame_abi112(unsigned int bytes, Register tmp) { - push_frame(bytes + frame::abi_112_size, tmp); +// Push a frame of size `bytes' plus abi_reg_args on top. +void MacroAssembler::push_frame_reg_args(unsigned int bytes, Register tmp) { + push_frame(bytes + frame::abi_reg_args_size, tmp); } // Setup up a new C frame with a spill area for non-volatile GPRs and // additional space for local variables. -void MacroAssembler::push_frame_abi112_nonvolatiles(unsigned int bytes, - Register tmp) { - push_frame(bytes + frame::abi_112_size + frame::spill_nonvolatiles_size, tmp); +void MacroAssembler::push_frame_reg_args_nonvolatiles(unsigned int bytes, + Register tmp) { + push_frame(bytes + frame::abi_reg_args_size + frame::spill_nonvolatiles_size, tmp); } // Pop current C frame. @@ -908,6 +915,42 @@ ld(R1_SP, _abi(callers_sp), R1_SP); } +#if defined(ABI_ELFv2) +address MacroAssembler::branch_to(Register r_function_entry, bool and_link) { + // TODO(asmundak): make sure the caller uses R12 as function descriptor + // most of the times. + if (R12 != r_function_entry) { + mr(R12, r_function_entry); + } + mtctr(R12); + // Do a call or a branch. + if (and_link) { + bctrl(); + } else { + bctr(); + } + _last_calls_return_pc = pc(); + + return _last_calls_return_pc; +} + +// Call a C function via a function descriptor and use full C +// calling conventions. Updates and returns _last_calls_return_pc. +address MacroAssembler::call_c(Register r_function_entry) { + return branch_to(r_function_entry, /*and_link=*/true); +} + +// For tail calls: only branch, don't link, so callee returns to caller of this function. +address MacroAssembler::call_c_and_return_to_caller(Register r_function_entry) { + return branch_to(r_function_entry, /*and_link=*/false); +} + +address MacroAssembler::call_c(address function_entry, relocInfo::relocType rt) { + load_const(R12, function_entry, R0); + return branch_to(R12, /*and_link=*/true); +} + +#else // Generic version of a call to C function via a function descriptor // with variable support for C calling conventions (TOC, ENV, etc.). // Updates and returns _last_calls_return_pc. @@ -998,10 +1041,10 @@ // so do a full call-c here. load_const(R11, (address)fd, R0); return branch_to(R11, /*and_link=*/true, - /*save toc=*/false, - /*restore toc=*/false, - /*load toc=*/true, - /*load env=*/true); + /*save toc=*/false, + /*restore toc=*/false, + /*load toc=*/true, + /*load env=*/true); } else { // it's a friend function, load the entry point and don't care about // toc and env. @@ -1056,6 +1099,7 @@ } return _last_calls_return_pc; } +#endif // ABI_ELFv2 void MacroAssembler::call_VM_base(Register oop_result, Register last_java_sp, @@ -1070,8 +1114,11 @@ // ARG1 must hold thread address. mr(R3_ARG1, R16_thread); - +#if defined(ABI_ELFv2) + address return_pc = call_c(entry_point, relocInfo::none); +#else address return_pc = call_c((FunctionDescriptor*)entry_point, relocInfo::none); +#endif reset_last_Java_frame(); @@ -1092,7 +1139,11 @@ void MacroAssembler::call_VM_leaf_base(address entry_point) { BLOCK_COMMENT("call_VM_leaf {"); +#if defined(ABI_ELFv2) + call_c(entry_point, relocInfo::none); +#else call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, entry_point), relocInfo::none); +#endif BLOCK_COMMENT("} call_VM_leaf"); } @@ -1627,8 +1678,9 @@ cmpwi(CCR0, temp, 0); beq(CCR0, result_reg!=noreg ? failure : fallthru); // length 0 - if (UseCompressedOops) + if (UseCompressedOops) { encode_heap_oop_not_null(super_klass); + } mtctr(temp); // load ctr @@ -1645,16 +1697,18 @@ addi(array_ptr, array_ptr, BytesPerHeapOop); bdnz(loop); - if (UseCompressedOops) + if (UseCompressedOops) { decode_heap_oop_not_null(super_klass); // restore super_klass + } bind(failure); if (result_reg!=noreg) li(result_reg, 1); // load non-zero result (indicates a miss) b(fallthru); bind(hit); - if (UseCompressedOops) + if (UseCompressedOops) { decode_heap_oop_not_null(super_klass); // restore super_klass + } 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); @@ -1957,6 +2011,7 @@ // 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, @@ -2148,7 +2203,7 @@ load_const_optimized(Rtmp, (address)byte_map_base, R0); srdi(Robj, Robj, CardTableModRefBS::card_shift); li(R0, 0); // dirty - if (UseConcMarkSweepGC) release(); + if (UseConcMarkSweepGC) membar(Assembler::StoreStore); stbx(R0, Rtmp, Robj); } @@ -2217,7 +2272,7 @@ // VM call need frame to access(write) O register. if (needs_frame) { save_LR_CR(Rtmp1); - push_frame_abi112(0, Rtmp2); + push_frame_reg_args(0, Rtmp2); } if (Rpre_val->is_volatile() && Robj == noreg) mr(R31, Rpre_val); // Save pre_val across C call if it was preloaded. @@ -2351,7 +2406,8 @@ #ifdef CC_INTERP ld(tmp1/*pc*/, _top_ijava_frame_abi(frame_manager_lr), sp); #else - Unimplemented(); + address entry = pc(); + load_const_optimized(tmp1, entry); #endif set_last_Java_frame(/*sp=*/sp, /*pc=*/tmp1); @@ -2376,7 +2432,7 @@ // Clear Array // Kills both input registers. tmp == R0 is allowed. void MacroAssembler::clear_memory_doubleword(Register base_ptr, Register cnt_dwords, Register tmp) { - // SAPJVM MD 2011-06-24 Procedure for large arrays (uses data cache block zero instruction). + // 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(), cl_dwords = cl_size>>3, @@ -2905,13 +2961,13 @@ mr(R0, tmp); // kill tmp save_LR_CR(tmp); - push_frame_abi112(nbytes_save, tmp); + push_frame_reg_args(nbytes_save, tmp); // restore tmp mr(tmp, R0); save_volatile_gprs(R1_SP, 112); // except R0 - // load FunctionDescriptor** + // load FunctionDescriptor** / entry_address * load_const(tmp, fd); - // load FunctionDescriptor* + // load FunctionDescriptor* / entry_address ld(tmp, 0, tmp); mr(R4_ARG2, oop); load_const(R3_ARG1, (address)msg); @@ -2991,3 +3047,15 @@ } #endif // !PRODUCT + +SkipIfEqualZero::SkipIfEqualZero(MacroAssembler* masm, Register temp, const bool* flag_addr) : _masm(masm), _label() { + int simm16_offset = masm->load_const_optimized(temp, (address)flag_addr, R0, true); + assert(sizeof(bool) == 1, "PowerPC ABI"); + masm->lbz(temp, simm16_offset, temp); + masm->cmpwi(CCR0, temp, 0); + masm->beq(CCR0, _label); +} + +SkipIfEqualZero::~SkipIfEqualZero() { + _masm->bind(_label); +}
--- a/src/cpu/ppc/vm/macroAssembler_ppc.hpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/cpu/ppc/vm/macroAssembler_ppc.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -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 2012, 2014 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 @@ -58,6 +58,21 @@ // Move register if destination register and target register are different inline void mr_if_needed(Register rd, Register rs); + inline void fmr_if_needed(FloatRegister rd, FloatRegister rs); + // This is dedicated for emitting scheduled mach nodes. For better + // readability of the ad file I put it here. + // Endgroups are not needed if + // - the scheduler is off + // - the scheduler found that there is a natural group end, in that + // case it reduced the size of the instruction used in the test + // yielding 'needed'. + inline void endgroup_if_needed(bool needed); + + // Memory barriers. + inline void membar(int bits); + inline void release(); + inline void acquire(); + inline void fence(); // nop padding void align(int modulus, int max = 252, int rem = 0); @@ -261,12 +276,12 @@ // Push a frame of size `bytes'. No abi space provided. void push_frame(unsigned int bytes, Register tmp); - // Push a frame of size `bytes' plus abi112 on top. - void push_frame_abi112(unsigned int bytes, Register tmp); + // Push a frame of size `bytes' plus abi_reg_args on top. + void push_frame_reg_args(unsigned int bytes, Register tmp); // Setup up a new C frame with a spill area for non-volatile GPRs and additional // space for local variables - void push_frame_abi112_nonvolatiles(unsigned int bytes, Register tmp); + void push_frame_reg_args_nonvolatiles(unsigned int bytes, Register tmp); // pop current C frame void pop_frame(); @@ -278,17 +293,31 @@ private: address _last_calls_return_pc; +#if defined(ABI_ELFv2) + // Generic version of a call to C function. + // Updates and returns _last_calls_return_pc. + address branch_to(Register function_entry, bool and_link); +#else // Generic version of a call to C function via a function descriptor // with variable support for C calling conventions (TOC, ENV, etc.). // updates and returns _last_calls_return_pc. address branch_to(Register function_descriptor, bool and_link, bool save_toc_before_call, bool restore_toc_after_call, bool load_toc_of_callee, bool load_env_of_callee); +#endif public: // Get the pc where the last call will return to. returns _last_calls_return_pc. inline address last_calls_return_pc(); +#if defined(ABI_ELFv2) + // Call a C function via a function descriptor and use full C + // calling conventions. Updates and returns _last_calls_return_pc. + address call_c(Register function_entry); + // For tail calls: only branch, don't link, so callee returns to caller of this function. + address call_c_and_return_to_caller(Register function_entry); + address call_c(address function_entry, relocInfo::relocType rt); +#else // Call a C function via a function descriptor and use full C // calling conventions. Updates and returns _last_calls_return_pc. address call_c(Register function_descriptor); @@ -297,6 +326,7 @@ address call_c(const FunctionDescriptor* function_descriptor, relocInfo::relocType rt); address call_c_using_toc(const FunctionDescriptor* function_descriptor, relocInfo::relocType rt, Register toc); +#endif protected: @@ -528,12 +558,14 @@ 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 ld_with_trap_null_check(Register d, int si16, Register s1); + inline void load_with_trap_null_check(Register d, int si16, Register s1); // Variant for heap OOPs including decompression of compressed OOPs. inline void load_heap_oop_with_trap_null_check(Register d, RegisterOrConstant offs, Register s1); // Load heap oop and decompress. Loaded oop may not be null. inline void load_heap_oop_not_null(Register d, RegisterOrConstant offs, Register s1 = noreg); + inline void store_heap_oop_not_null(Register d, RegisterOrConstant offs, Register s1, + /*specify if d must stay uncompressed*/ Register tmp = noreg); // Null allowed. inline void load_heap_oop(Register d, RegisterOrConstant offs, Register s1 = noreg); @@ -542,7 +574,7 @@ inline void load_klass(Register dst, Register src); // Encode/decode heap oop. Oop may not be null, else en/decoding goes wrong. - inline void encode_heap_oop_not_null(Register d); + inline Register encode_heap_oop_not_null(Register d, Register src = noreg); inline void decode_heap_oop_not_null(Register d); // Null allowed. @@ -622,7 +654,12 @@ // TODO: verify method and klass metadata (compare against vptr?) void _verify_method_ptr(Register reg, const char * msg, const char * file, int line) {} - void _verify_klass_ptr(Register reg, const char * msg, const char * file, int line){} + void _verify_klass_ptr(Register reg, const char * msg, const char * file, int line) {} + + // Convenience method returning function entry. For the ELFv1 case + // creates function descriptor at the current address and returs + // the pointer to it. For the ELFv2 case returns the current address. + inline address function_entry(); #define verify_method_ptr(reg) _verify_method_ptr(reg, "broken method " #reg, __FILE__, __LINE__) #define verify_klass_ptr(reg) _verify_klass_ptr(reg, "broken klass " #reg, __FILE__, __LINE__) @@ -648,4 +685,21 @@ void zap_from_to(Register low, int before, Register high, int after, Register val, Register addr) PRODUCT_RETURN; }; +// class SkipIfEqualZero: +// +// Instantiating this class will result in assembly code being output that will +// jump around any code emitted between the creation of the instance and it's +// automatic destruction at the end of a scope block, depending on the value of +// the flag passed to the constructor, which will be checked at run-time. +class SkipIfEqualZero : public StackObj { + private: + MacroAssembler* _masm; + Label _label; + + public: + // 'Temp' is a temp register that this object can use (and trash). + explicit SkipIfEqualZero(MacroAssembler*, Register temp, const bool* flag_addr); + ~SkipIfEqualZero(); +}; + #endif // CPU_PPC_VM_MACROASSEMBLER_PPC_HPP
--- a/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -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 2012, 2014 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 @@ -58,9 +58,26 @@ // Move register if destination register and target register are different. inline void MacroAssembler::mr_if_needed(Register rd, Register rs) { - if(rs !=rd) mr(rd, rs); + if (rs != rd) mr(rd, rs); +} +inline void MacroAssembler::fmr_if_needed(FloatRegister rd, FloatRegister rs) { + if (rs != rd) fmr(rd, rs); +} +inline void MacroAssembler::endgroup_if_needed(bool needed) { + if (needed) { + endgroup(); + } } +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(); +} +inline void MacroAssembler::release() { membar(LoadStore | StoreStore); } +inline void MacroAssembler::acquire() { membar(LoadLoad | LoadStore); } +inline void MacroAssembler::fence() { membar(LoadLoad | LoadStore | StoreLoad | StoreStore); } + // Address of the global TOC. inline address MacroAssembler::global_toc() { return CodeCache::low_bound(); @@ -266,9 +283,10 @@ // Do an explicit null check if access to a+offset will not raise a SIGSEGV. // Either issue a trap instruction that raises SIGTRAP, or do a compare that // branches to exception_entry. -// No support for compressed oops (base page of heap). Does not distinguish +// No support for compressed oops (base page of heap). Does not distinguish // loads and stores. -inline void MacroAssembler::null_check_throw(Register a, int offset, Register temp_reg, address exception_entry) { +inline void MacroAssembler::null_check_throw(Register a, int offset, Register temp_reg, + address exception_entry) { if (!ImplicitNullChecks || needs_explicit_null_check(offset) || !os::zero_page_read_protected()) { if (TrapBasedNullChecks) { assert(UseSIGTRAP, "sanity"); @@ -285,7 +303,7 @@ } } -inline void MacroAssembler::ld_with_trap_null_check(Register d, int si16, Register s1) { +inline void MacroAssembler::load_with_trap_null_check(Register d, int si16, Register s1) { if (!os::zero_page_read_protected()) { if (TrapBasedNullChecks) { trap_null_check(s1); @@ -315,6 +333,15 @@ } } +inline void MacroAssembler::store_heap_oop_not_null(Register d, RegisterOrConstant offs, Register s1, Register tmp) { + if (UseCompressedOops) { + Register compressedOop = encode_heap_oop_not_null((tmp != noreg) ? tmp : d, d); + stw(compressedOop, offs, s1); + } else { + std(d, offs, s1); + } +} + inline void MacroAssembler::load_heap_oop(Register d, RegisterOrConstant offs, Register s1) { if (UseCompressedOops) { lwz(d, offs, s1); @@ -324,18 +351,21 @@ } } - inline void MacroAssembler::load_klass(Register dst, Register src) { load_heap_oop_not_null(dst, oopDesc::klass_offset_in_bytes(), src); } -inline void MacroAssembler::encode_heap_oop_not_null(Register d) { +inline Register MacroAssembler::encode_heap_oop_not_null(Register d, Register src) { + Register current = (src!=noreg) ? src : d; // Compressed oop is in d if no src provided. if (Universe::narrow_oop_base() != NULL) { - sub(d, d, R30); + sub(d, current, R30); + current = d; } if (Universe::narrow_oop_shift() != 0) { - srdi(d, d, LogMinObjAlignmentInBytes); + srdi(d, current, LogMinObjAlignmentInBytes); + current = d; } + return current; // Encoded oop is in this register. } inline void MacroAssembler::decode_heap_oop_not_null(Register d) { @@ -384,4 +414,9 @@ twi(traptoEqual | traptoGreaterThanUnsigned, a/*reg a*/, si16); } +#if defined(ABI_ELFv2) +inline address MacroAssembler::function_entry() { return pc(); } +#else +inline address MacroAssembler::function_entry() { return emit_fd(); } +#endif #endif // CPU_PPC_VM_MACROASSEMBLER_PPC_INLINE_HPP
--- a/src/cpu/ppc/vm/methodHandles_ppc.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/cpu/ppc/vm/methodHandles_ppc.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 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 @@ -121,6 +121,7 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register method, Register target, Register temp, bool for_compiler_entry) { + Label L_no_such_method; assert(method == R19_method, "interpreter calling convention"); assert_different_registers(method, target, temp); __ verify_oop(method); @@ -134,17 +135,31 @@ __ lwz(temp, in_bytes(JavaThread::interp_only_mode_offset()), R16_thread); __ cmplwi(CCR0, temp, 0); __ beq(CCR0, run_compiled_code); + // Null method test is replicated below in compiled case, + // it might be able to address across the verify_thread() + __ cmplwi(CCR0, R19_method, 0); + __ beq(CCR0, L_no_such_method); __ ld(target, in_bytes(methodOopDesc::interpreter_entry_offset()), R19_method); __ mtctr(target); __ bctr(); __ BIND(run_compiled_code); } + // Compiled case, either static or fall-through from runtime conditional + __ cmplwi(CCR0, R19_method, 0); + __ beq(CCR0, L_no_such_method); + const ByteSize entry_offset = for_compiler_entry ? methodOopDesc::from_compiled_offset() : methodOopDesc::from_interpreted_offset(); __ ld(target, in_bytes(entry_offset), R19_method); __ mtctr(target); __ bctr(); + + __ bind(L_no_such_method); + assert(StubRoutines::throw_AbstractMethodError_entry() != NULL, "not yet generated!"); + __ load_const_optimized(target, StubRoutines::throw_AbstractMethodError_entry()); + __ mtctr(target); + __ bctr(); } @@ -453,11 +468,11 @@ if (Verbose) { tty->print_cr("Registers:"); - const int abi_offset = frame::abi_112_size / 8; + const int abi_offset = frame::abi_reg_args_size / 8; for (int i = R3->encoding(); i <= R12->encoding(); i++) { Register r = as_Register(i); int count = i - R3->encoding(); - // The registers are stored in reverse order on the stack (by save_volatile_gprs(R1_SP, abi_112_size)). + // The registers are stored in reverse order on the stack (by save_volatile_gprs(R1_SP, abi_reg_args_size)). tty->print("%3s=" PTR_FORMAT, r->name(), saved_regs[abi_offset + count]); if ((count + 1) % 4 == 0) { tty->cr(); @@ -524,9 +539,9 @@ __ save_LR_CR(R0); __ mr(R0, R1_SP); // saved_sp assert(Assembler::is_simm(-nbytes_save, 16), "Overwriting R0"); - // push_frame_abi112 only uses R0 if nbytes_save is wider than 16 bit - __ push_frame_abi112(nbytes_save, R0); - __ save_volatile_gprs(R1_SP, frame::abi_112_size); // Except R0. + // Push_frame_reg_args only uses R0 if nbytes_save is wider than 16 bit. + __ push_frame_reg_args(nbytes_save, R0); + __ save_volatile_gprs(R1_SP, frame::abi_reg_args_size); // Except R0. __ load_const(R3_ARG1, (address)adaptername); __ mr(R4_ARG2, R6); // method handle (See generate_method_handle_interpreter_entry above.)
--- a/src/cpu/ppc/vm/ppc.ad Thu Apr 24 16:21:06 2014 +0100 +++ b/src/cpu/ppc/vm/ppc.ad Tue Apr 29 21:57:16 2014 +0100 @@ -1012,7 +1012,11 @@ } int MachCallRuntimeNode::ret_addr_offset() { +#if defined(ABI_ELFv2) + return 28; +#else return 40; +#endif } //============================================================================= @@ -1075,7 +1079,7 @@ // Indicate if the safepoint node needs the polling page as an input. bool SafePointNode::needs_polling_address_input() { // The address is loaded from thread by a seperate node. - return LoadPollAddressFromThread; + return true; } //============================================================================= @@ -4708,20 +4712,25 @@ // Late expand emitter for runtime leaf calls. enc_class lateExpand_java_to_runtime_call(method meth) %{ + Node *toc = in(TypeFunc::ReturnAdr); + loadConLNodesTuple loadConLNodes_Entry; +#if defined(ABI_ELFv2) + jlong entry_address = (jlong) this->entry_point(); + assert(entry_address, "need address here"); + loadConLNodes_Entry = loadConLNodesTuple_create(C, ra_, toc, new (C) immLOper(entry_address), + false, OptoReg::Name(R12_H_num), OptoReg::Name(R12_num)); +#else // Get the struct that describes the function we are about to call. FunctionDescriptor* fd = (FunctionDescriptor*) this->entry_point(); assert(fd, "need fd here"); - - Node *toc = in(TypeFunc::ReturnAdr); + jlong entry_address = (jlong) fd->entry(); + // new nodes - loadConLNodesTuple loadConLNodes_Entry; loadConLNodesTuple loadConLNodes_Env; loadConLNodesTuple loadConLNodes_Toc; - MachNode *mtctr = NULL; - MachCallLeafNode *call = NULL; // Create nodes and operands for loading the entry point. - loadConLNodes_Entry = loadConLNodesTuple_create(C, ra_, toc, new (C) immLOper((jlong) fd->entry()), + loadConLNodes_Entry = loadConLNodesTuple_create(C, ra_, toc, new (C) immLOper(entry_address), false, OptoReg::Name(R12_H_num), OptoReg::Name(R12_num)); // Create nodes and operands for loading the env pointer. @@ -4741,9 +4750,9 @@ // Create nodes and operands for loading the Toc point. loadConLNodes_Toc = loadConLNodesTuple_create(C, ra_, toc, new (C) immLOper((jlong) fd->toc()), false, OptoReg::Name(R2_H_num), OptoReg::Name(R2_num)); +#endif // ABI_ELFv2 // mtctr node - mtctr = new (C) CallLeafDirect_mtctrNode(); - + MachNode *mtctr = new (C) CallLeafDirect_mtctrNode(); assert(loadConLNodes_Entry._last != NULL, "entry must exist"); mtctr->add_req(0, loadConLNodes_Entry._last); @@ -4751,10 +4760,10 @@ mtctr->_opnds[1] = new (C) iRegLdstOper(); // call node - call = new (C) CallLeafDirectNode(); + MachCallLeafNode *call = new (C) CallLeafDirectNode(); call->_opnds[0] = _opnds[0]; - call->_opnds[1] = new (C) methodOper((intptr_t) fd->entry()); // may get set later + call->_opnds[1] = new (C) methodOper((intptr_t) entry_address); // May get set later. // Make the new call node look like the old one. call->_name = _name; @@ -4784,9 +4793,11 @@ call->add_prec(in(i)); } +#if !defined(ABI_ELFv2) // ... and more prec. if (loadConLNodes_Env._last) call->add_prec(loadConLNodes_Env._last); if (loadConLNodes_Toc._last) call->add_prec(loadConLNodes_Toc._last); +#endif // registers ra_->set1(mtctr->_idx, OptoReg::Name(SR_CTR_num)); @@ -4794,10 +4805,12 @@ // Insert the new nodes. if (loadConLNodes_Entry._large_hi) nodes->push(loadConLNodes_Entry._large_hi); if (loadConLNodes_Entry._last) nodes->push(loadConLNodes_Entry._last); +#if !defined(ABI_ELFv2) if (loadConLNodes_Env._large_hi) nodes->push(loadConLNodes_Env._large_hi); if (loadConLNodes_Env._last) nodes->push(loadConLNodes_Env._last); if (loadConLNodes_Toc._large_hi) nodes->push(loadConLNodes_Toc._large_hi); if (loadConLNodes_Toc._last) nodes->push(loadConLNodes_Toc._last); +#endif nodes->push(mtctr); nodes->push(call); %} @@ -4824,6 +4837,10 @@ MacroAssembler _masm(&cbuf); const address start_pc = __ pc(); +#if defined(ABI_ELFv2) + address entry= !($meth$$method) ? NULL : (address)$meth$$method; + __ call_c(entry, relocInfo::runtime_call_type); +#else // The function we're going to call. FunctionDescriptor fdtemp; const FunctionDescriptor* fd = !($meth$$method) ? &fdtemp : (FunctionDescriptor*)$meth$$method; @@ -4834,6 +4851,7 @@ // 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); +#endif // Check the ret_addr_offset. assert(((MachCallRuntimeNode*)this)->ret_addr_offset() == __ last_calls_return_pc() - start_pc, @@ -5995,11 +6013,10 @@ assert($dst$$constant == 0x0, "dst must be 0x0"); MacroAssembler _masm(&cbuf); - Register Rpoll = reg_to_register_object($poll$$reg); // Mark the code position where the load from the safepoint // polling page was emitted as relocInfo::poll_type. __ relocate(relocInfo::poll_type); - __ load_from_polling_page(Rpoll); + __ load_from_polling_page($poll$$Register); %} enc_class enc_loadConPollAddr(iRegPdst poll) %{ @@ -6087,7 +6104,7 @@ // out_preserve_stack_slots for calls to C. Supports the var-args // backing area for register parms. // - varargs_C_out_slots_killed(((frame::abi_112_size - frame::jit_out_preserve_size) / VMRegImpl::stack_slot_size)); + varargs_C_out_slots_killed(((frame::abi_reg_args_size - frame::jit_out_preserve_size) / VMRegImpl::stack_slot_size)); // The after-PROLOG location of the return address. Location of // return address specifies a type (REG or STACK) and a number @@ -12363,9 +12380,8 @@ // LoadConPollAddr node is added in pd_post_matching_hook(). It must be // a seperate node so that the oop map is at the right location. instruct safePoint_poll_conPollAddr(rscratch2RegP poll) %{ - match(SafePoint); + match(SafePoint poll); predicate(!LoadPollAddressFromThread); - effect(KILL poll); // It caused problems to add the effect that r0 is killed, but this // effect no longer needs to be mentioned, since r0 is not contained
--- a/src/cpu/ppc/vm/register_ppc.hpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/cpu/ppc/vm/register_ppc.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -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 2012, 2014 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 @@ -579,15 +579,27 @@ // Register declarations to be used in frame manager assembly code. // Use only non-volatile registers in order to keep values across C-calls. +#ifdef CC_INTERP REGISTER_DECLARATION(Register, R14_state, R14); // address of new cInterpreter. REGISTER_DECLARATION(Register, R15_prev_state, R15); // address of old cInterpreter +#else // CC_INTERP +REGISTER_DECLARATION(Register, R14_bcp, R14); +REGISTER_DECLARATION(Register, R15_esp, R15); +REGISTER_DECLARATION(FloatRegister, F15_ftos, F15); +#endif // CC_INTERP REGISTER_DECLARATION(Register, R16_thread, R16); // address of current thread REGISTER_DECLARATION(Register, R17_tos, R17); // address of Java tos (prepushed). REGISTER_DECLARATION(Register, R18_locals, R18); // address of first param slot (receiver). REGISTER_DECLARATION(Register, R19_method, R19); // address of current method #ifndef DONT_USE_REGISTER_DEFINES +#ifdef CC_INTERP #define R14_state AS_REGISTER(Register, R14) #define R15_prev_state AS_REGISTER(Register, R15) +#else // CC_INTERP +#define R14_bcp AS_REGISTER(Register, R14) +#define R15_esp AS_REGISTER(Register, R15) +#define F15_ftos AS_REGISTER(FloatRegister, F15) +#endif // CC_INTERP #define R16_thread AS_REGISTER(Register, R16) #define R17_tos AS_REGISTER(Register, R17) #define R18_locals AS_REGISTER(Register, R18) @@ -607,6 +619,14 @@ REGISTER_DECLARATION(Register, R27_tmp7, R27); REGISTER_DECLARATION(Register, R28_tmp8, R28); REGISTER_DECLARATION(Register, R29_tmp9, R29); +#ifndef CC_INTERP +REGISTER_DECLARATION(Register, R24_dispatch_addr, R24); +REGISTER_DECLARATION(Register, R25_templateTableBase, R25); +REGISTER_DECLARATION(Register, R26_monitor, R26); +REGISTER_DECLARATION(Register, R27_constPoolCache, R27); +REGISTER_DECLARATION(Register, R28_mdx, R28); +#endif // CC_INTERP + #ifndef DONT_USE_REGISTER_DEFINES #define R21_tmp1 AS_REGISTER(Register, R21) #define R22_tmp2 AS_REGISTER(Register, R22) @@ -617,6 +637,16 @@ #define R27_tmp7 AS_REGISTER(Register, R27) #define R28_tmp8 AS_REGISTER(Register, R28) #define R29_tmp9 AS_REGISTER(Register, R29) +#ifndef CC_INTERP +// Lmonitors : monitor pointer +// LcpoolCache: constant pool cache +// mdx: method data index +#define R24_dispatch_addr AS_REGISTER(Register, R24) +#define R25_templateTableBase AS_REGISTER(Register, R25) +#define R26_monitor AS_REGISTER(Register, R26) +#define R27_constPoolCache AS_REGISTER(Register, R27) +#define R28_mdx AS_REGISTER(Register, R28) +#endif #define CCR4_is_synced AS_REGISTER(ConditionRegister, CCR4) #endif
--- a/src/cpu/ppc/vm/runtime_ppc.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/cpu/ppc/vm/runtime_ppc.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -87,7 +87,7 @@ address start = __ pc(); - int frame_size_in_bytes = frame::abi_112_size; + int frame_size_in_bytes = frame::abi_reg_args_size; OopMap* map = new OopMap(frame_size_in_bytes / sizeof(jint), 0); // Exception pc is 'return address' for stack walker. @@ -99,7 +99,7 @@ // Save callee-saved registers. // Push a C frame for the exception blob. It is needed for the C call later on. - __ push_frame_abi112(0, R11_scratch1); + __ push_frame_reg_args(0, R11_scratch1); // This call does all the hard work. It checks if an exception handler // exists in the method. @@ -109,8 +109,12 @@ __ set_last_Java_frame(/*sp=*/R1_SP, noreg); __ mr(R3_ARG1, R16_thread); +#if defined(ABI_ELFv2) + __ call_c((address) OptoRuntime::handle_exception_C, relocInfo::none); +#else __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, OptoRuntime::handle_exception_C), relocInfo::none); +#endif address calls_return_pc = __ last_calls_return_pc(); # ifdef ASSERT __ cmpdi(CCR0, R3_RET, 0); @@ -162,7 +166,11 @@ __ 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.
--- a/src/cpu/ppc/vm/sharedRuntime_ppc.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/cpu/ppc/vm/sharedRuntime_ppc.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 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 @@ -68,7 +68,7 @@ return_pc_is_thread_saved_exception_pc }; - static OopMap* push_frame_abi112_and_save_live_registers(MacroAssembler* masm, + static OopMap* push_frame_reg_args_and_save_live_registers(MacroAssembler* masm, int* out_frame_size_in_bytes, bool generate_oop_map, int return_pc_adjustment, @@ -201,12 +201,12 @@ RegisterSaver_LiveIntReg( R30 ), // r30 must be the last register }; -OopMap* RegisterSaver::push_frame_abi112_and_save_live_registers(MacroAssembler* masm, +OopMap* RegisterSaver::push_frame_reg_args_and_save_live_registers(MacroAssembler* masm, int* out_frame_size_in_bytes, bool generate_oop_map, int return_pc_adjustment, ReturnPCLocation return_pc_location) { - // Push an abi112-frame and store all registers which may be live. + // Push an abi_reg_args-frame and store all registers which may be live. // If requested, create an OopMap: Record volatile registers as // callee-save values in an OopMap so their save locations will be // propagated to the RegisterMap of the caller frame during @@ -222,7 +222,7 @@ sizeof(RegisterSaver::LiveRegType); const int register_save_size = regstosave_num * reg_size; const int frame_size_in_bytes = round_to(register_save_size, frame::alignment_in_bytes) - + frame::abi_112_size; + + frame::abi_reg_args_size; *out_frame_size_in_bytes = frame_size_in_bytes; const int frame_size_in_slots = frame_size_in_bytes / sizeof(jint); const int register_save_offset = frame_size_in_bytes - register_save_size; @@ -230,7 +230,7 @@ // OopMap frame size is in c2 stack slots (sizeof(jint)) not bytes or words. OopMap* map = generate_oop_map ? new OopMap(frame_size_in_slots, 0) : NULL; - BLOCK_COMMENT("push_frame_abi112_and_save_live_registers {"); + BLOCK_COMMENT("push_frame_reg_args_and_save_live_registers {"); // Save r30 in the last slot of the not yet pushed frame so that we // can use it as scratch reg. @@ -295,7 +295,7 @@ offset += reg_size; } - BLOCK_COMMENT("} push_frame_abi112_and_save_live_registers"); + BLOCK_COMMENT("} push_frame_reg_args_and_save_live_registers"); // And we're done. return map; @@ -700,15 +700,19 @@ int i; VMReg reg; - // Leave room for C-compatible ABI_112. - int stk = (frame::abi_112_size - frame::jit_out_preserve_size) / VMRegImpl::stack_slot_size; + // Leave room for C-compatible ABI_REG_ARGS. + int stk = (frame::abi_reg_args_size - frame::jit_out_preserve_size) / VMRegImpl::stack_slot_size; int arg = 0; int freg = 0; // Avoid passing C arguments in the wrong stack slots. +#if defined(ABI_ELFv2) + assert((SharedRuntime::out_preserve_stack_slots() + stk) * VMRegImpl::stack_slot_size == 96, + "passing C arguments in wrong stack slots"); +#else assert((SharedRuntime::out_preserve_stack_slots() + stk) * VMRegImpl::stack_slot_size == 112, "passing C arguments in wrong stack slots"); - +#endif // We fill-out regs AND regs2 if an argument must be passed in a // register AND in a stack slot. If regs2 is NULL in such a // situation, we bail-out with a fatal error. @@ -956,7 +960,12 @@ // Jump to the interpreter just as if interpreter was doing it. +#ifdef CC_INTERP const Register tos = R17_tos; +#else + const Register tos = R15_esp; + __ load_const_optimized(R25_templateTableBase, (address)Interpreter::dispatch_table((TosState)0), R11_scratch1); +#endif // load TOS __ addi(tos, R1_SP, st_off); @@ -993,7 +1002,12 @@ // save code can segv when fxsave instructions find improperly // aligned stack pointer. +#ifdef CC_INTERP const Register ld_ptr = R17_tos; +#else + const Register ld_ptr = R15_esp; +#endif + const Register value_regs[] = { R22_tmp2, R23_tmp3, R24_tmp4, R25_tmp5, R26_tmp6 }; const int num_value_regs = sizeof(value_regs) / sizeof(Register); int value_regs_index = 0; @@ -1084,8 +1098,8 @@ } } - BLOCK_COMMENT("Store method oop"); - // Store method oop into thread->callee_target. + BLOCK_COMMENT("Store method"); + // Store method into thread->callee_target. // We might end up in handle_wrong_method if the callee is // deoptimized as we race thru here. If that happens we don't want // to take a safepoint because the caller frame will look @@ -1505,7 +1519,11 @@ __ block_comment("block_for_jni_critical"); address entry_point = CAST_FROM_FN_PTR(address, SharedRuntime::block_for_jni_critical); +#if defined(ABI_ELFv2) + __ call_c(entry_point, relocInfo::runtime_call_type); +#else __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, entry_point), relocInfo::runtime_call_type); +#endif address start = __ pc() - __ offset(), calls_return_pc = __ last_calls_return_pc(); oop_maps->add_gc_map(calls_return_pc - start, map); @@ -1878,7 +1896,7 @@ // Layout of the native wrapper frame: // (stack grows upwards, memory grows downwards) // - // NW [ABI_112] <-- 1) R1_SP + // NW [ABI_REG_ARGS] <-- 1) R1_SP // [outgoing arguments] <-- 2) R1_SP + out_arg_slot_offset // [oopHandle area] <-- 3) R1_SP + oop_handle_offset (save area for critical natives) // klass <-- 4) R1_SP + klass_offset @@ -2212,8 +2230,8 @@ // slow case of monitor enter. Inline a special case of call_VM that // disallows any pending_exception. - // Save argument registers and leave room for C-compatible ABI_112. - int frame_size = frame::abi_112_size + + // Save argument registers and leave room for C-compatible ABI_REG_ARGS. + int frame_size = frame::abi_reg_args_size + round_to(total_c_args * wordSize, frame::alignment_in_bytes); __ mr(R11_scratch1, R1_SP); RegisterSaver::push_frame_and_save_argument_registers(masm, R12_scratch2, frame_size, total_c_args, out_regs, out_regs2); @@ -2251,9 +2269,12 @@ // The JNI call // -------------------------------------------------------------------------- - +#if defined(ABI_ELFv2) + __ call_c(native_func, relocInfo::runtime_call_type); +#else FunctionDescriptor* fd_native_method = (FunctionDescriptor*) native_func; __ call_c(fd_native_method, relocInfo::runtime_call_type); +#endif // Now, we are back from the native code. @@ -2604,7 +2625,15 @@ __ ld(frame_size_reg, 0, frame_sizes_reg); __ std(pc_reg, _abi(lr), R1_SP); __ push_frame(frame_size_reg, R0/*tmp*/); +#ifdef CC_INTERP __ std(R1_SP, _parent_ijava_frame_abi(initial_caller_sp), R1_SP); +#else +#ifdef ASSERT + __ load_const_optimized(pc_reg, 0x5afe); + __ std(pc_reg, _ijava_state_neg(ijava_reserved), R1_SP); +#endif + __ std(R1_SP, _ijava_state_neg(sender_sp), R1_SP); +#endif // CC_INTERP __ addi(number_of_frames_reg, number_of_frames_reg, -1); __ addi(frame_sizes_reg, frame_sizes_reg, wordSize); __ addi(pcs_reg, pcs_reg, wordSize); @@ -2676,7 +2705,15 @@ __ std(R12_scratch2, _abi(lr), R1_SP); // Initialize initial_caller_sp. +#ifdef CC_INTERP __ std(frame_size_reg/*old_sp*/, _parent_ijava_frame_abi(initial_caller_sp), R1_SP); +#else +#ifdef ASSERT + __ load_const_optimized(pc_reg, 0x5afe); + __ std(pc_reg, _ijava_state_neg(ijava_reserved), R1_SP); +#endif + __ std(frame_size_reg, _ijava_state_neg(sender_sp), R1_SP); +#endif // CC_INTERP #ifdef ASSERT // Make sure that there is at least one entry in the array. @@ -2703,7 +2740,9 @@ // Store it in the top interpreter frame. __ std(R0, _abi(lr), R1_SP); // Initialize frame_manager_lr of interpreter top frame. +#ifdef CC_INTERP __ std(R0, _top_ijava_frame_abi(frame_manager_lr), R1_SP); +#endif } #endif @@ -2719,7 +2758,7 @@ OopMapSet *oop_maps = new OopMapSet(); // size of ABI112 plus spill slots for R3_RET and F1_RET. - const int frame_size_in_bytes = frame::abi_112_spill_size; + const int frame_size_in_bytes = frame::abi_reg_args_spill_size; const int frame_size_in_slots = frame_size_in_bytes / sizeof(jint); int first_frame_size_in_bytes = 0; // frame size of "unpack frame" for call to fetch_unroll_info. @@ -2752,11 +2791,11 @@ // Push the "unpack frame" // Save everything in sight. - map = RegisterSaver::push_frame_abi112_and_save_live_registers(masm, - &first_frame_size_in_bytes, - /*generate_oop_map=*/ true, - return_pc_adjustment_no_exception, - RegisterSaver::return_pc_is_lr); + map = RegisterSaver::push_frame_reg_args_and_save_live_registers(masm, + &first_frame_size_in_bytes, + /*generate_oop_map=*/ true, + return_pc_adjustment_no_exception, + RegisterSaver::return_pc_is_lr); assert(map != NULL, "OopMap must have been created"); __ li(exec_mode_reg, Deoptimization::Unpack_deopt); @@ -2782,11 +2821,11 @@ // Push the "unpack frame". // Save everything in sight. assert(R4 == R4_ARG2, "exception pc must be in r4"); - RegisterSaver::push_frame_abi112_and_save_live_registers(masm, - &first_frame_size_in_bytes, - /*generate_oop_map=*/ false, - return_pc_adjustment_exception, - RegisterSaver::return_pc_is_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); @@ -2871,8 +2910,8 @@ // ...). // Spill live volatile registers since we'll do a call. - __ std( R3_RET, _abi_112_spill(spill_ret), R1_SP); - __ stfd(F1_RET, _abi_112_spill(spill_fret), R1_SP); + __ std( R3_RET, _abi_reg_args_spill(spill_ret), R1_SP); + __ stfd(F1_RET, _abi_reg_args_spill(spill_fret), R1_SP); // Let the unpacker layout information in the skeletal frames just // allocated. @@ -2884,8 +2923,8 @@ __ reset_last_Java_frame(); // Restore the volatiles saved above. - __ ld( R3_RET, _abi_112_spill(spill_ret), R1_SP); - __ lfd(F1_RET, _abi_112_spill(spill_fret), R1_SP); + __ ld( R3_RET, _abi_reg_args_spill(spill_ret), R1_SP); + __ lfd(F1_RET, _abi_reg_args_spill(spill_fret), R1_SP); // Pop the unpack frame. __ pop_frame(); @@ -2895,11 +2934,16 @@ // optional c2i, caller of deoptee, ...). // Initialize R14_state. +#ifdef CC_INTERP __ ld(R14_state, 0, R1_SP); - __ addi(R14_state, R14_state, - -frame::interpreter_frame_cinterpreterstate_size_in_bytes()); + __ addi(R14_state, R14_state, -frame::interpreter_frame_cinterpreterstate_size_in_bytes()); // Also inititialize R15_prev_state. __ restore_prev_state(); +#else + __ restore_interpreter_state(R11_scratch1); + __ load_const_optimized(R25_templateTableBase, (address)Interpreter::dispatch_table((TosState)0), R11_scratch1); +#endif // CC_INTERP + // Return to the interpreter entry point. __ blr(); @@ -2926,7 +2970,7 @@ Register unc_trap_reg = R23_tmp3; OopMapSet* oop_maps = new OopMapSet(); - int frame_size_in_bytes = frame::abi_112_size; + int frame_size_in_bytes = frame::abi_reg_args_size; OopMap* map = new OopMap(frame_size_in_bytes / sizeof(jint), 0); // stack: (deoptee, optional i2c, caller_of_deoptee, ...). @@ -2939,7 +2983,7 @@ __ save_LR_CR(R11_scratch1); // Push an "uncommon_trap" frame. - __ push_frame_abi112(0, R11_scratch1); + __ push_frame_reg_args(0, R11_scratch1); // stack: (unpack frame, deoptee, optional i2c, caller_of_deoptee, ...). @@ -2992,7 +3036,7 @@ // interpreter frames just created. // Push a simple "unpack frame" here. - __ push_frame_abi112(0, R11_scratch1); + __ push_frame_reg_args(0, R11_scratch1); // stack: (unpack frame, skeletal interpreter frame, ..., optional // skeletal interpreter frame, optional c2i, caller of deoptee, @@ -3018,11 +3062,17 @@ // stack: (top interpreter frame, ..., optional interpreter frame, // optional c2i, caller of deoptee, ...). +#ifdef CC_INTERP // Initialize R14_state, ... __ ld(R11_scratch1, 0, R1_SP); __ addi(R14_state, R11_scratch1, -frame::interpreter_frame_cinterpreterstate_size_in_bytes()); // also initialize R15_prev_state. __ restore_prev_state(); +#else + __ restore_interpreter_state(R11_scratch1); + __ load_const_optimized(R25_templateTableBase, (address)Interpreter::dispatch_table((TosState)0), R11_scratch1); +#endif // CC_INTERP + // Return to the interpreter entry point. __ blr(); @@ -3060,11 +3110,11 @@ } // Save registers, fpu state, and flags. - map = RegisterSaver::push_frame_abi112_and_save_live_registers(masm, - &frame_size_in_bytes, - /*generate_oop_map=*/ true, - /*return_pc_adjustment=*/0, - return_pc_location); + map = RegisterSaver::push_frame_reg_args_and_save_live_registers(masm, + &frame_size_in_bytes, + /*generate_oop_map=*/ true, + /*return_pc_adjustment=*/0, + return_pc_location); // The following is basically a call_VM. However, we need the precise // address of the call in order to generate an oopmap. Hence, we do all the @@ -3100,7 +3150,6 @@ frame_size_in_bytes, /*restore_ctr=*/true); - BLOCK_COMMENT(" Jump to forward_exception_entry."); // Jump to forward_exception_entry, with the issuing PC in LR // so it looks like the original nmethod called forward_exception_entry. @@ -3147,11 +3196,11 @@ address start = __ pc(); - map = RegisterSaver::push_frame_abi112_and_save_live_registers(masm, - &frame_size_in_bytes, - /*generate_oop_map*/ true, - /*return_pc_adjustment*/ 0, - RegisterSaver::return_pc_is_lr); + map = RegisterSaver::push_frame_reg_args_and_save_live_registers(masm, + &frame_size_in_bytes, + /*generate_oop_map*/ true, + /*return_pc_adjustment*/ 0, + RegisterSaver::return_pc_is_lr); // Use noreg as last_Java_pc, the return pc will be reconstructed // from the physical frame.
--- a/src/cpu/ppc/vm/stubGenerator_ppc.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/cpu/ppc/vm/stubGenerator_ppc.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 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 @@ -39,15 +39,15 @@ #include "runtime/stubCodeGenerator.hpp" #include "runtime/stubRoutines.hpp" #include "utilities/top.hpp" +#ifdef COMPILER2 +#include "opto/runtime.hpp" +#endif #ifdef TARGET_OS_FAMILY_aix # include "thread_aix.inline.hpp" #endif #ifdef TARGET_OS_FAMILY_linux # include "thread_linux.inline.hpp" #endif -#ifdef COMPILER2 -#include "opto/runtime.hpp" -#endif #define __ _masm-> @@ -79,11 +79,11 @@ StubCodeMark mark(this, "StubRoutines", "call_stub"); - address start = __ emit_fd(); + address start = __ function_entry(); // some sanity checks - assert((sizeof(frame::abi_48) % 16) == 0, "unaligned"); - assert((sizeof(frame::abi_112) % 16) == 0, "unaligned"); + assert((sizeof(frame::abi_minframe) % 16) == 0, "unaligned"); + assert((sizeof(frame::abi_reg_args) % 16) == 0, "unaligned"); assert((sizeof(frame::spill_nonvolatiles) % 16) == 0, "unaligned"); assert((sizeof(frame::parent_ijava_frame_abi) % 16) == 0, "unaligned"); assert((sizeof(frame::entry_frame_locals) % 16) == 0, "unaligned"); @@ -221,7 +221,7 @@ { BLOCK_COMMENT("Call frame manager or native entry."); // Call frame manager or native entry. - Register r_new_arg_entry = R14_state; + Register r_new_arg_entry = R14; // PPC_state; assert_different_registers(r_new_arg_entry, r_top_of_arguments_addr, r_arg_method, r_arg_thread); @@ -233,8 +233,12 @@ // R19_method - methodOop* // R16_thread - JavaThread* - // tos must point to last argument - element_size. + // Tos must point to last argument - element_size. +#ifdef CC_INTERP const Register tos = R17_tos; +#else + const Register tos = R15_esp; +#endif __ addi(tos, r_top_of_arguments_addr, -Interpreter::stackElementSize); // initialize call_stub locals (step 2) @@ -248,8 +252,11 @@ assert(tos != r_arg_thread && R19_method != r_arg_thread, "trashed r_arg_thread"); // Set R15_prev_state to 0 for simplifying checks in callee. +#ifdef CC_INTERP __ li(R15_prev_state, 0); - +#else + __ load_const_optimized(R25_templateTableBase, (address)Interpreter::dispatch_table((TosState)0), R11_scratch1); +#endif // Stack on entry to frame manager / native entry: // // F0 [TOP_IJAVA_FRAME_ABI] @@ -445,7 +452,7 @@ // Save LR/CR and copy exception pc (LR) into R4_ARG2. __ save_LR_CR(R4_ARG2); - __ push_frame_abi112(0, R0); + __ push_frame_reg_args(0, R0); // Find exception handler. __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), @@ -520,7 +527,7 @@ MacroAssembler* masm = new MacroAssembler(&code); OopMapSet* oop_maps = new OopMapSet(); - int frame_size_in_bytes = frame::abi_112_size; + int frame_size_in_bytes = frame::abi_reg_args_size; OopMap* map = new OopMap(frame_size_in_bytes / sizeof(jint), 0); StubCodeMark mark(this, "StubRoutines", "throw_exception"); @@ -530,7 +537,7 @@ __ save_LR_CR(R11_scratch1); // Push a frame. - __ push_frame_abi112(0, R11_scratch1); + __ push_frame_reg_args(0, R11_scratch1); address frame_complete_pc = __ pc(); @@ -552,8 +559,11 @@ if (arg2 != noreg) { __ mr(R5_ARG3, arg2); } - __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, runtime_entry), - relocInfo::none); +#if defined(ABI_ELFv2) + __ call_c(runtime_entry, relocInfo::none); +#else + __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, runtime_entry), relocInfo::none); +#endif // Set an oopmap for the call site. oop_maps->add_gc_map((int)(gc_map_pc - start), map); @@ -615,7 +625,7 @@ // 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_112_size + spill_slots; + const int frame_size = frame::abi_reg_args_size + spill_slots; Label filtered; // Is marking active? @@ -629,7 +639,7 @@ __ beq(CCR0, filtered); __ save_LR_CR(R0); - __ push_frame_abi112(spill_slots, 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); @@ -673,12 +683,12 @@ if (branchToEnd) { __ save_LR_CR(R0); // We need this frame only to spill LR. - __ push_frame_abi112(0, R0); + __ 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 { - // SAPJVM MD 2013-04-26 Tail call: fake call from stub caller by branching without linking. + // 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); @@ -743,7 +753,7 @@ StubCodeMark mark(this, "StubRoutines", "zero_words_aligned8"); // Implemented as in ClearArray. - address start = __ emit_fd(); + address start = __ function_entry(); Register base_ptr_reg = R3_ARG1; // tohw (needs to be 8b aligned) Register cnt_dwords_reg = R4_ARG2; // count (in dwords) @@ -821,7 +831,7 @@ // address generate_handler_for_unsafe_access() { StubCodeMark mark(this, "StubRoutines", "handler_for_unsafe_access"); - address start = __ emit_fd(); + address start = __ function_entry(); __ unimplemented("StubRoutines::handler_for_unsafe_access", 86); return start; } @@ -862,7 +872,7 @@ // to read from the safepoint polling page. address generate_load_from_poll() { StubCodeMark mark(this, "StubRoutines", "generate_load_from_poll"); - address start = __ emit_fd(); + address start = __ function_entry(); __ unimplemented("StubRoutines::verify_oop", 95); // TODO PPC port return start; } @@ -886,7 +896,7 @@ // address generate_fill(BasicType t, bool aligned, const char* name) { StubCodeMark mark(this, "StubRoutines", name); - address start = __ emit_fd(); + address start = __ function_entry(); const Register to = R3_ARG1; // source array address const Register value = R4_ARG2; // fill value @@ -1124,7 +1134,7 @@ // address generate_disjoint_byte_copy(bool aligned, const char * name) { StubCodeMark mark(this, "StubRoutines", name); - address start = __ emit_fd(); + address start = __ function_entry(); Register tmp1 = R6_ARG4; Register tmp2 = R7_ARG5; @@ -1255,15 +1265,21 @@ // address generate_conjoint_byte_copy(bool aligned, const char * name) { StubCodeMark mark(this, "StubRoutines", name); - address start = __ emit_fd(); + address start = __ function_entry(); Register tmp1 = R6_ARG4; 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 array_overlap_test(nooverlap_target, 0); // Do reverse copy. We assume the case of actual overlap is rare enough @@ -1346,7 +1362,7 @@ Register tmp3 = R8_ARG6; Register tmp4 = R9_ARG7; - address start = __ emit_fd(); + address start = __ function_entry(); Label l_1, l_2, l_3, l_4, l_5, l_6, l_7, l_8; // don't try anything fancy if arrays don't have many elements @@ -1475,15 +1491,21 @@ // address generate_conjoint_short_copy(bool aligned, const char * name) { StubCodeMark mark(this, "StubRoutines", name); - address start = __ emit_fd(); + address start = __ function_entry(); Register tmp1 = R6_ARG4; 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 array_overlap_test(nooverlap_target, 1); @@ -1598,7 +1620,7 @@ // address generate_disjoint_int_copy(bool aligned, const char * name) { StubCodeMark mark(this, "StubRoutines", name); - address start = __ emit_fd(); + address start = __ function_entry(); generate_disjoint_int_copy_core(aligned); __ blr(); return start; @@ -1682,11 +1704,17 @@ // address generate_conjoint_int_copy(bool aligned, const char * name) { StubCodeMark mark(this, "StubRoutines", name); - address start = __ emit_fd(); + 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 array_overlap_test(nooverlap_target, 2); @@ -1768,7 +1796,7 @@ // address generate_disjoint_long_copy(bool aligned, const char * name) { StubCodeMark mark(this, "StubRoutines", name); - address start = __ emit_fd(); + address start = __ function_entry(); generate_disjoint_long_copy_core(aligned); __ blr(); @@ -1850,11 +1878,17 @@ // address generate_conjoint_long_copy(bool aligned, const char * name) { StubCodeMark mark(this, "StubRoutines", name); - address start = __ emit_fd(); + 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 array_overlap_test(nooverlap_target, 3); generate_conjoint_long_copy_core(aligned); @@ -1876,11 +1910,17 @@ address generate_conjoint_oop_copy(bool aligned, const char * name, bool dest_uninitialized) { StubCodeMark mark(this, "StubRoutines", name); - address start = __ emit_fd(); + 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 gen_write_ref_array_pre_barrier(R3_ARG1, R4_ARG2, R5_ARG3, dest_uninitialized, R9_ARG7); @@ -1911,7 +1951,7 @@ // address generate_disjoint_oop_copy(bool aligned, const char * name, bool dest_uninitialized) { StubCodeMark mark(this, "StubRoutines", name); - address start = __ emit_fd(); + address start = __ function_entry(); gen_write_ref_array_pre_barrier(R3_ARG1, R4_ARG2, R5_ARG3, dest_uninitialized, R9_ARG7); @@ -1992,7 +2032,7 @@ StubCodeMark mark(this, "StubRoutines", name); // Entry point, pc or function descriptor. - *entry = __ emit_fd(); + *entry = __ function_entry(); // Load *adr into R4_ARG2, may fault. *fault_pc = __ pc(); @@ -2028,6 +2068,11 @@ StubRoutines::_forward_exception_entry = generate_forward_exception(); StubRoutines::_call_stub_entry = generate_call_stub(StubRoutines::_call_stub_return_address); StubRoutines::_catch_exception_entry = generate_catch_exception(); + + // Build this early so it's available for the interpreter. + StubRoutines::_throw_StackOverflowError_entry = + generate_throw_exception("StackOverflowError throw_exception", + CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError), false); } void generate_all() { @@ -2039,7 +2084,6 @@ // Handle IncompatibleClassChangeError in itable stubs. StubRoutines::_throw_IncompatibleClassChangeError_entry= generate_throw_exception("IncompatibleClassChangeError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_IncompatibleClassChangeError), false); StubRoutines::_throw_NullPointerException_at_call_entry= generate_throw_exception("NullPointerException at call throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException_at_call), false); - StubRoutines::_throw_StackOverflowError_entry = generate_throw_exception("StackOverflowError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError), false); StubRoutines::_handler_for_unsafe_access_entry = generate_handler_for_unsafe_access(); @@ -2049,7 +2093,7 @@ // arraycopy stubs used by compilers generate_arraycopy_stubs(); - // PPC uses stubs for safefetch. + // Safefetch stubs. generate_safefetch("SafeFetch32", sizeof(int), &StubRoutines::_safefetch32_entry, &StubRoutines::_safefetch32_fault_pc, &StubRoutines::_safefetch32_continuation_pc);
--- a/src/cpu/ppc/vm/stubRoutines_ppc_64.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/cpu/ppc/vm/stubRoutines_ppc_64.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -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 2012, 2014 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 @@ -23,17 +23,6 @@ * */ -#include "precompiled.hpp" -#include "runtime/deoptimization.hpp" -#include "runtime/frame.inline.hpp" -#include "runtime/stubRoutines.hpp" -#ifdef TARGET_OS_FAMILY_aix -# include "thread_aix.inline.hpp" -#endif -#ifdef TARGET_OS_FAMILY_linux -# include "thread_linux.inline.hpp" -#endif - // Implementation of the platform-specific part of StubRoutines - for // a description of how to extend it, see the stubRoutines.hpp file.
--- a/src/cpu/ppc/vm/stubRoutines_ppc_64.hpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/cpu/ppc/vm/stubRoutines_ppc_64.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -24,7 +24,7 @@ */ #ifndef CPU_PPC_VM_STUBROUTINES_PPC_64_HPP -#define CPU_PPC_VM_STUBROUTINES_OJDKPPC_HPP +#define CPU_PPC_VM_STUBROUTINES_PPC_64_HPP // This file holds the platform specific parts of the StubRoutines // definition. See stubRoutines.hpp for a description on how to
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright 2013, 2014 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_TEMPLATEINTERPRETERGENERATOR_PPC_HPP +#define CPU_PPC_VM_TEMPLATEINTERPRETERGENERATOR_PPC_HPP + + protected: + address generate_normal_entry(bool synchronized); + address generate_native_entry(bool synchronized); + address generate_math_entry(AbstractInterpreter::MethodKind kind); + address generate_empty_entry(void); + + void lock_method(Register Rflags, Register Rscratch1, Register Rscratch2, bool flags_preloaded=false); + void unlock_method(bool check_exceptions = true); + + void generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue); + void generate_counter_overflow(Label& continue_entry); + + void generate_fixed_frame(bool native_call, Register Rsize_of_parameters, Register Rsize_of_locals); + void generate_stack_overflow_check(Register Rframe_size, Register Rscratch1); + +#endif // CPU_PPC_VM_TEMPLATEINTERPRETERGENERATOR_PPC_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cpu/ppc/vm/templateInterpreter_ppc.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -0,0 +1,1842 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright 2013, 2014 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" +#ifndef CC_INTERP +#include "macroAssembler_ppc.inline.hpp" +#include "interpreter/bytecodeHistogram.hpp" +#include "interpreter/interpreter.hpp" +#include "interpreter/interpreterGenerator.hpp" +#include "interpreter/interpreterRuntime.hpp" +#include "interpreter/templateTable.hpp" +#include "oops/arrayOop.hpp" +#include "oops/methodDataOop.hpp" +#include "oops/methodOop.hpp" +#include "oops/oop.inline.hpp" +#include "prims/jvmtiExport.hpp" +#include "prims/jvmtiThreadState.hpp" +#include "runtime/arguments.hpp" +#include "runtime/deoptimization.hpp" +#include "runtime/frame.inline.hpp" +#include "runtime/globals.hpp" +#include "opto/c2_globals.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/stubRoutines.hpp" +#include "runtime/synchronizer.hpp" +#include "runtime/timer.hpp" +#include "runtime/vframeArray.hpp" +#include "utilities/debug.hpp" +#include "utilities/macros.hpp" + +#undef __ +#define __ _masm-> + +#ifdef PRODUCT +#define BLOCK_COMMENT(str) /* nothing */ +#else +#define BLOCK_COMMENT(str) __ block_comment(str) +#endif + +#define BIND(label) bind(label); BLOCK_COMMENT(#label ":") + +//----------------------------------------------------------------------------- + +// Actually we should never reach here since we do stack overflow checks before pushing any frame. +address TemplateInterpreterGenerator::generate_StackOverflowError_handler() { + address entry = __ pc(); + __ unimplemented("generate_StackOverflowError_handler"); + return entry; +} + +address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler(const char* name) { + address entry = __ pc(); + __ empty_expression_stack(); + __ load_const_optimized(R4_ARG2, (address) name); + // Index is in R17_tos. + __ mr(R5_ARG3, R17_tos); + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_ArrayIndexOutOfBoundsException)); + return entry; +} + +#if 0 +// Call special ClassCastException constructor taking object to cast +// and target class as arguments. +address TemplateInterpreterGenerator::generate_ClassCastException_verbose_handler(const char* name) { + address entry = __ pc(); + + // Target class oop is in register R6_ARG4 by convention! + + // Expression stack must be empty before entering the VM if an + // exception happened. + __ empty_expression_stack(); + // Setup parameters. + // Thread will be loaded to R3_ARG1. + __ load_const_optimized(R4_ARG2, (address) name); + __ mr(R5_ARG3, R17_tos); + // R6_ARG4 contains specified class. + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_ClassCastException_verbose)); +#ifdef ASSERT + // Above call must not return here since exception pending. + __ should_not_reach_here(); +#endif + return entry; +} +#endif + +address TemplateInterpreterGenerator::generate_ClassCastException_handler() { + address entry = __ pc(); + // Expression stack must be empty before entering the VM if an + // exception happened. + __ empty_expression_stack(); + + // Load exception object. + // Thread will be loaded to R3_ARG1. + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_ClassCastException), R17_tos); +#ifdef ASSERT + // Above call must not return here since exception pending. + __ should_not_reach_here(); +#endif + return entry; +} + +address TemplateInterpreterGenerator::generate_exception_handler_common(const char* name, const char* message, bool pass_oop) { + address entry = __ pc(); + //__ untested("generate_exception_handler_common"); + Register Rexception = R17_tos; + + // Expression stack must be empty before entering the VM if an exception happened. + __ empty_expression_stack(); + + __ load_const_optimized(R4_ARG2, (address) name, R11_scratch1); + if (pass_oop) { + __ mr(R5_ARG3, Rexception); + __ call_VM(Rexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::create_klass_exception), false); + } else { + __ load_const_optimized(R5_ARG3, (address) message, R11_scratch1); + __ call_VM(Rexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::create_exception), false); + } + + // Throw exception. + __ mr(R3_ARG1, Rexception); + __ load_const_optimized(R11_scratch1, Interpreter::throw_exception_entry(), R12_scratch2); + __ mtctr(R11_scratch1); + __ bctr(); + + return entry; +} + +address TemplateInterpreterGenerator::generate_continuation_for(TosState state) { + address entry = __ pc(); + __ unimplemented("generate_continuation_for"); + return entry; +} + +// This entry is returned to when a call returns to the interpreter. +// When we arrive here, we expect that the callee stack frame is already popped. +address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step) { + + address entry = __ pc(); + + // Move the value out of the return register back to the TOS cache of current frame. + switch (state) { + case ltos: + case btos: + case ctos: + case stos: + case atos: + case itos: __ mr(R17_tos, R3_RET); break; // RET -> TOS cache + case ftos: + case dtos: __ fmr(F15_ftos, F1_RET); break; // TOS cache -> GR_FRET + case vtos: break; // Nothing to do, this was a void return. + default : ShouldNotReachHere(); + } + + __ restore_interpreter_state(R11_scratch1); // Sets R11_scratch1 = fp. + __ ld(R12_scratch2, _ijava_state_neg(top_frame_sp), R11_scratch1); + __ resize_frame_absolute(R12_scratch2, R11_scratch1, R0); + + // Compiled code destroys templateTableBase, reload. + __ load_const_optimized(R25_templateTableBase, (address)Interpreter::dispatch_table((TosState)0), R12_scratch2); + + const Register cache = R11_scratch1; + const Register size = R12_scratch2; + Label Lgot_cache, Lgiant_index; + + if (EnableInvokeDynamic){ + __ lbz(R11_scratch1, 0, R14_bcp); + __ cmpdi(CCR0, R11_scratch1, Bytecodes::_invokedynamic); + __ beq(CCR0, Lgiant_index); + } + + __ get_cache_and_index_at_bcp(cache, 1); + + __ bind(Lgot_cache); + // Big Endian (get least significant byte of 64 bit value): + __ lbz(size, in_bytes(constantPoolCacheOopDesc::base_offset() + ConstantPoolCacheEntry::flags_offset()) + 7, cache); + __ sldi(size, size, Interpreter::logStackElementSize); + __ add(R15_esp, R15_esp, size); + __ dispatch_next(state, step); + + if (EnableInvokeDynamic){ + __ bind(Lgiant_index); + __ get_cache_and_index_at_bcp(cache, 1, sizeof(u4)); + __ b(Lgot_cache); + } + + return entry; +} + +address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state, int step) { + address entry = __ pc(); + // If state != vtos, we're returning from a native method, which put it's result + // into the result register. So move the value out of the return register back + // to the TOS cache of current frame. + + switch (state) { + case ltos: + case btos: + case ctos: + case stos: + case atos: + case itos: __ mr(R17_tos, R3_RET); break; // GR_RET -> TOS cache + case ftos: + case dtos: __ fmr(F15_ftos, F1_RET); break; // TOS cache -> GR_FRET + case vtos: break; // Nothing to do, this was a void return. + default : ShouldNotReachHere(); + } + + // Load LcpoolCache @@@ should be already set! + __ get_constant_pool_cache(R27_constPoolCache); + + // Handle a pending exception, fall through if none. + __ check_and_forward_exception(R11_scratch1, R12_scratch2); + + // Start executing bytecodes. + __ dispatch_next(state, step); + + return entry; +} + +// A result handler converts the native result into java format. +// Use the shared code between c++ and template interpreter. +address TemplateInterpreterGenerator::generate_result_handler_for(BasicType type) { + return AbstractInterpreterGenerator::generate_result_handler_for(type); +} + +address TemplateInterpreterGenerator::generate_safept_entry_for(TosState state, address runtime_entry) { + address entry = __ pc(); + + __ push(state); + __ call_VM(noreg, runtime_entry); + __ dispatch_via(vtos, Interpreter::_normal_table.table_for(vtos)); + + return entry; +} + +// Helpers for commoning out cases in the various type of method entries. + +// Increment invocation count & check for overflow. +// +// Note: checking for negative value instead of overflow +// so we have a 'sticky' overflow test. +// +void TemplateInterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue) { + // Note: In tiered we increment either counters in methodOop or in MDO depending if we're profiling or not. + Register Rscratch1 = R11_scratch1; + Register Rscratch2 = R12_scratch2; + Register R3_counters = R3_ARG1; + Label done; + + if (TieredCompilation) { + const int increment = InvocationCounter::count_increment; + const int mask = ((1 << Tier0InvokeNotifyFreqLog) - 1) << InvocationCounter::count_shift; + Label no_mdo, done; + if (ProfileInterpreter) { + const Register Rmdo = Rscratch1; + // If no method data exists, go to profile_continue. + __ ld(Rmdo, in_bytes(methodOopDesc::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(methodDataOopDesc::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset()); + __ lwz(Rscratch2, mdo_bc_offs, Rmdo); + __ addi(Rscratch2, Rscratch2, increment); + __ stw(Rscratch2, mdo_bc_offs, Rmdo); + __ load_const_optimized(Rscratch1, mask, R0); + __ and_(Rscratch1, Rscratch2, Rscratch1); + __ bne(CCR0, done); + __ b(*overflow); + } + + // Increment counter in methodOop + const int mo_bc_offs = in_bytes(methodOopDesc::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset()); + __ bind(no_mdo); + __ lwz(Rscratch2, mo_bc_offs, R19_method); + __ addi(Rscratch2, Rscratch2, increment); + __ stw(Rscratch2, mo_bc_offs, R19_method); + __ load_const_optimized(Rscratch1, mask, R0); + __ and_(Rscratch1, Rscratch2, Rscratch1); + __ beq(CCR0, *overflow); + + __ bind(done); + + } else { + + // Update standard invocation counters. + Register Rsum_ivc_bec = R4_ARG2; + __ increment_invocation_counter(Rsum_ivc_bec, R12_scratch2); + // Increment interpreter invocation counter. + if (ProfileInterpreter) { // %%% Merge this into methodDataOop. + Register interpreter_invocation_counter_addr = R11_scratch1; + __ lwz(R12_scratch2,in_bytes(methodOopDesc::interpreter_invocation_counter_offset()), R19_method); + __ addi(R12_scratch2, R12_scratch2, 1); + __ stw(R12_scratch2,in_bytes(methodOopDesc::interpreter_invocation_counter_offset()), R19_method); + } + // 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); + // Test to see if we should create a method data oop. + __ cmpw(CCR0, Rsum_ivc_bec, profile_limit); + __ blt(CCR0, *profile_method_continue); + // If no method data exists, go to profile_method. + __ test_method_data_pointer(*profile_method); + } + // 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"); + __ cmpw(CCR0, Rsum_ivc_bec, invocation_limit); + __ bge(CCR0, *overflow); + } + } +} + +// Generate code to initiate compilation on invocation counter overflow. +void TemplateInterpreterGenerator::generate_counter_overflow(Label& continue_entry) { + // Generate code to initiate compilation on the counter overflow. + + // InterpreterRuntime::frequency_counter_overflow takes one arguments, + // which indicates if the counter overflow occurs at a backwards branch (NULL bcp) + // We pass zero in. + // The call returns the address of the verified entry point for the method or NULL + // if the compilation did not complete (either went background or bailed out). + // + // Unlike the C++ interpreter above: Check exceptions! + // Assumption: Caller must set the flag "do_not_unlock_if_sychronized" if the monitor of a sync'ed + // method has not yet been created. Thus, no unlocking of a non-existing monitor can occur. + + __ li(R4_ARG2, 0); + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), R4_ARG2, true); + + // Returns verified_entry_point or NULL. + // We ignore it in any case. + __ b(continue_entry); +} + +void TemplateInterpreterGenerator::generate_stack_overflow_check(Register Rmem_frame_size, Register Rscratch1) { + assert_different_registers(Rmem_frame_size, Rscratch1); + __ generate_stack_overflow_check_with_compare_and_throw(Rmem_frame_size, Rscratch1); +} + +void TemplateInterpreterGenerator::unlock_method(bool check_exceptions) { + __ unlock_object(R26_monitor, check_exceptions); +} + +// Lock the current method, interpreter register window must be set up! +void TemplateInterpreterGenerator::lock_method(Register Rflags, Register Rscratch1, Register Rscratch2, bool flags_preloaded) { + const Register Robj_to_lock = Rscratch2; + + { + if (!flags_preloaded) { + __ lwz(Rflags, method_(access_flags)); + } + +#ifdef ASSERT + // Check if methods needs synchronization. + { + Label Lok; + __ testbitdi(CCR0, R0, Rflags, JVM_ACC_SYNCHRONIZED_BIT); + __ btrue(CCR0,Lok); + __ stop("method doesn't need synchronization"); + __ bind(Lok); + } +#endif // ASSERT + } + + // Get synchronization object to Rscratch2. + { + const int mirror_offset = in_bytes(Klass::java_mirror_offset()); + Label Lstatic; + Label Ldone; + + __ testbitdi(CCR0, R0, Rflags, JVM_ACC_STATIC_BIT); + __ btrue(CCR0, Lstatic); + + // Non-static case: load receiver obj from stack and we're done. + __ ld(Robj_to_lock, R18_locals); + __ b(Ldone); + + __ bind(Lstatic); // Static case: Lock the java mirror + __ ld(Robj_to_lock, in_bytes(methodOopDesc::const_offset()), R19_method); + __ ld(Robj_to_lock, in_bytes(constMethodOopDesc::constants_offset()), Robj_to_lock); + __ ld(Robj_to_lock, constantPoolOopDesc::pool_holder_offset_in_bytes(), Robj_to_lock); + __ ld(Robj_to_lock, mirror_offset, Robj_to_lock); + + __ bind(Ldone); + __ verify_oop(Robj_to_lock); + } + + // Got the oop to lock => execute! + __ add_monitor_to_stack(true, Rscratch1, R0); + + __ std(Robj_to_lock, BasicObjectLock::obj_offset_in_bytes(), R26_monitor); + __ lock_object(R26_monitor, Robj_to_lock); +} + +// Generate a fixed interpreter frame for pure interpreter +// and I2N native transition frames. +// +// Before (stack grows downwards): +// +// | ... | +// |------------- | +// | java arg0 | +// | ... | +// | java argn | +// | | <- R15_esp +// | | +// |--------------| +// | abi_112 | +// | | <- R1_SP +// |==============| +// +// +// After: +// +// | ... | +// | java arg0 |<- R18_locals +// | ... | +// | java argn | +// |--------------| +// | | +// | java locals | +// | | +// |--------------| +// | abi_48 | +// |==============| +// | | +// | istate | +// | | +// |--------------| +// | monitor |<- R26_monitor +// |--------------| +// | |<- R15_esp +// | expression | +// | stack | +// | | +// |--------------| +// | | +// | abi_112 |<- R1_SP +// |==============| +// +// The top most frame needs an abi space of 112 bytes. This space is needed, +// since we call to c. The c function may spill their arguments to the caller +// frame. When we call to java, we don't need these spill slots. In order to save +// space on the stack, we resize the caller. However, java local reside in +// the caller frame and the frame has to be increased. The frame_size for the +// current frame was calculated based on max_stack as size for the expression +// stack. At the call, just a part of the expression stack might be used. +// We don't want to waste this space and cut the frame back accordingly. +// The resulting amount for resizing is calculated as follows: +// resize = (number_of_locals - number_of_arguments) * slot_size +// + (R1_SP - R15_esp) + 48 +// +// The size for the callee frame is calculated: +// framesize = 112 + max_stack + monitor + state_size +// +// maxstack: Max number of slots on the expression stack, loaded from the methodOop. +// monitor: We statically reserve room for one monitor object. +// state_size: We save the current state of the interpreter to this area. +// +void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call, Register Rsize_of_parameters, Register Rsize_of_locals) { + Register parent_frame_resize = R6_ARG4, // Frame will grow by this number of bytes. + top_frame_size = R7_ARG5, + Rconst_method = R8_ARG6; + + assert_different_registers(Rsize_of_parameters, Rsize_of_locals, parent_frame_resize, top_frame_size); + + __ lhz(Rsize_of_parameters /* number of params */, method_(size_of_parameters)); + if (native_call) { + // If we're calling a native method, we reserve space for the worst-case signature + // handler varargs vector, which is max(Argument::n_register_parameters, parameter_count+2). + // We add two slots to the parameter_count, one for the jni + // environment and one for a possible native mirror. + Label skip_native_calculate_max_stack; + __ addi(top_frame_size, Rsize_of_parameters, 2); + __ cmpwi(CCR0, top_frame_size, Argument::n_register_parameters); + __ bge(CCR0, skip_native_calculate_max_stack); + __ li(top_frame_size, Argument::n_register_parameters); + __ bind(skip_native_calculate_max_stack); + __ sldi(Rsize_of_parameters, Rsize_of_parameters, Interpreter::logStackElementSize); + __ sldi(top_frame_size, top_frame_size, Interpreter::logStackElementSize); + __ sub(parent_frame_resize, R1_SP, R15_esp); // <0, off by Interpreter::stackElementSize! + __ mr(Rsize_of_locals, Rsize_of_parameters); + } else { + __ lhz(Rsize_of_locals, method_(size_of_locals)); + __ sldi(Rsize_of_parameters, Rsize_of_parameters, Interpreter::logStackElementSize); + __ sldi(Rsize_of_locals, Rsize_of_locals, Interpreter::logStackElementSize); + __ lhz(top_frame_size, method_(max_stack)); + __ sub(R11_scratch1, Rsize_of_locals, Rsize_of_parameters); // >=0 + __ sub(parent_frame_resize, R1_SP, R15_esp); // <0, off by Interpreter::stackElementSize! + __ sldi(top_frame_size, top_frame_size, Interpreter::logStackElementSize); + __ add(parent_frame_resize, parent_frame_resize, R11_scratch1); + } + + // Compute top frame size. + __ addi(top_frame_size, top_frame_size, frame::abi_reg_args_size + frame::ijava_state_size); + + // Cut back area between esp and max_stack. + __ addi(parent_frame_resize, parent_frame_resize, frame::abi_minframe_size - Interpreter::stackElementSize); + + __ round_to(top_frame_size, frame::alignment_in_bytes); + __ round_to(parent_frame_resize, frame::alignment_in_bytes); + // parent_frame_resize = (locals-parameters) - (ESP-SP-ABI48) Rounded to frame alignment size. + // Enlarge by locals-parameters (not in case of native_call), shrink by ESP-SP-ABI48. + + { + // -------------------------------------------------------------------------- + // Stack overflow check + + Label cont; + __ add(R11_scratch1, parent_frame_resize, top_frame_size); + generate_stack_overflow_check(R11_scratch1, R12_scratch2); + } + + // Set up interpreter state registers. + + __ add(R18_locals, R15_esp, Rsize_of_parameters); + // set up R27_constPoolCache + __ ld(R27_constPoolCache, in_bytes(methodOopDesc::const_offset()), R19_method); + __ ld(R27_constPoolCache, in_bytes(constMethodOopDesc::constants_offset()), R27_constPoolCache); + __ ld(R27_constPoolCache, constantPoolOopDesc::cache_offset_in_bytes(), R27_constPoolCache); + + // Set method data pointer. + if (ProfileInterpreter) { + Label zero_continue; + __ ld(R28_mdx, method_(method_data)); + __ cmpdi(CCR0, R28_mdx, 0); + __ beq(CCR0, zero_continue); + __ addi(R28_mdx, R28_mdx, in_bytes(methodDataOopDesc::data_offset())); + __ bind(zero_continue); + } + + if (native_call) { + __ li(R14_bcp, 0); // Must initialize. + } else { + Register Rconst_method = R11_scratch1; + __ ld(Rconst_method, method_(const)) ; + __ add(R14_bcp, in_bytes(constMethodOopDesc::codes_offset()), Rconst_method); + } + + // Resize parent frame. + __ mflr(R12_scratch2); + __ neg(parent_frame_resize, parent_frame_resize); + __ resize_frame(parent_frame_resize, R11_scratch1); + __ std(R12_scratch2, _abi(lr), R1_SP); + + __ addi(R26_monitor, R1_SP, - frame::ijava_state_size); + __ addi(R15_esp, R26_monitor, - Interpreter::stackElementSize); + + // Store values. + // R15_esp, R14_bcp, R26_monitor, R28_mdx are saved at java calls + // in InterpreterMacroAssembler::call_from_interpreter. + __ std(R19_method, _ijava_state_neg(method), R1_SP); + __ std(R21_sender_SP, _ijava_state_neg(sender_sp), R1_SP); + __ std(R27_constPoolCache, _ijava_state_neg(cpoolCache), R1_SP); + __ std(R18_locals, _ijava_state_neg(locals), R1_SP); + + // Note: esp, bcp, monitor, mdx live in registers. Hence, the correct version can only + // be found in the frame after save_interpreter_state is done. This is always true + // for non-top frames. But when a signal occurs, dumping the top frame can go wrong, + // because e.g. frame::interpreter_frame_bcp() will not access the correct value + // (Enhanced Stack Trace). + // The signal handler does not save the interpreter state into the frame. + __ li(R0, 0); +#ifdef ASSERT + // Fill remaining slots with constants. + __ load_const_optimized(R11_scratch1, 0x5afe); + __ load_const_optimized(R12_scratch2, 0xdead); +#endif + // We have to initialize some frame slots for native calls (accessed by GC). + if (native_call) { + __ std(R26_monitor, _ijava_state_neg(monitors), R1_SP); + __ std(R14_bcp, _ijava_state_neg(bcp), R1_SP); + if (ProfileInterpreter) { __ std(R28_mdx, _ijava_state_neg(mdx), R1_SP); } + } +#ifdef ASSERT + else { + __ std(R12_scratch2, _ijava_state_neg(monitors), R1_SP); + __ std(R12_scratch2, _ijava_state_neg(bcp), R1_SP); + __ std(R12_scratch2, _ijava_state_neg(mdx), R1_SP); + } + __ std(R11_scratch1, _ijava_state_neg(ijava_reserved), R1_SP); + __ std(R12_scratch2, _ijava_state_neg(esp), R1_SP); + __ std(R12_scratch2, _ijava_state_neg(lresult), R1_SP); + __ std(R12_scratch2, _ijava_state_neg(fresult), R1_SP); +#endif + __ subf(R12_scratch2, top_frame_size, R1_SP); + __ std(R0, _ijava_state_neg(oop_tmp), R1_SP); + __ std(R12_scratch2, _ijava_state_neg(top_frame_sp), R1_SP); + + // Push top frame. + __ push_frame(top_frame_size, R11_scratch1); +} + +// End of helpers + +// ============================================================================ +// Various method entries +// + +// Empty method, generate a very fast return. We must skip this entry if +// someone's debugging, indicated by the flag +// "interp_mode" in the Thread obj. +// Note: empty methods are generated mostly methods that do assertions, which are +// disabled in the "java opt build". +address TemplateInterpreterGenerator::generate_empty_entry(void) { + if (!UseFastEmptyMethods) { + NOT_PRODUCT(__ should_not_reach_here();) + return Interpreter::entry_for_kind(Interpreter::zerolocals); + } + + Label Lslow_path; + const Register Rjvmti_mode = R11_scratch1; + address entry = __ pc(); + + __ lwz(Rjvmti_mode, thread_(interp_only_mode)); + __ cmpwi(CCR0, Rjvmti_mode, 0); + __ bne(CCR0, Lslow_path); // jvmti_mode!=0 + + // Noone's debuggin: Simply return. + // Pop c2i arguments (if any) off when we return. +#ifdef ASSERT + __ ld(R9_ARG7, 0, R1_SP); + __ ld(R10_ARG8, 0, R21_sender_SP); + __ cmpd(CCR0, R9_ARG7, R10_ARG8); + __ asm_assert_eq("backlink", 0x545); +#endif // ASSERT + __ mr(R1_SP, R21_sender_SP); // Cut the stack back to where the caller started. + + // And we're done. + __ blr(); + + __ bind(Lslow_path); + assert(Interpreter::entry_for_kind(Interpreter::zerolocals), "Normal entry must have been generated by now"); + __ load_const_optimized(R11_scratch1, Interpreter::entry_for_kind(Interpreter::zerolocals), R12_scratch2); + __ mtctr(R11_scratch1); + __ bctr(); + __ flush(); + + return entry; +} + +// Support abs and sqrt like in compiler. +// For others we can use a normal (native) entry. + +inline bool math_entry_available(AbstractInterpreter::MethodKind kind) { + if (!InlineIntrinsics) return false; // Generate a vanilla entry. + + return ((kind==Interpreter::java_lang_math_sqrt && VM_Version::has_fsqrt()) || + (kind==Interpreter::java_lang_math_abs)); +} + +address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKind kind) { + if (!math_entry_available(kind)) return NULL; + + Label Lslow_path; + const Register Rjvmti_mode = R11_scratch1; + address entry = __ pc(); + + // Provide math entry with debugging on demand. + __ lwz(Rjvmti_mode, thread_(interp_only_mode)); + __ cmpwi(CCR0, Rjvmti_mode, 0); + __ bne(CCR0, Lslow_path); // jvmti_mode!=0 + + __ lfd(F1_RET, Interpreter::stackElementSize, R15_esp); + + // Pop c2i arguments (if any) off when we return. +#ifdef ASSERT + __ ld(R9_ARG7, 0, R1_SP); + __ ld(R10_ARG8, 0, R21_sender_SP); + __ cmpd(CCR0, R9_ARG7, R10_ARG8); + __ asm_assert_eq("backlink", 0x545); +#endif // ASSERT + __ mr(R1_SP, R21_sender_SP); // Cut the stack back to where the caller started. + + if (kind == Interpreter::java_lang_math_sqrt) { + __ fsqrt(F1_RET, F1_RET); + } else if (kind == Interpreter::java_lang_math_abs) { + __ fabs(F1_RET, F1_RET); + } else { + ShouldNotReachHere(); + } + + // And we're done. + __ blr(); + + // Provide slow path for JVMTI case. + __ bind(Lslow_path); + assert(Interpreter::entry_for_kind(Interpreter::zerolocals), "Normal entry must have been generated by now"); + __ load_const_optimized(R11_scratch1, Interpreter::entry_for_kind(Interpreter::zerolocals), R12_scratch2); + __ mtctr(R11_scratch1); + __ bctr(); + __ flush(); + + return entry; +} + +// Interpreter stub for calling a native method. (asm interpreter) +// This sets up a somewhat different looking stack for calling the +// native method than the typical interpreter frame setup. +// +// On entry: +// R19_method - methodOop +// R16_thread - JavaThread* +// R15_esp - intptr_t* sender tos +// +// abstract stack (grows up) +// [ IJava (caller of JNI callee) ] <-- ASP +// ... +address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { + + address entry = __ pc(); + + const bool inc_counter = UseCompiler || CountCompiledCalls; + __ verify_oop(R19_method); + + // ----------------------------------------------------------------------------- + // Allocate a new frame that represents the native callee (i2n frame). + // This is not a full-blown interpreter frame, but in particular, the + // following registers are valid after this: + // - R19_method + // - R18_local (points to start of argumuments to native function) + // + // abstract stack (grows up) + // [ IJava (caller of JNI callee) ] <-- ASP + // ... + + const Register signature_handler_fd = R11_scratch1; + const Register pending_exception = R0; + const Register result_handler_addr = R31; + const Register native_method_fd = R11_scratch1; + const Register access_flags = R22_tmp2; + const Register active_handles = R11_scratch1; // R26_monitor saved to state. + const Register sync_state = R12_scratch2; + const Register sync_state_addr = sync_state; // Address is dead after use. + const Register suspend_flags = R11_scratch1; + + //============================================================================= + // Allocate new frame and initialize interpreter state. + + Label exception_return; + Label exception_return_sync_check; + Label stack_overflow_return; + + // Generate new interpreter state and jump to stack_overflow_return in case of + // a stack overflow. + //generate_compute_interpreter_state(stack_overflow_return); + + Register size_of_parameters = R22_tmp2; + + generate_fixed_frame(true, size_of_parameters, R23_tmp3 /* out unused */); + + //============================================================================= + // Increment invocation counter. On overflow, entry to JNI method + // will be compiled. + Label invocation_counter_overflow, continue_after_compile; + if (inc_counter) { + if (synchronized) { + // Since at this point in the method invocation the exception handler + // would try to exit the monitor of synchronized methods which hasn't + // been entered yet, we set the thread local variable + // _do_not_unlock_if_synchronized to true. If any exception was thrown by + // runtime, exception handling i.e. unlock_if_synchronized_method will + // check this thread local flag. + // This flag has two effects, one is to force an unwind in the topmost + // interpreter frame and not perform an unlock while doing so. + __ li(R0, 1); + __ stb(R0, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()), R16_thread); + } + generate_counter_incr(&invocation_counter_overflow, NULL, NULL); + + __ BIND(continue_after_compile); + // Reset the _do_not_unlock_if_synchronized flag. + if (synchronized) { + __ li(R0, 0); + __ stb(R0, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()), R16_thread); + } + } + + // access_flags = method->access_flags(); + // Load access flags. + assert(access_flags->is_nonvolatile(), + "access_flags must be in a non-volatile register"); + // Type check. + // TODO ppc port assert(4 == methodOopDesc::sz_access_flags(), "unexpected field size"); + __ lwz(access_flags, method_(access_flags)); + + // We don't want to reload R19_method and access_flags after calls + // to some helper functions. + assert(R19_method->is_nonvolatile(), + "R19_method must be a non-volatile register"); + + // Check for synchronized methods. Must happen AFTER invocation counter + // check, so method is not locked if counter overflows. + + if (synchronized) { + lock_method(access_flags, R11_scratch1, R12_scratch2, true); + + // Update monitor in state. + __ ld(R11_scratch1, 0, R1_SP); + __ std(R26_monitor, _ijava_state_neg(monitors), R11_scratch1); + } + + // jvmti/jvmpi support + __ notify_method_entry(); + + //============================================================================= + // Get and call the signature handler. + + __ ld(signature_handler_fd, method_(signature_handler)); + Label call_signature_handler; + + __ cmpdi(CCR0, signature_handler_fd, 0); + __ bne(CCR0, call_signature_handler); + + // Method has never been called. Either generate a specialized + // handler or point to the slow one. + // + // Pass parameter 'false' to avoid exception check in call_VM. + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::prepare_native_call), R19_method, false); + + // Check for an exception while looking up the target method. If we + // incurred one, bail. + __ ld(pending_exception, thread_(pending_exception)); + __ cmpdi(CCR0, pending_exception, 0); + __ bne(CCR0, exception_return_sync_check); // Has pending exception. + + // Reload signature handler, it may have been created/assigned in the meanwhile. + __ ld(signature_handler_fd, method_(signature_handler)); + __ twi_0(signature_handler_fd); // Order wrt. load of klass mirror and entry point (isync is below). + + __ BIND(call_signature_handler); + + // Before we call the signature handler we push a new frame to + // protect the interpreter frame volatile registers when we return + // from jni but before we can get back to Java. + + // First set the frame anchor while the SP/FP registers are + // convenient and the slow signature handler can use this same frame + // anchor. + + // We have a TOP_IJAVA_FRAME here, which belongs to us. + __ set_top_ijava_frame_at_SP_as_last_Java_frame(R1_SP, R12_scratch2/*tmp*/); + + // Now the interpreter frame (and its call chain) have been + // invalidated and flushed. We are now protected against eager + // being enabled in native code. Even if it goes eager the + // registers will be reloaded as clean and we will invalidate after + // the call so no spurious flush should be possible. + + // Call signature handler and pass locals address. + // + // Our signature handlers copy required arguments to the C stack + // (outgoing C args), R3_ARG1 to R10_ARG8, and FARG1 to FARG13. + __ mr(R3_ARG1, R18_locals); + __ ld(signature_handler_fd, 0, signature_handler_fd); + + __ call_stub(signature_handler_fd); + // Reload method, it may have moved. + __ ld(R19_method, 0, R1_SP); + __ ld(R19_method, _ijava_state_neg(method), R19_method); + + // Remove the register parameter varargs slots we allocated in + // compute_interpreter_state. SP+16 ends up pointing to the ABI + // outgoing argument area. + // + // Not needed on PPC64. + //__ add(SP, SP, Argument::n_register_parameters*BytesPerWord); + + assert(result_handler_addr->is_nonvolatile(), "result_handler_addr must be in a non-volatile register"); + // Save across call to native method. + __ mr(result_handler_addr, R3_RET); + + __ isync(); // Acquire signature handler before trying to fetch the native entry point and klass mirror. + + // Set up fixed parameters and call the native method. + // If the method is static, get mirror into R4_ARG2. + { + Label method_is_not_static; + // Access_flags is non-volatile and still, no need to restore it. + + // Restore access flags. + __ testbitdi(CCR0, R0, access_flags, JVM_ACC_STATIC_BIT); + __ bfalse(CCR0, method_is_not_static); + + // constants = method->constants(); + __ ld(R11_scratch1, in_bytes(methodOopDesc::const_offset()), R19_method); + __ ld(R11_scratch1, in_bytes(constMethodOopDesc::constants_offset()), R11_scratch1); + // pool_holder = method->constants()->pool_holder(); + __ ld(R11_scratch1/*pool_holder*/, constantPoolOopDesc::pool_holder_offset_in_bytes(), + R11_scratch1/*constants*/); + + const int mirror_offset = in_bytes(Klass::java_mirror_offset()); + + // mirror = pool_holder->klass_part()->java_mirror(); + __ ld(R0/*mirror*/, mirror_offset, R11_scratch1/*pool_holder*/); + // state->_native_mirror = mirror; + + __ ld(R11_scratch1, 0, R1_SP); + __ std(R0/*mirror*/, _ijava_state_neg(oop_tmp), R11_scratch1); + // R4_ARG2 = &state->_oop_temp; + __ addi(R4_ARG2, R11_scratch1, _ijava_state_neg(oop_tmp)); + __ BIND(method_is_not_static); + } + + // At this point, arguments have been copied off the stack into + // their JNI positions. Oops are boxed in-place on the stack, with + // handles copied to arguments. The result handler address is in a + // register. + + // Pass JNIEnv address as first parameter. + __ addir(R3_ARG1, thread_(jni_environment)); + + // Load the native_method entry before we change the thread state. + __ ld(native_method_fd, method_(native_function)); + + //============================================================================= + // Transition from _thread_in_Java to _thread_in_native. As soon as + // we make this change the safepoint code needs to be certain that + // the last Java frame we established is good. The pc in that frame + // just needs to be near here not an actual return address. + + // We use release_store_fence to update values like the thread state, where + // we don't want the current thread to continue until all our prior memory + // accesses (including the new thread state) are visible to other threads. + __ li(R0, _thread_in_native); + __ release(); + + // TODO PPC port assert(4 == JavaThread::sz_thread_state(), "unexpected field size"); + __ stw(R0, thread_(thread_state)); + + if (UseMembar) { + __ fence(); + } + + //============================================================================= + // Call the native method. Argument registers must not have been + // overwritten since "__ call_stub(signature_handler);" (except for + // ARG1 and ARG2 for static methods). + __ call_c(native_method_fd); + + __ li(R0, 0); + __ ld(R11_scratch1, 0, R1_SP); + __ std(R3_RET, _ijava_state_neg(lresult), R11_scratch1); + __ stfd(F1_RET, _ijava_state_neg(fresult), R11_scratch1); + __ std(R0/*mirror*/, _ijava_state_neg(oop_tmp), R11_scratch1); // reset + + // Note: C++ interpreter needs the following here: + // The frame_manager_lr field, which we use for setting the last + // java frame, gets overwritten by the signature handler. Restore + // it now. + //__ get_PC_trash_LR(R11_scratch1); + //__ std(R11_scratch1, _top_ijava_frame_abi(frame_manager_lr), R1_SP); + + // Because of GC R19_method may no longer be valid. + + // Block, if necessary, before resuming in _thread_in_Java state. + // In order for GC to work, don't clear the last_Java_sp until after + // blocking. + + //============================================================================= + // Switch thread to "native transition" state before reading the + // synchronization state. This additional state is necessary + // because reading and testing the synchronization state is not + // atomic w.r.t. GC, as this scenario demonstrates: Java thread A, + // in _thread_in_native state, loads _not_synchronized and is + // preempted. VM thread changes sync state to synchronizing and + // suspends threads for GC. Thread A is resumed to finish this + // native method, but doesn't block here since it didn't see any + // synchronization in progress, and escapes. + + // We use release_store_fence to update values like the thread state, where + // we don't want the current thread to continue until all our prior memory + // accesses (including the new thread state) are visible to other threads. + __ li(R0/*thread_state*/, _thread_in_native_trans); + __ release(); + __ stw(R0/*thread_state*/, thread_(thread_state)); + if (UseMembar) { + __ fence(); + } + // Write serialization page so that the VM thread can do a pseudo remote + // membar. We use the current thread pointer to calculate a thread + // specific offset to write to within the page. This minimizes bus + // traffic due to cache line collision. + else { + __ serialize_memory(R16_thread, R11_scratch1, R12_scratch2); + } + + // Now before we return to java we must look for a current safepoint + // (a new safepoint can not start since we entered native_trans). + // We must check here because a current safepoint could be modifying + // the callers registers right this moment. + + // Acquire isn't strictly necessary here because of the fence, but + // sync_state is declared to be volatile, so we do it anyway + // (cmp-br-isync on one path, release (same as acquire on PPC64) on the other path). + int sync_state_offs = __ load_const_optimized(sync_state_addr, SafepointSynchronize::address_of_state(), /*temp*/R0, true); + + // TODO PPC port assert(4 == SafepointSynchronize::sz_state(), "unexpected field size"); + __ lwz(sync_state, sync_state_offs, sync_state_addr); + + // TODO PPC port assert(4 == Thread::sz_suspend_flags(), "unexpected field size"); + __ lwz(suspend_flags, thread_(suspend_flags)); + + Label sync_check_done; + Label do_safepoint; + // No synchronization in progress nor yet synchronized. + __ cmpwi(CCR0, sync_state, SafepointSynchronize::_not_synchronized); + // Not suspended. + __ cmpwi(CCR1, suspend_flags, 0); + + __ bne(CCR0, do_safepoint); + __ beq(CCR1, sync_check_done); + __ bind(do_safepoint); + __ isync(); + // Block. We do the call directly and leave the current + // last_Java_frame setup undisturbed. We must save any possible + // native result across the call. No oop is present. + + __ mr(R3_ARG1, R16_thread); + __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, JavaThread::check_special_condition_for_native_trans), + relocInfo::none); + + __ bind(sync_check_done); + + //============================================================================= + // <<<<<< Back in Interpreter Frame >>>>> + + // We are in thread_in_native_trans here and back in the normal + // interpreter frame. We don't have to do anything special about + // safepoints and we can switch to Java mode anytime we are ready. + + // Note: frame::interpreter_frame_result has a dependency on how the + // method result is saved across the call to post_method_exit. For + // native methods it assumes that the non-FPU/non-void result is + // saved in _native_lresult and a FPU result in _native_fresult. If + // this changes then the interpreter_frame_result implementation + // will need to be updated too. + + // On PPC64, we have stored the result directly after the native call. + + //============================================================================= + // Back in Java + + // We use release_store_fence to update values like the thread state, where + // we don't want the current thread to continue until all our prior memory + // accesses (including the new thread state) are visible to other threads. + __ li(R0/*thread_state*/, _thread_in_Java); + __ release(); + __ stw(R0/*thread_state*/, thread_(thread_state)); + if (UseMembar) { + __ fence(); + } + + __ reset_last_Java_frame(); + + + // Reload GR27_method, call killed it. We can't look at + // state->_method until we're back in java state because in java + // state gc can't happen until we get to a safepoint. + // + // We've set thread_state to _thread_in_Java already, so restoring + // R19_method from state works; R19_method is invalid, because + // GC may have happened. + __ ld(R19_method, 0, R1_SP); + __ ld(R19_method, _ijava_state_neg(method), R19_method); + + // jvmdi/jvmpi support. Whether we've got an exception pending or + // not, and whether unlocking throws an exception or not, we notify + // on native method exit. If we do have an exception, we'll end up + // in the caller's context to handle it, so if we don't do the + // notify here, we'll drop it on the floor. + __ notify_method_exit(true/*native method*/, + ilgl /*illegal state (not used for native methods)*/, + InterpreterMacroAssembler::NotifyJVMTI, + false /*check_exceptions*/); + + //============================================================================= + // Handle exceptions + + if (synchronized) { + // Don't check for exceptions since we're still in the i2n frame. Do that + // manually afterwards. + unlock_method(false); + } + + // Reset active handles after returning from native. + // thread->active_handles()->clear(); + __ ld(active_handles, thread_(active_handles)); + // TODO PPC port assert(4 == JNIHandleBlock::top_size_in_bytes(), "unexpected field size"); + __ li(R0, 0); + __ stw(R0, JNIHandleBlock::top_offset_in_bytes(), active_handles); + + Label exception_return_sync_check_already_unlocked; + __ ld(R0/*pending_exception*/, thread_(pending_exception)); + __ cmpdi(CCR0, R0/*pending_exception*/, 0); + __ bne(CCR0, exception_return_sync_check_already_unlocked); + + //----------------------------------------------------------------------------- + // No exception pending. + + // Move native method result back into proper registers and return. + // Invoke result handler (may unbox/promote). + __ ld(R11_scratch1, 0, R1_SP); + __ ld(R3_RET, _ijava_state_neg(lresult), R11_scratch1); + __ lfd(F1_RET, _ijava_state_neg(fresult), R11_scratch1); + __ call_stub(result_handler_addr); + + __ merge_frames(/*top_frame_sp*/ R21_sender_SP, /*return_pc*/ R0, R11_scratch1, R12_scratch2); + + // Must use the return pc which was loaded from the caller's frame + // as the VM uses return-pc-patching for deoptimization. + __ mtlr(R0); + __ blr(); + + //----------------------------------------------------------------------------- + // An exception is pending. We call into the runtime only if the + // caller was not interpreted. If it was interpreted the + // interpreter will do the correct thing. If it isn't interpreted + // (call stub/compiled code) we will change our return and continue. + + __ BIND(exception_return_sync_check); + + if (synchronized) { + // Don't check for exceptions since we're still in the i2n frame. Do that + // manually afterwards. + unlock_method(false); + } + __ BIND(exception_return_sync_check_already_unlocked); + + const Register return_pc = R31; + + __ ld(return_pc, 0, R1_SP); + __ ld(return_pc, _abi(lr), return_pc); + + // Get the address of the exception handler. + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), + R16_thread, + return_pc /* return pc */); + __ merge_frames(/*top_frame_sp*/ R21_sender_SP, noreg, R11_scratch1, R12_scratch2); + + // Load the PC of the the exception handler into LR. + __ mtlr(R3_RET); + + // Load exception into R3_ARG1 and clear pending exception in thread. + __ ld(R3_ARG1/*exception*/, thread_(pending_exception)); + __ li(R4_ARG2, 0); + __ std(R4_ARG2, thread_(pending_exception)); + + // Load the original return pc into R4_ARG2. + __ mr(R4_ARG2/*issuing_pc*/, return_pc); + + // Return to exception handler. + __ blr(); + + //============================================================================= + // Counter overflow. + + if (inc_counter) { + // Handle invocation counter overflow. + __ bind(invocation_counter_overflow); + + generate_counter_overflow(continue_after_compile); + } + + return entry; +} + +// Generic interpreted method entry to (asm) interpreter. +// +address TemplateInterpreterGenerator::generate_normal_entry(bool synchronized) { + bool inc_counter = UseCompiler || CountCompiledCalls; + address entry = __ pc(); + // Generate the code to allocate the interpreter stack frame. + Register Rsize_of_parameters = R4_ARG2, // Written by generate_fixed_frame. + Rsize_of_locals = R5_ARG3; // Written by generate_fixed_frame. + + generate_fixed_frame(false, Rsize_of_parameters, Rsize_of_locals); + +#ifdef FAST_DISPATCH + __ unimplemented("Fast dispatch in generate_normal_entry"); +#if 0 + __ set((intptr_t)Interpreter::dispatch_table(), IdispatchTables); + // Set bytecode dispatch table base. +#endif +#endif + + // -------------------------------------------------------------------------- + // Zero out non-parameter locals. + // Note: *Always* zero out non-parameter locals as Sparc does. It's not + // worth to ask the flag, just do it. + Register Rslot_addr = R6_ARG4, + Rnum = R7_ARG5; + Label Lno_locals, Lzero_loop; + + // Set up the zeroing loop. + __ subf(Rnum, Rsize_of_parameters, Rsize_of_locals); + __ subf(Rslot_addr, Rsize_of_parameters, R18_locals); + __ srdi_(Rnum, Rnum, Interpreter::logStackElementSize); + __ beq(CCR0, Lno_locals); + __ li(R0, 0); + __ mtctr(Rnum); + + // The zero locals loop. + __ bind(Lzero_loop); + __ std(R0, 0, Rslot_addr); + __ addi(Rslot_addr, Rslot_addr, -Interpreter::stackElementSize); + __ bdnz(Lzero_loop); + + __ bind(Lno_locals); + + // -------------------------------------------------------------------------- + // Counter increment and overflow check. + Label invocation_counter_overflow, + profile_method, + profile_method_continue; + if (inc_counter || ProfileInterpreter) { + + Register Rdo_not_unlock_if_synchronized_addr = R11_scratch1; + if (synchronized) { + // Since at this point in the method invocation the exception handler + // would try to exit the monitor of synchronized methods which hasn't + // been entered yet, we set the thread local variable + // _do_not_unlock_if_synchronized to true. If any exception was thrown by + // runtime, exception handling i.e. unlock_if_synchronized_method will + // check this thread local flag. + // This flag has two effects, one is to force an unwind in the topmost + // interpreter frame and not perform an unlock while doing so. + __ li(R0, 1); + __ stb(R0, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()), R16_thread); + } + // Increment invocation counter and check for overflow. + if (inc_counter) { + generate_counter_incr(&invocation_counter_overflow, &profile_method, &profile_method_continue); + } + + __ bind(profile_method_continue); + + // Reset the _do_not_unlock_if_synchronized flag. + if (synchronized) { + __ li(R0, 0); + __ stb(R0, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()), R16_thread); + } + } + + // -------------------------------------------------------------------------- + // Locking of synchronized methods. Must happen AFTER invocation_counter + // check and stack overflow check, so method is not locked if overflows. + if (synchronized) { + lock_method(R3_ARG1, R4_ARG2, R5_ARG3); + } +#ifdef ASSERT + else { + Label Lok; + __ lwz(R0, in_bytes(methodOopDesc::access_flags_offset()), R19_method); + __ andi_(R0, R0, JVM_ACC_SYNCHRONIZED); + __ asm_assert_eq("method needs synchronization", 0x8521); + __ bind(Lok); + } +#endif // ASSERT + + __ verify_thread(); + + // -------------------------------------------------------------------------- + // JVMTI support + __ notify_method_entry(); + + // -------------------------------------------------------------------------- + // Start executing instructions. + __ dispatch_next(vtos); + + // -------------------------------------------------------------------------- + // Out of line counter overflow and MDO creation code. + if (ProfileInterpreter) { + // We have decided to profile this method in the interpreter. + __ bind(profile_method); + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method)); + __ set_method_data_pointer_for_bcp(); + __ b(profile_method_continue); + } + + if (inc_counter) { + // Handle invocation counter overflow. + __ bind(invocation_counter_overflow); + generate_counter_overflow(profile_method_continue); + } + return entry; +} + +// ============================================================================= +// Entry points + +address AbstractInterpreterGenerator::generate_method_entry(AbstractInterpreter::MethodKind kind) { + // Determine code generation flags. + bool synchronized = false; + address entry_point = NULL; + + switch (kind) { + case Interpreter::zerolocals : break; + case Interpreter::zerolocals_synchronized: synchronized = true; break; + case Interpreter::native : entry_point = ((InterpreterGenerator*) this)->generate_native_entry(false); break; + case Interpreter::native_synchronized : entry_point = ((InterpreterGenerator*) this)->generate_native_entry(true); break; + case Interpreter::empty : entry_point = ((InterpreterGenerator*) this)->generate_empty_entry(); break; + case Interpreter::accessor : entry_point = ((InterpreterGenerator*) this)->generate_accessor_entry(); break; + case Interpreter::abstract : entry_point = ((InterpreterGenerator*) this)->generate_abstract_entry(); break; + + case Interpreter::java_lang_math_sin : // fall thru + case Interpreter::java_lang_math_cos : // fall thru + case Interpreter::java_lang_math_tan : // fall thru + case Interpreter::java_lang_math_abs : // fall thru + case Interpreter::java_lang_math_log : // fall thru + case Interpreter::java_lang_math_log10 : // fall thru + case Interpreter::java_lang_math_sqrt : // fall thru + case Interpreter::java_lang_math_pow : // fall thru + case Interpreter::java_lang_math_exp : entry_point = ((InterpreterGenerator*) this)->generate_math_entry(kind); break; + case Interpreter::java_lang_ref_reference_get + : entry_point = ((InterpreterGenerator*)this)->generate_Reference_get_entry(); break; + default : ShouldNotReachHere(); break; + } + + if (entry_point) { + return entry_point; + } + + return ((InterpreterGenerator*) this)->generate_normal_entry(synchronized); +} + +// These should never be compiled since the interpreter will prefer +// the compiled version to the intrinsic version. +bool AbstractInterpreter::can_be_compiled(methodHandle m) { + return !math_entry_available(method_kind(m)); +} + +// How much stack a method activation needs in stack slots. +// We must calc this exactly like in generate_fixed_frame. +// Note: This returns the conservative size assuming maximum alignment. +int AbstractInterpreter::size_top_interpreter_activation(methodOop method) { + const int max_alignment_size = 2; + const int abi_scratch = frame::abi_reg_args_size; + return method->max_locals() + method->max_stack() + frame::interpreter_frame_monitor_size() + max_alignment_size + abi_scratch; +} + +// Fills a sceletal interpreter frame generated during deoptimizations +// and returns the frame size in slots. +// +// Parameters: +// +// interpreter_frame == NULL: +// Only calculate the size of an interpreter activation, no actual layout. +// Note: This calculation must exactly parallel the frame setup +// in TemplateInterpreter::generate_normal_entry. But it does not +// account for the SP alignment, that might further enhance the +// frame size, depending on FP. +// +// interpreter_frame != NULL: +// set up the method, locals, and monitors. +// The frame interpreter_frame, if not NULL, is guaranteed to be the +// right size, as determined by a previous call to this method. +// It is also guaranteed to be walkable even though it is in a skeletal state +// +// is_top_frame == true: +// We're processing the *oldest* interpreter frame! +// +// pop_frame_extra_args: +// If this is != 0 we are returning to a deoptimized frame by popping +// off the callee frame. We want to re-execute the call that called the +// callee interpreted, but since the return to the interpreter would pop +// the arguments off advance the esp by dummy popframe_extra_args slots. +// Popping off those will establish the stack layout as it was before the call. +// +int AbstractInterpreter::layout_activation(methodOop method, + int tempcount, + int popframe_extra_args, + int moncount, + int caller_actual_parameters, + int callee_param_count, + int callee_locals, + frame* caller, + frame* interpreter_frame, + bool is_top_frame, + bool is_bottom_frame) { + + const int max_alignment_space = 2; + const int abi_scratch = is_top_frame ? (frame::abi_reg_args_size / Interpreter::stackElementSize) : + (frame::abi_minframe_size / Interpreter::stackElementSize) ; + const int conservative_framesize_in_slots = + method->max_stack() + callee_locals - callee_param_count + + (moncount * frame::interpreter_frame_monitor_size()) + max_alignment_space + + abi_scratch + frame::ijava_state_size / Interpreter::stackElementSize; + + assert(!is_top_frame || conservative_framesize_in_slots * 8 > frame::abi_reg_args_size + frame::ijava_state_size, "frame too small"); + + if (interpreter_frame == NULL) { + // Since we don't know the exact alignment, we return the conservative size. + return (conservative_framesize_in_slots & -2); + } else { + // Now we know our caller, calc the exact frame layout and size. + 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) ; + + 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; + intptr_t* sp = (intptr_t *) (((intptr_t) (esp_base- callee_locals + callee_param_count - method->max_stack()- abi_scratch)) & -StackAlignmentInBytes); + intptr_t* sender_sp = caller->sp() + (frame::abi_minframe_size - frame::abi_reg_args_size) / Interpreter::stackElementSize; + intptr_t* top_frame_sp = is_top_frame ? sp : sp + (frame::abi_minframe_size - frame::abi_reg_args_size) / Interpreter::stackElementSize; + + interpreter_frame->interpreter_frame_set_method(method); + interpreter_frame->interpreter_frame_set_locals(locals_base); + interpreter_frame->interpreter_frame_set_cpcache(method->constants()->cache()); + interpreter_frame->interpreter_frame_set_esp(esp); + interpreter_frame->interpreter_frame_set_monitor_end((BasicObjectLock *)monitor); + interpreter_frame->interpreter_frame_set_top_frame_sp(top_frame_sp); + if (!is_bottom_frame) { + interpreter_frame->interpreter_frame_set_sender_sp(sender_sp); + } + + int framesize_in_slots = caller->sp() - sp; + assert(!is_top_frame ||framesize_in_slots >= (frame::abi_reg_args_size / Interpreter::stackElementSize) + frame::ijava_state_size / Interpreter::stackElementSize, "frame too small"); + assert(framesize_in_slots <= conservative_framesize_in_slots, "exact frame size must be smaller than the convervative size!"); + return framesize_in_slots; + } +} + +// ============================================================================= +// Exceptions + +void TemplateInterpreterGenerator::generate_throw_exception() { + Register Rexception = R17_tos, + Rcontinuation = R3_RET; + + // -------------------------------------------------------------------------- + // Entry point if an method returns with a pending exception (rethrow). + Interpreter::_rethrow_exception_entry = __ pc(); + { + __ restore_interpreter_state(R11_scratch1); // Sets R11_scratch1 = fp. + __ ld(R12_scratch2, _ijava_state_neg(top_frame_sp), R11_scratch1); + __ resize_frame_absolute(R12_scratch2, R11_scratch1, R0); + + // Compiled code destroys templateTableBase, reload. + __ load_const_optimized(R25_templateTableBase, (address)Interpreter::dispatch_table((TosState)0), R11_scratch1); + } + + // Entry point if a interpreted method throws an exception (throw). + Interpreter::_throw_exception_entry = __ pc(); + { + __ mr(Rexception, R3_RET); + + __ verify_thread(); + __ verify_oop(Rexception); + + // Expression stack must be empty before entering the VM in case of an exception. + __ empty_expression_stack(); + // Find exception handler address and preserve exception oop. + // Call C routine to find handler and jump to it. + __ call_VM(Rexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::exception_handler_for_exception), Rexception); + __ mtctr(Rcontinuation); + // Push exception for exception handler bytecodes. + __ push_ptr(Rexception); + + // Jump to exception handler (may be remove activation entry!). + __ bctr(); + } + + // If the exception is not handled in the current frame the frame is + // removed and the exception is rethrown (i.e. exception + // continuation is _rethrow_exception). + // + // Note: At this point the bci is still the bxi for the instruction + // which caused the exception and the expression stack is + // empty. Thus, for any VM calls at this point, GC will find a legal + // oop map (with empty expression stack). + + // In current activation + // tos: exception + // bcp: exception bcp + + // -------------------------------------------------------------------------- + // JVMTI PopFrame support + + Interpreter::_remove_activation_preserving_args_entry = __ pc(); + { + // Set the popframe_processing bit in popframe_condition indicating that we are + // currently handling popframe, so that call_VMs that may happen later do not + // trigger new popframe handling cycles. + __ lwz(R11_scratch1, in_bytes(JavaThread::popframe_condition_offset()), R16_thread); + __ ori(R11_scratch1, R11_scratch1, JavaThread::popframe_processing_bit); + __ stw(R11_scratch1, in_bytes(JavaThread::popframe_condition_offset()), R16_thread); + + // Empty the expression stack, as in normal exception handling. + __ empty_expression_stack(); + __ unlock_if_synchronized_method(vtos, /* throw_monitor_exception */ false, /* install_monitor_exception */ false); + + // Check to see whether we are returning to a deoptimized frame. + // (The PopFrame call ensures that the caller of the popped frame is + // either interpreted or compiled and deoptimizes it if compiled.) + // Note that we don't compare the return PC against the + // deoptimization blob's unpack entry because of the presence of + // adapter frames in C2. + Label Lcaller_not_deoptimized; + Register return_pc = R3_ARG1; + __ ld(return_pc, 0, R1_SP); + __ ld(return_pc, _abi(lr), return_pc); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::interpreter_contains), return_pc); + __ cmpdi(CCR0, R3_RET, 0); + __ bne(CCR0, Lcaller_not_deoptimized); + + // The deoptimized case. + // In this case, we can't call dispatch_next() after the frame is + // popped, but instead must save the incoming arguments and restore + // them after deoptimization has occurred. + __ lhz(R4_ARG2, in_bytes(methodOopDesc::size_of_parameters_offset()), R19_method); + __ slwi(R4_ARG2, R4_ARG2, Interpreter::logStackElementSize); + __ addi(R5_ARG3, R18_locals, Interpreter::stackElementSize); + __ subf(R5_ARG3, R4_ARG2, R5_ARG3); + // Save these arguments. + __ call_VM_leaf(CAST_FROM_FN_PTR(address, Deoptimization::popframe_preserve_args), R16_thread, R4_ARG2, R5_ARG3); + + // Inform deoptimization that it is responsible for restoring these arguments. + __ load_const_optimized(R11_scratch1, JavaThread::popframe_force_deopt_reexecution_bit); + __ stw(R11_scratch1, in_bytes(JavaThread::popframe_condition_offset()), R16_thread); + + // Return from the current method into the deoptimization blob. Will eventually + // end up in the deopt interpeter entry, deoptimization prepared everything that + // we will reexecute the call that called us. + __ merge_frames(/*top_frame_sp*/ R21_sender_SP, /*reload return_pc*/ return_pc, R11_scratch1, R12_scratch2); + __ mtlr(return_pc); + __ blr(); + + // The non-deoptimized case. + __ bind(Lcaller_not_deoptimized); + + // Clear the popframe condition flag. + __ li(R0, 0); + __ stw(R0, in_bytes(JavaThread::popframe_condition_offset()), R16_thread); + + // Get out of the current method and re-execute the call that called us. + __ merge_frames(/*top_frame_sp*/ R21_sender_SP, /*return_pc*/ return_pc, R11_scratch1, R12_scratch2); + __ restore_interpreter_state(R11_scratch1); + __ ld(R12_scratch2, _ijava_state_neg(top_frame_sp), R11_scratch1); + __ resize_frame_absolute(R12_scratch2, R11_scratch1, R0); + __ mtlr(return_pc); + if (ProfileInterpreter) { + __ set_method_data_pointer_for_bcp(); + } + __ dispatch_next(vtos); + } + // end of JVMTI PopFrame support + + // -------------------------------------------------------------------------- + // Remove activation exception entry. + // This is jumped to if an interpreted method can't handle an exception itself + // (we come from the throw/rethrow exception entry above). We're going to call + // into the VM to find the exception handler in the caller, pop the current + // frame and return the handler we calculated. + Interpreter::_remove_activation_entry = __ pc(); + { + __ pop_ptr(Rexception); + __ verify_thread(); + __ verify_oop(Rexception); + __ std(Rexception, in_bytes(JavaThread::vm_result_offset()), R16_thread); + + __ unlock_if_synchronized_method(vtos, /* throw_monitor_exception */ false, true); + __ notify_method_exit(false, vtos, InterpreterMacroAssembler::SkipNotifyJVMTI, false); + + __ get_vm_result(Rexception); + + // We are done with this activation frame; find out where to go next. + // The continuation point will be an exception handler, which expects + // the following registers set up: + // + // RET: exception oop + // ARG2: Issuing PC (see generate_exception_blob()), only used if the caller is compiled. + + Register return_pc = R31; // Needs to survive the runtime call. + __ ld(return_pc, 0, R1_SP); + __ ld(return_pc, _abi(lr), return_pc); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), R16_thread, return_pc); + + // Remove the current activation. + __ merge_frames(/*top_frame_sp*/ R21_sender_SP, /*return_pc*/ noreg, R11_scratch1, R12_scratch2); + + __ mr(R4_ARG2, return_pc); + __ mtlr(R3_RET); + __ mr(R3_RET, Rexception); + __ blr(); + } +} + +// JVMTI ForceEarlyReturn support. +// Returns "in the middle" of a method with a "fake" return value. +address TemplateInterpreterGenerator::generate_earlyret_entry_for(TosState state) { + + Register Rscratch1 = R11_scratch1, + Rscratch2 = R12_scratch2; + + address entry = __ pc(); + __ empty_expression_stack(); + + __ load_earlyret_value(state, Rscratch1); + + __ ld(Rscratch1, in_bytes(JavaThread::jvmti_thread_state_offset()), R16_thread); + // Clear the earlyret state. + __ li(R0, 0); + __ stw(R0, in_bytes(JvmtiThreadState::earlyret_state_offset()), Rscratch1); + + __ remove_activation(state, false, false); + // Copied from TemplateTable::_return. + // Restoration of lr done by remove_activation. + switch (state) { + case ltos: + case btos: + case ctos: + case stos: + case atos: + case itos: __ mr(R3_RET, R17_tos); break; + case ftos: + case dtos: __ fmr(F1_RET, F15_ftos); break; + case vtos: // This might be a constructor. Final fields (and volatile fields on PPC64) need + // to get visible before the reference to the object gets stored anywhere. + __ membar(Assembler::StoreStore); break; + default : ShouldNotReachHere(); + } + __ blr(); + + return entry; +} // end of ForceEarlyReturn support + +//----------------------------------------------------------------------------- +// Helper for vtos entry point generation + +void TemplateInterpreterGenerator::set_vtos_entry_points(Template* t, + address& bep, + address& cep, + address& sep, + address& aep, + address& iep, + address& lep, + address& fep, + address& dep, + address& vep) { + assert(t->is_valid() && t->tos_in() == vtos, "illegal template"); + Label L; + + aep = __ pc(); __ push_ptr(); __ b(L); + fep = __ pc(); __ push_f(); __ b(L); + dep = __ pc(); __ push_d(); __ b(L); + lep = __ pc(); __ push_l(); __ b(L); + __ align(32, 12, 24); // align L + bep = cep = sep = + iep = __ pc(); __ push_i(); + vep = __ pc(); + __ bind(L); + generate_and_dispatch(t); +} + +//----------------------------------------------------------------------------- +// Generation of individual instructions + +// helpers for generate_and_dispatch + +InterpreterGenerator::InterpreterGenerator(StubQueue* code) + : TemplateInterpreterGenerator(code) { + generate_all(); // Down here so it can be "virtual". +} + +//----------------------------------------------------------------------------- + +// Non-product code +#ifndef PRODUCT +address TemplateInterpreterGenerator::generate_trace_code(TosState state) { + //__ flush_bundle(); + address entry = __ pc(); + + const char *bname = NULL; + uint tsize = 0; + switch(state) { + case ftos: + bname = "trace_code_ftos {"; + tsize = 2; + break; + case btos: + bname = "trace_code_btos {"; + tsize = 2; + break; + case ctos: + bname = "trace_code_ctos {"; + tsize = 2; + break; + case stos: + bname = "trace_code_stos {"; + tsize = 2; + break; + case itos: + bname = "trace_code_itos {"; + tsize = 2; + break; + case ltos: + bname = "trace_code_ltos {"; + tsize = 3; + break; + case atos: + bname = "trace_code_atos {"; + tsize = 2; + break; + case vtos: + // Note: In case of vtos, the topmost of stack value could be a int or doubl + // In case of a double (2 slots) we won't see the 2nd stack value. + // Maybe we simply should print the topmost 3 stack slots to cope with the problem. + bname = "trace_code_vtos {"; + tsize = 2; + + break; + case dtos: + bname = "trace_code_dtos {"; + tsize = 3; + break; + default: + ShouldNotReachHere(); + } + BLOCK_COMMENT(bname); + + // Support short-cut for TraceBytecodesAt. + // Don't call into the VM if we don't want to trace to speed up things. + Label Lskip_vm_call; + if (TraceBytecodesAt > 0 && TraceBytecodesAt < max_intx) { + int offs1 = __ load_const_optimized(R11_scratch1, (address) &TraceBytecodesAt, R0, true); + int offs2 = __ load_const_optimized(R12_scratch2, (address) &BytecodeCounter::_counter_value, R0, true); + __ ld(R11_scratch1, offs1, R11_scratch1); + __ lwa(R12_scratch2, offs2, R12_scratch2); + __ cmpd(CCR0, R12_scratch2, R11_scratch1); + __ blt(CCR0, Lskip_vm_call); + } + + __ push(state); + // Load 2 topmost expression stack values. + __ ld(R6_ARG4, tsize*Interpreter::stackElementSize, R15_esp); + __ ld(R5_ARG3, Interpreter::stackElementSize, R15_esp); + __ mflr(R31); + __ call_VM(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::trace_bytecode), /* unused */ R4_ARG2, R5_ARG3, R6_ARG4, false); + __ mtlr(R31); + __ pop(state); + + if (TraceBytecodesAt > 0 && TraceBytecodesAt < max_intx) { + __ bind(Lskip_vm_call); + } + __ blr(); + BLOCK_COMMENT("} trace_code"); + return entry; +} + +void TemplateInterpreterGenerator::count_bytecode() { + int offs = __ load_const_optimized(R11_scratch1, (address) &BytecodeCounter::_counter_value, R12_scratch2, true); + __ lwz(R12_scratch2, offs, R11_scratch1); + __ addi(R12_scratch2, R12_scratch2, 1); + __ stw(R12_scratch2, offs, R11_scratch1); +} + +void TemplateInterpreterGenerator::histogram_bytecode(Template* t) { + int offs = __ load_const_optimized(R11_scratch1, (address) &BytecodeHistogram::_counters[t->bytecode()], R12_scratch2, true); + __ lwz(R12_scratch2, offs, R11_scratch1); + __ addi(R12_scratch2, R12_scratch2, 1); + __ stw(R12_scratch2, offs, R11_scratch1); +} + +void TemplateInterpreterGenerator::histogram_bytecode_pair(Template* t) { + const Register addr = R11_scratch1, + tmp = R12_scratch2; + // Get index, shift out old bytecode, bring in new bytecode, and store it. + // _index = (_index >> log2_number_of_codes) | + // (bytecode << log2_number_of_codes); + int offs1 = __ load_const_optimized(addr, (address)&BytecodePairHistogram::_index, tmp, true); + __ lwz(tmp, offs1, addr); + __ srwi(tmp, tmp, BytecodePairHistogram::log2_number_of_codes); + __ ori(tmp, tmp, ((int) t->bytecode()) << BytecodePairHistogram::log2_number_of_codes); + __ stw(tmp, offs1, addr); + + // Bump bucket contents. + // _counters[_index] ++; + int offs2 = __ load_const_optimized(addr, (address)&BytecodePairHistogram::_counters, R0, true); + __ sldi(tmp, tmp, LogBytesPerInt); + __ add(addr, tmp, addr); + __ lwz(tmp, offs2, addr); + __ addi(tmp, tmp, 1); + __ stw(tmp, offs2, addr); +} + +void TemplateInterpreterGenerator::trace_bytecode(Template* t) { + // Call a little run-time stub to avoid blow-up for each bytecode. + // The run-time runtime saves the right registers, depending on + // the tosca in-state for the given template. + + assert(Interpreter::trace_code(t->tos_in()) != NULL, + "entry must have been generated"); + + // Note: we destroy LR here. + __ bl(Interpreter::trace_code(t->tos_in())); +} + +void TemplateInterpreterGenerator::stop_interpreter_at() { + Label L; + int offs1 = __ load_const_optimized(R11_scratch1, (address) &StopInterpreterAt, R0, true); + int offs2 = __ load_const_optimized(R12_scratch2, (address) &BytecodeCounter::_counter_value, R0, true); + __ ld(R11_scratch1, offs1, R11_scratch1); + __ lwa(R12_scratch2, offs2, R12_scratch2); + __ cmpd(CCR0, R12_scratch2, R11_scratch1); + __ bne(CCR0, L); + __ illtrap(); + __ bind(L); +} + +#endif // !PRODUCT +#endif // !CC_INTERP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cpu/ppc/vm/templateInterpreter_ppc.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright 2013, 2014 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_TEMPLATEINTERPRETER_PPC_HPP +#define CPU_PPC_VM_TEMPLATEINTERPRETER_PPC_HPP + + protected: + + // Size of interpreter code. Increase if too small. Interpreter will + // fail with a guarantee ("not enough space for interpreter generation"); + // if too small. + // Run with +PrintInterpreter to get the VM to print out the size. + // Max size with JVMTI + + const static int InterpreterCodeSize = 210*K; + +#endif // CPU_PPC_VM_TEMPLATEINTERPRETER_PPC_HPP + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cpu/ppc/vm/templateTable_ppc_64.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -0,0 +1,4261 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright 2013, 2014 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 "macroAssembler_ppc.inline.hpp" +#include "interpreter/interpreter.hpp" +#include "interpreter/interpreterRuntime.hpp" +#include "interpreter/templateTable.hpp" +#include "memory/universe.inline.hpp" +#include "oops/methodDataOop.hpp" +#include "oops/objArrayKlass.hpp" +#include "oops/oop.inline.hpp" +#include "prims/methodHandles.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/stubRoutines.hpp" +#include "runtime/synchronizer.hpp" +#include "utilities/macros.hpp" + +#ifndef CC_INTERP + +#undef __ +#define __ _masm-> + +static const bool support_IRIW_for_not_multiple_copy_atomic_cpu = true; + +// ============================================================================ +// Misc helpers + +// Do an oop store like *(base + index) = val OR *(base + offset) = val +// (only one of both variants is possible at the same time). +// Index can be noreg. +// Kills: +// Rbase, Rtmp +static void do_oop_store(InterpreterMacroAssembler* _masm, + Register Rbase, + RegisterOrConstant offset, + Register Rval, // Noreg means always null. + Register Rtmp1, + Register Rtmp2, + Register Rtmp3, + BarrierSet::Name barrier, + bool precise, + bool check_null) { + assert_different_registers(Rtmp1, Rtmp2, Rtmp3, Rval, Rbase); + + switch (barrier) { +#ifndef SERIALGC + case BarrierSet::G1SATBCT: + case BarrierSet::G1SATBCTLogging: + { + // Load and record the previous value. + __ g1_write_barrier_pre(Rbase, offset, + Rtmp3, /* holder of pre_val ? */ + Rtmp1, Rtmp2, false /* frame */); + + Label Lnull, Ldone; + if (Rval != noreg) { + if (check_null) { + __ cmpdi(CCR0, Rval, 0); + __ beq(CCR0, Lnull); + } + __ store_heap_oop_not_null(Rval, offset, Rbase, /*Rval must stay uncompressed.*/ Rtmp1); + // Mark the card. + if (!(offset.is_constant() && offset.as_constant() == 0) && precise) { + __ add(Rbase, offset, Rbase); + } + __ g1_write_barrier_post(Rbase, Rval, Rtmp1, Rtmp2, Rtmp3, /*filtered (fast path)*/ &Ldone); + if (check_null) { __ b(Ldone); } + } + + if (Rval == noreg || check_null) { // Store null oop. + Register Rnull = Rval; + __ bind(Lnull); + if (Rval == noreg) { + Rnull = Rtmp1; + __ li(Rnull, 0); + } + if (UseCompressedOops) { + __ stw(Rnull, offset, Rbase); + } else { + __ std(Rnull, offset, Rbase); + } + } + __ bind(Ldone); + } + break; +#endif // SERIALGC + case BarrierSet::CardTableModRef: + case BarrierSet::CardTableExtension: + { + Label Lnull, Ldone; + if (Rval != noreg) { + if (check_null) { + __ cmpdi(CCR0, Rval, 0); + __ beq(CCR0, Lnull); + } + __ store_heap_oop_not_null(Rval, offset, Rbase, /*Rval should better stay uncompressed.*/ Rtmp1); + // Mark the card. + if (!(offset.is_constant() && offset.as_constant() == 0) && precise) { + __ add(Rbase, offset, Rbase); + } + __ card_write_barrier_post(Rbase, Rval, Rtmp1); + if (check_null) { + __ b(Ldone); + } + } + + if (Rval == noreg || check_null) { // Store null oop. + Register Rnull = Rval; + __ bind(Lnull); + if (Rval == noreg) { + Rnull = Rtmp1; + __ li(Rnull, 0); + } + if (UseCompressedOops) { + __ stw(Rnull, offset, Rbase); + } else { + __ std(Rnull, offset, Rbase); + } + } + __ bind(Ldone); + } + break; + case BarrierSet::ModRef: + case BarrierSet::Other: + ShouldNotReachHere(); + break; + default: + ShouldNotReachHere(); + } +} + +// ============================================================================ +// Platform-dependent initialization + +void TemplateTable::pd_initialize() { + // No ppc64 specific initialization. +} + +Address TemplateTable::at_bcp(int offset) { + // Not used on ppc. + ShouldNotReachHere(); + return Address(); +} + +// Patches the current bytecode (ptr to it located in bcp) +// in the bytecode stream with a new one. +void TemplateTable::patch_bytecode(Bytecodes::Code new_bc, Register Rnew_bc, Register Rtemp, bool load_bc_into_bc_reg /*=true*/, int byte_no) { + // With sharing on, may need to test methodOop flag. + if (!RewriteBytecodes) return; + Label L_patch_done; + + switch (new_bc) { + case Bytecodes::_fast_aputfield: + case Bytecodes::_fast_bputfield: + case Bytecodes::_fast_cputfield: + case Bytecodes::_fast_dputfield: + case Bytecodes::_fast_fputfield: + case Bytecodes::_fast_iputfield: + case Bytecodes::_fast_lputfield: + case Bytecodes::_fast_sputfield: + { + // We skip bytecode quickening for putfield instructions when + // the put_code written to the constant pool cache is zero. + // This is required so that every execution of this instruction + // calls out to InterpreterRuntime::resolve_get_put to do + // additional, required work. + assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); + assert(load_bc_into_bc_reg, "we use bc_reg as temp"); + __ get_cache_and_index_at_bcp(Rtemp /* dst = cache */, 1); + // Big Endian: ((*(cache+indices))>>((1+byte_no)*8))&0xFF + __ lbz(Rnew_bc, in_bytes(constantPoolCacheOopDesc::base_offset() + ConstantPoolCacheEntry::indices_offset()) + 7 - (1 + byte_no), Rtemp); + __ cmpwi(CCR0, Rnew_bc, 0); + __ li(Rnew_bc, (unsigned int)(unsigned char)new_bc); + __ beq(CCR0, L_patch_done); + // __ isync(); // acquire not needed + break; + } + + default: + assert(byte_no == -1, "sanity"); + if (load_bc_into_bc_reg) { + __ li(Rnew_bc, (unsigned int)(unsigned char)new_bc); + } + } + + if (JvmtiExport::can_post_breakpoint()) { + Label L_fast_patch; + __ lbz(Rtemp, 0, R14_bcp); + __ cmpwi(CCR0, Rtemp, (unsigned int)(unsigned char)Bytecodes::_breakpoint); + __ bne(CCR0, L_fast_patch); + // Perform the quickening, slowly, in the bowels of the breakpoint table. + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::set_original_bytecode_at), R19_method, R14_bcp, Rnew_bc); + __ b(L_patch_done); + __ bind(L_fast_patch); + } + + // Patch bytecode. + __ stb(Rnew_bc, 0, R14_bcp); + + __ bind(L_patch_done); +} + +// ============================================================================ +// Individual instructions + +void TemplateTable::nop() { + transition(vtos, vtos); + // Nothing to do. +} + +void TemplateTable::shouldnotreachhere() { + transition(vtos, vtos); + __ stop("shouldnotreachhere bytecode"); +} + +void TemplateTable::aconst_null() { + transition(vtos, atos); + __ li(R17_tos, 0); +} + +void TemplateTable::iconst(int value) { + transition(vtos, itos); + assert(value >= -1 && value <= 5, ""); + __ li(R17_tos, value); +} + +void TemplateTable::lconst(int value) { + transition(vtos, ltos); + assert(value >= -1 && value <= 5, ""); + __ li(R17_tos, value); +} + +void TemplateTable::fconst(int value) { + transition(vtos, ftos); + static float zero = 0.0; + static float one = 1.0; + static float two = 2.0; + switch (value) { + default: ShouldNotReachHere(); + case 0: { + int simm16_offset = __ load_const_optimized(R11_scratch1, (address*)&zero, R0); + __ lfs(F15_ftos, simm16_offset, R11_scratch1); + break; + } + case 1: { + int simm16_offset = __ load_const_optimized(R11_scratch1, (address*)&one, R0); + __ lfs(F15_ftos, simm16_offset, R11_scratch1); + break; + } + case 2: { + int simm16_offset = __ load_const_optimized(R11_scratch1, (address*)&two, R0); + __ lfs(F15_ftos, simm16_offset, R11_scratch1); + break; + } + } +} + +void TemplateTable::dconst(int value) { + transition(vtos, dtos); + static double zero = 0.0; + static double one = 1.0; + switch (value) { + case 0: { + int simm16_offset = __ load_const_optimized(R11_scratch1, (address*)&zero, R0); + __ lfd(F15_ftos, simm16_offset, R11_scratch1); + break; + } + case 1: { + int simm16_offset = __ load_const_optimized(R11_scratch1, (address*)&one, R0); + __ lfd(F15_ftos, simm16_offset, R11_scratch1); + break; + } + default: ShouldNotReachHere(); + } +} + +void TemplateTable::bipush() { + transition(vtos, itos); + __ lbz(R17_tos, 1, R14_bcp); + __ extsb(R17_tos, R17_tos); +} + +void TemplateTable::sipush() { + transition(vtos, itos); + __ get_2_byte_integer_at_bcp(1, R17_tos, InterpreterMacroAssembler::Signed); +} + +void TemplateTable::ldc(bool wide) { + Register Rscratch1 = R11_scratch1, + Rscratch2 = R12_scratch2, + Rcpool = R3_ARG1; + + transition(vtos, vtos); + Label notInt, notString, notClass, exit; + + __ get_cpool_and_tags(Rcpool, Rscratch2); // Set Rscratch2 = &tags. + if (wide) { // Read index. + __ get_2_byte_integer_at_bcp(1, Rscratch1, InterpreterMacroAssembler::Unsigned); + } else { + __ lbz(Rscratch1, 1, R14_bcp); + } + + const int base_offset = constantPoolOopDesc::header_size() * wordSize; + const int tags_offset = typeArrayOopDesc::header_size(T_BYTE) * wordSize; + + // Get type from tags. + __ addi(Rscratch2, Rscratch2, tags_offset); + __ lbzx(Rscratch2, Rscratch2, Rscratch1); + + __ cmpwi(CCR0, Rscratch2, JVM_CONSTANT_UnresolvedString); // Unresolved string? + __ cmpwi(CCR1, Rscratch2, JVM_CONSTANT_UnresolvedClass); // Unresolved class? + __ cror(/*CR0 eq*/2, /*CR1 eq*/4+2, /*CR0 eq*/2); + __ cmpwi(CCR1, Rscratch2, JVM_CONSTANT_UnresolvedClassInError); // Unresolved class in error state? + __ cror(/*CR0 eq*/2, /*CR1 eq*/4+2, /*CR0 eq*/2); + + // Resolved class - need to call vm to get java mirror of the class. + __ cmpwi(CCR1, Rscratch2, JVM_CONSTANT_Class); + __ crnor(/*CR0 eq*/2, /*CR1 eq*/4+2, /*CR0 eq*/2); // Neither resolved class nor unresolved case from above? + __ beq(CCR0, notClass); + + __ li(R4, wide ? 1 : 0); + call_VM(R17_tos, CAST_FROM_FN_PTR(address, InterpreterRuntime::ldc), R4); + __ push(atos); + __ b(exit); + + __ align(32, 12); + __ bind(notClass); + __ addi(Rcpool, Rcpool, base_offset); + __ sldi(Rscratch1, Rscratch1, LogBytesPerWord); + __ cmpdi(CCR0, Rscratch2, JVM_CONSTANT_Integer); + __ bne(CCR0, notInt); + __ isync(); // Order load of constant wrt. tags. + __ lwax(R17_tos, Rcpool, Rscratch1); + __ push(itos); + __ b(exit); + + __ align(32, 12); + __ bind(notInt); + __ cmpdi(CCR0, Rscratch2, JVM_CONSTANT_String); + __ cmpdi(CCR1, Rscratch2, JVM_CONSTANT_Object); + __ crnor(/*CR0 eq*/2, /*CR1 eq*/4+2, /*CR0 eq*/2); + __ beq(CCR0, notString); + + __ isync(); // order load of constant wrt. tags + __ ldx(R17_tos, Rcpool, Rscratch1); + __ verify_oop(R17_tos); + __ push(atos); + __ b(exit); + + __ bind(notString); +#ifdef ASSERT + // String and Object are rewritten to fast_aldc + __ cmpdi(CCR0, Rscratch2, JVM_CONSTANT_Float); + __ asm_assert_eq("unexpected type", 0x8765); +#endif + __ isync(); // Order load of constant wrt. tags. + __ lfsx(F15_ftos, Rcpool, Rscratch1); + __ push(ftos); + + __ align(32, 12); + __ bind(exit); +} + +// Fast path for caching oop constants. +void TemplateTable::fast_aldc(bool wide) { + transition(vtos, atos); + + if (!EnableInvokeDynamic) { + // We should not encounter this bytecode if !EnableInvokeDynamic. + // The verifier will stop it. However, if we get past the verifier, + // this will stop the thread in a reasonable way, without crashing the JVM. + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_IncompatibleClassChangeError)); + // The call_VM checks for exception, so we should never return here. + __ should_not_reach_here(); + return; + } + + Label Ldone, LRet0; + const Register Rcache = R3_ARG1, + Rscratch = R11_scratch1; + + resolve_cache_and_index(f12_oop, R17_tos, Rcache, Rscratch, wide ? sizeof(u2) : sizeof(u1)); + + __ verify_oop(R17_tos); + + const Register Rcon_klass = Rcache; + const Register Rarray_klass = R4_ARG2; + + int ary_kl_offs = __ load_const_optimized(Rarray_klass, (address)Universe::systemObjArrayKlassObj_addr(), Rscratch, true); + __ load_klass(Rcon_klass, R17_tos); + __ ld(Rarray_klass, ary_kl_offs, Rarray_klass); + + __ cmpd(CCR0, Rarray_klass, Rcon_klass); + __ bne(CCR0, Ldone); + + // Load array length. + __ lwz(Rcon_klass, arrayOopDesc::length_offset_in_bytes(), R17_tos); + __ cmpwi(CCR0, Rcon_klass, 0); + __ beq(CCR0, LRet0); + + __ load_heap_oop(R17_tos, arrayOopDesc::base_offset_in_bytes(T_OBJECT), R17_tos); + __ load_dispatch_table(R11_scratch1, (address*)Interpreter::throw_exception_entry()); + __ mtctr(R11_scratch1); + __ bctr(); + + __ bind(LRet0); + __ li(R17_tos, 0); + + __ bind(Ldone); +} + +void TemplateTable::ldc2_w() { + transition(vtos, vtos); + Label Llong, Lexit; + + Register Rindex = R11_scratch1, + Rcpool = R12_scratch2, + Rtag = R3_ARG1; + __ get_2_byte_integer_at_bcp(1, Rindex, InterpreterMacroAssembler::Unsigned); + __ get_cpool_and_tags(Rcpool, Rtag); + + const int base_offset = constantPoolOopDesc::header_size() * wordSize; + const int tags_offset = typeArrayOopDesc::header_size(T_BYTE) * wordSize; + // Get type from tags. + __ addi(Rcpool, Rcpool, base_offset); + __ addi(Rtag, Rtag, tags_offset); + + __ lbzx(Rtag, Rtag, Rindex); + + __ sldi(Rindex, Rindex, LogBytesPerWord); + __ cmpdi(CCR0, Rtag, JVM_CONSTANT_Double); + __ bne(CCR0, Llong); + // A double can be placed at word-aligned locations in the constant pool. + // Check out Conversions.java for an example. + // Also constantPoolOopDesc::header_size() is 20, which makes it very difficult + // to double-align double on the constant pool. SG, 11/7/97 + __ isync(); // Order load of constant wrt. tags. + __ lfdx(F15_ftos, Rcpool, Rindex); + __ push(dtos); + __ b(Lexit); + + __ bind(Llong); + __ isync(); // Order load of constant wrt. tags. + __ ldx(R17_tos, Rcpool, Rindex); + __ push(ltos); + + __ bind(Lexit); +} + +// Get the locals index located in the bytecode stream at bcp + offset. +void TemplateTable::locals_index(Register Rdst, int offset) { + __ lbz(Rdst, offset, R14_bcp); +} + +void TemplateTable::iload() { + transition(vtos, itos); + + // Get the local value into tos + const Register Rindex = R22_tmp2; + locals_index(Rindex); + + // Rewrite iload,iload pair into fast_iload2 + // iload,caload pair into fast_icaload + if (RewriteFrequentPairs) { + Label Lrewrite, Ldone; + Register Rnext_byte = R3_ARG1, + Rrewrite_to = R6_ARG4, + Rscratch = R11_scratch1; + + // get next byte + __ lbz(Rnext_byte, Bytecodes::length_for(Bytecodes::_iload), R14_bcp); + + // if _iload, wait to rewrite to iload2. We only want to rewrite the + // last two iloads in a pair. Comparing against fast_iload means that + // the next bytecode is neither an iload or a caload, and therefore + // an iload pair. + __ cmpwi(CCR0, Rnext_byte, (unsigned int)(unsigned char)Bytecodes::_iload); + __ beq(CCR0, Ldone); + + __ cmpwi(CCR1, Rnext_byte, (unsigned int)(unsigned char)Bytecodes::_fast_iload); + __ li(Rrewrite_to, (unsigned int)(unsigned char)Bytecodes::_fast_iload2); + __ beq(CCR1, Lrewrite); + + __ cmpwi(CCR0, Rnext_byte, (unsigned int)(unsigned char)Bytecodes::_caload); + __ li(Rrewrite_to, (unsigned int)(unsigned char)Bytecodes::_fast_icaload); + __ beq(CCR0, Lrewrite); + + __ li(Rrewrite_to, (unsigned int)(unsigned char)Bytecodes::_fast_iload); + + __ bind(Lrewrite); + patch_bytecode(Bytecodes::_iload, Rrewrite_to, Rscratch, false); + __ bind(Ldone); + } + + __ load_local_int(R17_tos, Rindex, Rindex); +} + +// Load 2 integers in a row without dispatching +void TemplateTable::fast_iload2() { + transition(vtos, itos); + + __ lbz(R3_ARG1, 1, R14_bcp); + __ lbz(R17_tos, Bytecodes::length_for(Bytecodes::_iload) + 1, R14_bcp); + + __ load_local_int(R3_ARG1, R11_scratch1, R3_ARG1); + __ load_local_int(R17_tos, R12_scratch2, R17_tos); + __ push_i(R3_ARG1); +} + +void TemplateTable::fast_iload() { + transition(vtos, itos); + // Get the local value into tos + + const Register Rindex = R11_scratch1; + locals_index(Rindex); + __ load_local_int(R17_tos, Rindex, Rindex); +} + +// Load a local variable type long from locals area to TOS cache register. +// Local index resides in bytecodestream. +void TemplateTable::lload() { + transition(vtos, ltos); + + const Register Rindex = R11_scratch1; + locals_index(Rindex); + __ load_local_long(R17_tos, Rindex, Rindex); +} + +void TemplateTable::fload() { + transition(vtos, ftos); + + const Register Rindex = R11_scratch1; + locals_index(Rindex); + __ load_local_float(F15_ftos, Rindex, Rindex); +} + +void TemplateTable::dload() { + transition(vtos, dtos); + + const Register Rindex = R11_scratch1; + locals_index(Rindex); + __ load_local_double(F15_ftos, Rindex, Rindex); +} + +void TemplateTable::aload() { + transition(vtos, atos); + + const Register Rindex = R11_scratch1; + locals_index(Rindex); + __ load_local_ptr(R17_tos, Rindex, Rindex); +} + +void TemplateTable::locals_index_wide(Register Rdst) { + // Offset is 2, not 1, because Lbcp points to wide prefix code. + __ get_2_byte_integer_at_bcp(2, Rdst, InterpreterMacroAssembler::Unsigned); +} + +void TemplateTable::wide_iload() { + // Get the local value into tos. + + const Register Rindex = R11_scratch1; + locals_index_wide(Rindex); + __ load_local_int(R17_tos, Rindex, Rindex); +} + +void TemplateTable::wide_lload() { + transition(vtos, ltos); + + const Register Rindex = R11_scratch1; + locals_index_wide(Rindex); + __ load_local_long(R17_tos, Rindex, Rindex); +} + +void TemplateTable::wide_fload() { + transition(vtos, ftos); + + const Register Rindex = R11_scratch1; + locals_index_wide(Rindex); + __ load_local_float(F15_ftos, Rindex, Rindex); +} + +void TemplateTable::wide_dload() { + transition(vtos, dtos); + + const Register Rindex = R11_scratch1; + locals_index_wide(Rindex); + __ load_local_double(F15_ftos, Rindex, Rindex); +} + +void TemplateTable::wide_aload() { + transition(vtos, atos); + + const Register Rindex = R11_scratch1; + locals_index_wide(Rindex); + __ load_local_ptr(R17_tos, Rindex, Rindex); +} + +void TemplateTable::iaload() { + transition(itos, itos); + + const Register Rload_addr = R3_ARG1, + Rarray = R4_ARG2, + Rtemp = R5_ARG3; + __ index_check(Rarray, R17_tos /* index */, LogBytesPerInt, Rtemp, Rload_addr); + __ lwa(R17_tos, arrayOopDesc::base_offset_in_bytes(T_INT), Rload_addr); +} + +void TemplateTable::laload() { + transition(itos, ltos); + + const Register Rload_addr = R3_ARG1, + Rarray = R4_ARG2, + Rtemp = R5_ARG3; + __ index_check(Rarray, R17_tos /* index */, LogBytesPerLong, Rtemp, Rload_addr); + __ ld(R17_tos, arrayOopDesc::base_offset_in_bytes(T_LONG), Rload_addr); +} + +void TemplateTable::faload() { + transition(itos, ftos); + + const Register Rload_addr = R3_ARG1, + Rarray = R4_ARG2, + Rtemp = R5_ARG3; + __ index_check(Rarray, R17_tos /* index */, LogBytesPerInt, Rtemp, Rload_addr); + __ lfs(F15_ftos, arrayOopDesc::base_offset_in_bytes(T_FLOAT), Rload_addr); +} + +void TemplateTable::daload() { + transition(itos, dtos); + + const Register Rload_addr = R3_ARG1, + Rarray = R4_ARG2, + Rtemp = R5_ARG3; + __ index_check(Rarray, R17_tos /* index */, LogBytesPerLong, Rtemp, Rload_addr); + __ lfd(F15_ftos, arrayOopDesc::base_offset_in_bytes(T_DOUBLE), Rload_addr); +} + +void TemplateTable::aaload() { + transition(itos, atos); + + // tos: index + // result tos: array + const Register Rload_addr = R3_ARG1, + Rarray = R4_ARG2, + Rtemp = R5_ARG3; + __ index_check(Rarray, R17_tos /* index */, UseCompressedOops ? 2 : LogBytesPerWord, Rtemp, Rload_addr); + __ load_heap_oop(R17_tos, arrayOopDesc::base_offset_in_bytes(T_OBJECT), Rload_addr); + __ verify_oop(R17_tos); + //__ dcbt(R17_tos); // prefetch +} + +void TemplateTable::baload() { + transition(itos, itos); + + const Register Rload_addr = R3_ARG1, + Rarray = R4_ARG2, + Rtemp = R5_ARG3; + __ index_check(Rarray, R17_tos /* index */, 0, Rtemp, Rload_addr); + __ lbz(R17_tos, arrayOopDesc::base_offset_in_bytes(T_BYTE), Rload_addr); + __ extsb(R17_tos, R17_tos); +} + +void TemplateTable::caload() { + transition(itos, itos); + + const Register Rload_addr = R3_ARG1, + Rarray = R4_ARG2, + Rtemp = R5_ARG3; + __ index_check(Rarray, R17_tos /* index */, LogBytesPerShort, Rtemp, Rload_addr); + __ lhz(R17_tos, arrayOopDesc::base_offset_in_bytes(T_CHAR), Rload_addr); +} + +// Iload followed by caload frequent pair. +void TemplateTable::fast_icaload() { + transition(vtos, itos); + + const Register Rload_addr = R3_ARG1, + Rarray = R4_ARG2, + Rtemp = R11_scratch1; + + locals_index(R17_tos); + __ load_local_int(R17_tos, Rtemp, R17_tos); + __ index_check(Rarray, R17_tos /* index */, LogBytesPerShort, Rtemp, Rload_addr); + __ lhz(R17_tos, arrayOopDesc::base_offset_in_bytes(T_CHAR), Rload_addr); +} + +void TemplateTable::saload() { + transition(itos, itos); + + const Register Rload_addr = R11_scratch1, + Rarray = R12_scratch2, + Rtemp = R3_ARG1; + __ index_check(Rarray, R17_tos /* index */, LogBytesPerShort, Rtemp, Rload_addr); + __ lha(R17_tos, arrayOopDesc::base_offset_in_bytes(T_SHORT), Rload_addr); +} + +void TemplateTable::iload(int n) { + transition(vtos, itos); + + __ lwz(R17_tos, Interpreter::local_offset_in_bytes(n), R18_locals); +} + +void TemplateTable::lload(int n) { + transition(vtos, ltos); + + __ ld(R17_tos, Interpreter::local_offset_in_bytes(n + 1), R18_locals); +} + +void TemplateTable::fload(int n) { + transition(vtos, ftos); + + __ lfs(F15_ftos, Interpreter::local_offset_in_bytes(n), R18_locals); +} + +void TemplateTable::dload(int n) { + transition(vtos, dtos); + + __ lfd(F15_ftos, Interpreter::local_offset_in_bytes(n + 1), R18_locals); +} + +void TemplateTable::aload(int n) { + transition(vtos, atos); + + __ ld(R17_tos, Interpreter::local_offset_in_bytes(n), R18_locals); +} + +void TemplateTable::aload_0() { + transition(vtos, atos); + // According to bytecode histograms, the pairs: + // + // _aload_0, _fast_igetfield + // _aload_0, _fast_agetfield + // _aload_0, _fast_fgetfield + // + // occur frequently. If RewriteFrequentPairs is set, the (slow) + // _aload_0 bytecode checks if the next bytecode is either + // _fast_igetfield, _fast_agetfield or _fast_fgetfield and then + // rewrites the current bytecode into a pair bytecode; otherwise it + // rewrites the current bytecode into _0 that doesn't do + // the pair check anymore. + // + // Note: If the next bytecode is _getfield, the rewrite must be + // delayed, otherwise we may miss an opportunity for a pair. + // + // Also rewrite frequent pairs + // aload_0, aload_1 + // aload_0, iload_1 + // These bytecodes with a small amount of code are most profitable + // to rewrite. + + if (RewriteFrequentPairs) { + + Label Lrewrite, Ldont_rewrite; + Register Rnext_byte = R3_ARG1, + Rrewrite_to = R6_ARG4, + Rscratch = R11_scratch1; + + // Get next byte. + __ lbz(Rnext_byte, Bytecodes::length_for(Bytecodes::_aload_0), R14_bcp); + + // If _getfield, wait to rewrite. We only want to rewrite the last two bytecodes in a pair. + __ cmpwi(CCR0, Rnext_byte, (unsigned int)(unsigned char)Bytecodes::_getfield); + __ beq(CCR0, Ldont_rewrite); + + __ cmpwi(CCR1, Rnext_byte, (unsigned int)(unsigned char)Bytecodes::_fast_igetfield); + __ li(Rrewrite_to, (unsigned int)(unsigned char)Bytecodes::_fast_iaccess_0); + __ beq(CCR1, Lrewrite); + + __ cmpwi(CCR0, Rnext_byte, (unsigned int)(unsigned char)Bytecodes::_fast_agetfield); + __ li(Rrewrite_to, (unsigned int)(unsigned char)Bytecodes::_fast_aaccess_0); + __ beq(CCR0, Lrewrite); + + __ cmpwi(CCR1, Rnext_byte, (unsigned int)(unsigned char)Bytecodes::_fast_fgetfield); + __ li(Rrewrite_to, (unsigned int)(unsigned char)Bytecodes::_fast_faccess_0); + __ beq(CCR1, Lrewrite); + + __ li(Rrewrite_to, (unsigned int)(unsigned char)Bytecodes::_fast_aload_0); + + __ bind(Lrewrite); + patch_bytecode(Bytecodes::_aload_0, Rrewrite_to, Rscratch, false); + __ bind(Ldont_rewrite); + } + + // Do actual aload_0 (must do this after patch_bytecode which might call VM and GC might change oop). + aload(0); +} + +void TemplateTable::istore() { + transition(itos, vtos); + + const Register Rindex = R11_scratch1; + locals_index(Rindex); + __ store_local_int(R17_tos, Rindex); +} + +void TemplateTable::lstore() { + transition(ltos, vtos); + const Register Rindex = R11_scratch1; + locals_index(Rindex); + __ store_local_long(R17_tos, Rindex); +} + +void TemplateTable::fstore() { + transition(ftos, vtos); + + const Register Rindex = R11_scratch1; + locals_index(Rindex); + __ store_local_float(F15_ftos, Rindex); +} + +void TemplateTable::dstore() { + transition(dtos, vtos); + + const Register Rindex = R11_scratch1; + locals_index(Rindex); + __ store_local_double(F15_ftos, Rindex); +} + +void TemplateTable::astore() { + transition(vtos, vtos); + + const Register Rindex = R11_scratch1; + __ pop_ptr(); + __ verify_oop_or_return_address(R17_tos, Rindex); + locals_index(Rindex); + __ store_local_ptr(R17_tos, Rindex); +} + +void TemplateTable::wide_istore() { + transition(vtos, vtos); + + const Register Rindex = R11_scratch1; + __ pop_i(); + locals_index_wide(Rindex); + __ store_local_int(R17_tos, Rindex); +} + +void TemplateTable::wide_lstore() { + transition(vtos, vtos); + + const Register Rindex = R11_scratch1; + __ pop_l(); + locals_index_wide(Rindex); + __ store_local_long(R17_tos, Rindex); +} + +void TemplateTable::wide_fstore() { + transition(vtos, vtos); + + const Register Rindex = R11_scratch1; + __ pop_f(); + locals_index_wide(Rindex); + __ store_local_float(F15_ftos, Rindex); +} + +void TemplateTable::wide_dstore() { + transition(vtos, vtos); + + const Register Rindex = R11_scratch1; + __ pop_d(); + locals_index_wide(Rindex); + __ store_local_double(F15_ftos, Rindex); +} + +void TemplateTable::wide_astore() { + transition(vtos, vtos); + + const Register Rindex = R11_scratch1; + __ pop_ptr(); + __ verify_oop_or_return_address(R17_tos, Rindex); + locals_index_wide(Rindex); + __ store_local_ptr(R17_tos, Rindex); +} + +void TemplateTable::iastore() { + transition(itos, vtos); + + const Register Rindex = R3_ARG1, + Rstore_addr = R4_ARG2, + Rarray = R5_ARG3, + Rtemp = R6_ARG4; + __ pop_i(Rindex); + __ index_check(Rarray, Rindex, LogBytesPerInt, Rtemp, Rstore_addr); + __ stw(R17_tos, arrayOopDesc::base_offset_in_bytes(T_INT), Rstore_addr); + } + +void TemplateTable::lastore() { + transition(ltos, vtos); + + const Register Rindex = R3_ARG1, + Rstore_addr = R4_ARG2, + Rarray = R5_ARG3, + Rtemp = R6_ARG4; + __ pop_i(Rindex); + __ index_check(Rarray, Rindex, LogBytesPerLong, Rtemp, Rstore_addr); + __ std(R17_tos, arrayOopDesc::base_offset_in_bytes(T_LONG), Rstore_addr); + } + +void TemplateTable::fastore() { + transition(ftos, vtos); + + const Register Rindex = R3_ARG1, + Rstore_addr = R4_ARG2, + Rarray = R5_ARG3, + Rtemp = R6_ARG4; + __ pop_i(Rindex); + __ index_check(Rarray, Rindex, LogBytesPerInt, Rtemp, Rstore_addr); + __ stfs(F15_ftos, arrayOopDesc::base_offset_in_bytes(T_FLOAT), Rstore_addr); + } + +void TemplateTable::dastore() { + transition(dtos, vtos); + + const Register Rindex = R3_ARG1, + Rstore_addr = R4_ARG2, + Rarray = R5_ARG3, + Rtemp = R6_ARG4; + __ pop_i(Rindex); + __ index_check(Rarray, Rindex, LogBytesPerLong, Rtemp, Rstore_addr); + __ stfd(F15_ftos, arrayOopDesc::base_offset_in_bytes(T_DOUBLE), Rstore_addr); + } + +// Pop 3 values from the stack and... +void TemplateTable::aastore() { + transition(vtos, vtos); + + Label Lstore_ok, Lis_null, Ldone; + const Register Rindex = R3_ARG1, + Rarray = R4_ARG2, + Rscratch = R11_scratch1, + Rscratch2 = R12_scratch2, + Rarray_klass = R5_ARG3, + Rarray_element_klass = Rarray_klass, + Rvalue_klass = R6_ARG4, + Rstore_addr = R31; // Use register which survives VM call. + + __ ld(R17_tos, Interpreter::expr_offset_in_bytes(0), R15_esp); // Get value to store. + __ lwz(Rindex, Interpreter::expr_offset_in_bytes(1), R15_esp); // Get index. + __ ld(Rarray, Interpreter::expr_offset_in_bytes(2), R15_esp); // Get array. + + __ verify_oop(R17_tos); + __ index_check_without_pop(Rarray, Rindex, UseCompressedOops ? 2 : LogBytesPerWord, Rscratch, Rstore_addr); + // Rindex is dead! + Register Rscratch3 = Rindex; + + // Do array store check - check for NULL value first. + __ cmpdi(CCR0, R17_tos, 0); + __ beq(CCR0, Lis_null); + + __ load_klass(Rarray_klass, Rarray); + __ load_klass(Rvalue_klass, R17_tos); + + // Do fast instanceof cache test. + __ ld(Rarray_element_klass, in_bytes(objArrayKlass::element_klass_offset()), Rarray_klass); + + // Generate a fast subtype check. Branch to store_ok if no failure. Throw if failure. + __ gen_subtype_check(Rvalue_klass /*subklass*/, Rarray_element_klass /*superklass*/, Rscratch, Rscratch2, Rscratch3, Lstore_ok); + + // Fell through: subtype check failed => throw an exception. + __ load_dispatch_table(R11_scratch1, (address*)Interpreter::_throw_ArrayStoreException_entry); + __ mtctr(R11_scratch1); + __ bctr(); + + __ bind(Lis_null); + do_oop_store(_masm, Rstore_addr, arrayOopDesc::base_offset_in_bytes(T_OBJECT), noreg /* 0 */, + Rscratch, Rscratch2, Rscratch3, _bs->kind(), true /* precise */, false /* check_null */); + __ profile_null_seen(Rscratch, Rscratch2); + __ b(Ldone); + + // Store is OK. + __ bind(Lstore_ok); + do_oop_store(_masm, Rstore_addr, arrayOopDesc::base_offset_in_bytes(T_OBJECT), R17_tos /* value */, + Rscratch, Rscratch2, Rscratch3, _bs->kind(), true /* precise */, false /* check_null */); + + __ bind(Ldone); + // Adjust sp (pops array, index and value). + __ addi(R15_esp, R15_esp, 3 * Interpreter::stackElementSize); +} + +void TemplateTable::bastore() { + transition(itos, vtos); + + const Register Rindex = R11_scratch1, + Rarray = R12_scratch2, + Rscratch = R3_ARG1; + __ pop_i(Rindex); + // tos: val + // Rarray: array ptr (popped by index_check) + __ index_check(Rarray, Rindex, 0, Rscratch, Rarray); + __ stb(R17_tos, arrayOopDesc::base_offset_in_bytes(T_BYTE), Rarray); +} + +void TemplateTable::castore() { + transition(itos, vtos); + + const Register Rindex = R11_scratch1, + Rarray = R12_scratch2, + Rscratch = R3_ARG1; + __ pop_i(Rindex); + // tos: val + // Rarray: array ptr (popped by index_check) + __ index_check(Rarray, Rindex, LogBytesPerShort, Rscratch, Rarray); + __ sth(R17_tos, arrayOopDesc::base_offset_in_bytes(T_CHAR), Rarray); +} + +void TemplateTable::sastore() { + castore(); +} + +void TemplateTable::istore(int n) { + transition(itos, vtos); + __ stw(R17_tos, Interpreter::local_offset_in_bytes(n), R18_locals); +} + +void TemplateTable::lstore(int n) { + transition(ltos, vtos); + __ std(R17_tos, Interpreter::local_offset_in_bytes(n + 1), R18_locals); +} + +void TemplateTable::fstore(int n) { + transition(ftos, vtos); + __ stfs(F15_ftos, Interpreter::local_offset_in_bytes(n), R18_locals); +} + +void TemplateTable::dstore(int n) { + transition(dtos, vtos); + __ stfd(F15_ftos, Interpreter::local_offset_in_bytes(n + 1), R18_locals); +} + +void TemplateTable::astore(int n) { + transition(vtos, vtos); + + __ pop_ptr(); + __ verify_oop_or_return_address(R17_tos, R11_scratch1); + __ std(R17_tos, Interpreter::local_offset_in_bytes(n), R18_locals); +} + +void TemplateTable::pop() { + transition(vtos, vtos); + + __ addi(R15_esp, R15_esp, Interpreter::stackElementSize); +} + +void TemplateTable::pop2() { + transition(vtos, vtos); + + __ addi(R15_esp, R15_esp, Interpreter::stackElementSize * 2); +} + +void TemplateTable::dup() { + transition(vtos, vtos); + + __ ld(R11_scratch1, Interpreter::stackElementSize, R15_esp); + __ push_ptr(R11_scratch1); +} + +void TemplateTable::dup_x1() { + transition(vtos, vtos); + + Register Ra = R11_scratch1, + Rb = R12_scratch2; + // stack: ..., a, b + __ ld(Rb, Interpreter::stackElementSize, R15_esp); + __ ld(Ra, Interpreter::stackElementSize * 2, R15_esp); + __ std(Rb, Interpreter::stackElementSize * 2, R15_esp); + __ std(Ra, Interpreter::stackElementSize, R15_esp); + __ push_ptr(Rb); + // stack: ..., b, a, b +} + +void TemplateTable::dup_x2() { + transition(vtos, vtos); + + Register Ra = R11_scratch1, + Rb = R12_scratch2, + Rc = R3_ARG1; + + // stack: ..., a, b, c + __ ld(Rc, Interpreter::stackElementSize, R15_esp); // load c + __ ld(Ra, Interpreter::stackElementSize * 3, R15_esp); // load a + __ std(Rc, Interpreter::stackElementSize * 3, R15_esp); // store c in a + __ ld(Rb, Interpreter::stackElementSize * 2, R15_esp); // load b + // stack: ..., c, b, c + __ std(Ra, Interpreter::stackElementSize * 2, R15_esp); // store a in b + // stack: ..., c, a, c + __ std(Rb, Interpreter::stackElementSize, R15_esp); // store b in c + __ push_ptr(Rc); // push c + // stack: ..., c, a, b, c +} + +void TemplateTable::dup2() { + transition(vtos, vtos); + + Register Ra = R11_scratch1, + Rb = R12_scratch2; + // stack: ..., a, b + __ ld(Rb, Interpreter::stackElementSize, R15_esp); + __ ld(Ra, Interpreter::stackElementSize * 2, R15_esp); + __ push_2ptrs(Ra, Rb); + // stack: ..., a, b, a, b +} + +void TemplateTable::dup2_x1() { + transition(vtos, vtos); + + Register Ra = R11_scratch1, + Rb = R12_scratch2, + Rc = R3_ARG1; + // stack: ..., a, b, c + __ ld(Rc, Interpreter::stackElementSize, R15_esp); + __ ld(Rb, Interpreter::stackElementSize * 2, R15_esp); + __ std(Rc, Interpreter::stackElementSize * 2, R15_esp); + __ ld(Ra, Interpreter::stackElementSize * 3, R15_esp); + __ std(Ra, Interpreter::stackElementSize, R15_esp); + __ std(Rb, Interpreter::stackElementSize * 3, R15_esp); + // stack: ..., b, c, a + __ push_2ptrs(Rb, Rc); + // stack: ..., b, c, a, b, c +} + +void TemplateTable::dup2_x2() { + transition(vtos, vtos); + + Register Ra = R11_scratch1, + Rb = R12_scratch2, + Rc = R3_ARG1, + Rd = R4_ARG2; + // stack: ..., a, b, c, d + __ ld(Rb, Interpreter::stackElementSize * 3, R15_esp); + __ ld(Rd, Interpreter::stackElementSize, R15_esp); + __ std(Rb, Interpreter::stackElementSize, R15_esp); // store b in d + __ std(Rd, Interpreter::stackElementSize * 3, R15_esp); // store d in b + __ ld(Ra, Interpreter::stackElementSize * 4, R15_esp); + __ ld(Rc, Interpreter::stackElementSize * 2, R15_esp); + __ std(Ra, Interpreter::stackElementSize * 2, R15_esp); // store a in c + __ std(Rc, Interpreter::stackElementSize * 4, R15_esp); // store c in a + // stack: ..., c, d, a, b + __ push_2ptrs(Rc, Rd); + // stack: ..., c, d, a, b, c, d +} + +void TemplateTable::swap() { + transition(vtos, vtos); + // stack: ..., a, b + + Register Ra = R11_scratch1, + Rb = R12_scratch2; + // stack: ..., a, b + __ ld(Rb, Interpreter::stackElementSize, R15_esp); + __ ld(Ra, Interpreter::stackElementSize * 2, R15_esp); + __ std(Rb, Interpreter::stackElementSize * 2, R15_esp); + __ std(Ra, Interpreter::stackElementSize, R15_esp); + // stack: ..., b, a +} + +void TemplateTable::iop2(Operation op) { + transition(itos, itos); + + Register Rscratch = R11_scratch1; + + __ pop_i(Rscratch); + // tos = number of bits to shift + // Rscratch = value to shift + switch (op) { + case add: __ add(R17_tos, Rscratch, R17_tos); break; + case sub: __ sub(R17_tos, Rscratch, R17_tos); break; + case mul: __ mullw(R17_tos, Rscratch, R17_tos); break; + case _and: __ andr(R17_tos, Rscratch, R17_tos); break; + case _or: __ orr(R17_tos, Rscratch, R17_tos); break; + case _xor: __ xorr(R17_tos, Rscratch, R17_tos); break; + case shl: __ rldicl(R17_tos, R17_tos, 0, 64-5); __ slw(R17_tos, Rscratch, R17_tos); break; + case shr: __ rldicl(R17_tos, R17_tos, 0, 64-5); __ sraw(R17_tos, Rscratch, R17_tos); break; + case ushr: __ rldicl(R17_tos, R17_tos, 0, 64-5); __ srw(R17_tos, Rscratch, R17_tos); break; + default: ShouldNotReachHere(); + } +} + +void TemplateTable::lop2(Operation op) { + transition(ltos, ltos); + + Register Rscratch = R11_scratch1; + __ pop_l(Rscratch); + switch (op) { + case add: __ add(R17_tos, Rscratch, R17_tos); break; + case sub: __ sub(R17_tos, Rscratch, R17_tos); break; + case _and: __ andr(R17_tos, Rscratch, R17_tos); break; + case _or: __ orr(R17_tos, Rscratch, R17_tos); break; + case _xor: __ xorr(R17_tos, Rscratch, R17_tos); break; + default: ShouldNotReachHere(); + } +} + +void TemplateTable::idiv() { + transition(itos, itos); + + Label Lnormal, Lexception, Ldone; + Register Rdividend = R11_scratch1; // Used by irem. + + __ addi(R0, R17_tos, 1); + __ cmplwi(CCR0, R0, 2); + __ bgt(CCR0, Lnormal); // divisor <-1 or >1 + + __ cmpwi(CCR1, R17_tos, 0); + __ beq(CCR1, Lexception); // divisor == 0 + + __ pop_i(Rdividend); + __ mullw(R17_tos, Rdividend, R17_tos); // div by +/-1 + __ b(Ldone); + + __ bind(Lexception); + __ load_dispatch_table(R11_scratch1, (address*)Interpreter::_throw_ArithmeticException_entry); + __ mtctr(R11_scratch1); + __ bctr(); + + __ align(32, 12); + __ bind(Lnormal); + __ pop_i(Rdividend); + __ divw(R17_tos, Rdividend, R17_tos); // Can't divide minint/-1. + __ bind(Ldone); +} + +void TemplateTable::irem() { + transition(itos, itos); + + __ mr(R12_scratch2, R17_tos); + idiv(); + __ mullw(R17_tos, R17_tos, R12_scratch2); + __ subf(R17_tos, R17_tos, R11_scratch1); // Dividend set by idiv. +} + +void TemplateTable::lmul() { + transition(ltos, ltos); + + __ pop_l(R11_scratch1); + __ mulld(R17_tos, R11_scratch1, R17_tos); +} + +void TemplateTable::ldiv() { + transition(ltos, ltos); + + Label Lnormal, Lexception, Ldone; + Register Rdividend = R11_scratch1; // Used by lrem. + + __ addi(R0, R17_tos, 1); + __ cmpldi(CCR0, R0, 2); + __ bgt(CCR0, Lnormal); // divisor <-1 or >1 + + __ cmpdi(CCR1, R17_tos, 0); + __ beq(CCR1, Lexception); // divisor == 0 + + __ pop_l(Rdividend); + __ mulld(R17_tos, Rdividend, R17_tos); // div by +/-1 + __ b(Ldone); + + __ bind(Lexception); + __ load_dispatch_table(R11_scratch1, (address*)Interpreter::_throw_ArithmeticException_entry); + __ mtctr(R11_scratch1); + __ bctr(); + + __ align(32, 12); + __ bind(Lnormal); + __ pop_l(Rdividend); + __ divd(R17_tos, Rdividend, R17_tos); // Can't divide minint/-1. + __ bind(Ldone); +} + +void TemplateTable::lrem() { + transition(ltos, ltos); + + __ mr(R12_scratch2, R17_tos); + ldiv(); + __ mulld(R17_tos, R17_tos, R12_scratch2); + __ subf(R17_tos, R17_tos, R11_scratch1); // Dividend set by ldiv. +} + +void TemplateTable::lshl() { + transition(itos, ltos); + + __ rldicl(R17_tos, R17_tos, 0, 64-6); // Extract least significant bits. + __ pop_l(R11_scratch1); + __ sld(R17_tos, R11_scratch1, R17_tos); +} + +void TemplateTable::lshr() { + transition(itos, ltos); + + __ rldicl(R17_tos, R17_tos, 0, 64-6); // Extract least significant bits. + __ pop_l(R11_scratch1); + __ srad(R17_tos, R11_scratch1, R17_tos); +} + +void TemplateTable::lushr() { + transition(itos, ltos); + + __ rldicl(R17_tos, R17_tos, 0, 64-6); // Extract least significant bits. + __ pop_l(R11_scratch1); + __ srd(R17_tos, R11_scratch1, R17_tos); +} + +void TemplateTable::fop2(Operation op) { + transition(ftos, ftos); + + switch (op) { + case add: __ pop_f(F0_SCRATCH); __ fadds(F15_ftos, F0_SCRATCH, F15_ftos); break; + case sub: __ pop_f(F0_SCRATCH); __ fsubs(F15_ftos, F0_SCRATCH, F15_ftos); break; + case mul: __ pop_f(F0_SCRATCH); __ fmuls(F15_ftos, F0_SCRATCH, F15_ftos); break; + case div: __ pop_f(F0_SCRATCH); __ fdivs(F15_ftos, F0_SCRATCH, F15_ftos); break; + case rem: + __ pop_f(F1_ARG1); + __ fmr(F2_ARG2, F15_ftos); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::frem)); + __ fmr(F15_ftos, F1_RET); + break; + + default: ShouldNotReachHere(); + } +} + +void TemplateTable::dop2(Operation op) { + transition(dtos, dtos); + + switch (op) { + case add: __ pop_d(F0_SCRATCH); __ fadd(F15_ftos, F0_SCRATCH, F15_ftos); break; + case sub: __ pop_d(F0_SCRATCH); __ fsub(F15_ftos, F0_SCRATCH, F15_ftos); break; + case mul: __ pop_d(F0_SCRATCH); __ fmul(F15_ftos, F0_SCRATCH, F15_ftos); break; + case div: __ pop_d(F0_SCRATCH); __ fdiv(F15_ftos, F0_SCRATCH, F15_ftos); break; + case rem: + __ pop_d(F1_ARG1); + __ fmr(F2_ARG2, F15_ftos); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::drem)); + __ fmr(F15_ftos, F1_RET); + break; + + default: ShouldNotReachHere(); + } +} + +// Negate the value in the TOS cache. +void TemplateTable::ineg() { + transition(itos, itos); + + __ neg(R17_tos, R17_tos); +} + +// Negate the value in the TOS cache. +void TemplateTable::lneg() { + transition(ltos, ltos); + + __ neg(R17_tos, R17_tos); +} + +void TemplateTable::fneg() { + transition(ftos, ftos); + + __ fneg(F15_ftos, F15_ftos); +} + +void TemplateTable::dneg() { + transition(dtos, dtos); + + __ fneg(F15_ftos, F15_ftos); +} + +// Increments a local variable in place. +void TemplateTable::iinc() { + transition(vtos, vtos); + + const Register Rindex = R11_scratch1, + Rincrement = R0, + Rvalue = R12_scratch2; + + locals_index(Rindex); // Load locals index from bytecode stream. + __ lbz(Rincrement, 2, R14_bcp); // Load increment from the bytecode stream. + __ extsb(Rincrement, Rincrement); + + __ load_local_int(Rvalue, Rindex, Rindex); // Puts address of local into Rindex. + + __ add(Rvalue, Rincrement, Rvalue); + __ stw(Rvalue, 0, Rindex); +} + +void TemplateTable::wide_iinc() { + transition(vtos, vtos); + + Register Rindex = R11_scratch1, + Rlocals_addr = Rindex, + Rincr = R12_scratch2; + locals_index_wide(Rindex); + __ get_2_byte_integer_at_bcp(4, Rincr, InterpreterMacroAssembler::Signed); + __ load_local_int(R17_tos, Rlocals_addr, Rindex); + __ add(R17_tos, Rincr, R17_tos); + __ stw(R17_tos, 0, Rlocals_addr); +} + +void TemplateTable::convert() { + // %%%%% Factor this first part accross platforms +#ifdef ASSERT + TosState tos_in = ilgl; + TosState tos_out = ilgl; + switch (bytecode()) { + case Bytecodes::_i2l: // fall through + case Bytecodes::_i2f: // fall through + case Bytecodes::_i2d: // fall through + case Bytecodes::_i2b: // fall through + case Bytecodes::_i2c: // fall through + case Bytecodes::_i2s: tos_in = itos; break; + case Bytecodes::_l2i: // fall through + case Bytecodes::_l2f: // fall through + case Bytecodes::_l2d: tos_in = ltos; break; + case Bytecodes::_f2i: // fall through + case Bytecodes::_f2l: // fall through + case Bytecodes::_f2d: tos_in = ftos; break; + case Bytecodes::_d2i: // fall through + case Bytecodes::_d2l: // fall through + case Bytecodes::_d2f: tos_in = dtos; break; + default : ShouldNotReachHere(); + } + switch (bytecode()) { + case Bytecodes::_l2i: // fall through + case Bytecodes::_f2i: // fall through + case Bytecodes::_d2i: // fall through + case Bytecodes::_i2b: // fall through + case Bytecodes::_i2c: // fall through + case Bytecodes::_i2s: tos_out = itos; break; + case Bytecodes::_i2l: // fall through + case Bytecodes::_f2l: // fall through + case Bytecodes::_d2l: tos_out = ltos; break; + case Bytecodes::_i2f: // fall through + case Bytecodes::_l2f: // fall through + case Bytecodes::_d2f: tos_out = ftos; break; + case Bytecodes::_i2d: // fall through + case Bytecodes::_l2d: // fall through + case Bytecodes::_f2d: tos_out = dtos; break; + default : ShouldNotReachHere(); + } + transition(tos_in, tos_out); +#endif + + // Conversion + Label done; + switch (bytecode()) { + case Bytecodes::_i2l: + __ extsw(R17_tos, R17_tos); + break; + + case Bytecodes::_l2i: + // Nothing to do, we'll continue to work with the lower bits. + break; + + case Bytecodes::_i2b: + __ extsb(R17_tos, R17_tos); + break; + + case Bytecodes::_i2c: + __ rldicl(R17_tos, R17_tos, 0, 64-2*8); + break; + + case Bytecodes::_i2s: + __ extsh(R17_tos, R17_tos); + break; + + case Bytecodes::_i2d: + __ extsw(R17_tos, R17_tos); + case Bytecodes::_l2d: + __ push_l_pop_d(); + __ fcfid(F15_ftos, F15_ftos); + break; + + case Bytecodes::_i2f: + __ extsw(R17_tos, R17_tos); + __ push_l_pop_d(); + if (VM_Version::has_fcfids()) { // fcfids is >= Power7 only + // Comment: alternatively, load with sign extend could be done by lfiwax. + __ fcfids(F15_ftos, F15_ftos); + } else { + __ fcfid(F15_ftos, F15_ftos); + __ frsp(F15_ftos, F15_ftos); + } + break; + + case Bytecodes::_l2f: + if (VM_Version::has_fcfids()) { // fcfids is >= Power7 only + __ push_l_pop_d(); + __ fcfids(F15_ftos, F15_ftos); + } else { + // Avoid rounding problem when result should be 0x3f800001: need fixup code before fcfid+frsp. + __ mr(R3_ARG1, R17_tos); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::l2f)); + __ fmr(F15_ftos, F1_RET); + } + break; + + case Bytecodes::_f2d: + // empty + break; + + case Bytecodes::_d2f: + __ frsp(F15_ftos, F15_ftos); + break; + + case Bytecodes::_d2i: + case Bytecodes::_f2i: + __ fcmpu(CCR0, F15_ftos, F15_ftos); + __ li(R17_tos, 0); // 0 in case of NAN + __ bso(CCR0, done); + __ fctiwz(F15_ftos, F15_ftos); + __ push_d_pop_l(); + break; + + case Bytecodes::_d2l: + case Bytecodes::_f2l: + __ fcmpu(CCR0, F15_ftos, F15_ftos); + __ li(R17_tos, 0); // 0 in case of NAN + __ bso(CCR0, done); + __ fctidz(F15_ftos, F15_ftos); + __ push_d_pop_l(); + break; + + default: ShouldNotReachHere(); + } + __ bind(done); +} + +// Long compare +void TemplateTable::lcmp() { + transition(ltos, itos); + + const Register Rscratch = R11_scratch1; + __ pop_l(Rscratch); // first operand, deeper in stack + + __ cmpd(CCR0, Rscratch, R17_tos); // compare + __ mfcr(R17_tos); // set bit 32..33 as follows: <: 0b10, =: 0b00, >: 0b01 + __ srwi(Rscratch, R17_tos, 30); + __ srawi(R17_tos, R17_tos, 31); + __ orr(R17_tos, Rscratch, R17_tos); // set result as follows: <: -1, =: 0, >: 1 +} + +// fcmpl/fcmpg and dcmpl/dcmpg bytecodes +// unordered_result == -1 => fcmpl or dcmpl +// unordered_result == 1 => fcmpg or dcmpg +void TemplateTable::float_cmp(bool is_float, int unordered_result) { + const FloatRegister Rfirst = F0_SCRATCH, + Rsecond = F15_ftos; + const Register Rscratch = R11_scratch1; + + if (is_float) { + __ pop_f(Rfirst); + } else { + __ pop_d(Rfirst); + } + + Label Lunordered, Ldone; + __ fcmpu(CCR0, Rfirst, Rsecond); // compare + if (unordered_result) { + __ bso(CCR0, Lunordered); + } + __ mfcr(R17_tos); // set bit 32..33 as follows: <: 0b10, =: 0b00, >: 0b01 + __ srwi(Rscratch, R17_tos, 30); + __ srawi(R17_tos, R17_tos, 31); + __ orr(R17_tos, Rscratch, R17_tos); // set result as follows: <: -1, =: 0, >: 1 + if (unordered_result) { + __ b(Ldone); + __ bind(Lunordered); + __ load_const_optimized(R17_tos, unordered_result); + } + __ bind(Ldone); +} + +// Branch_conditional which takes TemplateTable::Condition. +void TemplateTable::branch_conditional(ConditionRegister crx, TemplateTable::Condition cc, Label& L, bool invert) { + bool positive = false; + Assembler::Condition cond = Assembler::equal; + switch (cc) { + case TemplateTable::equal: positive = true ; cond = Assembler::equal ; break; + case TemplateTable::not_equal: positive = false; cond = Assembler::equal ; break; + case TemplateTable::less: positive = true ; cond = Assembler::less ; break; + case TemplateTable::less_equal: positive = false; cond = Assembler::greater; break; + case TemplateTable::greater: positive = true ; cond = Assembler::greater; break; + case TemplateTable::greater_equal: positive = false; cond = Assembler::less ; break; + default: ShouldNotReachHere(); + } + int bo = (positive != invert) ? Assembler::bcondCRbiIs1 : Assembler::bcondCRbiIs0; + int bi = Assembler::bi0(crx, cond); + __ bc(bo, bi, L); +} + +void TemplateTable::branch(bool is_jsr, bool is_wide) { + + // Note: on SPARC, we use InterpreterMacroAssembler::if_cmp also. + __ verify_oop(R19_method); + __ verify_thread(); + + const Register Rscratch1 = R11_scratch1, + Rscratch2 = R12_scratch2, + Rscratch3 = R3_ARG1, + R4_counters = R4_ARG2, + bumped_count = R31, + Rdisp = R22_tmp2; + + __ profile_taken_branch(Rscratch1, bumped_count); + + // Get (wide) offset. + if (is_wide) { + __ get_4_byte_integer_at_bcp(1, Rdisp, InterpreterMacroAssembler::Signed); + } else { + __ get_2_byte_integer_at_bcp(1, Rdisp, InterpreterMacroAssembler::Signed); + } + + // -------------------------------------------------------------------------- + // Handle all the JSR stuff here, then exit. + // It's much shorter and cleaner than intermingling with the + // non-JSR normal-branch stuff occurring below. + if (is_jsr) { + // Compute return address as bci in Otos_i. + __ ld(Rscratch1, in_bytes(methodOopDesc::const_offset()), R19_method); + __ addi(Rscratch2, R14_bcp, -in_bytes(constMethodOopDesc::codes_offset()) + (is_wide ? 5 : 3)); + __ subf(R17_tos, Rscratch1, Rscratch2); + + // Bump bcp to target of JSR. + __ add(R14_bcp, Rdisp, R14_bcp); + // Push returnAddress for "ret" on stack. + __ push_ptr(R17_tos); + // And away we go! + __ dispatch_next(vtos); + return; + } + + // -------------------------------------------------------------------------- + // Normal (non-jsr) branch handling + + 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. + + // Check branch direction. + __ cmpdi(CCR0, Rdisp, 0); + __ bgt(CCR0, Lforward); + + //__ get_method_counters(R19_method, R4_counters, Lforward); + + 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; + + // If no method data exists, go to profile_continue. + __ ld(Rmdo, in_bytes(methodOopDesc::method_data_offset()), R19_method); + __ cmpdi(CCR0, Rmdo, 0); + __ beq(CCR0, Lno_mdo); + + // Increment backedge counter in the MDO. + const int mdo_bc_offs = in_bytes(methodDataOopDesc::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset()); + __ lwz(Rscratch2, mdo_bc_offs, Rmdo); + __ load_const_optimized(Rscratch3, mask, R0); + __ addi(Rscratch2, Rscratch2, increment); + __ stw(Rscratch2, mdo_bc_offs, Rmdo); + __ and_(Rscratch3, Rscratch2, Rscratch3); + __ bne(CCR0, Lforward); + __ b(Loverflow); + } + + // If there's no MDO, increment counter in methodOop. + const int mo_bc_offs = in_bytes(methodOopDesc::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset()); + __ bind(Lno_mdo); + __ lwz(Rscratch2, mo_bc_offs, R19_method); + __ load_const_optimized(Rscratch3, mask, R0); + __ addi(Rscratch2, Rscratch2, increment); + __ stw(Rscratch2, mo_bc_offs, R19_method); + __ 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); + + // Was an OSR adapter generated? + // O0 = osr nmethod + __ cmpdi(CCR0, R3_RET, 0); + __ beq(CCR0, Lforward); + + // Has the nmethod been invalidated already? + __ lwz(R0, nmethod::entry_bci_offset(), R3_RET); + __ cmpwi(CCR0, R0, InvalidOSREntryBci); + __ beq(CCR0, Lforward); + + // Migrate the interpreter frame off of the stack. + // We can use all registers because we will not return to interpreter from this point. + + // Save nmethod. + const Register osr_nmethod = R31; + __ mr(osr_nmethod, R3_RET); + __ set_top_ijava_frame_at_SP_as_last_Java_frame(R1_SP, R11_scratch1); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::OSR_migration_begin), R16_thread); + __ reset_last_Java_frame(); + // OSR buffer is in ARG1. + + // Remove the interpreter frame. + __ merge_frames(/*top_frame_sp*/ R21_sender_SP, /*return_pc*/ R0, R11_scratch1, R12_scratch2); + + // Jump to the osr code. + __ ld(R11_scratch1, nmethod::osr_entry_point_offset(), osr_nmethod); + __ mtlr(R0); + __ mtctr(R11_scratch1); + __ bctr(); + + } else { + + const Register invoke_ctr = Rscratch1; + // Update Backedge branch separately from invocations. + __ increment_backedge_counter(invoke_ctr, Rscratch2, Rscratch3); + + if (ProfileInterpreter) { + __ test_invocation_counter_for_mdp(invoke_ctr, Rscratch2, Lforward); + if (UseOnStackReplacement) { + __ test_backedge_count_for_osr(bumped_count, R14_bcp, Rscratch2); + } + } else { + if (UseOnStackReplacement) { + __ test_backedge_count_for_osr(invoke_ctr, R14_bcp, Rscratch2); + } + } + } + + __ bind(Lforward); + + } else { + // Bump bytecode pointer by displacement (take the branch). + __ add(R14_bcp, Rdisp, R14_bcp); // Add to bc addr. + } + // 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. +// Factored out common compare and branch code. +void TemplateTable::if_cmp_common(Register Rfirst, Register Rsecond, Register Rscratch1, Register Rscratch2, Condition cc, bool is_jint, bool cmp0) { + Label Lnot_taken; + // Note: The condition code we get is the condition under which we + // *fall through*! So we have to inverse the CC here. + + if (is_jint) { + if (cmp0) { + __ cmpwi(CCR0, Rfirst, 0); + } else { + __ cmpw(CCR0, Rfirst, Rsecond); + } + } else { + if (cmp0) { + __ cmpdi(CCR0, Rfirst, 0); + } else { + __ cmpd(CCR0, Rfirst, Rsecond); + } + } + branch_conditional(CCR0, cc, Lnot_taken, /*invert*/ true); + + // Conition is false => Jump! + branch(false, false); + + // Condition is not true => Continue. + __ align(32, 12); + __ bind(Lnot_taken); + __ profile_not_taken_branch(Rscratch1, Rscratch2); +} + +// Compare integer values with zero and fall through if CC holds, branch away otherwise. +void TemplateTable::if_0cmp(Condition cc) { + transition(itos, vtos); + + if_cmp_common(R17_tos, noreg, R11_scratch1, R12_scratch2, cc, true, true); +} + +// Compare integer values and fall through if CC holds, branch away otherwise. +// +// Interface: +// - Rfirst: First operand (older stack value) +// - tos: Second operand (younger stack value) +void TemplateTable::if_icmp(Condition cc) { + transition(itos, vtos); + + const Register Rfirst = R0, + Rsecond = R17_tos; + + __ pop_i(Rfirst); + if_cmp_common(Rfirst, Rsecond, R11_scratch1, R12_scratch2, cc, true, false); +} + +void TemplateTable::if_nullcmp(Condition cc) { + transition(atos, vtos); + + if_cmp_common(R17_tos, noreg, R11_scratch1, R12_scratch2, cc, false, true); +} + +void TemplateTable::if_acmp(Condition cc) { + transition(atos, vtos); + + const Register Rfirst = R0, + Rsecond = R17_tos; + + __ pop_ptr(Rfirst); + if_cmp_common(Rfirst, Rsecond, R11_scratch1, R12_scratch2, cc, false, false); +} + +void TemplateTable::ret() { + locals_index(R11_scratch1); + __ load_local_ptr(R17_tos, R11_scratch1, R11_scratch1); + + __ profile_ret(vtos, R17_tos, R11_scratch1, R12_scratch2); + + __ ld(R11_scratch1, in_bytes(methodOopDesc::const_offset()), R19_method); + __ add(R11_scratch1, R17_tos, R11_scratch1); + __ addi(R14_bcp, R11_scratch1, in_bytes(constMethodOopDesc::codes_offset())); + __ dispatch_next(vtos); +} + +void TemplateTable::wide_ret() { + transition(vtos, vtos); + + const Register Rindex = R3_ARG1, + Rscratch1 = R11_scratch1, + Rscratch2 = R12_scratch2; + + locals_index_wide(Rindex); + __ load_local_ptr(R17_tos, R17_tos, Rindex); + __ profile_ret(vtos, R17_tos, Rscratch1, R12_scratch2); + // Tos now contains the bci, compute the bcp from that. + __ ld(Rscratch1, in_bytes(methodOopDesc::const_offset()), R19_method); + __ addi(Rscratch2, R17_tos, in_bytes(constMethodOopDesc::codes_offset())); + __ add(R14_bcp, Rscratch1, Rscratch2); + __ dispatch_next(vtos); +} + +void TemplateTable::tableswitch() { + transition(itos, vtos); + + Label Ldispatch, Ldefault_case; + Register Rlow_byte = R3_ARG1, + Rindex = Rlow_byte, + Rhigh_byte = R4_ARG2, + Rdef_offset_addr = R5_ARG3, // is going to contain address of default offset + Rscratch1 = R11_scratch1, + Rscratch2 = R12_scratch2, + Roffset = R6_ARG4; + + // Align bcp. + __ addi(Rdef_offset_addr, R14_bcp, BytesPerInt); + __ clrrdi(Rdef_offset_addr, Rdef_offset_addr, log2_long((jlong)BytesPerInt)); + + // Load lo & hi. + __ lwz(Rlow_byte, BytesPerInt, Rdef_offset_addr); + __ lwz(Rhigh_byte, BytesPerInt * 2, Rdef_offset_addr); + + // Check for default case (=index outside [low,high]). + __ cmpw(CCR0, R17_tos, Rlow_byte); + __ cmpw(CCR1, R17_tos, Rhigh_byte); + __ blt(CCR0, Ldefault_case); + __ bgt(CCR1, Ldefault_case); + + // Lookup dispatch offset. + __ sub(Rindex, R17_tos, Rlow_byte); + __ extsw(Rindex, Rindex); + __ profile_switch_case(Rindex, Rhigh_byte /* scratch */, Rscratch1, Rscratch2); + __ sldi(Rindex, Rindex, LogBytesPerInt); + __ addi(Rindex, Rindex, 3 * BytesPerInt); + __ lwax(Roffset, Rdef_offset_addr, Rindex); + __ b(Ldispatch); + + __ bind(Ldefault_case); + __ profile_switch_default(Rhigh_byte, Rscratch1); + __ lwa(Roffset, 0, Rdef_offset_addr); + + __ bind(Ldispatch); + + __ add(R14_bcp, Roffset, R14_bcp); + __ dispatch_next(vtos); +} + +void TemplateTable::lookupswitch() { + transition(itos, itos); + __ stop("lookupswitch bytecode should have been rewritten"); +} + +// Table switch using linear search through cases. +// Bytecode stream format: +// Bytecode (1) | 4-byte padding | default offset (4) | count (4) | value/offset pair1 (8) | value/offset pair2 (8) | ... +// Note: Everything is big-endian format here. So on little endian machines, we have to revers offset and count and cmp value. +void TemplateTable::fast_linearswitch() { + transition(itos, vtos); + + Label Lloop_entry, Lsearch_loop, Lfound, Lcontinue_execution, Ldefault_case; + + Register Rcount = R3_ARG1, + Rcurrent_pair = R4_ARG2, + Rdef_offset_addr = R5_ARG3, // Is going to contain address of default offset. + Roffset = R31, // Might need to survive C call. + Rvalue = R12_scratch2, + Rscratch = R11_scratch1, + Rcmp_value = R17_tos; + + // Align bcp. + __ addi(Rdef_offset_addr, R14_bcp, BytesPerInt); + __ clrrdi(Rdef_offset_addr, Rdef_offset_addr, log2_long((jlong)BytesPerInt)); + + // Setup loop counter and limit. + __ lwz(Rcount, BytesPerInt, Rdef_offset_addr); // Load count. + __ addi(Rcurrent_pair, Rdef_offset_addr, 2 * BytesPerInt); // Rcurrent_pair now points to first pair. + + // Set up search loop. + __ cmpwi(CCR0, Rcount, 0); + __ beq(CCR0, Ldefault_case); + + __ mtctr(Rcount); + + // linear table search + __ bind(Lsearch_loop); + + __ lwz(Rvalue, 0, Rcurrent_pair); + __ lwa(Roffset, 1 * BytesPerInt, Rcurrent_pair); + + __ cmpw(CCR0, Rvalue, Rcmp_value); + __ beq(CCR0, Lfound); + + __ addi(Rcurrent_pair, Rcurrent_pair, 2 * BytesPerInt); + __ bdnz(Lsearch_loop); + + // default case + __ bind(Ldefault_case); + + __ lwa(Roffset, 0, Rdef_offset_addr); + if (ProfileInterpreter) { + __ profile_switch_default(Rdef_offset_addr, Rcount/* scratch */); + __ b(Lcontinue_execution); + } + + // Entry found, skip Roffset bytecodes and continue. + __ bind(Lfound); + if (ProfileInterpreter) { + // Calc the num of the pair we hit. Careful, Rcurrent_pair points 2 ints + // beyond the actual current pair due to the auto update load above! + __ sub(Rcurrent_pair, Rcurrent_pair, Rdef_offset_addr); + __ addi(Rcurrent_pair, Rcurrent_pair, - 2 * BytesPerInt); + __ srdi(Rcurrent_pair, Rcurrent_pair, LogBytesPerInt + 1); + __ profile_switch_case(Rcurrent_pair, Rcount /*scratch*/, Rdef_offset_addr/*scratch*/, Rscratch); + __ bind(Lcontinue_execution); + } + __ add(R14_bcp, Roffset, R14_bcp); + __ dispatch_next(vtos); +} + +// Table switch using binary search (value/offset pairs are ordered). +// Bytecode stream format: +// Bytecode (1) | 4-byte padding | default offset (4) | count (4) | value/offset pair1 (8) | value/offset pair2 (8) | ... +// Note: Everything is big-endian format here. So on little endian machines, we have to revers offset and count and cmp value. +void TemplateTable::fast_binaryswitch() { + + transition(itos, vtos); + // Implementation using the following core algorithm: (copied from Intel) + // + // int binary_search(int key, LookupswitchPair* array, int n) { + // // Binary search according to "Methodik des Programmierens" by + // // Edsger W. Dijkstra and W.H.J. Feijen, Addison Wesley Germany 1985. + // int i = 0; + // int j = n; + // while (i+1 < j) { + // // invariant P: 0 <= i < j <= n and (a[i] <= key < a[j] or Q) + // // with Q: for all i: 0 <= i < n: key < a[i] + // // where a stands for the array and assuming that the (inexisting) + // // element a[n] is infinitely big. + // int h = (i + j) >> 1; + // // i < h < j + // if (key < array[h].fast_match()) { + // j = h; + // } else { + // i = h; + // } + // } + // // R: a[i] <= key < a[i+1] or Q + // // (i.e., if key is within array, i is the correct index) + // return i; + // } + + // register allocation + const Register Rkey = R17_tos; // already set (tosca) + const Register Rarray = R3_ARG1; + const Register Ri = R4_ARG2; + const Register Rj = R5_ARG3; + const Register Rh = R6_ARG4; + const Register Rscratch = R11_scratch1; + + const int log_entry_size = 3; + const int entry_size = 1 << log_entry_size; + + Label found; + + // Find Array start, ... + __ addi(Rarray, R14_bcp, 3 * BytesPerInt); + __ clrrdi(Rarray, Rarray, log2_long((jlong)BytesPerInt)); + + // ... initialize i & j ... + __ li(Ri,0); + __ lwz(Rj, -BytesPerInt, Rarray); + + // ... and start. + Label entry; + __ b(entry); + + // binary search loop + { Label loop; + __ bind(loop); + // int h = (i + j) >> 1; + __ srdi(Rh, Rh, 1); + // if (key < array[h].fast_match()) { + // j = h; + // } else { + // i = h; + // } + __ sldi(Rscratch, Rh, log_entry_size); + __ lwzx(Rscratch, Rscratch, Rarray); + + // if (key < current value) + // Rh = Rj + // else + // Rh = Ri + Label Lgreater; + __ cmpw(CCR0, Rkey, Rscratch); + __ bge(CCR0, Lgreater); + __ mr(Rj, Rh); + __ b(entry); + __ bind(Lgreater); + __ mr(Ri, Rh); + + // while (i+1 < j) + __ bind(entry); + __ addi(Rscratch, Ri, 1); + __ cmpw(CCR0, Rscratch, Rj); + __ add(Rh, Ri, Rj); // start h = i + j >> 1; + + __ blt(CCR0, loop); + } + + // End of binary search, result index is i (must check again!). + Label default_case; + Label continue_execution; + if (ProfileInterpreter) { + __ mr(Rh, Ri); // Save index in i for profiling. + } + // Ri = value offset + __ sldi(Ri, Ri, log_entry_size); + __ add(Ri, Ri, Rarray); + __ lwz(Rscratch, 0, Ri); + + Label not_found; + // Ri = offset offset + __ cmpw(CCR0, Rkey, Rscratch); + __ beq(CCR0, not_found); + // entry not found -> j = default offset + __ lwz(Rj, -2 * BytesPerInt, Rarray); + __ b(default_case); + + __ bind(not_found); + // entry found -> j = offset + __ profile_switch_case(Rh, Rj, Rscratch, Rkey); + __ lwz(Rj, BytesPerInt, Ri); + + if (ProfileInterpreter) { + __ b(continue_execution); + } + + __ bind(default_case); // fall through (if not profiling) + __ profile_switch_default(Ri, Rscratch); + + __ bind(continue_execution); + + __ extsw(Rj, Rj); + __ add(R14_bcp, Rj, R14_bcp); + __ dispatch_next(vtos); +} + +void TemplateTable::_return(TosState state) { + transition(state, state); + assert(_desc->calls_vm(), + "inconsistent calls_vm information"); // call in remove_activation + + if (_desc->bytecode() == Bytecodes::_return_register_finalizer) { + + Register Rscratch = R11_scratch1, + Rklass = R12_scratch2, + Rklass_flags = Rklass; + Label Lskip_register_finalizer; + + // Check if the method has the FINALIZER flag set and call into the VM to finalize in this case. + assert(state == vtos, "only valid state"); + __ ld(R17_tos, 0, R18_locals); + + // Load klass of this obj. + __ load_klass(Rklass, R17_tos); + __ lwz(Rklass_flags, in_bytes(Klass::access_flags_offset()), Rklass); + __ testbitdi(CCR0, R0, Rklass_flags, exact_log2(JVM_ACC_HAS_FINALIZER)); + __ bfalse(CCR0, Lskip_register_finalizer); + + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::register_finalizer), R17_tos /* obj */); + + __ align(32, 12); + __ bind(Lskip_register_finalizer); + } + + // Move the result value into the correct register and remove memory stack frame. + __ remove_activation(state, /* throw_monitor_exception */ true); + // Restoration of lr done by remove_activation. + switch (state) { + case ltos: + case btos: + case ctos: + case stos: + case atos: + case itos: __ mr(R3_RET, R17_tos); break; + case ftos: + case dtos: __ fmr(F1_RET, F15_ftos); break; + case vtos: // This might be a constructor. Final fields (and volatile fields on PPC64) need + // to get visible before the reference to the object gets stored anywhere. + __ membar(Assembler::StoreStore); break; + default : ShouldNotReachHere(); + } + __ blr(); +} + +// ============================================================================ +// Constant pool cache access +// +// Memory ordering: +// +// Like done in C++ interpreter, we load the fields +// - _indices +// - _f12_oop +// acquired, because these are asked if the cache is already resolved. We don't +// want to float loads above this check. +// See also comments in ConstantPoolCacheEntry::bytecode_1(), +// ConstantPoolCacheEntry::bytecode_2() and ConstantPoolCacheEntry::f1(); + +// Call into the VM if call site is not yet resolved +// +// Input regs: +// - None, all passed regs are outputs. +// +// Returns: +// - Rcache: The const pool cache entry that contains the resolved result. +// - Rresult: Either noreg or output for f1/f2. +// +// Kills: +// - Rscratch +void TemplateTable::resolve_cache_and_index(int byte_no, Register Rresult, Register Rcache, Register Rscratch, size_t index_size) { + + __ get_cache_and_index_at_bcp(Rcache, 1, index_size); + Label Lresolved, Ldone; + if (byte_no == f12_oop) { + // We are resolved if the f1 field contains a non-null object (CallSite, etc.). + // This kind of CP cache entry does not need to match the flags byte, because + // there is a 1-1 relation between bytecode type and CP entry type. + assert_different_registers(Rresult, Rcache); + __ ld(Rresult, in_bytes(constantPoolCacheOopDesc::base_offset() + ConstantPoolCacheEntry::f1_offset()), Rcache); + // Acquire by cmp-br-isync (see below). + __ cmpdi(CCR0, Rresult, 0); + __ bne(CCR0, Lresolved); + } else { + assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); + // We are resolved if the indices offset contains the current bytecode. + // Big Endian: + __ lbz(Rscratch, in_bytes(constantPoolCacheOopDesc::base_offset() + ConstantPoolCacheEntry::indices_offset()) + 7 - (byte_no + 1), Rcache); + // Acquire by cmp-br-isync (see below). + __ cmpdi(CCR0, Rscratch, (int)bytecode()); + __ beq(CCR0, Lresolved); + } + + address entry = NULL; + switch (bytecode()) { + case Bytecodes::_getstatic : // fall through + case Bytecodes::_putstatic : // fall through + case Bytecodes::_getfield : // fall through + case Bytecodes::_putfield : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_get_put); break; + case Bytecodes::_invokevirtual : // fall through + case Bytecodes::_invokespecial : // fall through + case Bytecodes::_invokestatic : // fall through + case Bytecodes::_invokeinterface: entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invoke); break; + case Bytecodes::_invokehandle : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invokehandle); break; + case Bytecodes::_invokedynamic : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invokedynamic); break; + case Bytecodes::_fast_aldc : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc); break; + case Bytecodes::_fast_aldc_w : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc); break; + default : ShouldNotReachHere(); break; + } + __ mr(R3_ARG1, R16_thread); + __ li(R4_ARG2, (int)bytecode()); + __ call_VM(noreg, entry, true); + + // Update registers with resolved info in case GC happened. + __ get_cache_and_index_at_bcp(Rcache, 1, index_size); + + if (Rresult != noreg && byte_no == f12_oop) { + // Need to reload resolved oop, GC could have happened during stepping back to java. + __ ld(Rresult, in_bytes(constantPoolCacheOopDesc::base_offset() + ConstantPoolCacheEntry::f1_offset()), Rcache); + __ twi_0(Rresult); // Acquire by twi-isync. + } else { + __ b(Ldone); + } + + __ bind(Lresolved); + __ isync(); // Order load wrt. succeeding loads. + __ bind(Ldone); +} + +// Load the constant pool cache entry at field accesses into registers. +// The Rcache and Rindex registers must be set before call. +// Input: +// - Rcache, Rindex +// Output: +// - Robj, Roffset, Rflags +void TemplateTable::load_field_cp_cache_entry(Register Robj, + Register Rcache, + Register Rindex /* unused on PPC64 */, + Register Roffset, + Register Rflags, + bool is_static = false) { + assert_different_registers(Rcache, Rflags, Roffset); + // assert(Rindex == noreg, "parameter not used on PPC64"); + + ByteSize cp_base_offset = constantPoolCacheOopDesc::base_offset(); + __ ld(Rflags, in_bytes(cp_base_offset) + in_bytes(ConstantPoolCacheEntry::flags_offset()), Rcache); + __ ld(Roffset, in_bytes(cp_base_offset) + in_bytes(ConstantPoolCacheEntry::f2_offset()), Rcache); + if (is_static) { + __ ld(Robj, in_bytes(cp_base_offset) + in_bytes(ConstantPoolCacheEntry::f1_offset()), Rcache); + //__ ld(Robj, in_bytes(Klass::java_mirror_offset()), Robj); + // Acquire not needed here. Following access has an address dependency on this value. + } +} + +// Load the constant pool cache entry at invokes into registers. +// Resolve if necessary. + +// Input Registers: +// - None, bcp is used, though +// +// Return registers: +// - Rmethod (f1 field or f2 if invokevirtual) +// - Ritable_index (f2 field) +// - Rflags (flags field) +// +// Kills: +// - R21 +// +void TemplateTable::load_invoke_cp_cache_entry(int byte_no, + Register Rmethod, + Register Ritable_index, + Register Rflags, + bool is_invokevirtual, + bool is_invokevfinal, + bool is_invokedynamic) { + + ByteSize cp_base_offset = constantPoolCacheOopDesc::base_offset(); + // Determine constant pool cache field offsets. + const int method_offset = in_bytes(cp_base_offset + (is_invokevirtual ? ConstantPoolCacheEntry::f2_offset() : ConstantPoolCacheEntry::f1_offset())); + const int flags_offset = in_bytes(cp_base_offset + ConstantPoolCacheEntry::flags_offset()); + // Access constant pool cache fields. + const int index_offset = in_bytes(cp_base_offset + ConstantPoolCacheEntry::f2_offset()); + + Register Rcache = R21_tmp1; // Note: same register as R21_sender_SP. + + if (is_invokevfinal) { + assert(Ritable_index == noreg, "register not used"); + // Already resolved. + __ get_cache_and_index_at_bcp(Rcache, 1); + __ ld(Rmethod, method_offset, Rcache); + __ ld(Rflags, flags_offset, Rcache); + } else if (byte_no == f12_oop) { + // Invokedynamic or plain methodhandle call. + const size_t index_size = (is_invokedynamic ? sizeof(u4) : sizeof(u2)); + { + Register Rscratch = Rmethod; + resolve_cache_and_index(byte_no, Ritable_index, Rcache, Rscratch, index_size); + } + __ ld(Rmethod, index_offset, Rcache); + __ ld(Rflags, flags_offset, Rcache); + } else { + { + Register Rscratch = Rmethod; + resolve_cache_and_index(byte_no, noreg, Rcache, Rscratch, sizeof(u2)); + } + __ ld(Rmethod, method_offset, Rcache); + __ ld(Rflags, flags_offset, Rcache); + + if (Ritable_index != noreg) { + __ ld(Ritable_index, index_offset, Rcache); + } + } +} + +// ============================================================================ +// Field access + +// Volatile variables demand their effects be made known to all CPU's +// in order. Store buffers on most chips allow reads & writes to +// reorder; the JMM's ReadAfterWrite.java test fails in -Xint mode +// without some kind of memory barrier (i.e., it's not sufficient that +// the interpreter does not reorder volatile references, the hardware +// also must not reorder them). +// +// According to the new Java Memory Model (JMM): +// (1) All volatiles are serialized wrt to each other. ALSO reads & +// writes act as aquire & release, so: +// (2) A read cannot let unrelated NON-volatile memory refs that +// happen after the read float up to before the read. It's OK for +// non-volatile memory refs that happen before the volatile read to +// float down below it. +// (3) Similar a volatile write cannot let unrelated NON-volatile +// memory refs that happen BEFORE the write float down to after the +// write. It's OK for non-volatile memory refs that happen after the +// volatile write to float up before it. +// +// We only put in barriers around volatile refs (they are expensive), +// not _between_ memory refs (that would require us to track the +// flavor of the previous memory refs). Requirements (2) and (3) +// require some barriers before volatile stores and after volatile +// loads. These nearly cover requirement (1) but miss the +// volatile-store-volatile-load case. This final case is placed after +// volatile-stores although it could just as well go before +// volatile-loads. + +// The registers cache and index expected to be set before call. +// Correct values of the cache and index registers are preserved. +// Kills: +// Rcache (if has_tos) +// Rscratch +void TemplateTable::jvmti_post_field_access(Register Rcache, Register Rscratch, bool is_static, bool has_tos) { + + assert_different_registers(Rcache, Rscratch); + + if (JvmtiExport::can_post_field_access()) { + ByteSize cp_base_offset = constantPoolCacheOopDesc::base_offset(); + Label Lno_field_access_post; + + // Check if post field access in enabled. + int offs = __ load_const_optimized(Rscratch, JvmtiExport::get_field_access_count_addr(), R0, true); + __ lwz(Rscratch, offs, Rscratch); + + __ cmpwi(CCR0, Rscratch, 0); + __ beq(CCR0, Lno_field_access_post); + + // Post access enabled - do it! + __ addi(Rcache, Rcache, in_bytes(cp_base_offset)); + if (is_static) { + __ li(R17_tos, 0); + } else { + if (has_tos) { + // The fast bytecode versions have obj ptr in register. + // Thus, save object pointer before call_VM() clobbers it + // put object on tos where GC wants it. + __ push_ptr(R17_tos); + } else { + // Load top of stack (do not pop the value off the stack). + __ ld(R17_tos, Interpreter::expr_offset_in_bytes(0), R15_esp); + } + __ verify_oop(R17_tos); + } + // tos: object pointer or NULL if static + // cache: cache entry pointer + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_access), R17_tos, Rcache); + if (!is_static && has_tos) { + // Restore object pointer. + __ pop_ptr(R17_tos); + __ verify_oop(R17_tos); + } else { + // Cache is still needed to get class or obj. + __ get_cache_and_index_at_bcp(Rcache, 1); + } + + __ align(32, 12); + __ bind(Lno_field_access_post); + } +} + +// kills R11_scratch1 +void TemplateTable::pop_and_check_object(Register Roop) { + Register Rtmp = R11_scratch1; + + assert_different_registers(Rtmp, Roop); + __ pop_ptr(Roop); + // For field access must check obj. + __ null_check_throw(Roop, -1, Rtmp); + __ verify_oop(Roop); +} + +// PPC64: implement volatile loads as fence-store-acquire. +void TemplateTable::getfield_or_static(int byte_no, bool is_static) { + transition(vtos, vtos); + + Label Lexit, Lacquire; + + const Register Rcache = R3_ARG1, + Rclass_or_obj = R22_tmp2, + Roffset = R23_tmp3, + Rflags = R31, + Rbtable = R5_ARG3, + Rbc = R6_ARG4, + Rscratch = R12_scratch2; + + static address field_branch_table[number_of_states], + static_branch_table[number_of_states]; + + address* branch_table = is_static ? static_branch_table : field_branch_table; + + // Get field offset. + resolve_cache_and_index(byte_no, noreg, Rcache, Rscratch, sizeof(u2)); + + // JVMTI support + jvmti_post_field_access(Rcache, Rscratch, is_static, false); + + // Load after possible GC. + load_field_cp_cache_entry(Rclass_or_obj, Rcache, noreg, Roffset, Rflags, is_static); + + // Load pointer to branch table. + __ load_const_optimized(Rbtable, (address)branch_table, Rscratch); + + // Get volatile flag. + __ rldicl(Rscratch, Rflags, 64-ConstantPoolCacheEntry::is_volatile_shift, 63); // Extract volatile bit. + // Note: sync is needed before volatile load on PPC64. + + // Check field type. + __ rldicl(Rflags, Rflags, 64-ConstantPoolCacheEntry::tos_state_shift, 64-ConstantPoolCacheEntry::tos_state_bits); + +#ifdef ASSERT + Label LFlagInvalid; + __ cmpldi(CCR0, Rflags, number_of_states); + __ bge(CCR0, LFlagInvalid); +#endif + + // Load from branch table and dispatch (volatile case: one instruction ahead). + __ sldi(Rflags, Rflags, LogBytesPerWord); + __ cmpwi(CCR6, Rscratch, 1); // Volatile? + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ sldi(Rscratch, Rscratch, exact_log2(BytesPerInstWord)); // Volatile ? size of 1 instruction : 0. + } + __ ldx(Rbtable, Rbtable, Rflags); + + // Get the obj from stack. + if (!is_static) { + pop_and_check_object(Rclass_or_obj); // Kills R11_scratch1. + } else { + __ verify_oop(Rclass_or_obj); + } + + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ subf(Rbtable, Rscratch, Rbtable); // Point to volatile/non-volatile entry point. + } + __ mtctr(Rbtable); + __ bctr(); + +#ifdef ASSERT + __ bind(LFlagInvalid); + __ stop("got invalid flag", 0x654); + + // __ bind(Lvtos); + address pc_before_fence = __ pc(); + __ fence(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(__ pc() - pc_before_fence == (ptrdiff_t)BytesPerInstWord, "must be single instruction"); + assert(branch_table[vtos] == 0, "can't compute twice"); + branch_table[vtos] = __ pc(); // non-volatile_entry point + __ stop("vtos unexpected", 0x655); +#endif + + __ align(32, 28, 28); // Align load. + // __ bind(Ldtos); + __ fence(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[dtos] == 0, "can't compute twice"); + branch_table[dtos] = __ pc(); // non-volatile_entry point + __ lfdx(F15_ftos, Rclass_or_obj, Roffset); + __ push(dtos); + if (!is_static) patch_bytecode(Bytecodes::_fast_dgetfield, Rbc, Rscratch); + __ bne(CCR6, Lexit); // Non-volatile? + __ fcmpu(CCR0, F15_ftos, F15_ftos); // Acquire by cmp-br-isync. + __ beq_predict_taken(CCR0, Lacquire); + __ b(Lacquire); // In case of NAN. + + __ align(32, 28, 28); // Align load. + // __ bind(Lftos); + __ fence(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[ftos] == 0, "can't compute twice"); + branch_table[ftos] = __ pc(); // non-volatile_entry point + __ lfsx(F15_ftos, Rclass_or_obj, Roffset); + __ push(ftos); + if (!is_static) patch_bytecode(Bytecodes::_fast_fgetfield, Rbc, Rscratch); + __ bne(CCR6, Lexit); // Non-volatile? + __ fcmpu(CCR0, F15_ftos, F15_ftos); // Acquire by cmp-br-isync. + __ beq_predict_taken(CCR0, Lacquire); + __ b(Lacquire); // In case of NAN. + + __ align(32, 28, 28); // Align load. + // __ bind(Litos); + __ fence(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[itos] == 0, "can't compute twice"); + branch_table[itos] = __ pc(); // non-volatile_entry point + __ lwax(R17_tos, Rclass_or_obj, Roffset); + __ push(itos); + if (!is_static) patch_bytecode(Bytecodes::_fast_igetfield, Rbc, Rscratch); + __ bne(CCR6, Lexit); // Non-volatile? + __ twi_0(R17_tos); // Acquire by cmp-twi-isync. + __ b(Lacquire); + + __ align(32, 28, 28); // Align load. + // __ bind(Lltos); + __ fence(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[ltos] == 0, "can't compute twice"); + branch_table[ltos] = __ pc(); // non-volatile_entry point + __ ldx(R17_tos, Rclass_or_obj, Roffset); + __ push(ltos); + if (!is_static) patch_bytecode(Bytecodes::_fast_lgetfield, Rbc, Rscratch); + __ bne(CCR6, Lexit); // Non-volatile? + __ twi_0(R17_tos); // Acquire by cmp-twi-isync. + __ b(Lacquire); + + __ align(32, 28, 28); // Align load. + // __ bind(Lbtos); + __ fence(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[btos] == 0, "can't compute twice"); + branch_table[btos] = __ pc(); // non-volatile_entry point + __ lbzx(R17_tos, Rclass_or_obj, Roffset); + __ extsb(R17_tos, R17_tos); + __ push(btos); + if (!is_static) patch_bytecode(Bytecodes::_fast_bgetfield, Rbc, Rscratch); + __ bne(CCR6, Lexit); // Non-volatile? + __ twi_0(R17_tos); // Acquire by cmp-twi-isync. + __ b(Lacquire); + + __ align(32, 28, 28); // Align load. + // __ bind(Lctos); + __ fence(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[ctos] == 0, "can't compute twice"); + branch_table[ctos] = __ pc(); // non-volatile_entry point + __ lhzx(R17_tos, Rclass_or_obj, Roffset); + __ push(ctos); + if (!is_static) patch_bytecode(Bytecodes::_fast_cgetfield, Rbc, Rscratch); + __ bne(CCR6, Lexit); // Non-volatile? + __ twi_0(R17_tos); // Acquire by cmp-twi-isync. + __ b(Lacquire); + + __ align(32, 28, 28); // Align load. + // __ bind(Lstos); + __ fence(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[stos] == 0, "can't compute twice"); + branch_table[stos] = __ pc(); // non-volatile_entry point + __ lhax(R17_tos, Rclass_or_obj, Roffset); + __ push(stos); + if (!is_static) patch_bytecode(Bytecodes::_fast_sgetfield, Rbc, Rscratch); + __ bne(CCR6, Lexit); // Non-volatile? + __ twi_0(R17_tos); // Acquire by cmp-twi-isync. + __ b(Lacquire); + + __ align(32, 28, 28); // Align load. + // __ bind(Latos); + __ fence(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[atos] == 0, "can't compute twice"); + branch_table[atos] = __ pc(); // non-volatile_entry point + __ load_heap_oop(R17_tos, (RegisterOrConstant)Roffset, Rclass_or_obj); + __ verify_oop(R17_tos); + __ push(atos); + //__ dcbt(R17_tos); // prefetch + if (!is_static) patch_bytecode(Bytecodes::_fast_agetfield, Rbc, Rscratch); + __ bne(CCR6, Lexit); // Non-volatile? + __ twi_0(R17_tos); // Acquire by cmp-twi-isync. + // fallthru __ b(Lacquire); + + __ align(32, 12, 28); // Align Lexit. + __ bind(Lacquire); + __ isync(); // acquire + __ bind(Lexit); + +#ifdef ASSERT + for (int i = 0; i<number_of_states; ++i) { + assert(branch_table[i], "get initialization"); + //tty->print_cr("get: %s_branch_table[%d] = 0x%llx (opcode 0x%llx)", + // is_static ? "static" : "field", i, branch_table[i], *((unsigned int*)branch_table[i])); + } +#endif +} + +void TemplateTable::getfield(int byte_no) { + getfield_or_static(byte_no, false); +} + +void TemplateTable::getstatic(int byte_no) { + getfield_or_static(byte_no, true); +} + +// The registers cache and index expected to be set before call. +// The function may destroy various registers, just not the cache and index registers. +void TemplateTable::jvmti_post_field_mod(Register Rcache, Register Rscratch, bool is_static) { + + assert_different_registers(Rcache, Rscratch, R6_ARG4); + + if (JvmtiExport::can_post_field_modification()) { + Label Lno_field_mod_post; + + // Check if post field access in enabled. + int offs = __ load_const_optimized(Rscratch, JvmtiExport::get_field_modification_count_addr(), R0, true); + __ lwz(Rscratch, offs, Rscratch); + + __ cmpwi(CCR0, Rscratch, 0); + __ beq(CCR0, Lno_field_mod_post); + + // Do the post + ByteSize cp_base_offset = constantPoolCacheOopDesc::base_offset(); + const Register Robj = Rscratch; + + __ addi(Rcache, Rcache, in_bytes(cp_base_offset)); + if (is_static) { + // Life is simple. Null out the object pointer. + __ li(Robj, 0); + } else { + // In case of the fast versions, value lives in registers => put it back on tos. + int offs = Interpreter::expr_offset_in_bytes(0); + Register base = R15_esp; + switch(bytecode()) { + case Bytecodes::_fast_aputfield: __ push_ptr(); offs += Interpreter::stackElementSize; break; + case Bytecodes::_fast_iputfield: // Fall through + case Bytecodes::_fast_bputfield: // Fall through + case Bytecodes::_fast_cputfield: // Fall through + case Bytecodes::_fast_sputfield: __ push_i(); offs += Interpreter::stackElementSize; break; + case Bytecodes::_fast_lputfield: __ push_l(); offs += 2*Interpreter::stackElementSize; break; + case Bytecodes::_fast_fputfield: __ push_f(); offs += Interpreter::stackElementSize; break; + case Bytecodes::_fast_dputfield: __ push_d(); offs += 2*Interpreter::stackElementSize; break; + default: { + offs = 0; + base = Robj; + const Register Rflags = Robj; + Label is_one_slot; + // Life is harder. The stack holds the value on top, followed by the + // object. We don't know the size of the value, though; it could be + // one or two words depending on its type. As a result, we must find + // the type to determine where the object is. + __ ld(Rflags, in_bytes(ConstantPoolCacheEntry::flags_offset()), Rcache); // Big Endian + __ rldicl(Rflags, Rflags, 64-ConstantPoolCacheEntry::tos_state_shift, 64-ConstantPoolCacheEntry::tos_state_bits); + + __ cmpwi(CCR0, Rflags, ltos); + __ cmpwi(CCR1, Rflags, dtos); + __ addi(base, R15_esp, Interpreter::expr_offset_in_bytes(1)); + __ crnor(/*CR0 eq*/2, /*CR1 eq*/4+2, /*CR0 eq*/2); + __ beq(CCR0, is_one_slot); + __ addi(base, R15_esp, Interpreter::expr_offset_in_bytes(2)); + __ bind(is_one_slot); + break; + } + } + __ ld(Robj, offs, base); + __ verify_oop(Robj); + } + + __ addi(R6_ARG4, R15_esp, Interpreter::expr_offset_in_bytes(0)); + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_modification), Robj, Rcache, R6_ARG4); + __ get_cache_and_index_at_bcp(Rcache, 1); + + // In case of the fast versions, value lives in registers => put it back on tos. + switch(bytecode()) { + case Bytecodes::_fast_aputfield: __ pop_ptr(); break; + case Bytecodes::_fast_iputfield: // Fall through + case Bytecodes::_fast_bputfield: // Fall through + case Bytecodes::_fast_cputfield: // Fall through + case Bytecodes::_fast_sputfield: __ pop_i(); break; + case Bytecodes::_fast_lputfield: __ pop_l(); break; + case Bytecodes::_fast_fputfield: __ pop_f(); break; + case Bytecodes::_fast_dputfield: __ pop_d(); break; + default: break; // Nothin' to do. + } + + __ align(32, 12); + __ bind(Lno_field_mod_post); + } +} + +// PPC64: implement volatile stores as release-store (return bytecode contains an additional release). +void TemplateTable::putfield_or_static(int byte_no, bool is_static) { + Label Lexit; + + const Register Rcache = R5_ARG3, // Do not use ARG1/2 (causes trouble in jvmti_post_field_mod). + Rclass_or_obj = R31, // Needs to survive C call. + Roffset = R22_tmp2, // Needs to survive C call. + Rflags = R3_ARG1, + Rbtable = R4_ARG2, + Rscratch = R11_scratch1, + Rscratch2 = R12_scratch2, + Rscratch3 = R6_ARG4, + Rbc = Rscratch3; + const ConditionRegister CR_is_vol = CCR2; // Non-volatile condition register (survives runtime call in do_oop_store). + + static address field_branch_table[number_of_states], + static_branch_table[number_of_states]; + + address* branch_table = is_static ? static_branch_table : field_branch_table; + + // Stack (grows up): + // value + // obj + + // Load the field offset. + resolve_cache_and_index(byte_no, noreg, Rcache, Rscratch, sizeof(u2)); + jvmti_post_field_mod(Rcache, Rscratch, is_static); + load_field_cp_cache_entry(Rclass_or_obj, Rcache, noreg, Roffset, Rflags, is_static); + + // Load pointer to branch table. + __ load_const_optimized(Rbtable, (address)branch_table, Rscratch); + + // Get volatile flag. + __ rldicl(Rscratch, Rflags, 64-ConstantPoolCacheEntry::is_volatile_shift, 63); // Extract volatile bit. + + // Check the field type. + __ rldicl(Rflags, Rflags, 64-ConstantPoolCacheEntry::tos_state_shift, 64-ConstantPoolCacheEntry::tos_state_bits); + +#ifdef ASSERT + Label LFlagInvalid; + __ cmpldi(CCR0, Rflags, number_of_states); + __ bge(CCR0, LFlagInvalid); +#endif + + // Load from branch table and dispatch (volatile case: one instruction ahead). + __ sldi(Rflags, Rflags, LogBytesPerWord); + if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { __ cmpwi(CR_is_vol, Rscratch, 1); } // Volatile? + __ sldi(Rscratch, Rscratch, exact_log2(BytesPerInstWord)); // Volatile? size of instruction 1 : 0. + __ ldx(Rbtable, Rbtable, Rflags); + + __ subf(Rbtable, Rscratch, Rbtable); // Point to volatile/non-volatile entry point. + __ mtctr(Rbtable); + __ bctr(); + +#ifdef ASSERT + __ bind(LFlagInvalid); + __ stop("got invalid flag", 0x656); + + // __ bind(Lvtos); + address pc_before_release = __ pc(); + __ release(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(__ pc() - pc_before_release == (ptrdiff_t)BytesPerInstWord, "must be single instruction"); + assert(branch_table[vtos] == 0, "can't compute twice"); + branch_table[vtos] = __ pc(); // non-volatile_entry point + __ stop("vtos unexpected", 0x657); +#endif + + __ align(32, 28, 28); // Align pop. + // __ bind(Ldtos); + __ release(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[dtos] == 0, "can't compute twice"); + branch_table[dtos] = __ pc(); // non-volatile_entry point + __ pop(dtos); + if (!is_static) { pop_and_check_object(Rclass_or_obj); } // Kills R11_scratch1. + __ stfdx(F15_ftos, Rclass_or_obj, Roffset); + if (!is_static) { patch_bytecode(Bytecodes::_fast_dputfield, Rbc, Rscratch, true, byte_no); } + if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ bne(CR_is_vol, Lexit); // Non-volatile? + __ fence(); + } + __ b(Lexit); + + __ align(32, 28, 28); // Align pop. + // __ bind(Lftos); + __ release(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[ftos] == 0, "can't compute twice"); + branch_table[ftos] = __ pc(); // non-volatile_entry point + __ pop(ftos); + if (!is_static) { pop_and_check_object(Rclass_or_obj); } // Kills R11_scratch1. + __ stfsx(F15_ftos, Rclass_or_obj, Roffset); + if (!is_static) { patch_bytecode(Bytecodes::_fast_fputfield, Rbc, Rscratch, true, byte_no); } + if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ bne(CR_is_vol, Lexit); // Non-volatile? + __ fence(); + } + __ b(Lexit); + + __ align(32, 28, 28); // Align pop. + // __ bind(Litos); + __ release(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[itos] == 0, "can't compute twice"); + branch_table[itos] = __ pc(); // non-volatile_entry point + __ pop(itos); + if (!is_static) { pop_and_check_object(Rclass_or_obj); } // Kills R11_scratch1. + __ stwx(R17_tos, Rclass_or_obj, Roffset); + if (!is_static) { patch_bytecode(Bytecodes::_fast_iputfield, Rbc, Rscratch, true, byte_no); } + if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ bne(CR_is_vol, Lexit); // Non-volatile? + __ fence(); + } + __ b(Lexit); + + __ align(32, 28, 28); // Align pop. + // __ bind(Lltos); + __ release(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[ltos] == 0, "can't compute twice"); + branch_table[ltos] = __ pc(); // non-volatile_entry point + __ pop(ltos); + if (!is_static) { pop_and_check_object(Rclass_or_obj); } // Kills R11_scratch1. + __ stdx(R17_tos, Rclass_or_obj, Roffset); + if (!is_static) { patch_bytecode(Bytecodes::_fast_lputfield, Rbc, Rscratch, true, byte_no); } + if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ bne(CR_is_vol, Lexit); // Non-volatile? + __ fence(); + } + __ b(Lexit); + + __ align(32, 28, 28); // Align pop. + // __ bind(Lbtos); + __ release(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[btos] == 0, "can't compute twice"); + branch_table[btos] = __ pc(); // non-volatile_entry point + __ pop(btos); + if (!is_static) { pop_and_check_object(Rclass_or_obj); } // Kills R11_scratch1. + __ stbx(R17_tos, Rclass_or_obj, Roffset); + if (!is_static) { patch_bytecode(Bytecodes::_fast_bputfield, Rbc, Rscratch, true, byte_no); } + if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ bne(CR_is_vol, Lexit); // Non-volatile? + __ fence(); + } + __ b(Lexit); + + __ align(32, 28, 28); // Align pop. + // __ bind(Lctos); + __ release(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[ctos] == 0, "can't compute twice"); + branch_table[ctos] = __ pc(); // non-volatile_entry point + __ pop(ctos); + if (!is_static) { pop_and_check_object(Rclass_or_obj); } // Kills R11_scratch1.. + __ sthx(R17_tos, Rclass_or_obj, Roffset); + if (!is_static) { patch_bytecode(Bytecodes::_fast_cputfield, Rbc, Rscratch, true, byte_no); } + if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ bne(CR_is_vol, Lexit); // Non-volatile? + __ fence(); + } + __ b(Lexit); + + __ align(32, 28, 28); // Align pop. + // __ bind(Lstos); + __ release(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[stos] == 0, "can't compute twice"); + branch_table[stos] = __ pc(); // non-volatile_entry point + __ pop(stos); + if (!is_static) { pop_and_check_object(Rclass_or_obj); } // Kills R11_scratch1. + __ sthx(R17_tos, Rclass_or_obj, Roffset); + if (!is_static) { patch_bytecode(Bytecodes::_fast_sputfield, Rbc, Rscratch, true, byte_no); } + if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ bne(CR_is_vol, Lexit); // Non-volatile? + __ fence(); + } + __ b(Lexit); + + __ align(32, 28, 28); // Align pop. + // __ bind(Latos); + __ release(); // Volatile entry point (one instruction before non-volatile_entry point). + assert(branch_table[atos] == 0, "can't compute twice"); + branch_table[atos] = __ pc(); // Non-volatile_entry point. + __ pop(atos); + if (!is_static) { pop_and_check_object(Rclass_or_obj); } // kills R11_scratch1 + do_oop_store(_masm, Rclass_or_obj, Roffset, R17_tos, Rscratch, Rscratch2, Rscratch3, _bs->kind(), false /* precise */, true /* check null */); + if (!is_static) { patch_bytecode(Bytecodes::_fast_aputfield, Rbc, Rscratch, true, byte_no); } + if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ bne(CR_is_vol, Lexit); // Non-volatile? + __ fence(); + } + // fallthru: __ b(Lexit); + + __ align(32, 12); + __ bind(Lexit); +#ifdef ASSERT + for (int i = 0; i<number_of_states; ++i) { + assert(branch_table[i], "put initialization"); + //tty->print_cr("put: %s_branch_table[%d] = 0x%llx (opcode 0x%llx)", + // is_static ? "static" : "field", i, branch_table[i], *((unsigned int*)branch_table[i])); + } +#endif +} + +void TemplateTable::putfield(int byte_no) { + putfield_or_static(byte_no, false); +} + +void TemplateTable::putstatic(int byte_no) { + putfield_or_static(byte_no, true); +} + +// See SPARC. On PPC64, we have a different jvmti_post_field_mod which does the job. +void TemplateTable::jvmti_post_fast_field_mod() { + __ should_not_reach_here(); +} + +void TemplateTable::fast_storefield(TosState state) { + transition(state, vtos); + + const Register Rcache = R5_ARG3, // Do not use ARG1/2 (causes trouble in jvmti_post_field_mod). + Rclass_or_obj = R31, // Needs to survive C call. + Roffset = R22_tmp2, // Needs to survive C call. + Rflags = R3_ARG1, + Rscratch = R11_scratch1, + Rscratch2 = R12_scratch2, + Rscratch3 = R4_ARG2; + const ConditionRegister CR_is_vol = CCR2; // Non-volatile condition register (survives runtime call in do_oop_store). + + // Constant pool already resolved => Load flags and offset of field. + __ get_cache_and_index_at_bcp(Rcache, 1); + jvmti_post_field_mod(Rcache, Rscratch, false /* not static */); + load_field_cp_cache_entry(noreg, Rcache, noreg, Roffset, Rflags, false); + + // Get the obj and the final store addr. + pop_and_check_object(Rclass_or_obj); // Kills R11_scratch1. + + // Get volatile flag. + __ rldicl_(Rscratch, Rflags, 64-ConstantPoolCacheEntry::is_volatile_shift, 63); // Extract volatile bit. + if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { __ cmpdi(CR_is_vol, Rscratch, 1); } + { + Label LnotVolatile; + __ beq(CCR0, LnotVolatile); + __ release(); + __ align(32, 12); + __ bind(LnotVolatile); + } + + // Do the store and fencing. + switch(bytecode()) { + case Bytecodes::_fast_aputfield: + // Store into the field. + do_oop_store(_masm, Rclass_or_obj, Roffset, R17_tos, Rscratch, Rscratch2, Rscratch3, _bs->kind(), false /* precise */, true /* check null */); + break; + + case Bytecodes::_fast_iputfield: + __ stwx(R17_tos, Rclass_or_obj, Roffset); + break; + + case Bytecodes::_fast_lputfield: + __ stdx(R17_tos, Rclass_or_obj, Roffset); + break; + + case Bytecodes::_fast_bputfield: + __ stbx(R17_tos, Rclass_or_obj, Roffset); + break; + + case Bytecodes::_fast_cputfield: + case Bytecodes::_fast_sputfield: + __ sthx(R17_tos, Rclass_or_obj, Roffset); + break; + + case Bytecodes::_fast_fputfield: + __ stfsx(F15_ftos, Rclass_or_obj, Roffset); + break; + + case Bytecodes::_fast_dputfield: + __ stfdx(F15_ftos, Rclass_or_obj, Roffset); + break; + + default: ShouldNotReachHere(); + } + + if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { + Label LnotVolatile; + __ bne(CR_is_vol, LnotVolatile); + __ fence(); + __ align(32, 12); + __ bind(LnotVolatile); + } +} + +void TemplateTable::fast_accessfield(TosState state) { + transition(atos, state); + + Label Lexit, LisVolatile; + ByteSize cp_base_offset = constantPoolCacheOopDesc::base_offset(); + + const Register Rcache = R3_ARG1, + Rclass_or_obj = R17_tos, + Roffset = R22_tmp2, + Rflags = R23_tmp3, + Rscratch = R12_scratch2; + + // Constant pool already resolved. Get the field offset. + __ get_cache_and_index_at_bcp(Rcache, 1); + load_field_cp_cache_entry(noreg, Rcache, noreg, Roffset, Rflags, false); + + // JVMTI support + jvmti_post_field_access(Rcache, Rscratch, false, true); + + // Get the load address. + __ null_check_throw(Rclass_or_obj, -1, Rscratch); + + // Get volatile flag. + __ rldicl_(Rscratch, Rflags, 64-ConstantPoolCacheEntry::is_volatile_shift, 63); // Extract volatile bit. + __ bne(CCR0, LisVolatile); + + switch(bytecode()) { + case Bytecodes::_fast_agetfield: + { + __ load_heap_oop(R17_tos, (RegisterOrConstant)Roffset, Rclass_or_obj); + __ verify_oop(R17_tos); + __ b(Lexit); + + __ bind(LisVolatile); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); } + __ load_heap_oop(R17_tos, (RegisterOrConstant)Roffset, Rclass_or_obj); + __ verify_oop(R17_tos); + __ twi_0(R17_tos); + __ isync(); + break; + } + case Bytecodes::_fast_igetfield: + { + __ lwax(R17_tos, Rclass_or_obj, Roffset); + __ b(Lexit); + + __ bind(LisVolatile); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); } + __ lwax(R17_tos, Rclass_or_obj, Roffset); + __ twi_0(R17_tos); + __ isync(); + break; + } + case Bytecodes::_fast_lgetfield: + { + __ ldx(R17_tos, Rclass_or_obj, Roffset); + __ b(Lexit); + + __ bind(LisVolatile); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); } + __ ldx(R17_tos, Rclass_or_obj, Roffset); + __ twi_0(R17_tos); + __ isync(); + break; + } + case Bytecodes::_fast_bgetfield: + { + __ lbzx(R17_tos, Rclass_or_obj, Roffset); + __ extsb(R17_tos, R17_tos); + __ b(Lexit); + + __ bind(LisVolatile); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); } + __ lbzx(R17_tos, Rclass_or_obj, Roffset); + __ twi_0(R17_tos); + __ extsb(R17_tos, R17_tos); + __ isync(); + break; + } + case Bytecodes::_fast_cgetfield: + { + __ lhzx(R17_tos, Rclass_or_obj, Roffset); + __ b(Lexit); + + __ bind(LisVolatile); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); } + __ lhzx(R17_tos, Rclass_or_obj, Roffset); + __ twi_0(R17_tos); + __ isync(); + break; + } + case Bytecodes::_fast_sgetfield: + { + __ lhax(R17_tos, Rclass_or_obj, Roffset); + __ b(Lexit); + + __ bind(LisVolatile); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); } + __ lhax(R17_tos, Rclass_or_obj, Roffset); + __ twi_0(R17_tos); + __ isync(); + break; + } + case Bytecodes::_fast_fgetfield: + { + __ lfsx(F15_ftos, Rclass_or_obj, Roffset); + __ b(Lexit); + + __ bind(LisVolatile); + Label Ldummy; + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); } + __ lfsx(F15_ftos, Rclass_or_obj, Roffset); + __ fcmpu(CCR0, F15_ftos, F15_ftos); // Acquire by cmp-br-isync. + __ bne_predict_not_taken(CCR0, Ldummy); + __ bind(Ldummy); + __ isync(); + break; + } + case Bytecodes::_fast_dgetfield: + { + __ lfdx(F15_ftos, Rclass_or_obj, Roffset); + __ b(Lexit); + + __ bind(LisVolatile); + Label Ldummy; + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); } + __ lfdx(F15_ftos, Rclass_or_obj, Roffset); + __ fcmpu(CCR0, F15_ftos, F15_ftos); // Acquire by cmp-br-isync. + __ bne_predict_not_taken(CCR0, Ldummy); + __ bind(Ldummy); + __ isync(); + break; + } + default: ShouldNotReachHere(); + } + __ align(32, 12); + __ bind(Lexit); +} + +void TemplateTable::fast_xaccess(TosState state) { + transition(vtos, state); + + Label Lexit, LisVolatile; + ByteSize cp_base_offset = constantPoolCacheOopDesc::base_offset(); + const Register Rcache = R3_ARG1, + Rclass_or_obj = R17_tos, + Roffset = R22_tmp2, + Rflags = R23_tmp3, + Rscratch = R12_scratch2; + + __ ld(Rclass_or_obj, 0, R18_locals); + + // Constant pool already resolved. Get the field offset. + __ get_cache_and_index_at_bcp(Rcache, 2); + load_field_cp_cache_entry(noreg, Rcache, noreg, Roffset, Rflags, false); + + // JVMTI support not needed, since we switch back to single bytecode as soon as debugger attaches. + + // Needed to report exception at the correct bcp. + __ addi(R14_bcp, R14_bcp, 1); + + // Get the load address. + __ null_check_throw(Rclass_or_obj, -1, Rscratch); + + // Get volatile flag. + __ rldicl_(Rscratch, Rflags, 64-ConstantPoolCacheEntry::is_volatile_shift, 63); // Extract volatile bit. + __ bne(CCR0, LisVolatile); + + switch(state) { + case atos: + { + __ load_heap_oop(R17_tos, (RegisterOrConstant)Roffset, Rclass_or_obj); + __ verify_oop(R17_tos); + __ b(Lexit); + + __ bind(LisVolatile); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); } + __ load_heap_oop(R17_tos, (RegisterOrConstant)Roffset, Rclass_or_obj); + __ verify_oop(R17_tos); + __ twi_0(R17_tos); + __ isync(); + break; + } + case itos: + { + __ lwax(R17_tos, Rclass_or_obj, Roffset); + __ b(Lexit); + + __ bind(LisVolatile); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); } + __ lwax(R17_tos, Rclass_or_obj, Roffset); + __ twi_0(R17_tos); + __ isync(); + break; + } + case ftos: + { + __ lfsx(F15_ftos, Rclass_or_obj, Roffset); + __ b(Lexit); + + __ bind(LisVolatile); + Label Ldummy; + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); } + __ lfsx(F15_ftos, Rclass_or_obj, Roffset); + __ fcmpu(CCR0, F15_ftos, F15_ftos); // Acquire by cmp-br-isync. + __ bne_predict_not_taken(CCR0, Ldummy); + __ bind(Ldummy); + __ isync(); + break; + } + default: ShouldNotReachHere(); + } + __ align(32, 12); + __ bind(Lexit); + __ addi(R14_bcp, R14_bcp, -1); +} + +// ============================================================================ +// Calls +#if 0 // HS25? +// Common code for invoke +// +// Input: +// - byte_no +// +// Output: +// - Rmethod: The method to invoke next. +// - Rret_addr: The return address to return to. +// - Rindex: MethodType (invokehandle) or CallSite obj (invokedynamic) +// - Rrecv: Cache for "this" pointer, might be noreg if static call. +// - Rflags: Method flags from const pool cache. +// +// Kills: +// - Rscratch1 +// +void TemplateTable::prepare_invoke(int byte_no, + Register Rmethod, // linked method (or i-klass) + Register Rret_addr,// return address + Register Rindex, // itable index, MethodType, etc. + Register Rrecv, // If caller wants to see it. + Register Rflags, // If caller wants to test it. + Register Rscratch + ) { + // Determine flags. + const Bytecodes::Code code = bytecode(); + const bool is_invokeinterface = code == Bytecodes::_invokeinterface; + const bool is_invokedynamic = code == Bytecodes::_invokedynamic; + const bool is_invokehandle = code == Bytecodes::_invokehandle; + const bool is_invokevirtual = code == Bytecodes::_invokevirtual; + const bool is_invokespecial = code == Bytecodes::_invokespecial; + const bool load_receiver = (Rrecv != noreg); + assert(load_receiver == (code != Bytecodes::_invokestatic && code != Bytecodes::_invokedynamic), ""); + + assert_different_registers(Rmethod, Rindex, Rflags, Rscratch); + assert_different_registers(Rmethod, Rrecv, Rflags, Rscratch); + assert_different_registers(Rret_addr, Rscratch); + + load_invoke_cp_cache_entry(byte_no, Rmethod, Rindex, Rflags, is_invokevirtual, false, is_invokedynamic); + + // Saving of SP done in call_from_interpreter. + + // Maybe push "appendix" to arguments. + if (is_invokedynamic || is_invokehandle) { + Label Ldone; + __ rldicl_(R0, Rflags, 64-ConstantPoolCacheEntry::has_appendix_shift, 63); + __ beq(CCR0, Ldone); + // Push "appendix" (MethodType, CallSite, etc.). + // This must be done before we get the receiver, + // since the parameter_size includes it. + __ load_resolved_reference_at_index(Rscratch, Rindex); + __ verify_oop(Rscratch); + __ push_ptr(Rscratch); + __ bind(Ldone); + } + + // Load receiver if needed (after appendix is pushed so parameter size is correct). + if (load_receiver) { + const Register Rparam_count = Rscratch; + __ andi(Rparam_count, Rflags, ConstantPoolCacheEntry::parameter_size_mask); + __ load_receiver(Rparam_count, Rrecv); + __ verify_oop(Rrecv); + } + + // Get return address. + { + Register Rtable_addr = Rscratch; + Register Rret_type = Rret_addr; + address table_addr = (address) Interpreter::invoke_return_entry_table_for(code); + + // Get return type. It's coded into the upper 4 bits of the lower half of the 64 bit value. + __ rldicl(Rret_type, Rflags, 64-ConstantPoolCacheEntry::tos_state_shift, 64-ConstantPoolCacheEntry::tos_state_bits); + __ load_dispatch_table(Rtable_addr, (address*)table_addr); + __ sldi(Rret_type, Rret_type, LogBytesPerWord); + // Get return address. + __ ldx(Rret_addr, Rtable_addr, Rret_type); + } +} +#endif + +// Helper for virtual calls. Load target out of vtable and jump off! +// Kills all passed registers. +void TemplateTable::generate_vtable_call(Register Rrecv_klass, Register Rindex, Register Rret, Register Rtemp) { + + assert_different_registers(Rrecv_klass, Rtemp, Rret); + const Register Rtarget_method = Rindex; + + // Get target methodOop & entry point. + const int base = instanceKlass::vtable_start_offset() * wordSize; + // Calc vtable addr scale the vtable index by 8. + __ sldi(Rindex, Rindex, exact_log2(vtableEntry::size() * wordSize)); + // Load target. + __ addi(Rrecv_klass, Rrecv_klass, base + vtableEntry::method_offset_in_bytes()); + __ ldx(Rtarget_method, Rindex, Rrecv_klass); + __ call_from_interpreter(Rtarget_method, Rret, Rrecv_klass /* scratch1 */, Rtemp /* scratch2 */); +} + +// Virtual or final call. Final calls are rewritten on the fly to run through "fast_finalcall" next time. +void TemplateTable::invokevirtual(int byte_no) { + transition(vtos, vtos); + + Register Rtable_addr = R11_scratch1, + Rret_type = R12_scratch2, + Rret_addr = R5_ARG3, + Rflags = R22_tmp2, // Should survive C call. + Rrecv = R3_ARG1, + Rrecv_klass = Rrecv, + Rvtableindex_or_method = R31, // Should survive C call. + Rnum_params = R4_ARG2, + Rnew_bc = R6_ARG4; + + Label LnotFinal; + + load_invoke_cp_cache_entry(byte_no, Rvtableindex_or_method, noreg, Rflags, /*virtual*/ true, false, false); + + __ testbitdi(CCR0, R0, Rflags, ConstantPoolCacheEntry::is_vfinal_shift); + __ bfalse(CCR0, LnotFinal); + + patch_bytecode(Bytecodes::_fast_invokevfinal, Rnew_bc, R12_scratch2); + invokevfinal_helper(Rvtableindex_or_method, Rflags, R11_scratch1, R12_scratch2); + + __ align(32, 12); + __ bind(LnotFinal); + // Load "this" pointer (receiver). + __ rldicl(Rnum_params, Rflags, 64, 48); + __ load_receiver(Rnum_params, Rrecv); + __ verify_oop(Rrecv); + + // Get return type. It's coded into the upper 4 bits of the lower half of the 64 bit value. + __ rldicl(Rret_type, Rflags, 64-ConstantPoolCacheEntry::tos_state_shift, 64-ConstantPoolCacheEntry::tos_state_bits); + __ load_dispatch_table(Rtable_addr, Interpreter::return_3_addrs_by_index_table()); + __ sldi(Rret_type, Rret_type, LogBytesPerWord); + __ ldx(Rret_addr, Rret_type, Rtable_addr); + __ null_check_throw(Rrecv, oopDesc::klass_offset_in_bytes(), R11_scratch1); + __ load_heap_oop_not_null(Rrecv_klass, oopDesc::klass_offset_in_bytes(), Rrecv); + __ verify_oop(Rrecv_klass); + __ profile_virtual_call(Rrecv_klass, R11_scratch1, R12_scratch2, false); + + generate_vtable_call(Rrecv_klass, Rvtableindex_or_method, Rret_addr, R11_scratch1); +} + +void TemplateTable::fast_invokevfinal(int byte_no) { + transition(vtos, vtos); + + assert(byte_no == f2_byte, "use this argument"); + Register Rflags = R22_tmp2, + Rmethod = R31; + load_invoke_cp_cache_entry(byte_no, Rmethod, noreg, Rflags, /*virtual*/ true, /*is_invokevfinal*/ true, false); + invokevfinal_helper(Rmethod, Rflags, R11_scratch1, R12_scratch2); +} + +void TemplateTable::invokevfinal_helper(Register RmethodOop, Register Rflags, Register Rscratch1, Register Rscratch2) { + + assert_different_registers(RmethodOop, Rflags, Rscratch1, Rscratch2); + __ verify_oop(RmethodOop); + + // Load receiver from stack slot. + Register Rrecv = Rscratch2; + Register Rnum_params = Rrecv; + + __ lhz(Rnum_params, in_bytes(methodOopDesc::size_of_parameters_offset()), RmethodOop); + + // Get return address. + Register Rtable_addr = Rscratch1, + Rret_addr = Rflags, + Rret_type = Rret_addr; + // Get return type. It's coded into the upper 4 bits of the lower half of the 64 bit value. + __ rldicl(Rret_type, Rflags, 64-ConstantPoolCacheEntry::tos_state_shift, 64-ConstantPoolCacheEntry::tos_state_bits); + __ load_dispatch_table(Rtable_addr, Interpreter::return_3_addrs_by_index_table()); + __ sldi(Rret_type, Rret_type, LogBytesPerWord); + __ ldx(Rret_addr, Rret_type, Rtable_addr); + + // Load receiver and receiver NULL check. + __ load_receiver(Rnum_params, Rrecv); + __ null_check_throw(Rrecv, -1, Rscratch1); + + __ profile_final_call(Rrecv, Rscratch1); + + // Do the call. + __ call_from_interpreter(RmethodOop, Rret_addr, Rscratch1, Rscratch2); +} + +void TemplateTable::invokespecial(int byte_no) { + assert(byte_no == f1_byte, "use this argument"); + transition(vtos, vtos); + + Register Rtable_addr = R3_ARG1, + Rret_type = R4_ARG2, + Rret_addr = R5_ARG3, + Rflags = R6_ARG4, + Rreceiver = R7_ARG5, + Rmethod = R31; + + load_invoke_cp_cache_entry(byte_no, Rmethod, R11_scratch1, Rflags, /*virtual*/ false, false, false); + + __ verify_oop(Rmethod); + __ lhz(R11_scratch1, in_bytes(methodOopDesc::size_of_parameters_offset()), Rmethod); + __ load_receiver(R11_scratch1, Rreceiver); + + // Receiver NULL check. + __ null_check_throw(Rreceiver, -1, R11_scratch1); + + __ profile_call(R11_scratch1,R12_scratch2); + + // Get return type. It's coded into the upper 4 bits of the lower half of the 64 bit value. + __ rldicl(Rret_type, Rflags, 64-ConstantPoolCacheEntry::tos_state_shift, 64-ConstantPoolCacheEntry::tos_state_bits); + __ load_dispatch_table(Rtable_addr, Interpreter::return_3_addrs_by_index_table()); + __ sldi(Rret_type, Rret_type, LogBytesPerWord); + __ ldx(Rret_addr,Rret_type, Rtable_addr); + + __ call_from_interpreter(Rmethod, Rret_addr, R11_scratch1, R12_scratch2); +} + +void TemplateTable::invokestatic(int byte_no) { + assert(byte_no == f1_byte, "use this argument"); + transition(vtos, vtos); + + Register Rtable_addr = R3_ARG1, + Rret_type = R4_ARG2, + Rret_addr = R5_ARG3, + Rflags = R6_ARG4; + + load_invoke_cp_cache_entry(byte_no, R19_method, R11_scratch1, Rflags, /*virtual*/ false, false, false); + + __ verify_oop(R19_method); + + __ profile_call(R11_scratch1, R12_scratch2); + + // Get return type. It's coded into the upper 4 bits of the lower half of the 64 bit value. + __ rldicl(Rret_type, Rflags, 64-ConstantPoolCacheEntry::tos_state_shift, 64-ConstantPoolCacheEntry::tos_state_bits); + __ load_dispatch_table(Rtable_addr, Interpreter::return_3_addrs_by_index_table()); + __ sldi(Rret_type, Rret_type, LogBytesPerWord); + __ ldx(Rret_addr,Rret_type, Rtable_addr); + + __ call_from_interpreter(R19_method, Rret_addr, R11_scratch1, R12_scratch2); +} + +void TemplateTable::invokeinterface_object_method(Register Rrecv_klass, + Register Rret, + Register Rflags, + Register Rindex, + Register Rtemp1, + Register Rtemp2) { + + assert_different_registers(Rindex, Rret, Rrecv_klass, Rflags, Rtemp1, Rtemp2); + Label LnotFinal; + + // Check for vfinal. + __ testbitdi(CCR0, R0, Rflags, ConstantPoolCacheEntry::is_vfinal_shift); + __ bfalse(CCR0, LnotFinal); + + Register Rscratch = Rflags; // Rflags is dead now. + + // Final call case. + __ profile_final_call(Rtemp1, Rscratch); + // Do the final call - the index (f2) contains the methodOop. + __ call_from_interpreter(Rindex, Rret, Rscratch, Rrecv_klass /* scratch */); + + // Non-final callc case. + __ bind(LnotFinal); + __ profile_virtual_call(Rrecv_klass, Rtemp1, Rscratch, false); + generate_vtable_call(Rrecv_klass, Rindex, Rret, Rscratch); +} + +void TemplateTable::invokeinterface(int byte_no) { + assert(byte_no == f1_byte, "use this argument"); + transition(vtos, vtos); + + const Register Rscratch1 = R11_scratch1, + Rscratch2 = R12_scratch2, + Rscratch3 = R9_ARG7, + Rscratch4 = R10_ARG8, + Rtable_addr = Rscratch2, + Rinterface_klass = R5_ARG3, + Rret_type = R8_ARG6, + Rret_addr = Rret_type, + Rindex = R6_ARG4, + Rreceiver = R4_ARG2, + Rrecv_klass = Rreceiver, + Rflags = R7_ARG5; + + load_invoke_cp_cache_entry(byte_no, Rinterface_klass, Rindex, Rflags, /*virtual*/ false, false, false); + // Get receiver from expression stack. + Register Rparam_count = Rscratch1; + __ andi(Rparam_count, Rflags, ConstantPoolCacheEntry::parameter_size_mask); + __ load_receiver(Rparam_count, Rreceiver); + __ verify_oop(Rreceiver); + + // Get return address. + __ rldicl(Rret_type, Rflags, 64-ConstantPoolCacheEntry::tos_state_shift, 64-ConstantPoolCacheEntry::tos_state_bits); + __ load_dispatch_table(Rtable_addr, Interpreter::return_5_addrs_by_index_table()); + __ sldi(Rret_type, Rret_type, LogBytesPerWord); + __ ldx(Rret_addr, Rret_type, Rtable_addr); + + // Get receiver klass. + __ null_check_throw(Rreceiver, oopDesc::klass_offset_in_bytes(), Rscratch3); + __ load_klass(Rrecv_klass, Rreceiver); + __ verify_oop(Rrecv_klass); + + // Check corner case object method. + Label LobjectMethod; + + __ testbitdi(CCR0, R0, Rflags, ConstantPoolCacheEntry::is_forced_virtual_shift); + __ btrue(CCR0, LobjectMethod); + + // Fallthrough: The normal invokeinterface case. + __ profile_virtual_call(Rrecv_klass, Rscratch1, Rscratch2, false); + + // Find entry point to call. + Label Lthrow_icc, Lthrow_ame; + // Result will be returned in Rindex. + __ mr(Rscratch4, Rrecv_klass); + __ mr(Rscratch3, Rindex); + __ lookup_interface_method(Rrecv_klass, Rinterface_klass, Rindex, Rindex, Rscratch1, Rscratch2, Lthrow_icc); + + __ cmpdi(CCR0, Rindex, 0); + __ beq(CCR0, Lthrow_ame); + // Found entry. Jump off! + __ call_from_interpreter(Rindex, Rret_addr, Rscratch1, Rscratch2); + + // Vtable entry was NULL => Throw abstract method error. + __ bind(Lthrow_ame); + __ mr(Rrecv_klass, Rscratch4); + __ mr(Rindex, Rscratch3); + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError)); + + // Interface was not found => Throw incompatible class change error. + __ bind(Lthrow_icc); + __ mr(Rrecv_klass, Rscratch4); + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_IncompatibleClassChangeError)); + + __ should_not_reach_here(); + + // Special case of invokeinterface called for virtual method of + // java.lang.Object. See ConstantPoolCacheEntry::set_method() for details: + // The invokeinterface was rewritten to a invokevirtual, hence we have + // to handle this corner case. This code isn't produced by javac, but could + // be produced by another compliant java compiler. + __ bind(LobjectMethod); + invokeinterface_object_method(Rrecv_klass, Rret_addr, Rflags, Rindex, Rscratch1, Rscratch2); +} + +// Common code for invokedynamic and invokehandle. +// +// Input: +// - byte_no +// +// Output: +// - Rmethod: The method oop to invoke next. +// - Rret_addr: The return address to return to. +// - Runextended_SP: The register the unextended SP will be saved in. +// - Rappendix: MethodType (invokehandle) or CallSite obj (invokedynamic). +// - Rflags: Method flags from const pool cache. +// - Rrecv: Cache for "this" pointer, might be noreg if static call. +// +// Kills: +// - Rscratch1 +void TemplateTable::prepare_indy_invoke(int byte_no, Register Rmethod, Register Rret_addr, Register Runextended_SP, + Register Rappendix, Register Rflags, Register Rrecv, Register Rscratch1) { + // Determine flags. + const Bytecodes::Code code = bytecode(); + const bool is_invokeinterface = code == Bytecodes::_invokeinterface; + const bool is_invokedynamic = code == Bytecodes::_invokedynamic; + const bool is_invokehandle = code == Bytecodes::_invokehandle; + const bool is_invokevirtual = code == Bytecodes::_invokevirtual; + const bool is_invokespecial = code == Bytecodes::_invokespecial; + const bool load_receiver = (Rrecv != noreg); + + load_invoke_cp_cache_entry(byte_no, Rmethod, Rappendix, Rflags, is_invokevirtual, false, is_invokedynamic); + + // Saving of SP done in call_from_interpreter. + + // Maybe push "appendix" to arguments. + if (is_invokedynamic || is_invokehandle) { + Label Ldone; + __ verify_oop(Rappendix); + __ rldicl_(R0, Rflags, 64-ConstantPoolCacheEntry::has_appendix_shift, 63); + __ beq(CCR0, Ldone); + // Push "appendix" (MethodType, CallSite, etc.). + // This must be done before we get the receiver, + // since the parameter_size includes it. + __ push_ptr(Rappendix); + __ bind(Ldone); + } + + // Load receiver if needed (after appendix is pushed so parameter size is correct). + if (load_receiver) { + const Register Rparam_count = Rscratch1; + __ andi(Rparam_count, Rflags, ConstantPoolCacheEntry::parameter_size_mask); + __ load_receiver(Rparam_count, Rrecv); + __ verify_oop(Rrecv); + } + + // Get return address. + { + Register Rtable_addr = Rscratch1; + Register Rret_type = Rret_addr; + address table_addr = (is_invokeinterface || is_invokedynamic) ? + (address) Interpreter::return_5_addrs_by_index_table() : (address) Interpreter::return_3_addrs_by_index_table(); + + // Get return type. It's coded into the upper 4 bits of the lower half of the 64 bit value. + __ rldicl(Rret_type, Rflags, 64-ConstantPoolCacheEntry::tos_state_shift, 64-ConstantPoolCacheEntry::tos_state_bits); + __ load_dispatch_table(Rtable_addr, (address*)table_addr); + __ sldi(Rret_type, Rret_type, LogBytesPerWord); + // Get return address. + __ ldx(Rret_addr, Rtable_addr, Rret_type); + } +} + +void TemplateTable::invokedynamic(int byte_no) { + transition(vtos, vtos); + + assert(byte_no == f12_oop, "use this argument"); + + const Register Rcallsite = R3_ARG1, + Rret_addr = R4_ARG2, + Rflags = R5_ARG3, + Rscratch1 = R11_scratch1, + Rscratch2 = R12_scratch2; + + if (!EnableInvokeDynamic) { + // We should not encounter this bytecode if !EnableInvokeDynamic. + // The verifier will stop it. However, if we get past the verifier, + // this will stop the thread in a reasonable way, without crashing the JVM. + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_IncompatibleClassChangeError)); + // The call_VM checks for exception, so we should never return here. + __ should_not_reach_here(); + return; + } + + prepare_indy_invoke(byte_no, R19_method, Rret_addr, R21_sender_SP, Rcallsite, Rflags, noreg, Rscratch1); + + // Profile this call. + __ profile_call(Rscratch1, Rscratch2); + + // Off we go. With the new method handles, we don't jump to a method handle + // entry any more. Instead, we pushed an "appendix" in prepare invoke, which happens + // to be the callsite object the bootstrap method returned. This is passed to a + // "link" method which does the dispatch (Most likely just grabs the MH stored + // inside the callsite and does an invokehandle). + __ call_from_interpreter(R19_method, Rret_addr, Rscratch1 /* scratch1 */, Rscratch2 /* scratch2 */); +} + +void TemplateTable::invokehandle(int byte_no) { + transition(vtos, vtos); + + assert(byte_no == f12_oop, "use this argument"); + + const Register Rmethod_type = R3_ARG1, + Rret_addr = R4_ARG2, + Rflags = R5_ARG3, + Rrecv = R6_ARG4, + Rscratch1 = R11_scratch1, + Rscratch2 = R12_scratch2, + Rmethod = R31; + + if (!EnableInvokeDynamic) { + // Rewriter does not generate this bytecode. + __ should_not_reach_here(); + return; + } + + prepare_indy_invoke(byte_no, Rmethod, Rret_addr, R21_sender_SP, Rmethod_type, Rflags, Rrecv, Rscratch1); + __ null_check_throw(Rrecv, -1, Rscratch2); + + __ profile_final_call(Rrecv, Rscratch1); + + // Still no call from handle => We call the method handle interpreter here. + __ call_from_interpreter(Rmethod, Rret_addr, Rscratch1 /* scratch1 */, Rscratch2 /* scratch2 */); +} + +// ============================================================================= +// Allocation + +// Puts allocated obj ref onto the expression stack. +void TemplateTable::_new() { + transition(vtos, atos); + + Label Lslow_case, + Ldone, + Linitialize_header, + Lallocate_shared, + Linitialize_object; // Including clearing the fields. + + const Register RallocatedObject = R17_tos, + RinstanceKlass = R9_ARG7, + Rscratch = R11_scratch1, + Roffset = R8_ARG6, + Rinstance_size = Roffset, + Rcpool = R4_ARG2, + Rtags = R3_ARG1, + Rindex = R5_ARG3; + + // -------------------------------------------------------------------------- + // Check if fast case is possible. + + // Load index of constant pool entry. + __ get_2_byte_integer_at_bcp(1, Rindex, InterpreterMacroAssembler::Unsigned); + // Load pointers to const pool and const pool's tags array. + __ get_cpool_and_tags(Rcpool, Rtags); + + // Make sure the class we're about to instantiate has been resolved + // This is done before loading instanceKlass to be consistent with the order + // how Constant Pool is updated (see constantPoolOopDesc::klass_at_put). + __ addi(Rtags, Rtags, typeArrayOopDesc::header_size(T_BYTE) * wordSize); + __ lbzx(Rtags, Rindex, Rtags); + + __ cmpdi(CCR0, Rtags, JVM_CONSTANT_Class); + __ bne(CCR0, Lslow_case); + + // Get instanceKlass. + __ sldi(Roffset, Rindex, LogBytesPerWord); + __ addi(Roffset, Roffset, sizeof(constantPoolOopDesc)); + __ isync(); // Order load of instance Klass wrt. tags. + __ ldx(RinstanceKlass, Roffset, Rcpool); + + // Make sure klass is fully initialized and get instance_size. + __ lbz(Rscratch, in_bytes(instanceKlass::init_state_offset()), RinstanceKlass); + __ lwz(Rinstance_size, in_bytes(Klass::layout_helper_offset()), RinstanceKlass); + + __ cmpdi(CCR0, Rscratch, instanceKlass::fully_initialized); + __ bne(CCR0, Lslow_case); + + // Make sure klass does not have has_finalizer, or is abstract, or interface or java/lang/Class. + __ testbitdi(CCR0, R0, Rinstance_size, Klass::_lh_instance_slow_path_bit); + __ bne(CCR0, Lslow_case); + + // -------------------------------------------------------------------------- + // Fast case: + // Allocate the instance. + // 1) Try to allocate in the TLAB. + // 2) If fail, and the TLAB is not full enough to discard, allocate in the shared Eden. + // 3) If the above fails (or is not applicable), go to a slow case (creates a new TLAB, etc.). + const bool allow_shared_alloc = Universe::heap()->supports_inline_contig_alloc() && !CMSIncrementalMode; + + if (UseTLAB) { + Register RoldTopValue = RallocatedObject; // Object will be allocated here if it fits. + Register RnewTopValue = R6_ARG4; + Register RendValue = R7_ARG5; + + // Check if we can allocate in the TLAB. + __ ld(RoldTopValue, in_bytes(JavaThread::tlab_top_offset()), R16_thread); + __ ld(RendValue, in_bytes(JavaThread::tlab_end_offset()), R16_thread); + + __ add(RnewTopValue, Rinstance_size, RoldTopValue); + + // If there is enough space, we do not CAS and do not clear. + __ cmpld(CCR0, RnewTopValue, RendValue); + __ bgt(CCR0, allow_shared_alloc ? Lallocate_shared : Lslow_case); + + __ std(RnewTopValue, in_bytes(JavaThread::tlab_top_offset()), R16_thread); + + if (ZeroTLAB) { + // The fields have already been cleared. + __ b(Linitialize_header); + } else { + // Initialize both the header and fields. + __ b(Linitialize_object); + } + + // Fall through: TLAB was too small. + if (allow_shared_alloc) { + Register RtlabWasteLimitValue = R10_ARG8; + Register RfreeValue = RnewTopValue; + + __ bind(Lallocate_shared); + // Check if tlab should be discarded (refill_waste_limit >= free). + __ ld(RtlabWasteLimitValue, in_bytes(JavaThread::tlab_refill_waste_limit_offset()), R16_thread); + __ subf(RfreeValue, RoldTopValue, RendValue); + __ srdi(RfreeValue, RfreeValue, LogHeapWordSize); // in dwords + __ cmpld(CCR0, RtlabWasteLimitValue, RfreeValue); + __ bge(CCR0, Lslow_case); + + // Increment waste limit to prevent getting stuck on this slow path. + __ addi(RtlabWasteLimitValue, RtlabWasteLimitValue, (int)ThreadLocalAllocBuffer::refill_waste_limit_increment()); + __ std(RtlabWasteLimitValue, in_bytes(JavaThread::tlab_refill_waste_limit_offset()), R16_thread); + } + // else: No allocation in the shared eden. // fallthru: __ b(Lslow_case); + } + // else: Always go the slow path. + + // -------------------------------------------------------------------------- + // slow case + __ bind(Lslow_case); + call_VM(R17_tos, CAST_FROM_FN_PTR(address, InterpreterRuntime::_new), Rcpool, Rindex); + + if (UseTLAB) { + __ b(Ldone); + // -------------------------------------------------------------------------- + // Init1: Zero out newly allocated memory. + + if (!ZeroTLAB || allow_shared_alloc) { + // Clear object fields. + __ bind(Linitialize_object); + + // Initialize remaining object fields. + Register Rbase = Rtags; + __ addi(Rinstance_size, Rinstance_size, 7 - (int)sizeof(oopDesc)); + __ addi(Rbase, RallocatedObject, sizeof(oopDesc)); + __ srdi(Rinstance_size, Rinstance_size, 3); + + // Clear out object skipping header. Takes also care of the zero length case. + __ clear_memory_doubleword(Rbase, Rinstance_size); + // fallthru: __ b(Linitialize_header); + } + + // -------------------------------------------------------------------------- + // Init2: Initialize the header: mark, klass + __ bind(Linitialize_header); + + // Init mark. + if (UseBiasedLocking) { + __ ld(Rscratch, in_bytes(Klass::prototype_header_offset()), RinstanceKlass); + } else { + __ load_const_optimized(Rscratch, markOopDesc::prototype(), R0); + } + __ std(Rscratch, oopDesc::mark_offset_in_bytes(), RallocatedObject); + + // Init klass. + if (UseCompressedOops) { + __ li(R0, 0); + __ stw(R0, oopDesc::klass_gap_offset_in_bytes(), RallocatedObject); // klass gap if compressed + } + __ store_heap_oop_not_null(RinstanceKlass, oopDesc::klass_offset_in_bytes(), RallocatedObject); // klass (last for cms) + + // Check and trigger dtrace event. + { + SkipIfEqualZero skip_if(_masm, Rscratch, &DTraceAllocProbes); + __ push(atos); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_object_alloc)); + __ pop(atos); + } + } + + // continue + __ bind(Ldone); + + // Must prevent reordering of stores for object initialization with stores that publish the new object. + __ membar(Assembler::StoreStore); +} + +void TemplateTable::newarray() { + transition(itos, atos); + + __ lbz(R4, 1, R14_bcp); + __ extsw(R5, R17_tos); + call_VM(R17_tos, CAST_FROM_FN_PTR(address, InterpreterRuntime::newarray), R4, R5 /* size */); + + // Must prevent reordering of stores for object initialization with stores that publish the new object. + __ membar(Assembler::StoreStore); +} + +void TemplateTable::anewarray() { + transition(itos, atos); + + __ get_constant_pool(R4); + __ get_2_byte_integer_at_bcp(1, R5, InterpreterMacroAssembler::Unsigned); + __ extsw(R6, R17_tos); // size + call_VM(R17_tos, CAST_FROM_FN_PTR(address, InterpreterRuntime::anewarray), R4 /* pool */, R5 /* index */, R6 /* size */); + + // Must prevent reordering of stores for object initialization with stores that publish the new object. + __ membar(Assembler::StoreStore); +} + +// Allocate a multi dimensional array +void TemplateTable::multianewarray() { + transition(vtos, atos); + + Register Rptr = R31; // Needs to survive C call. + + // Put ndims * wordSize into frame temp slot + __ lbz(Rptr, 3, R14_bcp); + __ sldi(Rptr, Rptr, Interpreter::logStackElementSize); + // Esp points past last_dim, so set to R4 to first_dim address. + __ add(R4, Rptr, R15_esp); + call_VM(R17_tos, CAST_FROM_FN_PTR(address, InterpreterRuntime::multianewarray), R4 /* first_size_address */); + // Pop all dimensions off the stack. + __ add(R15_esp, Rptr, R15_esp); + + // Must prevent reordering of stores for object initialization with stores that publish the new object. + __ membar(Assembler::StoreStore); +} + +void TemplateTable::arraylength() { + transition(atos, itos); + + Label LnoException; + __ verify_oop(R17_tos); + __ null_check_throw(R17_tos, arrayOopDesc::length_offset_in_bytes(), R11_scratch1); + __ lwa(R17_tos, arrayOopDesc::length_offset_in_bytes(), R17_tos); +} + +// ============================================================================ +// Typechecks + +void TemplateTable::checkcast() { + transition(atos, atos); + + Label Ldone, Lis_null, Lquicked, Lresolved; + Register Roffset = R5_ARG3, + RobjKlass = R4_ARG2, + RspecifiedKlass = R6_ARG4, // Generate_ClassCastException_verbose_handler will expect this register. + Rcpool = R11_scratch1, + Rtags = R12_scratch2; + + // Null does not pass. + __ cmpdi(CCR0, R17_tos, 0); + __ beq(CCR0, Lis_null); + + // Get constant pool tag to find out if the bytecode has already been "quickened". + __ get_cpool_and_tags(Rcpool, Rtags); + + __ get_2_byte_integer_at_bcp(1, Roffset, InterpreterMacroAssembler::Unsigned); + + __ addi(Rtags, Rtags, typeArrayOopDesc::header_size(T_BYTE) * wordSize); + __ lbzx(Rtags, Rtags, Roffset); + + __ sldi(Roffset, Roffset, LogBytesPerWord); + + __ cmpdi(CCR0, Rtags, JVM_CONSTANT_Class); + __ beq(CCR0, Lquicked); + + // Call into the VM to "quicken" instanceof. + __ push_ptr(); // for GC + call_VM(RspecifiedKlass, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc)); + __ pop_ptr(); // Restore receiver. + __ b(Lresolved); + + // Extract target class from constant pool. + __ bind(Lquicked); + __ isync(); // Order load of specified Klass wrt. tags. + __ addi(Roffset, Roffset, sizeof(constantPoolOopDesc)); + __ ldx(RspecifiedKlass, Rcpool, Roffset); + + // Do the checkcast. + __ bind(Lresolved); + // Get value klass in RobjKlass. + __ load_klass(RobjKlass, R17_tos); + // Generate a fast subtype check. Branch to cast_ok if no failure. Return 0 if failure. + __ gen_subtype_check(RobjKlass, RspecifiedKlass, /*3 temp regs*/ Roffset, Rcpool, Rtags, /*target if subtype*/ Ldone); + + // Not a subtype; so must throw exception + // Target class oop is in register R6_ARG4 == RspecifiedKlass by convention. + __ load_dispatch_table(R11_scratch1, (address*)Interpreter::_throw_ClassCastException_entry); + __ mtctr(R11_scratch1); + __ bctr(); + + // Profile the null case. + __ align(32, 12); + __ bind(Lis_null); + __ profile_null_seen(R11_scratch1, Rtags); // Rtags used as scratch. + + __ align(32, 12); + __ bind(Ldone); +} + +// Output: +// - tos == 0: Obj was null or not an instance of class. +// - tos == 1: Obj was an instance of class. +void TemplateTable::instanceof() { + transition(atos, itos); + + Label Ldone, Lis_null, Lquicked, Lresolved; + Register Roffset = R5_ARG3, + RobjKlass = R4_ARG2, + RspecifiedKlass = R6_ARG4, // Generate_ClassCastException_verbose_handler will expect the value in this register. + Rcpool = R11_scratch1, + Rtags = R12_scratch2; + + // Null does not pass. + __ cmpdi(CCR0, R17_tos, 0); + __ beq(CCR0, Lis_null); + + // Get constant pool tag to find out if the bytecode has already been "quickened". + __ get_cpool_and_tags(Rcpool, Rtags); + + __ get_2_byte_integer_at_bcp(1, Roffset, InterpreterMacroAssembler::Unsigned); + + __ addi(Rtags, Rtags, typeArrayOopDesc::header_size(T_BYTE) * wordSize); + __ lbzx(Rtags, Rtags, Roffset); + + __ sldi(Roffset, Roffset, LogBytesPerWord); + + __ cmpdi(CCR0, Rtags, JVM_CONSTANT_Class); + __ beq(CCR0, Lquicked); + + // Call into the VM to "quicken" instanceof. + __ push_ptr(); // for GC + call_VM(RspecifiedKlass, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc)); + __ pop_ptr(); // Restore receiver. + __ b(Lresolved); + + // Extract target class from constant pool. + __ bind(Lquicked); + __ isync(); // Order load of specified Klass wrt. tags. + __ addi(Roffset, Roffset, sizeof(constantPoolOopDesc)); + __ ldx(RspecifiedKlass, Rcpool, Roffset); + + // Do the checkcast. + __ bind(Lresolved); + // Get value klass in RobjKlass. + __ load_klass(RobjKlass, R17_tos); + // Generate a fast subtype check. Branch to cast_ok if no failure. Return 0 if failure. + __ li(R17_tos, 1); + __ gen_subtype_check(RobjKlass, RspecifiedKlass, /*3 temp regs*/ Roffset, Rcpool, Rtags, /*target if subtype*/ Ldone); + __ li(R17_tos, 0); + + if (ProfileInterpreter) { + __ b(Ldone); + } + + // Profile the null case. + __ align(32, 12); + __ bind(Lis_null); + __ profile_null_seen(Rcpool, Rtags); // Rcpool and Rtags used as scratch. + + __ align(32, 12); + __ bind(Ldone); +} + +// ============================================================================= +// Breakpoints + +void TemplateTable::_breakpoint() { + transition(vtos, vtos); + + // Get the unpatched byte code. + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::get_original_bytecode_at), R19_method, R14_bcp); + __ mr(R31, R3_RET); + + // Post the breakpoint event. + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::_breakpoint), R19_method, R14_bcp); + + // Complete the execution of original bytecode. + __ dispatch_Lbyte_code(vtos, R31, Interpreter::normal_table(vtos)); +} + +// ============================================================================= +// Exceptions + +void TemplateTable::athrow() { + transition(atos, vtos); + + // Exception oop is in tos + __ verify_oop(R17_tos); + + __ null_check_throw(R17_tos, -1, R11_scratch1); + + // Throw exception interpreter entry expects exception oop to be in R3. + __ mr(R3_RET, R17_tos); + __ load_dispatch_table(R11_scratch1, (address*)Interpreter::throw_exception_entry()); + __ mtctr(R11_scratch1); + __ bctr(); +} + +// ============================================================================= +// Synchronization +// Searches the basic object lock list on the stack for a free slot +// and uses it to lock the obect in tos. +// +// Recursive locking is enabled by exiting the search if the same +// object is already found in the list. Thus, a new basic lock obj lock +// is allocated "higher up" in the stack and thus is found first +// at next monitor exit. +void TemplateTable::monitorenter() { + transition(atos, vtos); + + __ verify_oop(R17_tos); + + Register Rcurrent_monitor = R11_scratch1, + Rcurrent_obj = R12_scratch2, + Robj_to_lock = R17_tos, + Rscratch1 = R3_ARG1, + Rscratch2 = R4_ARG2, + Rscratch3 = R5_ARG3, + Rcurrent_obj_addr = R6_ARG4; + + // ------------------------------------------------------------------------------ + // Null pointer exception. + __ null_check_throw(Robj_to_lock, -1, R11_scratch1); + + // Try to acquire a lock on the object. + // Repeat until succeeded (i.e., until monitorenter returns true). + + // ------------------------------------------------------------------------------ + // Find a free slot in the monitor block. + Label Lfound, Lexit, Lallocate_new; + ConditionRegister found_free_slot = CCR0, + found_same_obj = CCR1, + reached_limit = CCR6; + { + Label Lloop, Lentry; + Register Rlimit = Rcurrent_monitor; + + // Set up search loop - start with topmost monitor. + __ add(Rcurrent_obj_addr, BasicObjectLock::obj_offset_in_bytes(), R26_monitor); + + __ ld(Rlimit, 0, R1_SP); + __ addi(Rlimit, Rlimit, - (frame::ijava_state_size + frame::interpreter_frame_monitor_size_in_bytes() - BasicObjectLock::obj_offset_in_bytes())); // Monitor base + + // Check if any slot is present => short cut to allocation if not. + __ cmpld(reached_limit, Rcurrent_obj_addr, Rlimit); + __ bgt(reached_limit, Lallocate_new); + + // Pre-load topmost slot. + __ ld(Rcurrent_obj, 0, Rcurrent_obj_addr); + __ addi(Rcurrent_obj_addr, Rcurrent_obj_addr, frame::interpreter_frame_monitor_size() * wordSize); + // The search loop. + __ bind(Lloop); + // Found free slot? + __ cmpdi(found_free_slot, Rcurrent_obj, 0); + // Is this entry for same obj? If so, stop the search and take the found + // free slot or allocate a new one to enable recursive locking. + __ cmpd(found_same_obj, Rcurrent_obj, Robj_to_lock); + __ cmpld(reached_limit, Rcurrent_obj_addr, Rlimit); + __ beq(found_free_slot, Lexit); + __ beq(found_same_obj, Lallocate_new); + __ bgt(reached_limit, Lallocate_new); + // Check if last allocated BasicLockObj reached. + __ ld(Rcurrent_obj, 0, Rcurrent_obj_addr); + __ addi(Rcurrent_obj_addr, Rcurrent_obj_addr, frame::interpreter_frame_monitor_size() * wordSize); + // Next iteration if unchecked BasicObjectLocks exist on the stack. + __ b(Lloop); + } + + // ------------------------------------------------------------------------------ + // Check if we found a free slot. + __ bind(Lexit); + + __ addi(Rcurrent_monitor, Rcurrent_obj_addr, -(frame::interpreter_frame_monitor_size() * wordSize) - BasicObjectLock::obj_offset_in_bytes()); + __ addi(Rcurrent_obj_addr, Rcurrent_obj_addr, - frame::interpreter_frame_monitor_size() * wordSize); + __ b(Lfound); + + // We didn't find a free BasicObjLock => allocate one. + __ align(32, 12); + __ bind(Lallocate_new); + __ add_monitor_to_stack(false, Rscratch1, Rscratch2); + __ mr(Rcurrent_monitor, R26_monitor); + __ addi(Rcurrent_obj_addr, R26_monitor, BasicObjectLock::obj_offset_in_bytes()); + + // ------------------------------------------------------------------------------ + // We now have a slot to lock. + __ bind(Lfound); + + // Increment bcp to point to the next bytecode, so exception handling for async. exceptions work correctly. + // The object has already been poped from the stack, so the expression stack looks correct. + __ addi(R14_bcp, R14_bcp, 1); + + __ std(Robj_to_lock, 0, Rcurrent_obj_addr); + __ lock_object(Rcurrent_monitor, Robj_to_lock); + + // Check if there's enough space on the stack for the monitors after locking. + Label Lskip_stack_check; + // Optimization: If the monitors stack section is less then a std page size (4K) don't run + // the stack check. There should be enough shadow pages to fit that in. + __ ld(Rscratch3, 0, R1_SP); + __ sub(Rscratch3, Rscratch3, R26_monitor); + __ cmpdi(CCR0, Rscratch3, 4*K); + __ blt(CCR0, Lskip_stack_check); + + DEBUG_ONLY(__ untested("stack overflow check during monitor enter");) + __ li(Rscratch1, 0); + __ generate_stack_overflow_check_with_compare_and_throw(Rscratch1, Rscratch2); + + __ align(32, 12); + __ bind(Lskip_stack_check); + + // The bcp has already been incremented. Just need to dispatch to next instruction. + __ dispatch_next(vtos); +} + +void TemplateTable::monitorexit() { + transition(atos, vtos); + __ verify_oop(R17_tos); + + Register Rcurrent_monitor = R11_scratch1, + Rcurrent_obj = R12_scratch2, + Robj_to_lock = R17_tos, + Rcurrent_obj_addr = R3_ARG1, + Rlimit = R4_ARG2; + Label Lfound, Lillegal_monitor_state; + + // Check corner case: unbalanced monitorEnter / Exit. + __ ld(Rlimit, 0, R1_SP); + __ addi(Rlimit, Rlimit, - (frame::ijava_state_size + frame::interpreter_frame_monitor_size_in_bytes())); // Monitor base + + // Null pointer check. + __ null_check_throw(Robj_to_lock, -1, R11_scratch1); + + __ cmpld(CCR0, R26_monitor, Rlimit); + __ bgt(CCR0, Lillegal_monitor_state); + + // Find the corresponding slot in the monitors stack section. + { + Label Lloop; + + // Start with topmost monitor. + __ addi(Rcurrent_obj_addr, R26_monitor, BasicObjectLock::obj_offset_in_bytes()); + __ addi(Rlimit, Rlimit, BasicObjectLock::obj_offset_in_bytes()); + __ ld(Rcurrent_obj, 0, Rcurrent_obj_addr); + __ addi(Rcurrent_obj_addr, Rcurrent_obj_addr, frame::interpreter_frame_monitor_size() * wordSize); + + __ bind(Lloop); + // Is this entry for same obj? + __ cmpd(CCR0, Rcurrent_obj, Robj_to_lock); + __ beq(CCR0, Lfound); + + // Check if last allocated BasicLockObj reached. + + __ ld(Rcurrent_obj, 0, Rcurrent_obj_addr); + __ cmpld(CCR0, Rcurrent_obj_addr, Rlimit); + __ addi(Rcurrent_obj_addr, Rcurrent_obj_addr, frame::interpreter_frame_monitor_size() * wordSize); + + // Next iteration if unchecked BasicObjectLocks exist on the stack. + __ ble(CCR0, Lloop); + } + + // Fell through without finding the basic obj lock => throw up! + __ bind(Lillegal_monitor_state); + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_illegal_monitor_state_exception)); + __ should_not_reach_here(); + + __ align(32, 12); + __ bind(Lfound); + __ addi(Rcurrent_monitor, Rcurrent_obj_addr, + -(frame::interpreter_frame_monitor_size() * wordSize) - BasicObjectLock::obj_offset_in_bytes()); + __ unlock_object(Rcurrent_monitor); +} + +// ============================================================================ +// Wide bytecodes + +// Wide instructions. Simply redirects to the wide entry point for that instruction. +void TemplateTable::wide() { + transition(vtos, vtos); + + const Register Rtable = R11_scratch1, + Rindex = R12_scratch2, + Rtmp = R0; + + __ lbz(Rindex, 1, R14_bcp); + + __ load_dispatch_table(Rtable, Interpreter::_wentry_point); + + __ slwi(Rindex, Rindex, LogBytesPerWord); + __ ldx(Rtmp, Rtable, Rindex); + __ mtctr(Rtmp); + __ bctr(); + // Note: the bcp increment step is part of the individual wide bytecode implementations. +} +#endif // !CC_INTERP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cpu/ppc/vm/templateTable_ppc_64.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright 2013, 2014 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_TEMPLATETABLE_PPC_64_HPP +#define CPU_PPC_VM_TEMPLATETABLE_PPC_64_HPP + + static void invokevfinal_helper(Register RmethodOop, Register Rflags, Register Rscratch1, Register Rscratch2); + static void generate_vtable_call(Register Rrecv_klass, Register Rindex, Register Rret, Register Rtemp); + static void invokeinterface_object_method(Register Rrecv_klass, Register Rret, Register Rflags, Register Rindex, Register Rtemp, Register Rtemp2); + static void prepare_indy_invoke(int byte_no, Register Rmethod, Register Rret_addr, Register Runextended_SP, Register Rmethod_type, Register Rflags, Register Rrecv, Register Rscratch1); + + // Branch_conditional which takes TemplateTable::Condition. + static void branch_conditional(ConditionRegister crx, TemplateTable::Condition cc, Label& L, bool invert = false); + static void if_cmp_common(Register Rfirst, Register Rsecond, Register Rscratch1, Register Rscratch2, Condition cc, bool is_jint, bool cmp0); + +#endif // CPU_PPC_VM_TEMPLATETABLE_PPC_64_HPP
--- a/src/cpu/ppc/vm/vm_version_ppc.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/cpu/ppc/vm/vm_version_ppc.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 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 @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "assembler_ppc.inline.hpp" +#include "macroAssembler_ppc.inline.hpp" #include "memory/resourceArea.hpp" #include "runtime/java.hpp" #include "runtime/stubCodeGenerator.hpp" @@ -164,7 +165,7 @@ uint32_t *code = (uint32_t *)a->pc(); // Emit code. - void (*test1)() = (void(*)())(void *)a->emit_fd(); + void (*test1)() = (void(*)())(void *)a->function_entry(); Label l1; @@ -238,7 +239,7 @@ a->blr(); // Emit code. - void (*test2)() = (void(*)())(void *)a->emit_fd(); + void (*test2)() = (void(*)())(void *)a->function_entry(); // uint32_t *code = (uint32_t *)a->pc(); Label l2; @@ -379,8 +380,12 @@ #endif // COMPILER2 void VM_Version::determine_features() { +#if defined(ABI_ELFv2) + const int code_size = (num_features+1+2*7)*BytesPerInstWord; // TODO(asmundak): calculation is incorrect. +#else // 7 InstWords for each call (function descriptor + blr instruction). const int code_size = (num_features+1+2*7)*BytesPerInstWord; +#endif int features = 0; // create test area @@ -396,8 +401,11 @@ // Must be set to true so we can generate the test code. _features = VM_Version::all_features_m; + // Must be set to true so we can generate the test code. + _features = VM_Version::all_features_m; + // Emit code. - void (*test)(address addr, uint64_t offset)=(void(*)(address addr, uint64_t offset))(void *)a->emit_fd(); + void (*test)(address addr, uint64_t offset)=(void(*)(address addr, uint64_t offset))(void *)a->function_entry(); uint32_t *code = (uint32_t *)a->pc(); // Don't use R0 in ldarx. // Keep R3_ARG1 unmodified, it contains &field (see below). @@ -415,7 +423,7 @@ a->blr(); // Emit function to set one cache line to zero. Emit function descriptor and get pointer to it. - void (*zero_cacheline_func_ptr)(char*) = (void(*)(char*))(void *)a->emit_fd(); + void (*zero_cacheline_func_ptr)(char*) = (void(*)(char*))(void *)a->function_entry(); a->dcbz(R3_ARG1); // R3_ARG1 = addr a->blr();
--- a/src/cpu/ppc/vm/vm_version_ppc.hpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/cpu/ppc/vm/vm_version_ppc.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 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
--- a/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -113,7 +113,7 @@ // If the vtable entry is null, the method is abstract. address ame_addr = __ pc(); // ame = abstract method error - __ ld_with_trap_null_check(R12_scratch2, in_bytes(methodOopDesc::from_compiled_offset()), R19_method); + __ load_with_trap_null_check(R12_scratch2, in_bytes(methodOopDesc::from_compiled_offset()), R19_method); __ mtctr(R12_scratch2); __ bctr(); masm->flush();
--- a/src/cpu/sparc/vm/frame_sparc.inline.hpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/cpu/sparc/vm/frame_sparc.inline.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -228,6 +228,10 @@ inline constantPoolCacheOop* frame::interpreter_frame_cache_addr() const { return (constantPoolCacheOop*)sp_addr_at( LcpoolCache->sp_offset_in_saved_window()); } + +inline oop* frame::interpreter_frame_temp_oop_addr() const { + return (oop *)(fp() + interpreter_frame_oop_temp_offset); +} #endif // CC_INTERP
--- a/src/cpu/x86/vm/frame_x86.inline.hpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/cpu/x86/vm/frame_x86.inline.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -245,6 +245,10 @@ } } +inline oop* frame::interpreter_frame_temp_oop_addr() const { + return (oop *)(fp() + interpreter_frame_oop_temp_offset); +} + #endif /* CC_INTERP */ inline int frame::pd_oop_map_offset_adjustment() const {
--- a/src/cpu/zero/vm/globals_zero.hpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/cpu/zero/vm/globals_zero.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -43,6 +43,7 @@ define_pd_global(intx, CodeEntryAlignment, 32); define_pd_global(intx, OptoLoopAlignment, 16); define_pd_global(intx, InlineFrequencyCount, 100); +define_pd_global(intx, InlineSmallCode, 1000 ); define_pd_global(intx, PreInflateSpin, 10); define_pd_global(intx, StackYellowPages, 2); @@ -69,6 +70,4 @@ develop(bool, TrapBasedRangeChecks, false, \ "Not supported on this platform.") \ -define_pd_global(intx, InlineSmallCode, 1000 ); - #endif // CPU_ZERO_VM_GLOBALS_ZERO_HPP
--- a/src/os/aix/vm/mutex_aix.inline.hpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/os/aix/vm/mutex_aix.inline.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -1,6 +1,5 @@ /* * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 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 @@ -23,11 +22,16 @@ * */ -#ifndef OS_AIX_VM_MUTEX_AIX_INLINE_HPP -#define OS_AIX_VM_MUTEX_AIX_INLINE_HPP +#ifndef OS_LINUX_VM_MUTEX_LINUX_INLINE_HPP +#define OS_LINUX_VM_MUTEX_LINUX_INLINE_HPP #include "os_aix.inline.hpp" #include "runtime/interfaceSupport.hpp" #include "thread_aix.inline.hpp" -#endif // OS_AIX_VM_MUTEX_AIX_INLINE_HPP + +// Reconciliation History +// mutex_solaris.inline.hpp 1.5 99/06/22 16:38:49 +// End + +#endif // OS_LINUX_VM_MUTEX_LINUX_INLINE_HPP
--- a/src/os/bsd/vm/os_bsd.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/os/bsd/vm/os_bsd.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -284,7 +284,7 @@ static char cpu_arch[] = "amd64"; #elif defined(ARM) static char cpu_arch[] = "arm"; -#elif defined(PPC) +#elif defined(PPC32) static char cpu_arch[] = "ppc"; #elif defined(SPARC) # ifdef _LP64
--- a/src/os/linux/vm/os_linux.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/os/linux/vm/os_linux.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -2005,7 +2005,11 @@ {EM_SPARC32PLUS, EM_SPARC, ELFCLASS32, ELFDATA2MSB, (char*)"Sparc 32"}, {EM_SPARCV9, EM_SPARCV9, ELFCLASS64, ELFDATA2MSB, (char*)"Sparc v9 64"}, {EM_PPC, EM_PPC, ELFCLASS32, ELFDATA2MSB, (char*)"Power PC 32"}, +#if defined(VM_LITTLE_ENDIAN) + {EM_PPC64, EM_PPC64, ELFCLASS64, ELFDATA2LSB, (char*)"Power PC 64"}, +#else {EM_PPC64, EM_PPC64, ELFCLASS64, ELFDATA2MSB, (char*)"Power PC 64"}, +#endif {EM_ARM, EM_ARM, ELFCLASS32, ELFDATA2LSB, (char*)"ARM"}, {EM_S390, EM_S390, ELFCLASSNONE, ELFDATA2MSB, (char*)"IBM System/390"}, {EM_ALPHA, EM_ALPHA, ELFCLASS64, ELFDATA2LSB, (char*)"Alpha"},
--- a/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -94,7 +94,6 @@ // Initialize the memory stack limit. address mem_stk_limit = ((JavaThread *)thread)->stack_yellow_zone_base() + (os::vm_page_size() * StackShadowPages); - thread->set_memory_stack_limit(mem_stk_limit); } // Frame information (pc, sp, fp) retrieved via ucontext
--- a/src/os_cpu/aix_ppc/vm/threadLS_aix_ppc.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/os_cpu/aix_ppc/vm/threadLS_aix_ppc.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 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 @@ -25,14 +25,14 @@ #include "precompiled.hpp" #include "runtime/threadLocalStorage.hpp" -#include "thread_aix.inline.hpp" +#include "runtime/thread.hpp" void ThreadLocalStorage::generate_code_for_get_thread() { - // nothing we can do here for user-level thread + // Nothing we can do here for user-level thread. } void ThreadLocalStorage::pd_init() { - // Nothing to do + // Nothing to do. } void ThreadLocalStorage::pd_set_thread(Thread* thread) {
--- a/src/os_cpu/aix_ppc/vm/thread_aix_ppc.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/os_cpu/aix_ppc/vm/thread_aix_ppc.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 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 @@ -24,8 +24,8 @@ */ #include "precompiled.hpp" -#include "runtime/frame.inline.hpp" -#include "thread_aix.inline.hpp" +#include "runtime/frame.hpp" +#include "runtime/thread.hpp" // Forte Analyzer AsyncGetCallTrace profiling support is not implemented on Aix/PPC. bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, bool isInJava) {
--- a/src/os_cpu/bsd_zero/vm/os_bsd_zero.hpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/os_cpu/bsd_zero/vm/os_bsd_zero.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -36,7 +36,7 @@ // Atomically copy 64 bits of data static void atomic_copy64(volatile void *src, volatile void *dst) { -#if defined(PPC) && !defined(_LP64) +#if defined(PPC32) double tmp; asm volatile ("lfd %0, 0(%1)\n" "stfd %0, 0(%2)\n"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/os_cpu/linux_ppc/vm/bytes_linux_ppc.inline.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright 2014 Google Inc. 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_CPU_LINUX_PPC_VM_BYTES_LINUX_PPC_INLINE_HPP +#define OS_CPU_LINUX_PPC_VM_BYTES_LINUX_PPC_INLINE_HPP + +#if defined(VM_LITTLE_ENDIAN) +#include <byteswap.h> + +// Efficient swapping of data bytes from Java byte +// ordering to native byte ordering and vice versa. +inline u2 Bytes::swap_u2(u2 x) { return bswap_16(x); } +inline u4 Bytes::swap_u4(u4 x) { return bswap_32(x); } +inline u8 Bytes::swap_u8(u8 x) { return bswap_64(x); } +#endif // VM_LITTLE_ENDIAN + +#endif // OS_CPU_LINUX_PPC_VM_BYTES_LINUX_PPC_INLINE_HPP
--- a/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -106,8 +106,6 @@ // Initialize the memory stack limit. address mem_stk_limit = thread->stack_base() - thread->stack_size() + ((StackShadowPages + StackYellowPages + StackRedPages) * os::vm_page_size()); - - thread->set_memory_stack_limit(mem_stk_limit); } // Frame information (pc, sp, fp) retrieved via ucontext
--- a/src/os_cpu/linux_ppc/vm/thread_linux_ppc.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/os_cpu/linux_ppc/vm/thread_linux_ppc.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 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 @@ -24,8 +24,8 @@ */ #include "precompiled.hpp" -#include "runtime/frame.inline.hpp" -#include "thread_linux.inline.hpp" +#include "runtime/frame.hpp" +#include "runtime/thread.hpp" // Forte Analyzer AsyncGetCallTrace profiling support is not implemented on Linux/PPC. bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, bool isInJava) {
--- a/src/os_cpu/linux_zero/vm/os_linux_zero.hpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/os_cpu/linux_zero/vm/os_linux_zero.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -36,7 +36,7 @@ // Atomically copy 64 bits of data static void atomic_copy64(volatile void *src, volatile void *dst) { -#if defined(PPC) && !defined(_LP64) +#if defined(PPC32) double tmp; asm volatile ("lfd %0, 0(%1)\n" "stfd %0, 0(%2)\n"
--- a/src/share/vm/adlc/output_c.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/share/vm/adlc/output_c.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -2551,9 +2551,9 @@ fprintf(fp, " // Access to ins and operands for late expand.\n"); const int buflen = 2000; - char idxbuf[buflen]; char *ib = idxbuf; sprintf(ib, ""); - char nbuf [buflen]; char *nb = nbuf; sprintf(nb, ""); - char opbuf [buflen]; char *ob = opbuf; sprintf(ob, ""); + char idxbuf[buflen]; char *ib = idxbuf; idxbuf[0] = '\0'; + char nbuf [buflen]; char *nb = nbuf; nbuf[0] = '\0'; + char opbuf [buflen]; char *ob = opbuf; opbuf[0] = '\0'; encoding->_parameter_type.reset(); encoding->_parameter_name.reset();
--- a/src/share/vm/code/relocInfo.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/share/vm/code/relocInfo.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -622,7 +622,7 @@ } void trampoline_stub_Relocation::pack_data_to(CodeSection* dest ) { - short* p = (short*) dest->locs_end(); + short* p = (short*) dest->locs_end(); CodeSection* insts = dest->outer()->insts(); normalize_address(_owner, insts); p = pack_1_int_to(p,scaled_offset(_owner, insts->start() )); @@ -1198,6 +1198,12 @@ tty->print(" | [static_call=" INTPTR_FORMAT "]", r->static_call()); break; } + case relocInfo::trampoline_stub_type: + { + trampoline_stub_Relocation* r = (trampoline_stub_Relocation*) reloc(); + tty->print(" | [trampoline owner=" INTPTR_FORMAT "]", r->owner()); + break; + } } tty->cr(); }
--- a/src/share/vm/code/relocInfo.hpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/share/vm/code/relocInfo.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -268,7 +268,7 @@ poll_return_type = 11, // polling instruction for safepoints at return breakpoint_type = 12, // an initialization barrier or safepoint trampoline_stub_type = 13, // stub-entry for trampoline - yet_unused_type = 14, // Still unused + yet_unused_type_1 = 14, // Still unused data_prefix_tag = 15, // tag for a prefix (carries data arguments) type_mask = 15 // A mask which selects only the above values }; @@ -1118,14 +1118,14 @@ // is the chance that this branch can not reach all possible code locations. // If the relocation finds that a branch is too far for the instruction // in the code, it can patch it to jump to the trampoline where is -// sufficient space for a far branch. Needed on PPC. +// sufficient space for a far branch. Needed on PPC. class trampoline_stub_Relocation : public Relocation { relocInfo::relocType type() { return relocInfo::trampoline_stub_type; } public: static RelocationHolder spec(address static_call) { RelocationHolder rh = newHolder(); - return (new(rh) trampoline_stub_Relocation(static_call)); + return (new (rh) trampoline_stub_Relocation(static_call)); } private: @@ -1143,7 +1143,7 @@ // Return the address of the NativeCall that owns the trampoline. address owner() { return _owner; } - void pack_data_to( CodeSection * dest); + void pack_data_to(CodeSection * dest); void unpack_data(); // Find the trampoline stub for a call.
--- a/src/share/vm/interpreter/abstractInterpreter.hpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/share/vm/interpreter/abstractInterpreter.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -44,8 +44,8 @@ #ifdef TARGET_ARCH_MODEL_arm # include "interp_masm_arm.hpp" #endif -#ifdef TARGET_ARCH_MODEL_ppc -# include "interp_masm_ppc.hpp" +#ifdef TARGET_ARCH_MODEL_ppc_32 +# include "interp_masm_ppc_32.hpp" #endif #ifdef TARGET_ARCH_MODEL_ppc_64 # include "interp_masm_ppc_64.hpp"
--- a/src/share/vm/interpreter/bytecodeInterpreter.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/share/vm/interpreter/bytecodeInterpreter.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -31,7 +31,6 @@ #include "interpreter/bytecodeInterpreterProfiling.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/interpreterRuntime.hpp" -#include "memory/cardTableModRefBS.hpp" #include "memory/resourceArea.hpp" #include "oops/objArrayKlass.hpp" #include "oops/oop.inline.hpp" @@ -154,7 +153,7 @@ RESET_LAST_JAVA_FRAME(); \ CACHE_STATE(); -// Normal throw of a java error +// Normal throw of a java error. #define VM_JAVA_ERROR(name, msg, note_a_trap) \ VM_JAVA_ERROR_NO_JUMP(name, msg, note_a_trap) \ goto handle_exception; @@ -346,7 +345,7 @@ && (mdo_last_branch_taken_count >= (uint)InvocationCounter::InterpreterBackwardBranchLimit)\ /* When ProfileInterpreter is on, the backedge_count comes */ \ /* from the methodDataOop, which value does not get reset on */ \ - /* the call to frequency_counter_overflow(). To avoid */ \ + /* the call to frequency_counter_overflow(). To avoid */ \ /* excessive calls to the overflow routine while the method is */ \ /* being compiled, add a second test to make sure the overflow */ \ /* function is called only once every overflow_frequency. */ \ @@ -357,7 +356,7 @@ && INVOCATION_COUNT->reached_BackwardBranchLimit(BACKEDGE_COUNT); \ } \ if (do_OSR) { \ - nmethod* osr_nmethod; \ + nmethod* osr_nmethod; \ OSR_REQUEST(osr_nmethod, branch_pc); \ if (osr_nmethod != NULL && osr_nmethod->osr_entry_bci() != InvalidOSREntryBci) { \ intptr_t* buf; \ @@ -412,11 +411,11 @@ * On some architectures/platforms it should be possible to do this implicitly */ #undef CHECK_NULL -#define CHECK_NULL(obj_) \ - if ((obj_) == NULL) { \ - VM_JAVA_ERROR(vmSymbols::java_lang_NullPointerException(), NULL, note_nullCheck_trap); \ - } \ - VERIFY_OOP(obj_) +#define CHECK_NULL(obj_) \ + if ((obj_) == NULL) { \ + VM_JAVA_ERROR(vmSymbols::java_lang_NullPointerException(), NULL, note_nullCheck_trap); \ + } \ + VERIFY_OOP(obj_) #define VMdoubleConstZero() 0.0 #define VMdoubleConstOne() 1.0 @@ -439,29 +438,29 @@ CACHE_LOCALS(); // Call the VM with last java frame only. -#define CALL_VM_NAKED_LJF(func) \ - DECACHE_STATE(); \ - SET_LAST_JAVA_FRAME(); \ - func; \ - RESET_LAST_JAVA_FRAME(); \ - CACHE_STATE(); \ +#define CALL_VM_NAKED_LJF(func) \ + DECACHE_STATE(); \ + SET_LAST_JAVA_FRAME(); \ + func; \ + RESET_LAST_JAVA_FRAME(); \ + CACHE_STATE(); // Call the VM. Don't check for pending exceptions. -#define CALL_VM_NOCHECK(func) \ - CALL_VM_NAKED_LJF(func) \ - if (THREAD->pop_frame_pending() && \ - !THREAD->pop_frame_in_process()) { \ - goto handle_Pop_Frame; \ - } \ - if (THREAD->jvmti_thread_state() && \ - THREAD->jvmti_thread_state()->is_earlyret_pending()) { \ - goto handle_Early_Return; \ - } +#define CALL_VM_NOCHECK(func) \ + CALL_VM_NAKED_LJF(func) \ + if (THREAD->pop_frame_pending() && \ + !THREAD->pop_frame_in_process()) { \ + goto handle_Pop_Frame; \ + } \ + if (THREAD->jvmti_thread_state() && \ + THREAD->jvmti_thread_state()->is_earlyret_pending()) { \ + goto handle_Early_Return; \ + } // Call the VM and check for pending exceptions -#define CALL_VM(func, label) { \ - CALL_VM_NOCHECK(func); \ - if (THREAD->has_pending_exception()) goto label; \ +#define CALL_VM(func, label) { \ + CALL_VM_NOCHECK(func); \ + if (THREAD->has_pending_exception()) goto label; \ } /* @@ -663,7 +662,7 @@ switch (istate->msg()) { case initialize: { - if (initialized++) ShouldNotReachHere(); // Only one initialize call + if (initialized++) ShouldNotReachHere(); // Only one initialize call. _compiling = (UseCompiler || CountCompiledCalls); #ifdef VM_JVMTI _jvmti_interp_events = JvmtiExport::can_post_interpreter_events(); @@ -682,7 +681,7 @@ INCR_INVOCATION_COUNT; if (INVOCATION_COUNT->reached_InvocationLimit(BACKEDGE_COUNT)) { CALL_VM((void)InterpreterRuntime::frequency_counter_overflow(THREAD, NULL), handle_exception); - // We no longer retry on a counter overflow + // We no longer retry on a counter overflow. } // Get or create profile data. Check for pending (async) exceptions. BI_PROFILE_GET_OR_CREATE_METHOD_DATA(handle_exception); @@ -707,103 +706,99 @@ } #endif // HACK - // lock method if synchronized + // Lock method if synchronized. if (METHOD->is_synchronized()) { - // oop rcvr = locals[0].j.r; - oop rcvr; - if (METHOD->is_static()) { - rcvr = METHOD->constants()->pool_holder()->java_mirror(); - } else { - rcvr = LOCALS_OBJECT(0); - VERIFY_OOP(rcvr); - } - // The initial monitor is ours for the taking - // Monitor not filled in frame manager any longer as this caused race condition with biased locking. - BasicObjectLock* mon = &istate->monitor_base()[-1]; - mon->set_obj(rcvr); - bool success = false; - uintptr_t epoch_mask_in_place = (uintptr_t)markOopDesc::epoch_mask_in_place; - markOop mark = rcvr->mark(); - intptr_t hash = (intptr_t) markOopDesc::no_hash; - // implies UseBiasedLocking - if (mark->has_bias_pattern()) { - uintptr_t thread_ident; - uintptr_t anticipated_bias_locking_value; - thread_ident = (uintptr_t)istate->thread(); - anticipated_bias_locking_value = - (((uintptr_t)rcvr->klass()->klass_part()->prototype_header() | thread_ident) ^ (uintptr_t)mark) & - ~((uintptr_t) markOopDesc::age_mask_in_place); - - if (anticipated_bias_locking_value == 0) { - // already biased towards this thread, nothing to do + // oop rcvr = locals[0].j.r; + oop rcvr; + if (METHOD->is_static()) { + rcvr = METHOD->constants()->pool_holder()->java_mirror(); + } else { + rcvr = LOCALS_OBJECT(0); + VERIFY_OOP(rcvr); + } + // The initial monitor is ours for the taking. + // Monitor not filled in frame manager any longer as this caused race condition with biased locking. + BasicObjectLock* mon = &istate->monitor_base()[-1]; + mon->set_obj(rcvr); + bool success = false; + uintptr_t epoch_mask_in_place = (uintptr_t)markOopDesc::epoch_mask_in_place; + markOop mark = rcvr->mark(); + intptr_t hash = (intptr_t) markOopDesc::no_hash; + // Implies UseBiasedLocking. + if (mark->has_bias_pattern()) { + uintptr_t thread_ident; + uintptr_t anticipated_bias_locking_value; + thread_ident = (uintptr_t)istate->thread(); + anticipated_bias_locking_value = + (((uintptr_t)rcvr->klass()->klass_part()->prototype_header() | thread_ident) ^ (uintptr_t)mark) & + ~((uintptr_t) markOopDesc::age_mask_in_place); + + if (anticipated_bias_locking_value == 0) { + // Already biased towards this thread, nothing to do. + if (PrintBiasedLockingStatistics) { + (* BiasedLocking::biased_lock_entry_count_addr())++; + } + success = true; + } else if ((anticipated_bias_locking_value & markOopDesc::biased_lock_mask_in_place) != 0) { + // Try to revoke bias. + markOop header = rcvr->klass()->klass_part()->prototype_header(); + if (hash != markOopDesc::no_hash) { + header = header->copy_set_hash(hash); + } + if (Atomic::cmpxchg_ptr(header, rcvr->mark_addr(), mark) == mark) { + if (PrintBiasedLockingStatistics) + (*BiasedLocking::revoked_lock_entry_count_addr())++; + } + } else if ((anticipated_bias_locking_value & epoch_mask_in_place) != 0) { + // Try to rebias. + markOop new_header = (markOop) ( (intptr_t) rcvr->klass()->klass_part()->prototype_header() | thread_ident); + if (hash != markOopDesc::no_hash) { + new_header = new_header->copy_set_hash(hash); + } + if (Atomic::cmpxchg_ptr((void*)new_header, rcvr->mark_addr(), mark) == mark) { if (PrintBiasedLockingStatistics) { - (* BiasedLocking::biased_lock_entry_count_addr())++; - } - success = true; - } - else if ((anticipated_bias_locking_value & markOopDesc::biased_lock_mask_in_place) != 0) { - // try revoke bias - markOop header = rcvr->klass()->klass_part()->prototype_header(); - if (hash != markOopDesc::no_hash) { - header = header->copy_set_hash(hash); + (* BiasedLocking::rebiased_lock_entry_count_addr())++; } - if (Atomic::cmpxchg_ptr(header, rcvr->mark_addr(), mark) == mark) { - if (PrintBiasedLockingStatistics) - (*BiasedLocking::revoked_lock_entry_count_addr())++; - } + } else { + CALL_VM(InterpreterRuntime::monitorenter(THREAD, mon), handle_exception); } - else if ((anticipated_bias_locking_value & epoch_mask_in_place) !=0) { - // try rebias - markOop new_header = (markOop) ( (intptr_t) rcvr->klass()->klass_part()->prototype_header() | thread_ident); - if (hash != markOopDesc::no_hash) { - new_header = new_header->copy_set_hash(hash); - } - if (Atomic::cmpxchg_ptr((void*)new_header, rcvr->mark_addr(), mark) == mark) { - if (PrintBiasedLockingStatistics) - (* BiasedLocking::rebiased_lock_entry_count_addr())++; - } - else { - CALL_VM(InterpreterRuntime::monitorenter(THREAD, mon), handle_exception); - } - success = true; + success = true; + } else { + // Try to bias towards thread in case object is anonymously biased. + markOop header = (markOop) ((uintptr_t) mark & + ((uintptr_t)markOopDesc::biased_lock_mask_in_place | + (uintptr_t)markOopDesc::age_mask_in_place | epoch_mask_in_place)); + if (hash != markOopDesc::no_hash) { + header = header->copy_set_hash(hash); } - else { - // Try to bias towards thread in case object is anonymously biased. - markOop header = (markOop) ((uintptr_t) mark & - ((uintptr_t)markOopDesc::biased_lock_mask_in_place | - (uintptr_t)markOopDesc::age_mask_in_place | epoch_mask_in_place)); - if (hash != markOopDesc::no_hash) { - header = header->copy_set_hash(hash); + markOop new_header = (markOop) ((uintptr_t) header | thread_ident); + // Debugging hint. + DEBUG_ONLY(mon->lock()->set_displaced_header((markOop) (uintptr_t) 0xdeaddead);) + if (Atomic::cmpxchg_ptr((void*)new_header, rcvr->mark_addr(), header) == header) { + if (PrintBiasedLockingStatistics) { + (* BiasedLocking::anonymously_biased_lock_entry_count_addr())++; } - markOop new_header = (markOop) ((uintptr_t) header | thread_ident); - // Debugging hint. - DEBUG_ONLY(mon->lock()->set_displaced_header((markOop) (uintptr_t) 0xdeaddead);) - if (Atomic::cmpxchg_ptr((void*)new_header, rcvr->mark_addr(), header) == header) { - if (PrintBiasedLockingStatistics) - (* BiasedLocking::anonymously_biased_lock_entry_count_addr())++; - } - else { - CALL_VM(InterpreterRuntime::monitorenter(THREAD, mon), handle_exception); - } - success = true; + } else { + CALL_VM(InterpreterRuntime::monitorenter(THREAD, mon), handle_exception); + } + success = true; + } + } + + // Traditional lightweight locking. + if (!success) { + markOop displaced = rcvr->mark()->set_unlocked(); + mon->lock()->set_displaced_header(displaced); + bool call_vm = UseHeavyMonitors; + if (call_vm || Atomic::cmpxchg_ptr(mon, rcvr->mark_addr(), displaced) != displaced) { + // Is it simple recursive case? + if (!call_vm && THREAD->is_lock_owned((address) displaced->clear_lock_bits())) { + mon->lock()->set_displaced_header(NULL); + } else { + CALL_VM(InterpreterRuntime::monitorenter(THREAD, mon), handle_exception); } } - - // Traditional lightweight locking. - if (!success) { - markOop displaced = rcvr->mark()->set_unlocked(); - mon->lock()->set_displaced_header(displaced); - // UseHeavyMonitors support in CC_INTERP. - bool call_vm = UseHeavyMonitors; - if (call_vm || Atomic::cmpxchg_ptr(mon, rcvr->mark_addr(), displaced) != displaced) { - // Is it simple recursive case? - if (!call_vm && THREAD->is_lock_owned((address) displaced->clear_lock_bits())) { - mon->lock()->set_displaced_header(NULL); - } else { - CALL_VM(InterpreterRuntime::monitorenter(THREAD, mon), handle_exception); - } - } - } + } } THREAD->clr_do_not_unlock(); @@ -825,10 +820,6 @@ case popping_frame: { // returned from a java call to pop the frame, restart the call // clear the message so we don't confuse ourselves later - // Commented out ShouldNotReachHere() below, because we do reach - // here when the frame manager calls the interpreter loop after - // popping the top frame. - // ShouldNotReachHere(); // we don't return this. assert(THREAD->pop_frame_in_process(), "wrong frame pop state"); istate->set_msg(no_request); if (_compiling) { @@ -954,26 +945,25 @@ header = header->copy_set_hash(hash); } if (Atomic::cmpxchg_ptr(header, lockee->mark_addr(), mark) == mark) { - if (PrintBiasedLockingStatistics) + if (PrintBiasedLockingStatistics) { (*BiasedLocking::revoked_lock_entry_count_addr())++; + } } - } - else if ((anticipated_bias_locking_value & epoch_mask_in_place) !=0) { + } else if ((anticipated_bias_locking_value & epoch_mask_in_place) !=0) { // try rebias markOop new_header = (markOop) ( (intptr_t) lockee->klass()->klass_part()->prototype_header() | thread_ident); if (hash != markOopDesc::no_hash) { new_header = new_header->copy_set_hash(hash); } if (Atomic::cmpxchg_ptr((void*)new_header, lockee->mark_addr(), mark) == mark) { - if (PrintBiasedLockingStatistics) + if (PrintBiasedLockingStatistics) { (* BiasedLocking::rebiased_lock_entry_count_addr())++; - } - else { + } + } else { CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception); } success = true; - } - else { + } else { // try to bias towards thread in case object is anonymously biased markOop header = (markOop) ((uintptr_t) mark & ((uintptr_t)markOopDesc::biased_lock_mask_in_place | (uintptr_t)markOopDesc::age_mask_in_place | epoch_mask_in_place)); @@ -984,10 +974,10 @@ // debugging hint DEBUG_ONLY(entry->lock()->set_displaced_header((markOop) (uintptr_t) 0xdeaddead);) if (Atomic::cmpxchg_ptr((void*)new_header, lockee->mark_addr(), header) == header) { - if (PrintBiasedLockingStatistics) + if (PrintBiasedLockingStatistics) { (* BiasedLocking::anonymously_biased_lock_entry_count_addr())++; - } - else { + } + } else { CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception); } success = true; @@ -998,7 +988,6 @@ if (!success) { markOop displaced = lockee->mark()->set_unlocked(); entry->lock()->set_displaced_header(displaced); - // UseHeavyMonitors support in CC_INTERP. bool call_vm = UseHeavyMonitors; if (call_vm || Atomic::cmpxchg_ptr(entry, lockee->mark_addr(), displaced) != displaced) { // Is it simple recursive case? @@ -1614,14 +1603,14 @@ } // Profile switch. BI_PROFILE_UPDATE_SWITCH(/*switch_index=*/key); - // Does this really need a full backedge check (osr?) + // Does this really need a full backedge check (osr)? address branch_pc = pc; UPDATE_PC_AND_TOS(skip, -1); DO_BACKEDGE_CHECKS(skip, branch_pc); CONTINUE; } - /* Goto pc whose table entry matches specified key */ + /* Goto pc whose table entry matches specified key. */ CASE(_lookupswitch): { jint* lpc = (jint*)VMalignWordUp(pc+1); @@ -1632,13 +1621,13 @@ int newindex = 0; int32_t npairs = Bytes::get_Java_u4((address) &lpc[1]); while (--npairs >= 0) { - lpc += 2; - if (key == (int32_t)Bytes::get_Java_u4((address)lpc)) { - skip = Bytes::get_Java_u4((address)&lpc[1]); - index = newindex; - break; - } - newindex += 1; + lpc += 2; + if (key == (int32_t)Bytes::get_Java_u4((address)lpc)) { + skip = Bytes::get_Java_u4((address)&lpc[1]); + index = newindex; + break; + } + newindex += 1; } // Profile switch. BI_PROFILE_UPDATE_SWITCH(/*switch_index=*/index); @@ -1745,7 +1734,7 @@ ARRAY_INTRO(-2); \ SET_ ## stackRes(*(T2 *)(((address) arrObj->base(T)) + index * sizeof(T2)), -1); \ extra; \ - UPDATE_PC_AND_CONTINUE(1); \ + UPDATE_PC_AND_CONTINUE(1); \ } CASE(_iaload): @@ -1753,16 +1742,9 @@ CASE(_faload): ARRAY_LOADTO32(T_FLOAT, jfloat, "%f", STACK_FLOAT, 0); CASE(_aaload): { - // Decode compressed oop. - if (UseCompressedOops) { ARRAY_INTRO(-2); - address oopAdr = ((address) arrObj->base(T_OBJECT)) + index * sizeof(narrowOop); - oop decodedOop = oopDesc::decode_heap_oop(*(narrowOop*)(oopAdr)); - SET_STACK_OBJECT(decodedOop, -2); + SET_STACK_OBJECT(((objArrayOop) arrObj)->obj_at(index), -2); UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1); - } else { - ARRAY_LOADTO32(T_OBJECT, oop, INTPTR_FORMAT, STACK_OBJECT, 0); - } } CASE(_baload): ARRAY_LOADTO32(T_BYTE, jbyte, "%d", STACK_INT, 0); @@ -1825,8 +1807,6 @@ // Profile checkcast with null_seen and receiver. BI_PROFILE_UPDATE_CHECKCAST(/*null_seen=*/true, NULL); } - // G1GC port. Use accessor instead of storing manually. - // Takes care of write barriers internally and replaces the code above. ((objArrayOopDesc *) arrObj)->obj_at_put(index, rhsObject); UPDATE_PC_AND_TOS_AND_CONTINUE(1, -3); } @@ -1941,7 +1921,6 @@ if (!success) { markOop displaced = lockee->mark()->set_unlocked(); entry->lock()->set_displaced_header(displaced); - // UseHeavyMonitors support in CC_INTERP bool call_vm = UseHeavyMonitors; if (call_vm || Atomic::cmpxchg_ptr(entry, lockee->mark_addr(), displaced) != displaced) { // Is it simple recursive case? @@ -1972,7 +1951,6 @@ markOop header = lock->displaced_header(); most_recent->set_obj(NULL); if (!lockee->mark()->has_bias_pattern()) { - // UseHeavyMonitors support in CC_INTERP bool call_vm = UseHeavyMonitors; // If it isn't recursive we either must swap old header or call the runtime if (header != NULL || call_vm) { @@ -2267,8 +2245,7 @@ result->set_klass(k_entry); // Must prevent reordering of stores for object initialization // with stores that publish the new object. - // On IA64 the publishing stores are performed with release semantics. - NOT_IA64(OrderAccess::storestore()); + OrderAccess::storestore(); SET_STACK_OBJECT(result, 0); UPDATE_PC_AND_TOS_AND_CONTINUE(3, 1); } @@ -2279,8 +2256,7 @@ handle_exception); // Must prevent reordering of stores for object initialization // with stores that publish the new object. - // On IA64 the publishing stores are performed with release semantics. - NOT_IA64(OrderAccess::storestore()); + OrderAccess::storestore(); SET_STACK_OBJECT(THREAD->vm_result(), 0); THREAD->set_vm_result(NULL); UPDATE_PC_AND_TOS_AND_CONTINUE(3, 1); @@ -2292,8 +2268,7 @@ handle_exception); // Must prevent reordering of stores for object initialization // with stores that publish the new object. - // On IA64 the publishing stores are performed with release semantics. - NOT_IA64(OrderAccess::storestore()); + OrderAccess::storestore(); SET_STACK_OBJECT(THREAD->vm_result(), -1); THREAD->set_vm_result(NULL); UPDATE_PC_AND_CONTINUE(3); @@ -2310,8 +2285,7 @@ handle_exception); // Must prevent reordering of stores for object initialization // with stores that publish the new object. - // On IA64 the publishing stores are performed with release semantics. - NOT_IA64(OrderAccess::storestore()); + OrderAccess::storestore(); SET_STACK_OBJECT(THREAD->vm_result(), -dims); THREAD->set_vm_result(NULL); UPDATE_PC_AND_TOS_AND_CONTINUE(4, -(dims-1)); @@ -2321,7 +2295,7 @@ VERIFY_OOP(STACK_OBJECT(-1)); u2 index = Bytes::get_Java_u2(pc+1); // Constant pool may have actual klass or unresolved klass. If it is - // unresolved we must resolve it + // unresolved we must resolve it. if (METHOD->constants()->tag_at(index).is_unresolved_klass()) { CALL_VM(InterpreterRuntime::quicken_io_cc(THREAD), handle_exception); } @@ -2329,11 +2303,9 @@ klassOop objKlassOop = STACK_OBJECT(-1)->klass(); //ebx // // Check for compatibilty. This check must not GC!! - // Seems way more expensive now that we must dispatch + // Seems way more expensive now that we must dispatch. // - if (objKlassOop != klassOf && - !objKlassOop->klass_part()->is_subtype_of(klassOf)) { - + if (objKlassOop != klassOf && !objKlassOop->klass_part()->is_subtype_of(klassOf)) { // Decrement counter at checkcast. BI_PROFILE_SUBTYPECHECK_FAILED(objKlassOop); ResourceMark rm(THREAD); @@ -2360,7 +2332,7 @@ VERIFY_OOP(STACK_OBJECT(-1)); u2 index = Bytes::get_Java_u2(pc+1); // Constant pool may have actual klass or unresolved klass. If it is - // unresolved we must resolve it + // unresolved we must resolve it. if (METHOD->constants()->tag_at(index).is_unresolved_klass()) { CALL_VM(InterpreterRuntime::quicken_io_cc(THREAD), handle_exception); } @@ -2368,7 +2340,7 @@ klassOop objKlassOop = STACK_OBJECT(-1)->klass(); // // Check for compatibilty. This check must not GC!! - // Seems way more expensive now that we must dispatch + // Seems way more expensive now that we must dispatch. // if ( objKlassOop == klassOf || objKlassOop->klass_part()->is_subtype_of(klassOf)) { SET_STACK_INT(1, -1); @@ -2529,6 +2501,7 @@ UPDATE_PC_AND_RETURN(0); // I'll be back... } + CASE(_invokehandle): { if (!EnableInvokeDynamic) { @@ -2541,12 +2514,10 @@ if (! cache->is_resolved((Bytecodes::Code) opcode)) { CALL_VM(InterpreterRuntime::resolve_invokehandle(THREAD), handle_exception); - // GC might move cache while returning from VM call. - cache = cp->entry_at(index); // reload + cache = cp->entry_at(index); } methodOop method = cache->f2_as_vfinal_method(); - VERIFY_OOP(method); if (cache->has_appendix()) { @@ -2593,9 +2564,9 @@ // Profile 'special case of invokeinterface' final call. BI_PROFILE_UPDATE_FINALCALL(); } else { - // get receiver + // Get receiver. int parms = cache->parameter_size(); - // Same comments as invokevirtual apply here + // Same comments as invokevirtual apply here. oop rcvr = STACK_OBJECT(-parms); VERIFY_OOP(rcvr); instanceKlass* rcvrKlass = (instanceKlass*)rcvr->klass()->klass_part(); @@ -2742,8 +2713,7 @@ handle_exception); // Must prevent reordering of stores for object initialization // with stores that publish the new object. - // On IA64 the publishing stores are performed with release semantics. - NOT_IA64(OrderAccess::storestore()); + OrderAccess::storestore(); SET_STACK_OBJECT(THREAD->vm_result(), -1); THREAD->set_vm_result(NULL); @@ -2805,7 +2775,7 @@ CASE(_ret): { // Profile ret. BI_PROFILE_UPDATE_RET(/*bci=*/((int)(intptr_t)(LOCALS_ADDR(pc[1])))); - // now, update the pc + // Now, update the pc. pc = istate->method()->code_base() + (intptr_t)(LOCALS_ADDR(pc[1])); UPDATE_PC_AND_CONTINUE(0); } @@ -2906,76 +2876,82 @@ // No handler in this activation, unwind and try again THREAD->set_pending_exception(except_oop(), NULL, 0); goto handle_return; - } /* handle_exception: */ + } // handle_exception: // Return from an interpreter invocation with the result of the interpretation // on the top of the Java Stack (or a pending exception) -handle_Pop_Frame: - - // We don't really do anything special here except we must be aware - // that we can get here without ever locking the method (if sync). - // Also we skip the notification of the exit. - - istate->set_msg(popping_frame); - // Clear pending so while the pop is in process - // we don't start another one if a call_vm is done. - THREAD->clr_pop_frame_pending(); - // Let interpreter (only) see the we're in the process of popping a frame - THREAD->set_pop_frame_in_process(); - - goto handle_return; - -// ForceEarlyReturn ends a method, and returns to the caller with a return value -// given by the invoker of the early return. -handle_Early_Return: - - istate->set_msg(early_return); - - // Clear expression stack. - topOfStack = istate->stack_base() - Interpreter::stackElementWords; - - // Push the value to be returned. - switch (istate->method()->result_type()) { - case T_BOOLEAN: - case T_SHORT: - case T_BYTE: - case T_CHAR: - case T_INT: - SET_STACK_INT(THREAD->jvmti_thread_state()->earlyret_value().i, 0); - MORE_STACK(1); - break; - case T_LONG: - SET_STACK_LONG(THREAD->jvmti_thread_state()->earlyret_value().j, 1); - MORE_STACK(2); - break; - case T_FLOAT: - SET_STACK_FLOAT(THREAD->jvmti_thread_state()->earlyret_value().f, 0); - MORE_STACK(1); - break; - case T_DOUBLE: - SET_STACK_DOUBLE(THREAD->jvmti_thread_state()->earlyret_value().d, 1); - MORE_STACK(2); - break; - case T_ARRAY: - case T_OBJECT: - SET_STACK_OBJECT(THREAD->jvmti_thread_state()->earlyret_oop(), 0); - MORE_STACK(1); - break; - } - - THREAD->jvmti_thread_state()->clr_earlyret_value(); - THREAD->jvmti_thread_state()->set_earlyret_oop(NULL); - THREAD->jvmti_thread_state()->clr_earlyret_pending(); - -handle_return: - { + handle_Pop_Frame: { + + // We don't really do anything special here except we must be aware + // that we can get here without ever locking the method (if sync). + // Also we skip the notification of the exit. + + istate->set_msg(popping_frame); + // Clear pending so while the pop is in process + // we don't start another one if a call_vm is done. + THREAD->clr_pop_frame_pending(); + // Let interpreter (only) see the we're in the process of popping a frame + THREAD->set_pop_frame_in_process(); + + goto handle_return; + + } // handle_Pop_Frame + + // ForceEarlyReturn ends a method, and returns to the caller with a return value + // given by the invoker of the early return. + handle_Early_Return: { + + istate->set_msg(early_return); + + // Clear expression stack. + topOfStack = istate->stack_base() - Interpreter::stackElementWords; + + JvmtiThreadState *ts = THREAD->jvmti_thread_state(); + + // Push the value to be returned. + switch (istate->method()->result_type()) { + case T_BOOLEAN: + case T_SHORT: + case T_BYTE: + case T_CHAR: + case T_INT: + SET_STACK_INT(ts->earlyret_value().i, 0); + MORE_STACK(1); + break; + case T_LONG: + SET_STACK_LONG(ts->earlyret_value().j, 1); + MORE_STACK(2); + break; + case T_FLOAT: + SET_STACK_FLOAT(ts->earlyret_value().f, 0); + MORE_STACK(1); + break; + case T_DOUBLE: + SET_STACK_DOUBLE(ts->earlyret_value().d, 1); + MORE_STACK(2); + break; + case T_ARRAY: + case T_OBJECT: + SET_STACK_OBJECT(ts->earlyret_oop(), 0); + MORE_STACK(1); + break; + } + + ts->clr_earlyret_value(); + ts->set_earlyret_oop(NULL); + ts->clr_earlyret_pending(); + + // Fall through to handle_return. + + } // handle_Early_Return + + handle_return: { // A storestore barrier is required to order initialization of // final fields with publishing the reference to the object that // holds the field. Without the barrier the value of final fields - // can be observed to change. On IA64 the publishing stores are - // performed with release semantics. - NOT_IA64(OrderAccess::storestore()); + // can be observed to change. + OrderAccess::storestore(); DECACHE_STATE(); @@ -3101,6 +3077,16 @@ illegal_state_oop = THREAD->pending_exception(); THREAD->clear_pending_exception(); } + } else if (UseHeavyMonitors) { + { + // Prevent any HandleMarkCleaner from freeing our live handles. + HandleMark __hm(THREAD); + CALL_VM_NOCHECK(InterpreterRuntime::monitorexit(THREAD, base)); + } + if (THREAD->has_pending_exception()) { + if (!suppress_error) illegal_state_oop = THREAD->pending_exception(); + THREAD->clear_pending_exception(); + } } else { BasicLock* lock = base->lock(); markOop header = lock->displaced_header(); @@ -3177,7 +3163,7 @@ // assert(!suppress_error || (suppress_error && illegal_state_oop() == NULL), "Error was not suppressed"); if (illegal_state_oop() != NULL || original_exception() != NULL) { - // inform the frame manager we have no result + // Inform the frame manager we have no result. istate->set_msg(throwing_exception); if (illegal_state_oop() != NULL) THREAD->set_pending_exception(illegal_state_oop(), NULL, 0); @@ -3202,7 +3188,6 @@ THREAD->set_popframe_condition_bit(JavaThread::popframe_force_deopt_reexecution_bit); } } else { - // Don't overwrite the message 'popping_frame'. istate->set_msg(return_from_method); } @@ -3482,7 +3467,6 @@ tty->print_cr("result_to_call._bcp_advance: %d ", this->_result._to_call._bcp_advance); tty->print_cr("osr._osr_buf: " INTPTR_FORMAT, (uintptr_t) this->_result._osr._osr_buf); tty->print_cr("osr._osr_entry: " INTPTR_FORMAT, (uintptr_t) this->_result._osr._osr_entry); - tty->print_cr("result_return_kind 0x%x ", (int) this->_result._return_kind); tty->print_cr("prev_link: " INTPTR_FORMAT, (uintptr_t) this->_prev_link); tty->print_cr("native_mirror: " INTPTR_FORMAT, (uintptr_t) this->_oop_temp); tty->print_cr("stack_base: " INTPTR_FORMAT, (uintptr_t) this->_stack_base);
--- a/src/share/vm/interpreter/bytecodeInterpreterProfiling.hpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/share/vm/interpreter/bytecodeInterpreterProfiling.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012 SAP AG. All rights reserved. + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2013 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 @@ -34,8 +34,8 @@ // Global settings ///////////////////////////////////////////////////////////// -// Enables profiling support -#if defined(COMPILER2) && defined(PPC64) +// Enables profiling support. +#if defined(COMPILER2) #define CC_INTERP_PROFILE #endif @@ -75,7 +75,6 @@ // Non-dummy implementations /////////////////////////////////////////////////// - // Accessors for the current method data pointer 'mdx'. #define MDX() (istate->mdx()) #define SET_MDX(mdx) \ @@ -248,7 +247,7 @@ ReceiverTypeData::set_null_seen(MDX()); \ } else { \ /* Template interpreter doesn't increment count. */ \ - /* ReceiverTypeData::increment_count_no_overflow(MDX());*/ \ + /* ReceiverTypeData::increment_count_no_overflow(MDX()); */ \ ReceiverTypeData::increment_receiver_count_no_overflow(MDX(), receiver); \ } \ SET_MDX(ReceiverTypeData::advance(MDX())); \
--- a/src/share/vm/interpreter/interpreterRuntime.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/share/vm/interpreter/interpreterRuntime.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -251,18 +251,15 @@ //------------------------------------------------------------------------------------------------------------------------ // Exceptions -// Assume the compiler is (or will be) interested in this event. -// If necessary, create an MDO to hold the information, and record it. -void InterpreterRuntime::note_trap(JavaThread* thread, int reason, TRAPS) { - assert(ProfileTraps, "call me only if profiling"); - methodHandle trap_method(thread, method(thread)); - +void InterpreterRuntime::note_trap_inner(JavaThread* thread, int reason, + methodHandle trap_method, int trap_bci, TRAPS) { if (trap_method.not_null()) { methodDataHandle trap_mdo(thread, trap_method->method_data()); if (trap_mdo.is_null()) { methodOopDesc::build_interpreter_method_data(trap_method, THREAD); if (HAS_PENDING_EXCEPTION) { - assert((PENDING_EXCEPTION->is_a(SystemDictionary::OutOfMemoryError_klass())), "we expect only an OOM error here"); + assert((PENDING_EXCEPTION->is_a(SystemDictionary::OutOfMemoryError_klass())), + "we expect only an OOM error here"); CLEAR_PENDING_EXCEPTION; } trap_mdo = methodDataHandle(thread, trap_method->method_data()); @@ -271,38 +268,25 @@ if (trap_mdo.not_null()) { // Update per-method count of trap events. The interpreter // is updating the MDO to simulate the effect of compiler traps. - int trap_bci = trap_method->bci_from(bcp(thread)); Deoptimization::update_method_data_from_interpreter(trap_mdo, trap_bci, reason); } } } +// Assume the compiler is (or will be) interested in this event. +// If necessary, create an MDO to hold the information, and record it. +void InterpreterRuntime::note_trap(JavaThread* thread, int reason, TRAPS) { + assert(ProfileTraps, "call me only if profiling"); + methodHandle trap_method(thread, method(thread)); + int trap_bci = trap_method->bci_from(bcp(thread)); + note_trap_inner(thread, reason, trap_method, trap_bci, THREAD); +} + #ifdef CC_INTERP // As legacy note_trap, but we have more arguments. IRT_ENTRY(void, InterpreterRuntime::note_trap(JavaThread* thread, int reason, methodOop method, int trap_bci)) methodHandle trap_method(method); - - // START derived from note_trap - // passed as arg: methodHandle trap_method(thread, method(thread)); - if (trap_method.not_null()) { - methodDataHandle trap_mdo(thread, trap_method->method_data()); - if (trap_mdo.is_null()) { - methodOopDesc::build_interpreter_method_data(trap_method, THREAD); - if (HAS_PENDING_EXCEPTION) { - assert((PENDING_EXCEPTION->is_a(SystemDictionary::OutOfMemoryError_klass())), "we expect only an OOM error here"); - CLEAR_PENDING_EXCEPTION; - } - trap_mdo = trap_method->method_data(); - // and fall through... - } - if (trap_mdo.not_null()) { - // Update per-method count of trap events. The interpreter - // is updating the MDO to simulate the effect of compiler traps. - // Passed as arg int trap_bci = trap_method->bci_from(bcp(thread)); - Deoptimization::update_method_data_from_interpreter(trap_mdo, trap_bci, reason); - } - } - // END derived from note_trap + note_trap_inner(thread, reason, trap_method, trap_bci, THREAD); IRT_END // Class Deoptimization is not visible in BytecodeInterpreter, so we need a wrapper
--- a/src/share/vm/interpreter/interpreterRuntime.hpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/share/vm/interpreter/interpreterRuntime.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -80,13 +80,15 @@ static ConstantPoolCacheEntry* cache_entry_at(JavaThread *thread, int i) { return method(thread)->constants()->cache()->entry_at(i); } static ConstantPoolCacheEntry* cache_entry(JavaThread *thread) { return cache_entry_at(thread, Bytes::get_native_u2(bcp(thread) + 1)); } + static void note_trap_inner(JavaThread* thread, int reason, + methodHandle trap_method, int trap_bci, TRAPS); static void note_trap(JavaThread *thread, int reason, TRAPS); #ifdef CC_INTERP // Profile traps in C++ interpreter. static void note_trap(JavaThread* thread, int reason, methodOop method, int trap_bci); #endif // CC_INTERP - // Inner work method for Interpreter's frequency counter overflow + // Inner work method for Interpreter's frequency counter overflow. static nmethod* frequency_counter_overflow_inner(JavaThread* thread, address branch_bcp); public: @@ -117,13 +119,13 @@ static void throw_pending_exception(JavaThread* thread); #ifdef CC_INTERP - // Profile traps in C++ interpreter + // Profile traps in C++ interpreter. static void note_nullCheck_trap (JavaThread* thread, methodOop method, int trap_bci); static void note_div0Check_trap (JavaThread* thread, methodOop method, int trap_bci); static void note_rangeCheck_trap(JavaThread* thread, methodOop method, int trap_bci); static void note_classCheck_trap(JavaThread* thread, methodOop method, int trap_bci); static void note_arrayCheck_trap(JavaThread* thread, methodOop method, int trap_bci); - // A dummy for makros that shall not profile traps + // A dummy for makros that shall not profile traps. static void note_no_trap(JavaThread* thread, methodOop method, int trap_bci) {} #endif // CC_INTERP
--- a/src/share/vm/interpreter/invocationCounter.hpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/share/vm/interpreter/invocationCounter.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -96,20 +96,24 @@ int get_BackwardBranchLimit() const { return InterpreterBackwardBranchLimit >> number_of_noncount_bits; } int get_ProfileLimit() const { return InterpreterProfileLimit >> number_of_noncount_bits; } +#ifdef CC_INTERP // Test counter using scaled limits like the asm interpreter would do rather than doing // the shifts to normalize the counter. // Checks sum of invocation_counter and backedge_counter as the template interpreter does. bool reached_InvocationLimit(InvocationCounter *back_edge_count) const { - return (_counter & count_mask) + (back_edge_count->_counter & count_mask) >= (unsigned int) InterpreterInvocationLimit; + return (_counter & count_mask) + (back_edge_count->_counter & count_mask) >= + (unsigned int) InterpreterInvocationLimit; } bool reached_BackwardBranchLimit(InvocationCounter *back_edge_count) const { - return (_counter & count_mask) + (back_edge_count->_counter & count_mask) >= (unsigned int) InterpreterBackwardBranchLimit; + return (_counter & count_mask) + (back_edge_count->_counter & count_mask) >= + (unsigned int) InterpreterBackwardBranchLimit; } - - // Do this just like asm interpreter does for max speed + // Do this just like asm interpreter does for max speed. bool reached_ProfileLimit(InvocationCounter *back_edge_count) const { - return (_counter & count_mask) + (back_edge_count->_counter & count_mask) >= (unsigned int) InterpreterProfileLimit; + return (_counter & count_mask) + (back_edge_count->_counter & count_mask) >= + (unsigned int) InterpreterProfileLimit; } +#endif // CC_INTERP void increment() { _counter += count_increment; }
--- a/src/share/vm/interpreter/templateTable.hpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/share/vm/interpreter/templateTable.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -43,8 +43,11 @@ #ifdef TARGET_ARCH_MODEL_arm # include "interp_masm_arm.hpp" #endif -#ifdef TARGET_ARCH_MODEL_ppc -# include "interp_masm_ppc.hpp" +#ifdef TARGET_ARCH_MODEL_ppc_32 +# include "interp_masm_ppc_32.hpp" +#endif +#ifdef TARGET_ARCH_MODEL_ppc_64 +# include "interp_masm_ppc_64.hpp" #endif #ifndef CC_INTERP @@ -374,8 +377,11 @@ #ifdef TARGET_ARCH_MODEL_arm # include "templateTable_arm.hpp" #endif -#ifdef TARGET_ARCH_MODEL_ppc -# include "templateTable_ppc.hpp" +#ifdef TARGET_ARCH_MODEL_ppc_32 +# include "templateTable_ppc_32.hpp" +#endif +#ifdef TARGET_ARCH_MODEL_ppc_64 +# include "templateTable_ppc_64.hpp" #endif };
--- a/src/share/vm/oops/methodDataOop.hpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/share/vm/oops/methodDataOop.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -620,7 +620,7 @@ increment_uint_at_no_overflow(layout, count_off); } - // Support counter decrementation at checkcast / subtype check failed + // Support counter decrementation at checkcast / subtype check failed. static void decrement_count(DataLayout* layout) { increment_uint_at_no_overflow(layout, count_off, -1); }
--- a/src/share/vm/opto/generateOptoStub.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/share/vm/opto/generateOptoStub.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -235,7 +235,7 @@ #if defined(SPARC) || (defined(IA64) && !defined(AIX)) store_to_memory(NULL, adr_flags, intcon(0), T_INT, NoAlias); #endif -#if defined(IA64) && !defined(AIX) +#if (defined(IA64) && !defined(AIX)) Node* adr_last_Java_fp = basic_plus_adr(top(), thread, in_bytes(JavaThread::last_Java_fp_offset())); store_to_memory(NULL, adr_last_Java_fp, null(), T_ADDRESS, NoAlias); #endif
--- a/src/share/vm/prims/forte.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/share/vm/prims/forte.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -56,7 +56,7 @@ // Native interfaces for use by Forte tools. -#if !defined(IA64) || defined(AIX) +#if !defined(IA64) && !defined(PPC64) class vframeStreamForte : public vframeStreamCommon { public: @@ -626,7 +626,7 @@ // Method to let libcollector know about a dynamically loaded function. // Because it is weakly bound, the calls become NOP's when the library // isn't present. -#if defined(__APPLE__) || defined(AIX) +#ifdef __APPLE__ // XXXDARWIN: Link errors occur even when __attribute__((weak_import)) // is added #define collector_func_load(x0,x1,x2,x3,x4,x5,x6) (0) @@ -645,14 +645,14 @@ #endif // !_WINDOWS } // end extern "C" -#endif // !IA64 +#endif // !IA64 && !PPC64 void Forte::register_stub(const char* name, address start, address end) { -#if !defined(_WINDOWS) && (!defined(IA64) || defined(AIX)) +#if !defined(_WINDOWS) && !defined(IA64) && !defined(PPC64) assert(pointer_delta(end, start, sizeof(jbyte)) < INT_MAX, "Code size exceeds maximum range"); collector_func_load((char*)name, NULL, NULL, start, pointer_delta(end, start, sizeof(jbyte)), 0, NULL); -#endif // !_WINDOWS && !IA64 +#endif // !_WINDOWS && !IA64 && !PPC64 }
--- a/src/share/vm/runtime/arguments.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/share/vm/runtime/arguments.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -3278,14 +3278,11 @@ UseBiasedLocking = false; } -#ifdef CC_INTERP - // Clear flags not supported by the C++ interpreter -#if !defined(PPC64) - // Now supported by CC_INTERP, but not tested with other ports than PPC. - LP64_ONLY(FLAG_SET_DEFAULT(UseCompressedOops, false)); +#ifdef ZERO + // Clear flags not supported on zero. FLAG_SET_DEFAULT(ProfileInterpreter, false); FLAG_SET_DEFAULT(UseBiasedLocking, false); -#endif + LP64_ONLY(FLAG_SET_DEFAULT(UseCompressedOops, false)); #endif // CC_INTERP #ifdef COMPILER2
--- a/src/share/vm/runtime/frame.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/share/vm/runtime/frame.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -930,22 +930,11 @@ if (istate->msg() == BytecodeInterpreter::call_method) { f->do_oop((oop*)&istate->_result._to_call._callee); } - #endif /* CC_INTERP */ -#if !defined(PPC32) || defined(ZERO) - if (m->is_native()) { -#ifdef CC_INTERP - f->do_oop((oop*)&istate->_oop_temp); -#else - f->do_oop((oop*)( fp() + interpreter_frame_oop_temp_offset )); -#endif /* CC_INTERP */ + if (m->is_native() PPC32_ONLY(&& m->is_static())) { + f->do_oop(interpreter_frame_temp_oop_addr()); } -#else // PPC32 - if (m->is_native() && m->is_static()) { - f->do_oop(interpreter_frame_mirror_addr()); - } -#endif // PPC32 int max_locals = m->is_native() ? m->size_of_parameters() : m->max_locals();
--- a/src/share/vm/runtime/frame.hpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/share/vm/runtime/frame.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -315,6 +315,9 @@ void interpreter_frame_set_monitor_end(BasicObjectLock* value); #endif // CC_INTERP + // Address of the temp oop in the frame. Needed as GC root. + oop* interpreter_frame_temp_oop_addr() const; + // BasicObjectLocks: // // interpreter_frame_monitor_begin is higher in memory than interpreter_frame_monitor_end @@ -351,9 +354,6 @@ void interpreter_frame_set_method(methodOop method); methodOop* interpreter_frame_method_addr() const; constantPoolCacheOop* interpreter_frame_cache_addr() const; -#ifdef PPC32 - oop* interpreter_frame_mirror_addr() const; -#endif public: // Entry frames
--- a/src/share/vm/runtime/frame.inline.hpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/share/vm/runtime/frame.inline.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -87,6 +87,13 @@ return is_entry_frame() && entry_frame_is_first(); } +#ifdef CC_INTERP +inline oop* frame::interpreter_frame_temp_oop_addr() const { + interpreterState istate = get_interpreterState(); + return (oop *)&istate->_oop_temp; +} +#endif // CC_INTERP + // here are the platform-dependent bodies: #ifdef TARGET_ARCH_x86
--- a/src/share/vm/runtime/globals.hpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/share/vm/runtime/globals.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -2724,7 +2724,9 @@ "Profile at the bytecode level during interpretation") \ \ develop(bool, TraceProfileInterpreter, false, \ - "Trace profiling at the bytecode level during interpretation") \ + "Trace profiling at the bytecode level during interpretation. " \ + "This outputs the profiling information collected to improve " \ + "jit compilation.") \ \ develop_pd(bool, ProfileTraps, \ "Profile deoptimization traps at the bytecode level") \
--- a/src/share/vm/runtime/os.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/share/vm/runtime/os.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -996,7 +996,7 @@ // if C stack is walkable beyond current frame. The check for fp() is not // necessary on Sparc, but it's harmless. bool os::is_first_C_frame(frame* fr) { -#if defined(IA64) && !defined(AIX) +#if (defined(IA64) && !defined(AIX)) // In order to walk native frames on Itanium, we need to access the unwind // table, which is inside ELF. We don't want to parse ELF after fatal error, // so return true for IA64. If we need to support C stack walking on IA64,
--- a/src/share/vm/runtime/stubRoutines.hpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/share/vm/runtime/stubRoutines.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -114,8 +114,8 @@ #ifdef TARGET_ARCH_MODEL_arm # include "stubRoutines_arm.hpp" #endif -#ifdef TARGET_ARCH_MODEL_ppc -# include "stubRoutines_ppc.hpp" +#ifdef TARGET_ARCH_MODEL_ppc_32 +# include "stubRoutines_ppc_32.hpp" #endif #ifdef TARGET_ARCH_MODEL_ppc_64 # include "stubRoutines_ppc_64.hpp"
--- a/src/share/vm/runtime/thread.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/share/vm/runtime/thread.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -315,6 +315,9 @@ void Thread::record_stack_base_and_size() { set_stack_base(os::current_stack_base()); set_stack_size(os::current_stack_size()); + if (is_Java_thread()) { + ((JavaThread*) this)->set_stack_overflow_limit(); + } // CR 7190089: on Solaris, primordial thread's stack is adjusted // in initialize_thread(). Without the adjustment, stack size is // incorrect if stack is set to unlimited (ulimit -s unlimited).
--- a/src/share/vm/runtime/thread.hpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/share/vm/runtime/thread.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -41,6 +41,7 @@ #include "runtime/stubRoutines.hpp" #include "runtime/threadLocalStorage.hpp" #include "runtime/unhandledOops.hpp" +#include "utilities/macros.hpp" #include "services/memRecorder.hpp" #include "trace/traceBackend.hpp" #include "trace/traceMacros.hpp" @@ -544,19 +545,6 @@ return (_stack_base >= adr && adr >= (_stack_base - _stack_size)); } -#ifdef CC_INTERP - // The cppInterpreter does not support implicit checks, thus we check - // stack overflow by comparison. We precompute the limit of the stack - // and load it from here to simplify the check in assembly. - protected: - address _memory_stack_limit; - - public: - address memory_stack_limit() { return _memory_stack_limit; } - void set_memory_stack_limit(address limit) { _memory_stack_limit = limit; } - static ByteSize memory_stack_limit_offset() { return byte_offset_of(Thread, _memory_stack_limit); } -#endif - uintptr_t self_raw_id() { return _self_raw_id; } void set_self_raw_id(uintptr_t value) { _self_raw_id = value; } @@ -908,7 +896,11 @@ private: - StackGuardState _stack_guard_state; + StackGuardState _stack_guard_state; + + // Precompute the limit of the stack as used in stack overflow checks. + // We load it from here to simplify the stack overflow check in assembly. + address _stack_overflow_limit; // Compiler exception handling (NOTE: The _exception_oop is *NOT* the same as _pending_exception. It is // used to temp. parsing values into and out of the runtime system during exception handling for compiled @@ -1325,6 +1317,14 @@ // and reguard if possible. bool reguard_stack(void); + address stack_overflow_limit() { return _stack_overflow_limit; } + void set_stack_overflow_limit() { + _stack_overflow_limit = _stack_base - _stack_size + + ((StackShadowPages + + StackYellowPages + + StackRedPages) * os::vm_page_size()); + } + // Misc. accessors/mutators void set_do_not_unlock(void) { _do_not_unlock_if_synchronized = true; } void clr_do_not_unlock(void) { _do_not_unlock_if_synchronized = false; } @@ -1359,6 +1359,7 @@ static ByteSize exception_oop_offset() { return byte_offset_of(JavaThread, _exception_oop ); } static ByteSize exception_pc_offset() { return byte_offset_of(JavaThread, _exception_pc ); } static ByteSize exception_handler_pc_offset() { return byte_offset_of(JavaThread, _exception_handler_pc); } + static ByteSize stack_overflow_limit_offset() { return byte_offset_of(JavaThread, _stack_overflow_limit); } static ByteSize is_method_handle_return_offset() { return byte_offset_of(JavaThread, _is_method_handle_return); } static ByteSize stack_guard_state_offset() { return byte_offset_of(JavaThread, _stack_guard_state ); } static ByteSize suspend_flags_offset() { return byte_offset_of(JavaThread, _suspend_flags ); }
--- a/src/share/vm/utilities/elfFile.cpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/share/vm/utilities/elfFile.cpp Tue Apr 29 21:57:16 2014 +0100 @@ -129,8 +129,7 @@ return false; } add_string_table(table); - } - else if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) { + } else if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) { // symbol tables ElfSymbolTable* table = new (std::nothrow) ElfSymbolTable(m_file, shdr); if (table == NULL) { @@ -141,7 +140,7 @@ } } -#if defined(PPC64) +#if defined(PPC64) && !defined(ABI_ELFv2) // Now read the .opd section wich contains the PPC64 function descriptor table. // The .opd section is only available on PPC64 (see for example: // http://refspecs.linuxfoundation.org/LSB_3.1.1/LSB-Core-PPC64/LSB-Core-PPC64/specialsections.html)
--- a/src/share/vm/utilities/macros.hpp Thu Apr 24 16:21:06 2014 +0100 +++ b/src/share/vm/utilities/macros.hpp Tue Apr 29 21:57:16 2014 +0100 @@ -228,10 +228,13 @@ #endif #if defined(PPC32) || defined(PPC64) +#ifndef PPC #define PPC +#endif #define PPC_ONLY(code) code #define NOT_PPC(code) #else +#undef PPC #define PPC_ONLY(code) #define NOT_PPC(code) code #endif