changeset 2059:9508a52cbd32

Add deoptimization blob support.
author Thomas Wuerthinger <wuerthinger@ssw.jku.at>
date Wed, 19 Jan 2011 15:48:15 +0100
parents 8f033d37798a
children 40bcc41390e4
files c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/HotSpotRuntime.java c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/HotSpotTypeResolved.java c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/HotSpotVMConfig.java c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/HotSpotXirGenerator.java c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/TemplateFlag.java src/cpu/x86/vm/sharedRuntime_x86_64.cpp src/share/vm/c1x/c1x_CodeInstaller.cpp src/share/vm/c1x/c1x_JavaAccess.hpp src/share/vm/c1x/c1x_VMEntries.cpp src/share/vm/code/codeBlob.hpp src/share/vm/runtime/deoptimization.cpp
diffstat 11 files changed, 222 insertions(+), 46 deletions(-) [+]
line wrap: on
line diff
--- 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;
+    }
 }
--- 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.
--- 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;
--- 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);
     }
--- 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;
--- 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
--- 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");
--- 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                                                                             \
--- 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()));
--- 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;     }
+
 };
 
 
--- 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