# HG changeset patch # User Gary Benson # Date 1236608768 14400 # Node ID 146e5d33e990ca5aee7fa3c2515c9f09e1b1ef1d # Parent f7efa3c95c17edff5411f8b1ed5e155d621b8fe4 2009-03-09 Gary Benson * 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) diff -r f7efa3c95c17 -r 146e5d33e990 ChangeLog --- 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 + + * 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 * ports/hotspot/src/share/vm/shark/sharkBuilder.hpp diff -r f7efa3c95c17 -r 146e5d33e990 ports/hotspot/src/share/vm/includeDB_shark --- 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 diff -r f7efa3c95c17 -r 146e5d33e990 ports/hotspot/src/share/vm/shark/sharkBlock.cpp --- 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; diff -r f7efa3c95c17 -r 146e5d33e990 ports/hotspot/src/share/vm/shark/sharkConstantPool.cpp --- 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() diff -r f7efa3c95c17 -r 146e5d33e990 ports/hotspot/src/share/vm/shark/sharkRuntime.cpp --- 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 diff -r f7efa3c95c17 -r 146e5d33e990 ports/hotspot/src/share/vm/shark/sharkRuntime.hpp --- 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); }; diff -r f7efa3c95c17 -r 146e5d33e990 ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.cpp --- 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"); diff -r f7efa3c95c17 -r 146e5d33e990 ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.hpp --- 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;