changeset 1730:146e5d33e990

2009-03-09 Gary Benson <gbenson@redhat.com> * ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.hpp (SharkTopLevelBlock::_trap_request): New field. (SharkTopLevelBlock::trap_request): New method. (SharkTopLevelBlock::scan_for_traps): Likewise. (SharkTopLevelBlock::has_trap): Rewritten. (SharkTopLevelBlock::trap_index): Removed method. * ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.cpp (SharkTopLevelBlock::scan_for_traps): New method. (SharkTopLevelBlock::emit_IR): s/trap_index/trap_request/. (SharkTopLevelBlock::get_virtual_callee): Removed slow case. * ports/hotspot/src/share/vm/shark/sharkConstantPool.cpp (SharkConstantPool::cache_entry_at): Removed slow case. * ports/hotspot/src/share/vm/shark/sharkRuntime.hpp (SharkRuntime::_resolve_get_put): Removed. (SharkRuntime::_resolve_invoke): Likewise. (SharkRuntime::resolve_get_put): Likewise. (SharkRuntime::resolve_invoke): Likewise. (SharkRuntime::resolve_get_put_C): Likewise. (SharkRuntime::resolve_invoke_C): Likewise. (SharkRuntime::uncommon_trap_C): s/index/trap_request/. * ports/hotspot/src/share/vm/shark/sharkRuntime.cpp (SharkRuntime::_resolve_get_put): Removed. (SharkRuntime::_resolve_invoke): Likewise. (SharkRuntime::initialize): Removed initialization for the above. (SharkRuntime::resolve_get_put_C): Removed. (SharkRuntime::resolve_invoke_C): Likewise. (SharkRuntime::uncommon_trap_C): s/index/trap_request/. * ports/hotspot/src/share/vm/shark/sharkBlock.cpp (SharkBlock::do_field_access): Mismatch case now handled by trap. * ports/hotspot/src/share/vm/includeDB_shark: Updated. (transplanted from a28649aea20fad5a814c3cd8d56b8ed704c7203b)
author Gary Benson <gbenson@redhat.com>
date Mon, 09 Mar 2009 10:26:08 -0400
parents f7efa3c95c17
children 5e454391b4ce
files ChangeLog ports/hotspot/src/share/vm/includeDB_shark ports/hotspot/src/share/vm/shark/sharkBlock.cpp ports/hotspot/src/share/vm/shark/sharkConstantPool.cpp ports/hotspot/src/share/vm/shark/sharkRuntime.cpp ports/hotspot/src/share/vm/shark/sharkRuntime.hpp ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.cpp ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.hpp
diffstat 8 files changed, 168 insertions(+), 272 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Fri Mar 06 09:47:04 2009 -0500
+++ b/ChangeLog	Mon Mar 09 10:26:08 2009 -0400
@@ -1,3 +1,40 @@
+2009-03-09  Gary Benson  <gbenson@redhat.com>
+
+	* ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.hpp
+	(SharkTopLevelBlock::_trap_request): New field.
+	(SharkTopLevelBlock::trap_request): New method.
+	(SharkTopLevelBlock::scan_for_traps): Likewise.
+	(SharkTopLevelBlock::has_trap): Rewritten.
+	(SharkTopLevelBlock::trap_index): Removed method.
+	* ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.cpp
+	(SharkTopLevelBlock::scan_for_traps): New method.
+	(SharkTopLevelBlock::emit_IR): s/trap_index/trap_request/.
+	(SharkTopLevelBlock::get_virtual_callee): Removed slow case.
+
+	* ports/hotspot/src/share/vm/shark/sharkConstantPool.cpp
+	(SharkConstantPool::cache_entry_at): Removed slow case.
+
+	* ports/hotspot/src/share/vm/shark/sharkRuntime.hpp
+	(SharkRuntime::_resolve_get_put): Removed.
+	(SharkRuntime::_resolve_invoke): Likewise.
+	(SharkRuntime::resolve_get_put): Likewise.
+	(SharkRuntime::resolve_invoke): Likewise.
+	(SharkRuntime::resolve_get_put_C): Likewise.
+	(SharkRuntime::resolve_invoke_C): Likewise.
+	(SharkRuntime::uncommon_trap_C): s/index/trap_request/.
+	* ports/hotspot/src/share/vm/shark/sharkRuntime.cpp
+	(SharkRuntime::_resolve_get_put): Removed.
+	(SharkRuntime::_resolve_invoke): Likewise.
+	(SharkRuntime::initialize): Removed initialization for the above.
+	(SharkRuntime::resolve_get_put_C): Removed.
+	(SharkRuntime::resolve_invoke_C): Likewise.
+	(SharkRuntime::uncommon_trap_C): s/index/trap_request/.
+
+	* ports/hotspot/src/share/vm/shark/sharkBlock.cpp
+	(SharkBlock::do_field_access): Mismatch case now handled by trap.
+
+	* ports/hotspot/src/share/vm/includeDB_shark: Updated.
+
 2009-03-06  Gary Benson  <gbenson@redhat.com>
 
 	* ports/hotspot/src/share/vm/shark/sharkBuilder.hpp
