# HG changeset patch # User Thomas Wuerthinger # Date 1295448495 -3600 # Node ID 9508a52cbd32857a8d41cadecfdc6f6ac9ed6b48 # Parent 8f033d37798a9b55d91499fde2694ad96384e5f6 Add deoptimization blob support. diff -r 8f033d37798a -r 9508a52cbd32 c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/HotSpotRuntime.java --- a/c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/HotSpotRuntime.java Tue Jan 18 10:19:59 2011 +0100 +++ b/c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/HotSpotRuntime.java Wed Jan 19 15:48:15 2011 +0100 @@ -228,4 +228,9 @@ public int getCustomStackAreaSize() { return 8; } + + @Override + public boolean supportsArrayCopyIntrinsic() { + return true; + } } diff -r 8f033d37798a -r 9508a52cbd32 c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/HotSpotTypeResolved.java --- a/c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/HotSpotTypeResolved.java Tue Jan 18 10:19:59 2011 +0100 +++ b/c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/HotSpotTypeResolved.java Wed Jan 19 15:48:15 2011 +0100 @@ -25,7 +25,6 @@ import com.sun.cri.ci.*; import com.sun.cri.ri.*; -import com.sun.hotspot.c1x.logging.*; /** * Implementation of RiType for resolved non-primitive HotSpot classes. diff -r 8f033d37798a -r 9508a52cbd32 c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/HotSpotVMConfig.java --- a/c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/HotSpotVMConfig.java Tue Jan 18 10:19:59 2011 +0100 +++ b/c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/HotSpotVMConfig.java Wed Jan 19 15:48:15 2011 +0100 @@ -46,6 +46,7 @@ public int arrayClassElementOffset; public int threadTlabTopOffset; public int threadTlabEndOffset; + public int threadObjectOffset; public int instanceHeaderPrototypeOffset; public int threadExceptionOopOffset; public int threadExceptionPcOffset; diff -r 8f033d37798a -r 9508a52cbd32 c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/HotSpotXirGenerator.java --- a/c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/HotSpotXirGenerator.java Tue Jan 18 10:19:59 2011 +0100 +++ b/c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/HotSpotXirGenerator.java Wed Jan 19 15:48:15 2011 +0100 @@ -681,6 +681,20 @@ } }; + private XirOperand genArrayLength(XirOperand array, boolean implicitNullException) { + XirOperand length = asm.createTemp("length", CiKind.Int); + genArrayLength(asm, length, array, implicitNullException); + return length; + } + + private void genArrayLength(CiXirAssembler asm, XirOperand length, XirOperand array, boolean implicitNullException) { + if (implicitNullException) { + // asm.nop(1); + asm.mark(MARK_IMPLICIT_NULL); + } + asm.pload(CiKind.Int, length, array, asm.i(config.arrayLengthOffset), implicitNullException); + } + private KindTemplates arrayLoadTemplates = new KindTemplates(NULL_CHECK, READ_BARRIER, BOUNDS_CHECK, GIVEN_LENGTH) { @Override @@ -699,12 +713,7 @@ if (is(GIVEN_LENGTH, flags)) { length = asm.createInputParameter("length", CiKind.Int); } else { - length = asm.createTemp("length", CiKind.Int); - if (implicitNullException) { - //asm.nop(1); - asm.mark(MARK_IMPLICIT_NULL); - } - asm.pload(CiKind.Int, length, array, asm.i(config.arrayLengthOffset), implicitNullException); + length = genArrayLength(array, implicitNullException); } asm.jugteq(failBoundsCheck, index, length); implicitNullException = false; @@ -724,6 +733,135 @@ } }; + private SimpleTemplates currentThreadTemplates = new SimpleTemplates() { + @Override + protected XirTemplate create(CiXirAssembler asm, long flags) { + XirOperand result = asm.restart(CiKind.Object); + XirOperand thread = asm.createRegisterTemp("thread", CiKind.Word, AMD64.r15); + asm.pload(CiKind.Object, result, thread, asm.i(config.threadObjectOffset), false); + return asm.finishTemplate("currentThread"); + } + }; + + @Override + public XirSnippet genCurrentThread(XirSite site) { + return new XirSnippet(currentThreadTemplates.get(site)); + } + + private KindTemplates arrayCopyTemplates = new KindTemplates() { + + @Override + protected XirTemplate create(CiXirAssembler asm, long flags, CiKind kind) { + asm.restart(CiKind.Void); + XirParameter src = asm.createInputParameter("src", CiKind.Object); + XirParameter srcPos = asm.createInputParameter("srcPos", CiKind.Int); + XirParameter dest = asm.createInputParameter("dest", CiKind.Object); + XirParameter destPos = asm.createInputParameter("destPos", CiKind.Int); + XirParameter length = asm.createInputParameter("length", CiKind.Int); + + XirOperand tempSrc = asm.createTemp("tempSrc", CiKind.Word); + XirOperand tempDest = asm.createTemp("tempDest", CiKind.Word); + XirOperand lengthOperand = asm.createTemp("lengthOperand", CiKind.Int); + + // Calculate the factor for the repeat move instruction. + int elementSize = kind.sizeInBytes(target.wordSize); + int factor; + boolean wordSize; + if (elementSize >= target.wordSize) { + assert elementSize % target.wordSize == 0; + wordSize = true; + factor = elementSize / target.wordSize; + } else { + factor = elementSize; + wordSize = false; + } + + // Adjust the length if the factor is not 1. + if (factor != 1) { + asm.shl(lengthOperand, length, asm.i(CiUtil.log2(factor))); + } else { + asm.mov(lengthOperand, length); + } + + // Set the start and the end pointer. + asm.lea(tempSrc, src, srcPos, config.getArrayOffset(kind), Scale.fromInt(elementSize)); + asm.lea(tempDest, dest, destPos, config.getArrayOffset(kind), Scale.fromInt(elementSize)); + + XirLabel reverse = null; + XirLabel normal = null; + + if (!is(INPUTS_DIFFERENT, flags) && !is(INPUTS_SAME, flags)) { + normal = asm.createInlineLabel("reverse"); + asm.jneq(normal, src, dest); + } + + if (!is(INPUTS_DIFFERENT, flags)) { + reverse = asm.createInlineLabel("reverse"); + asm.jlt(reverse, srcPos, destPos); + } + + if (!is(INPUTS_DIFFERENT, flags) && !is(INPUTS_SAME, flags)) { + asm.bindInline(normal); + } + + // Everything set up => repeat mov. + if (wordSize) { + asm.repmov(tempSrc, tempDest, lengthOperand); + } else { + asm.repmovb(tempSrc, tempDest, lengthOperand); + } + + if (!is(INPUTS_DIFFERENT, flags)) { + + XirLabel end = asm.createInlineLabel("end"); + asm.jmp(end); + + // Implement reverse copy, because srcPos < destPos and src == dest. + asm.bindInline(reverse); + + CiKind copyKind = wordSize ? CiKind.Word : CiKind.Byte; + XirOperand tempValue = asm.createTemp("tempValue", copyKind); + XirLabel start = asm.createInlineLabel("start"); + asm.bindInline(start); + asm.sub(lengthOperand, lengthOperand, asm.i(1)); + asm.jlt(end, lengthOperand, asm.i(0)); + + Scale scale = wordSize ? Scale.fromInt(target.wordSize) : Scale.Times1; + asm.pload(copyKind, tempValue, tempSrc, lengthOperand, 0, scale, false); + asm.pstore(copyKind, tempDest, lengthOperand, tempValue, 0, scale, false); + + asm.jmp(start); + asm.bindInline(end); + } + + if (kind == CiKind.Object) { + // Do write barriers + asm.lea(tempDest, dest, destPos, config.getArrayOffset(kind), Scale.fromInt(elementSize)); + asm.shr(tempDest, tempDest, asm.i(config.cardtableShift)); + asm.pstore(CiKind.Boolean, asm.w(config.cardtableStartAddress), tempDest, asm.b(false), false); + + XirOperand tempDestEnd = tempSrc; // Reuse src temp + asm.lea(tempDestEnd, dest, destPos, config.getArrayOffset(kind), Scale.fromInt(elementSize)); + asm.add(tempDestEnd, tempDestEnd, length); + asm.shr(tempDestEnd, tempDestEnd, asm.i(config.cardtableShift)); + + // Jump to out-of-line write barrier loop if the array is big. + XirLabel writeBarrierLoop = asm.createOutOfLineLabel("writeBarrierLoop"); + asm.jneq(writeBarrierLoop, tempDest, tempSrc); + XirLabel back = asm.createInlineLabel("back"); + asm.bindInline(back); + + asm.bindOutOfLine(writeBarrierLoop); + asm.pstore(CiKind.Boolean, asm.w(config.cardtableStartAddress), tempDestEnd, asm.b(false), false); + asm.sub(tempDestEnd, tempDestEnd, asm.i(1)); + asm.jneq(writeBarrierLoop, tempDestEnd, tempDest); + asm.jmp(back); + } + + return asm.finishTemplate("arraycopy<" + kind + ">"); + } + }; + private KindTemplates arrayStoreTemplates = new KindTemplates(NULL_CHECK, WRITE_BARRIER, BOUNDS_CHECK, STORE_CHECK, GIVEN_LENGTH) { @Override @@ -994,6 +1132,23 @@ } @Override + public XirSnippet genArrayCopy(XirSite site, XirArgument src, XirArgument srcPos, XirArgument dest, XirArgument destPos, XirArgument length, RiType elementType, boolean inputsSame, boolean inputsDifferent) { + if (elementType == null) { + return null; + } + assert !inputsDifferent || !inputsSame; + XirTemplate template = null; + if (inputsDifferent) { + template = arrayCopyTemplates.get(site, elementType.kind(), INPUTS_DIFFERENT); + } else if (inputsSame) { + template = arrayCopyTemplates.get(site, elementType.kind(), INPUTS_SAME); + } else { + template = arrayCopyTemplates.get(site, elementType.kind()); + } + return new XirSnippet(template, src, srcPos, dest, destPos, length); + } + + @Override public XirSnippet genArrayLength(XirSite site, XirArgument array) { return new XirSnippet(arrayLengthTemplates.get(site), array); } diff -r 8f033d37798a -r 9508a52cbd32 c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/TemplateFlag.java --- a/c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/TemplateFlag.java Tue Jan 18 10:19:59 2011 +0100 +++ b/c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/TemplateFlag.java Wed Jan 19 15:48:15 2011 +0100 @@ -21,7 +21,7 @@ package com.sun.hotspot.c1x; enum TemplateFlag { - NULL_CHECK, UNRESOLVED, READ_BARRIER, WRITE_BARRIER, STORE_CHECK, BOUNDS_CHECK, GIVEN_LENGTH, STATIC_METHOD, SYNCHRONIZED; + NULL_CHECK, UNRESOLVED, READ_BARRIER, WRITE_BARRIER, STORE_CHECK, BOUNDS_CHECK, GIVEN_LENGTH, INPUTS_DIFFERENT, INPUTS_SAME, STATIC_METHOD, SYNCHRONIZED; private static final long FIRST_FLAG = 0x0000000100000000L; public static final long FLAGS_MASK = 0x0000FFFF00000000L; diff -r 8f033d37798a -r 9508a52cbd32 src/cpu/x86/vm/sharedRuntime_x86_64.cpp --- a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Tue Jan 18 10:19:59 2011 +0100 +++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Wed Jan 19 15:48:15 2011 +0100 @@ -2655,6 +2655,40 @@ __ bind(no_pending_exception); #endif + // (tw) Start of C1X uncommon trap code. + __ jmp(cont); + + int uncommon_trap_offset = __ pc() - start; + + // Warning: Duplicate code + + // Save everything in sight. + map = RegisterSaver::save_live_registers(masm, 0, &frame_size_in_words); + + // Normal deoptimization + + + // fetch_unroll_info needs to call last_java_frame() + __ set_last_Java_frame(noreg, noreg, NULL); + + __ movl(c_rarg1, (int32_t)Deoptimization::Unpack_reexecute); + __ movl(r14, c_rarg1); // save into r14 for later call to unpack_frames + __ mov(c_rarg0, r15_thread); + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap))); + + // Need to have an oopmap that tells fetch_unroll_info where to + // find any register it might need. + + oop_maps->add_gc_map( __ pc()-start, map->deep_copy()); + + __ reset_last_Java_frame(false, false); + + Label after_fetch_unroll_info_call; + __ jmp(after_fetch_unroll_info_call); + + + // (tw) End of C1X uncommon trap code. + __ bind(cont); // Call C code. Need thread and this frame, but NOT official VM entry @@ -2684,6 +2718,8 @@ __ reset_last_Java_frame(false, false); + __ bind(after_fetch_unroll_info_call); + // Load UnrollBlock* into rdi __ mov(rdi, rax); @@ -2845,6 +2881,7 @@ _deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, reexecute_offset, frame_size_in_words); _deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset); + _deopt_blob->set_uncommon_trap_offset(uncommon_trap_offset); } #ifdef COMPILER2 diff -r 8f033d37798a -r 9508a52cbd32 src/share/vm/c1x/c1x_CodeInstaller.cpp --- a/src/share/vm/c1x/c1x_CodeInstaller.cpp Tue Jan 18 10:19:59 2011 +0100 +++ b/src/share/vm/c1x/c1x_CodeInstaller.cpp Wed Jan 19 15:48:15 2011 +0100 @@ -523,6 +523,9 @@ } else if (runtime_call == CiRuntimeCall::RegisterFinalizer()) { call->set_destination(Runtime1::entry_for(Runtime1::register_finalizer_id)); _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec(), Assembler::call32_operand); + } else if (runtime_call == CiRuntimeCall::Deoptimize()) { + call->set_destination(SharedRuntime::deopt_blob()->uncommon_trap()); + _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec(), Assembler::call32_operand); } else { runtime_call->print(); fatal("runtime_call not implemented"); diff -r 8f033d37798a -r 9508a52cbd32 src/share/vm/c1x/c1x_JavaAccess.hpp --- a/src/share/vm/c1x/c1x_JavaAccess.hpp Tue Jan 18 10:19:59 2011 +0100 +++ b/src/share/vm/c1x/c1x_JavaAccess.hpp Wed Jan 19 15:48:15 2011 +0100 @@ -180,6 +180,7 @@ static_oop_field(CiRuntimeCall, ArithmeticLog, "Lcom/sun/cri/ci/CiRuntimeCall;"); \ static_oop_field(CiRuntimeCall, ArithmeticLog10, "Lcom/sun/cri/ci/CiRuntimeCall;"); \ static_oop_field(CiRuntimeCall, ArithmeticSin, "Lcom/sun/cri/ci/CiRuntimeCall;"); \ + static_oop_field(CiRuntimeCall, Deoptimize, "Lcom/sun/cri/ci/CiRuntimeCall;"); \ end_class \ start_class(RiMethod) \ end_class \ diff -r 8f033d37798a -r 9508a52cbd32 src/share/vm/c1x/c1x_VMEntries.cpp --- a/src/share/vm/c1x/c1x_VMEntries.cpp Tue Jan 18 10:19:59 2011 +0100 +++ b/src/share/vm/c1x/c1x_VMEntries.cpp Wed Jan 19 15:48:15 2011 +0100 @@ -517,6 +517,7 @@ set_int(env, config, "klassStateFullyInitialized", (int)instanceKlass::fully_initialized); set_int(env, config, "threadTlabTopOffset", in_bytes(JavaThread::tlab_top_offset())); set_int(env, config, "threadTlabEndOffset", in_bytes(JavaThread::tlab_end_offset())); + set_int(env, config, "threadObjectOffset", in_bytes(JavaThread::threadObj_offset())); set_int(env, config, "instanceHeaderPrototypeOffset", Klass::prototype_header_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes()); set_int(env, config, "threadExceptionOopOffset", in_bytes(JavaThread::exception_oop_offset())); set_int(env, config, "threadExceptionPcOffset", in_bytes(JavaThread::exception_pc_offset())); diff -r 8f033d37798a -r 9508a52cbd32 src/share/vm/code/codeBlob.hpp --- a/src/share/vm/code/codeBlob.hpp Tue Jan 18 10:19:59 2011 +0100 +++ b/src/share/vm/code/codeBlob.hpp Wed Jan 19 15:48:15 2011 +0100 @@ -352,6 +352,10 @@ int _unpack_with_exception_in_tls; + // (tw) Offset when C1X calls uncommon_trap. + int _uncommon_trap_offset; + + // Creation support DeoptimizationBlob( CodeBuffer* cb, @@ -407,6 +411,14 @@ assert(code_contains(code_begin() + _unpack_with_exception_in_tls), "must be PC inside codeblob"); } address unpack_with_exception_in_tls() const { return code_begin() + _unpack_with_exception_in_tls; } + + // (tw) Offset when C1X calls uncommon_trap. + void set_uncommon_trap_offset(int offset) { + _uncommon_trap_offset = offset; + assert(contains(code_begin() + _uncommon_trap_offset), "must be PC inside codeblob"); + } + address uncommon_trap() const { return code_begin() + _uncommon_trap_offset; } + }; diff -r 8f033d37798a -r 9508a52cbd32 src/share/vm/runtime/deoptimization.cpp --- a/src/share/vm/runtime/deoptimization.cpp Tue Jan 18 10:19:59 2011 +0100 +++ b/src/share/vm/runtime/deoptimization.cpp Wed Jan 19 15:48:15 2011 +0100 @@ -1149,7 +1149,6 @@ JRT_END -#if defined(COMPILER2) || defined(SHARK) void Deoptimization::load_class_by_index(constantPoolHandle constant_pool, int index, TRAPS) { // in case of an unresolved klass entry, load the class. if (constant_pool->tag_at(index).is_unresolved_klass()) { @@ -1892,40 +1891,3 @@ if (xtty != NULL) xtty->tail("statistics"); } } -#else // COMPILER2 || SHARK - - -// Stubs for C1 only system. -bool Deoptimization::trap_state_is_recompiled(int trap_state) { - return false; -} - -const char* Deoptimization::trap_reason_name(int reason) { - return "unknown"; -} - -void Deoptimization::print_statistics() { - // no output -} - -void -Deoptimization::update_method_data_from_interpreter(methodDataHandle trap_mdo, int trap_bci, int reason) { - // no udpate -} - -int Deoptimization::trap_state_has_reason(int trap_state, int reason) { - return 0; -} - -void Deoptimization::gather_statistics(DeoptReason reason, DeoptAction action, - Bytecodes::Code bc) { - // no update -} - -const char* Deoptimization::format_trap_state(char* buf, size_t buflen, - int trap_state) { - jio_snprintf(buf, buflen, "#%d", trap_state); - return buf; -} - -#endif // COMPILER2 || SHARK