void Rewriter::rewrite_invokedynamic(address bcp, int offset, bool reverse) { address p = bcp + offset; assert(p[-1] == Bytecodes::_invokedynamic, "not invokedynamic bytecode"); if (!reverse) { int cp_index = Bytes::get_Java_u2(p); int cpc = maybe_add_cp_cache_entry(cp_index); // add lazily int cpc2 = add_secondary_cp_cache_entry(cpc); // The second secondary entry is required to store the MethodType and // must be the next entry. int cpc3 = add_secondary_cp_cache_entry(cpc); assert(cpc2 + 1 == cpc3, err_msg_res("must be consecutive: %d + 1 == %d", cpc2, cpc3)); // Replace the trailing four bytes with a CPC index for the dynamic // call site. Unlike other CPC entries, there is one per bytecode, // not just one per distinct CP entry. In other words, the // CPC-to-CP relation is many-to-one for invokedynamic entries. // This means we must use a larger index size than u2 to address // all these entries. That is the main reason invokedynamic // must have a five-byte instruction format. (Of course, other JVM // implementations can use the bytes for other purposes.) Bytes::put_native_u4(p, constantPoolCacheOopDesc::encode_secondary_index(cpc2)); // Note: We use native_u4 format exclusively for 4-byte indexes. } else { int cache_index = constantPoolCacheOopDesc::decode_secondary_index( Bytes::get_native_u4(p)); int secondary_index = cp_cache_secondary_entry_main_index(cache_index); int pool_index = cp_cache_entry_pool_index(secondary_index); assert(_pool->tag_at(pool_index).is_invoke_dynamic(), "wrong index"); // zero out 4 bytes Bytes::put_Java_u4(p, 0); Bytes::put_Java_u2(p, pool_index); } }
void Rewriter::rewrite_invokedynamic(address bcp, int offset, int delete_me) { address p = bcp + offset; assert(p[-1] == Bytecodes::_invokedynamic, ""); int cp_index = Bytes::get_Java_u2(p); int cpc = maybe_add_cp_cache_entry(cp_index); // add lazily int cpc2 = add_secondary_cp_cache_entry(cpc); // Replace the trailing four bytes with a CPC index for the dynamic // call site. Unlike other CPC entries, there is one per bytecode, // not just one per distinct CP entry. In other words, the // CPC-to-CP relation is many-to-one for invokedynamic entries. // This means we must use a larger index size than u2 to address // all these entries. That is the main reason invokedynamic // must have a five-byte instruction format. (Of course, other JVM // implementations can use the bytes for other purposes.) Bytes::put_native_u4(p, constantPoolCacheOopDesc::encode_secondary_index(cpc2)); // Note: We use native_u4 format exclusively for 4-byte indexes. }
// Adjust the invocation bytecode for a signature-polymorphic method (MethodHandle.invoke, etc.) void Rewriter::maybe_rewrite_invokehandle(address opc, int cp_index, bool reverse) { if (!reverse) { if ((*opc) == (u1)Bytecodes::_invokevirtual || // allow invokespecial as an alias, although it would be very odd: (*opc) == (u1)Bytecodes::_invokespecial) { assert(_pool->tag_at(cp_index).is_method(), "wrong index"); // Determine whether this is a signature-polymorphic method. if (cp_index >= _method_handle_invokers.length()) return; int status = _method_handle_invokers[cp_index]; assert(status >= -1 && status <= 1, "oob tri-state"); if (status == 0) { if (_pool->klass_ref_at_noresolve(cp_index) == vmSymbols::java_lang_invoke_MethodHandle() && MethodHandles::is_signature_polymorphic_name(SystemDictionary::MethodHandle_klass(), _pool->name_ref_at(cp_index))) { assert(has_cp_cache(cp_index), "should already have an entry"); int cpc = maybe_add_cp_cache_entry(cp_index); // should already have an entry int cpc2 = add_secondary_cp_cache_entry(cpc); status = +1; } else { status = -1; } _method_handle_invokers[cp_index] = status; } // We use a special internal bytecode for such methods (if non-static). // The basic reason for this is that such methods need an extra "appendix" argument // to transmit the call site's intended call type. if (status > 0) { (*opc) = (u1)Bytecodes::_invokehandle; } } } else { // Do not need to look at cp_index. if ((*opc) == (u1)Bytecodes::_invokehandle) { (*opc) = (u1)Bytecodes::_invokevirtual; // Ignore corner case of original _invokespecial instruction. // This is safe because (a) the signature polymorphic method was final, and // (b) the implementation of MethodHandle will not call invokespecial on it. } } }