--- a/ports/hotspot/src/share/vm/includeDB_shark	Fri Mar 06 09:47:04 2009 -0500
+++ b/ports/hotspot/src/share/vm/includeDB_shark	Mon Mar 09 10:26:08 2009 -0400
@@ -171,7 +171,6 @@
 sharkConstantPool.cpp                   methodOop.hpp
 sharkConstantPool.cpp                   sharkBuilder.hpp
 sharkConstantPool.cpp                   sharkConstantPool.hpp
-sharkConstantPool.cpp                   sharkRuntime.hpp
 sharkConstantPool.cpp                   sharkState.inline.hpp
 sharkConstantPool.cpp                   sharkType.hpp
 sharkConstantPool.cpp                   sharkValue.inline.hpp
@@ -285,6 +284,7 @@
 sharkTopLevelBlock.cpp                  ciType.hpp
 sharkTopLevelBlock.cpp                  ciTypeFlow.hpp
 sharkTopLevelBlock.cpp                  debug.hpp
+sharkTopLevelBlock.cpp                  deoptimization.hpp
 sharkTopLevelBlock.cpp                  llvmHeaders.hpp
 sharkTopLevelBlock.cpp                  shark_globals.hpp
 sharkTopLevelBlock.cpp                  sharkTopLevelBlock.hpp
--- a/ports/hotspot/src/share/vm/shark/sharkBlock.cpp	Fri Mar 06 09:47:04 2009 -0500
+++ b/ports/hotspot/src/share/vm/shark/sharkBlock.cpp	Mon Mar 09 10:26:08 2009 -0400
@@ -968,10 +968,7 @@
   bool will_link;
   ciField *field = iter()->get_field(will_link);
   assert(will_link, "typeflow responsibility");
-
-  // Check the bytecode matches the field
-  if (is_field == field->is_static())
-    Unimplemented();
+  assert(is_field != field->is_static(), "mismatch");
 
   // Pop the value off the stack where necessary
   SharkValue *value = NULL;
--- a/ports/hotspot/src/share/vm/shark/sharkConstantPool.cpp	Fri Mar 06 09:47:04 2009 -0500
+++ b/ports/hotspot/src/share/vm/shark/sharkConstantPool.cpp	Mon Mar 09 10:26:08 2009 -0400
@@ -87,8 +87,10 @@
   // bizarre hack but it's the same as
   // constantPoolOopDesc::field_or_method_at().
   which = Bytes::swap_u2(which);
+  assert(target()->holder()->is_cache_entry_resolved(which, block()->bc()),
+         "should be");
 
-  Value *entry = builder()->CreateIntToPtr(
+  return builder()->CreateIntToPtr(
     builder()->CreateAdd(
       builder()->CreatePtrToInt(
         cache(), SharkType::intptr_type()),
@@ -96,74 +98,6 @@
         in_bytes(constantPoolCacheOopDesc::base_offset()) +
         which * sizeof(ConstantPoolCacheEntry))),
     SharkType::cpCacheEntry_type());
-
-  // Resolve the entry if necessary
-  if (target()->holder()->is_cache_entry_resolved(which, block()->bc()))
-    return entry;
-
-  int shift;
-  switch (ConstantPoolCacheEntry::bytecode_number(block()->bc())) {
-  case 1:
-    shift = 16;
-    break;
-  case 2:
-    shift = 24;
-    break;
-  default:
-    ShouldNotReachHere();
-  }
-
-  Value *opcode = builder()->CreateAnd(
-    builder()->CreateLShr(
-      builder()->CreateValueOfStructEntry(
-        entry, ConstantPoolCacheEntry::indices_offset(),
-        SharkType::intptr_type()),
-      LLVMValue::intptr_constant(shift)),
-    LLVMValue::intptr_constant(0xff));
-
-  BasicBlock *orig_block = builder()->GetInsertBlock();
-  SharkState *orig_state = block()->current_state()->copy();
-
-  BasicBlock *resolve  = block()->function()->CreateBlock("resolve");
-  BasicBlock *resolved = block()->function()->CreateBlock("resolved");
-
-  builder()->CreateCondBr(
-    builder()->CreateICmpNE(opcode, LLVMValue::intptr_constant(block()->bc())),
-    resolve, resolved);
-
-  builder()->SetInsertPoint(resolve);
-  Constant *resolver;
-  switch (block()->bc()) {
-  case Bytecodes::_invokestatic:
-  case Bytecodes::_invokespecial:
-  case Bytecodes::_invokevirtual:
-  case Bytecodes::_invokeinterface:
-    resolver = SharkRuntime::resolve_invoke();
-    break;
-
-  case Bytecodes::_getfield:
-  case Bytecodes::_getstatic:
-  case Bytecodes::_putfield:
-  case Bytecodes::_putstatic:
-    resolver = SharkRuntime::resolve_get_put();
-    break;
-
-  default:
-    ShouldNotReachHere();
-  }
-
-  block()->call_vm(
-    resolver,
-    entry,
-    LLVMValue::jint_constant(block()->bci()),
-    LLVMValue::jint_constant(block()->bc()));
-  BasicBlock *resolve_block = builder()->GetInsertBlock();  
-  builder()->CreateBr(resolved);
-
-  builder()->SetInsertPoint(resolved);
-  block()->current_state()->merge(orig_state, orig_block, resolve_block);
-
-  return entry;
 }
 
 Value *SharkConstantPool::java_mirror()
--- a/ports/hotspot/src/share/vm/shark/sharkRuntime.cpp	Fri Mar 06 09:47:04 2009 -0500
+++ b/ports/hotspot/src/share/vm/shark/sharkRuntime.cpp	Mon Mar 09 10:26:08 2009 -0400
@@ -36,8 +36,6 @@
 Constant* SharkRuntime::_anewarray;
 Constant* SharkRuntime::_multianewarray;
 Constant* SharkRuntime::_register_finalizer;
-Constant* SharkRuntime::_resolve_get_put;
-Constant* SharkRuntime::_resolve_invoke;
 Constant* SharkRuntime::_resolve_klass;
 Constant* SharkRuntime::_safepoint;
 Constant* SharkRuntime::_throw_ArrayIndexOutOfBoundsException;
@@ -123,20 +121,6 @@
 
   params.clear();
   params.push_back(SharkType::thread_type());
-  params.push_back(SharkType::cpCacheEntry_type());
-  params.push_back(SharkType::jint_type());
-  params.push_back(SharkType::jint_type());
-  _resolve_get_put = builder->make_function(
-    (intptr_t) resolve_get_put_C,
-    FunctionType::get(Type::VoidTy, params, false),
-    "SharkRuntime__resolve_get_put");
-  _resolve_invoke = builder->make_function(
-    (intptr_t) resolve_invoke_C,
-    FunctionType::get(Type::VoidTy, params, false),
-    "SharkRuntime__resolve_invoke");
-
-  params.clear();
-  params.push_back(SharkType::thread_type());
   _safepoint = builder->make_function(
     (intptr_t) SafepointSynchronize::block,
     FunctionType::get(Type::VoidTy, params, false),
@@ -349,138 +333,6 @@
 }
 JRT_END
 
-JRT_ENTRY(void, SharkRuntime::resolve_get_put_C(JavaThread*             thread,
-                                                ConstantPoolCacheEntry* entry,
-                                                int                     bci,
-                                                Bytecodes::Code      bytecode))
-{
-  // Resolve the field
-  FieldAccessInfo info;
-  {
-    constantPoolHandle pool(thread, method(thread)->constants());
-    JvmtiHideSingleStepping jhss(thread);
-    LinkResolver::resolve_field(
-      info, pool, two_byte_index(thread, bci), bytecode, false, CHECK);
-  }
-
-  // Check if link resolution caused the cache to be updated
-  if (entry->is_resolved(bytecode))
-    return;
-  
-  // Compute auxiliary field attributes
-  TosState state = as_TosState(info.field_type());
-
-  // We need to delay resolving put instructions on final fields
-  // until we actually invoke one. This is required so we throw
-  // exceptions at the correct place. If we do not resolve completely
-  // in the current pass, leaving the put_code set to zero will
-  // cause the next put instruction to reresolve.
-  bool is_put =
-    (bytecode == Bytecodes::_putfield || bytecode == Bytecodes::_putstatic);
-  Bytecodes::Code put_code = (Bytecodes::Code) 0;
-
-  // We also need to delay resolving getstatic instructions until the
-  // class is intitialized.  This is required so that access to the
-  // static field will call the initialization function every time
-  // until the class is completely initialized as per 2.17.5 in JVM
-  // Specification.
-  instanceKlass *klass = instanceKlass::cast(info.klass()->as_klassOop());
-  bool is_static =
-    (bytecode == Bytecodes::_getstatic || bytecode == Bytecodes::_putstatic);
-  bool uninitialized_static = (is_static && !klass->is_initialized());
-  Bytecodes::Code get_code = (Bytecodes::Code) 0;
-
-  if (!uninitialized_static) {
-    get_code = ((is_static) ? Bytecodes::_getstatic : Bytecodes::_getfield);
-    if (is_put || !info.access_flags().is_final()) {
-      put_code = ((is_static) ? Bytecodes::_putstatic : Bytecodes::_putfield);
-    }
-  }
-
-  // Update the cache entry
-  entry->set_field(
-    get_code,
-    put_code,
-    info.klass(),
-    info.field_index(),
-    info.field_offset(),
-    state,
-    info.access_flags().is_final(),
-    info.access_flags().is_volatile());
-}
-JRT_END
-
-JRT_ENTRY(void, SharkRuntime::resolve_invoke_C(JavaThread*             thread,
-                                               ConstantPoolCacheEntry* entry,
-                                               int                     bci,
-                                               Bytecodes::Code       bytecode))
-{
-  // Find the receiver
-  Handle receiver(thread, NULL);
-  if (bytecode == Bytecodes::_invokevirtual ||
-      bytecode == Bytecodes::_invokeinterface) {
-    ResourceMark rm(thread);
-    methodHandle mh(thread, method(thread));
-    Bytecode_invoke *call = Bytecode_invoke_at(mh, bci);
-    symbolHandle signature(thread, call->signature());
-    ArgumentSizeComputer asc(signature);
-    receiver = Handle(thread, (oop) tos_at(thread, asc.size()));
-    assert(
-      receiver.is_null() ||
-      (Universe::heap()->is_in_reserved(receiver()) &&
-       Universe::heap()->is_in_reserved(receiver->klass())), "sanity check");
-  }
-
-  // Resolve the method
-  CallInfo info;
-  {
-    constantPoolHandle pool(thread, method(thread)->constants());
-    JvmtiHideSingleStepping jhss(thread);
-    LinkResolver::resolve_invoke(
-      info, receiver, pool, two_byte_index(thread, bci), bytecode, CHECK);
-    if (JvmtiExport::can_hotswap_or_post_breakpoint()) {
-      int retry_count = 0;
-      while (info.resolved_method()->is_old()) {
-        // It is very unlikely that method is redefined more than 100
-        // times in the middle of resolve. If it is looping here more
-        // than 100 times means then there could be a bug here.
-        guarantee((retry_count++ < 100),
-                  "Could not resolve to latest version of redefined method");
-        // method is redefined in the middle of resolve so re-try.
-        LinkResolver::resolve_invoke(
-          info, receiver, pool, two_byte_index(thread, bci), bytecode, CHECK);
-      }
-    }
-  }
-
-  // Check if link resolution caused the cache to be updated
-  if (entry->is_resolved(bytecode))
-    return;
-
-  // Update the cache entry
-  methodHandle rm = info.resolved_method();
-  if (bytecode == Bytecodes::_invokeinterface) {
-    if (rm->method_holder() == SystemDictionary::object_klass()) {
-      // Workaround for the case where we encounter an invokeinterface,
-      // but should really have an invokevirtual since the resolved
-      // method is a virtual method in java.lang.Object. This is a
-      // corner case in the spec but is presumably legal, and while
-      // javac does not generate this code there's no reason it could
-      // not be produced by a compliant java compiler.  See
-      // cpCacheOop.cpp for more details.
-      assert(rm->is_final() || info.has_vtable_index(), "should be set");
-      entry->set_method(bytecode, rm, info.vtable_index()); 
-    }
-    else {
-      entry->set_interface_call(rm, klassItable::compute_itable_index(rm()));
-    }
-  }
-  else {
-    entry->set_method(bytecode, rm, info.vtable_index());
-  }
-}
-JRT_END
-
 JRT_ENTRY(void, SharkRuntime::resolve_klass_C(JavaThread* thread, int index))
 {
   klassOop klass = method(thread)->constants()->klass_at(index, CHECK);
@@ -535,7 +387,7 @@
   return object_klass->klass_part()->is_subtype_of(check_klass);
 }
 
-void SharkRuntime::uncommon_trap_C(JavaThread* thread, int index)
+void SharkRuntime::uncommon_trap_C(JavaThread* thread, int trap_request)
 {
   // In C2, uncommon_trap_blob creates a frame, so all the various
   // deoptimization functions expect to find the frame of the method
@@ -547,7 +399,7 @@
   // Initiate the trap
   thread->set_last_Java_frame();
   Deoptimization::UnrollBlock *urb =
-    Deoptimization::uncommon_trap(thread, index);
+    Deoptimization::uncommon_trap(thread, trap_request);
   thread->reset_last_Java_frame();
 
   // Pop our dummy frame and the frame being deoptimized
--- a/ports/hotspot/src/share/vm/shark/sharkRuntime.hpp	Fri Mar 06 09:47:04 2009 -0500
+++ b/ports/hotspot/src/share/vm/shark/sharkRuntime.hpp	Mon Mar 09 10:26:08 2009 -0400
@@ -37,8 +37,6 @@
   static llvm::Constant* _anewarray;
   static llvm::Constant* _multianewarray;
   static llvm::Constant* _register_finalizer;
-  static llvm::Constant* _resolve_get_put;
-  static llvm::Constant* _resolve_invoke;
   static llvm::Constant* _resolve_klass;
   static llvm::Constant* _safepoint;
   static llvm::Constant* _throw_ArrayIndexOutOfBoundsException;
@@ -77,14 +75,6 @@
   {
     return _register_finalizer;
   }
-  static llvm::Constant* resolve_get_put()
-  {
-    return _resolve_get_put;
-  }
-  static llvm::Constant* resolve_invoke()
-  {
-    return _resolve_invoke;
-  }
   static llvm::Constant* resolve_klass()
   {
     return _resolve_klass;
@@ -120,14 +110,6 @@
 
   static void register_finalizer_C(JavaThread* thread, oop object);
 
-  static void resolve_get_put_C(JavaThread*             thread,
-                                ConstantPoolCacheEntry* entry,
-                                int                     bci,
-                                Bytecodes::Code         bytecode);
-  static void resolve_invoke_C(JavaThread*             thread,
-                               ConstantPoolCacheEntry* entry,
-                               int                     bci,
-                               Bytecodes::Code         bytecode);
   static void resolve_klass_C(JavaThread* thread, int index);
   static void throw_ArrayIndexOutOfBoundsException_C(JavaThread* thread,
                                                      const char* file,
@@ -218,5 +200,5 @@
  private:
   static void dump_C(const char *name, intptr_t value);
   static bool is_subtype_of_C(klassOop check_klass, klassOop object_klass); 
-  static void uncommon_trap_C(JavaThread* thread, int index);
+  static void uncommon_trap_C(JavaThread* thread, int trap_request);
 };
--- a/ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.cpp	Fri Mar 06 09:47:04 2009 -0500
+++ b/ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.cpp	Mon Mar 09 10:26:08 2009 -0400
@@ -143,6 +143,99 @@
   }
 };
 
+int SharkTopLevelBlock::scan_for_traps()
+{
+  // If typeflow got one then we're already done
+  if (ciblock()->has_trap()) {
+    return Deoptimization::make_trap_request(
+      Deoptimization::Reason_unloaded,
+      Deoptimization::Action_reinterpret,
+      ciblock()->trap_index());
+  }
+
+  // Scan the bytecode
+  iter()->reset_to_bci(start());
+  while (iter()->next_bci() < limit()) {
+    iter()->next();
+
+    ciField *field;
+    ciMethod *method;
+    bool will_link;
+    bool is_field;
+
+    int index = -1;
+
+    switch (bc()) {
+    case Bytecodes::_getfield:
+    case Bytecodes::_getstatic:
+    case Bytecodes::_putfield:
+    case Bytecodes::_putstatic:
+      field = iter()->get_field(will_link);
+      assert(will_link, "typeflow responsibility");
+      is_field = (bc() == Bytecodes::_getfield || bc() == Bytecodes::_putfield);
+
+      // If the bytecode does not match the field then bail out to
+      // the interpreter to throw an IncompatibleClassChangeError
+      if (is_field == field->is_static()) {
+        return Deoptimization::make_trap_request(
+                 Deoptimization::Reason_unhandled,
+                 Deoptimization::Action_none);
+      }
+
+      // If this is a getfield or putfield then there won't be a
+      // pool access and we're done
+      if (is_field)
+        break;
+
+      // There won't be a pool access if this is a getstatic that
+      // resolves to a handled constant either
+      if (bc() == Bytecodes::_getstatic && field->is_constant()) {
+        if (SharkValue::from_ciConstant(field->constant_value()))
+          break;
+      }
+
+      // Continue to the check
+      index = iter()->get_field_index();
+      break;
+
+    case Bytecodes::_invokespecial:
+    case Bytecodes::_invokestatic:
+    case Bytecodes::_invokevirtual:
+    case Bytecodes::_invokeinterface:
+      method = iter()->get_method(will_link);
+      assert(will_link, "typeflow responsibility");
+
+      // If this is a non-final invokevirtual then there won't
+      // be a pool access.  We do need to check that its holder
+      // is linked, however, because its vtable won't have been
+      // set up otherwise.
+      if (bc() == Bytecodes::_invokevirtual && !method->is_final_method()) {
+        if (!method->holder()->is_linked()) {
+          return Deoptimization::make_trap_request(
+            Deoptimization::Reason_uninitialized,
+            Deoptimization::Action_reinterpret);
+        }
+        break;
+      }
+
+      // Continue to the check
+      index = iter()->get_method_index();
+      break;
+    }
+
+    // If we found a constant pool access on this bytecode then check it
+    if (index != -1) {
+      if (!target()->holder()->is_cache_entry_resolved(
+             Bytes::swap_u2(index), bc())) {
+        return Deoptimization::make_trap_request(
+          Deoptimization::Reason_uninitialized,
+          Deoptimization::Action_reinterpret);
+      }
+    }
+  }
+  return TRAP_NO_TRAPS;
+}
+
 SharkState* SharkTopLevelBlock::entry_state()
 {
   if (_entry_state == NULL) {
@@ -243,7 +336,7 @@
     builder()->CreateCall2(
       SharkRuntime::uncommon_trap(),
       thread(),
-      LLVMValue::jint_constant(trap_index()));
+      LLVMValue::jint_constant(trap_request()));
     builder()->CreateRetVoid();
     return;
   }
@@ -860,8 +953,8 @@
 }
 
 Value *SharkTopLevelBlock::get_callee(CallType    call_type,
-                              ciMethod*   method,
-                              SharkValue* receiver)
+                                      ciMethod*   method,
+                                      SharkValue* receiver)
 {
   switch (call_type) {
   case CALL_DIRECT:
@@ -901,34 +994,19 @@
     SharkType::jobject_type(),
     "klass");
 
-  Value *index;
-  if (!method->holder()->is_linked()) {
-    // Yuck, we have to do this one slow :(
-    // XXX should we trap on this?
-    NOT_PRODUCT(warning("unresolved invokevirtual in %s", function()->name()));
-    SharkConstantPool constants(this);
-    Value *cache = constants.cache_entry_at(iter()->get_method_index());
-    index = builder()->CreateValueOfStructEntry(
-      cache, ConstantPoolCacheEntry::f2_offset(),
-      SharkType::intptr_type(),
-      "index");
-  }
-  else {
-    index = LLVMValue::intptr_constant(method->vtable_index());
-  }
-
   return builder()->CreateLoad(
     builder()->CreateArrayAddress(
       klass,
       SharkType::methodOop_type(),
       vtableEntry::size() * wordSize,
       in_ByteSize(instanceKlass::vtable_start_offset() * wordSize),
-      index),
+      LLVMValue::intptr_constant(method->vtable_index())),
     "callee");
 }
 
 // Interpreter-style virtual call lookup
-Value* SharkTopLevelBlock::get_virtual_callee(Value *cache, SharkValue *receiver)
+Value* SharkTopLevelBlock::get_virtual_callee(Value *cache,
+                                              SharkValue *receiver)
 {
   BasicBlock *final      = function()->CreateBlock("final");
   BasicBlock *not_final  = function()->CreateBlock("not_final");
--- a/ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.hpp	Fri Mar 06 09:47:04 2009 -0500
+++ b/ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.hpp	Mon Mar 09 10:26:08 2009 -0400
@@ -29,6 +29,7 @@
     : SharkBlock(function->builder(), function->target(), function->iter()),
       _function(function),
       _ciblock(ciblock),
+      _trap_request(TRAP_UNCHECKED),
       _entered(false),
       _needs_phis(false),
       _entry_state(NULL),
@@ -60,14 +61,6 @@
   {
     return ciblock()->pre_order();
   }
-  bool has_trap() const
-  {
-    return ciblock()->has_trap();
-  }
-  int trap_index() const
-  {
-    return ciblock()->trap_index();
-  }
   bool is_private_copy() const
   {
     return ciblock()->is_backedge_copy();
@@ -114,6 +107,29 @@
   }
   SharkTopLevelBlock* bci_successor(int bci) const;
 
+  // Traps
+ private:
+  enum {
+    TRAP_UNCHECKED = 232323, // > any constant pool index
+    TRAP_NO_TRAPS
+  };
+  int _trap_request;
+
+ public:
+  int trap_request()
+  {
+    if (_trap_request == TRAP_UNCHECKED)
+      _trap_request = scan_for_traps();
+    return _trap_request;
+  }
+  bool has_trap()
+  {
+    return trap_request() != TRAP_NO_TRAPS;
+  }
+
+ private:
+  int scan_for_traps();
+
   // Entry state
  private:
   bool _entered;