7056328: JSR 292 invocation sometimes fails in adapters for types not on boot class path
Reviewed-by: never
--- a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp Thu Jun 23 17:14:06 2011 -0700
@@ -266,7 +266,7 @@
void TemplateTable::ldc(bool wide) {
transition(vtos, vtos);
- Label call_ldc, notInt, notString, notClass, exit;
+ Label call_ldc, notInt, isString, notString, notClass, exit;
if (wide) {
__ get_2_byte_integer_at_bcp(1, G3_scratch, O1, InterpreterMacroAssembler::Unsigned);
@@ -317,8 +317,11 @@
__ bind(notInt);
// __ cmp(O2, JVM_CONSTANT_String);
+ __ brx(Assembler::equal, true, Assembler::pt, isString);
+ __ delayed()->cmp(O2, JVM_CONSTANT_Object);
__ brx(Assembler::notEqual, true, Assembler::pt, notString);
__ delayed()->ldf(FloatRegisterImpl::S, O0, O1, Ftos_f);
+ __ bind(isString);
__ ld_ptr(O0, O1, Otos_i);
__ verify_oop(Otos_i);
__ push(atos);
--- a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp Thu Jun 23 17:14:06 2011 -0700
@@ -373,15 +373,17 @@
__ jcc(Assembler::equal, L);
__ cmpl(rdx, JVM_CONSTANT_String);
__ jcc(Assembler::equal, L);
+ __ cmpl(rdx, JVM_CONSTANT_Object);
+ __ jcc(Assembler::equal, L);
__ stop("unexpected tag type in ldc");
__ bind(L);
}
#endif
Label isOop;
// atos and itos
- // String is only oop type we will see here
- __ cmpl(rdx, JVM_CONSTANT_String);
- __ jccb(Assembler::equal, isOop);
+ // Integer is only non-oop type we will see here
+ __ cmpl(rdx, JVM_CONSTANT_Integer);
+ __ jccb(Assembler::notEqual, isOop);
__ movl(rax, Address(rcx, rbx, Address::times_ptr, base_offset));
__ push(itos);
__ jmp(Done);
--- a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp Thu Jun 23 17:14:06 2011 -0700
@@ -385,6 +385,8 @@
__ jcc(Assembler::equal, L);
__ cmpl(rdx, JVM_CONSTANT_String);
__ jcc(Assembler::equal, L);
+ __ cmpl(rdx, JVM_CONSTANT_Object);
+ __ jcc(Assembler::equal, L);
__ stop("unexpected tag type in ldc");
__ bind(L);
}
--- a/hotspot/src/share/vm/ci/ciEnv.cpp Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/ci/ciEnv.cpp Thu Jun 23 17:14:06 2011 -0700
@@ -50,6 +50,7 @@
#include "oops/oop.inline.hpp"
#include "oops/oop.inline2.hpp"
#include "prims/jvmtiExport.hpp"
+#include "prims/methodHandleWalk.hpp"
#include "runtime/init.hpp"
#include "runtime/reflection.hpp"
#include "runtime/sharedRuntime.hpp"
@@ -371,6 +372,7 @@
// ------------------------------------------------------------------
// ciEnv::get_klass_by_name_impl
ciKlass* ciEnv::get_klass_by_name_impl(ciKlass* accessing_klass,
+ constantPoolHandle cpool,
ciSymbol* name,
bool require_local) {
ASSERT_IN_VM;
@@ -386,7 +388,7 @@
sym->utf8_length()-2,
KILL_COMPILE_ON_FATAL_(_unloaded_ciinstance_klass));
ciSymbol* strippedname = get_symbol(strippedsym);
- return get_klass_by_name_impl(accessing_klass, strippedname, require_local);
+ return get_klass_by_name_impl(accessing_klass, cpool, strippedname, require_local);
}
// Check for prior unloaded klass. The SystemDictionary's answers
@@ -443,6 +445,7 @@
// Get element ciKlass recursively.
ciKlass* elem_klass =
get_klass_by_name_impl(accessing_klass,
+ cpool,
get_symbol(elem_sym),
require_local);
if (elem_klass != NULL && elem_klass->is_loaded()) {
@@ -451,6 +454,19 @@
}
}
+ if (found_klass() == NULL && !cpool.is_null() && cpool->has_preresolution()) {
+ // Look inside the constant pool for pre-resolved class entries.
+ for (int i = cpool->length() - 1; i >= 1; i--) {
+ if (cpool->tag_at(i).is_klass()) {
+ klassOop kls = cpool->resolved_klass_at(i);
+ if (Klass::cast(kls)->name() == sym) {
+ found_klass = KlassHandle(THREAD, kls);
+ break;
+ }
+ }
+ }
+ }
+
if (found_klass() != NULL) {
// Found it. Build a CI handle.
return get_object(found_klass())->as_klass();
@@ -468,6 +484,7 @@
ciSymbol* klass_name,
bool require_local) {
GUARDED_VM_ENTRY(return get_klass_by_name_impl(accessing_klass,
+ constantPoolHandle(),
klass_name,
require_local);)
}
@@ -508,13 +525,14 @@
if (klass.is_null()) {
// Not found in constant pool. Use the name to do the lookup.
ciKlass* k = get_klass_by_name_impl(accessor,
+ cpool,
get_symbol(klass_name),
false);
// Calculate accessibility the hard way.
if (!k->is_loaded()) {
is_accessible = false;
} else if (k->loader() != accessor->loader() &&
- get_klass_by_name_impl(accessor, k->name(), true) == NULL) {
+ get_klass_by_name_impl(accessor, cpool, k->name(), true) == NULL) {
// Loaded only remotely. Not linked yet.
is_accessible = false;
} else {
@@ -565,7 +583,7 @@
index = cpc_entry->constant_pool_index();
oop obj = cpc_entry->f1();
if (obj != NULL) {
- assert(obj->is_instance(), "must be an instance");
+ assert(obj->is_instance() || obj->is_array(), "must be a Java reference");
ciObject* ciobj = get_object(obj);
return ciConstant(T_OBJECT, ciobj);
}
@@ -607,7 +625,7 @@
return ciConstant(T_OBJECT, klass->java_mirror());
} else if (tag.is_object()) {
oop obj = cpool->object_at(index);
- assert(obj->is_instance(), "must be an instance");
+ assert(obj->is_instance() || obj->is_array(), "must be a Java reference");
ciObject* ciobj = get_object(obj);
return ciConstant(T_OBJECT, ciobj);
} else if (tag.is_method_type()) {
@@ -729,9 +747,35 @@
Symbol* name_sym = cpool->name_ref_at(index);
Symbol* sig_sym = cpool->signature_ref_at(index);
+ if (cpool->has_preresolution()
+ || (holder == ciEnv::MethodHandle_klass() &&
+ methodOopDesc::is_method_handle_invoke_name(name_sym))) {
+ // Short-circuit lookups for JSR 292-related call sites.
+ // That is, do not rely only on name-based lookups, because they may fail
+ // if the names are not resolvable in the boot class loader (7056328).
+ switch (bc) {
+ case Bytecodes::_invokevirtual:
+ case Bytecodes::_invokeinterface:
+ case Bytecodes::_invokespecial:
+ case Bytecodes::_invokestatic:
+ {
+ methodOop m = constantPoolOopDesc::method_at_if_loaded(cpool, index, bc);
+ if (m != NULL) {
+ return get_object(m)->as_method();
+ }
+ }
+ }
+ }
+
if (holder_is_accessible) { // Our declared holder is loaded.
instanceKlass* lookup = declared_holder->get_instanceKlass();
methodOop m = lookup_method(accessor->get_instanceKlass(), lookup, name_sym, sig_sym, bc);
+ if (m != NULL &&
+ (bc == Bytecodes::_invokestatic
+ ? instanceKlass::cast(m->method_holder())->is_not_initialized()
+ : !instanceKlass::cast(m->method_holder())->is_loaded())) {
+ m = NULL;
+ }
if (m != NULL) {
// We found the method.
return get_object(m)->as_method();
@@ -1046,7 +1090,7 @@
// ciEnv::find_system_klass
ciKlass* ciEnv::find_system_klass(ciSymbol* klass_name) {
VM_ENTRY_MARK;
- return get_klass_by_name_impl(NULL, klass_name, false);
+ return get_klass_by_name_impl(NULL, constantPoolHandle(), klass_name, false);
}
// ------------------------------------------------------------------
--- a/hotspot/src/share/vm/ci/ciEnv.hpp Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/ci/ciEnv.hpp Thu Jun 23 17:14:06 2011 -0700
@@ -137,6 +137,7 @@
// Implementation methods for loading and constant pool access.
ciKlass* get_klass_by_name_impl(ciKlass* accessing_klass,
+ constantPoolHandle cpool,
ciSymbol* klass_name,
bool require_local);
ciKlass* get_klass_by_index_impl(constantPoolHandle cpool,
--- a/hotspot/src/share/vm/ci/ciField.cpp Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/ci/ciField.cpp Thu Jun 23 17:14:06 2011 -0700
@@ -287,7 +287,7 @@
}
ciType* ciField::compute_type_impl() {
- ciKlass* type = CURRENT_ENV->get_klass_by_name_impl(_holder, _signature, false);
+ ciKlass* type = CURRENT_ENV->get_klass_by_name_impl(_holder, constantPoolHandle(), _signature, false);
if (!type->is_primitive_type() && is_shared()) {
// We must not cache a pointer to an unshared type, in a shared field.
bool type_is_also_shared = false;
--- a/hotspot/src/share/vm/ci/ciMethod.cpp Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/ci/ciMethod.cpp Thu Jun 23 17:14:06 2011 -0700
@@ -125,7 +125,8 @@
_name = env->get_symbol(h_m()->name());
_holder = env->get_object(h_m()->method_holder())->as_instance_klass();
ciSymbol* sig_symbol = env->get_symbol(h_m()->signature());
- _signature = new (env->arena()) ciSignature(_holder, sig_symbol);
+ constantPoolHandle cpool = h_m()->constants();
+ _signature = new (env->arena()) ciSignature(_holder, cpool, sig_symbol);
_method_data = NULL;
// Take a snapshot of these values, so they will be commensurate with the MDO.
if (ProfileInterpreter || TieredCompilation) {
@@ -152,7 +153,7 @@
// These fields are always filled in.
_name = name;
_holder = holder;
- _signature = new (CURRENT_ENV->arena()) ciSignature(_holder, signature);
+ _signature = new (CURRENT_ENV->arena()) ciSignature(_holder, constantPoolHandle(), signature);
_intrinsic_id = vmIntrinsics::_none;
_liveness = NULL;
_can_be_statically_bound = false;
--- a/hotspot/src/share/vm/ci/ciMethodHandle.cpp Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/ci/ciMethodHandle.cpp Thu Jun 23 17:14:06 2011 -0700
@@ -41,6 +41,16 @@
VM_ENTRY_MARK;
Handle h(get_oop());
methodHandle callee(_callee->get_methodOop());
+ assert(callee->is_method_handle_invoke(), "");
+ oop mt1 = callee->method_handle_type();
+ oop mt2 = java_lang_invoke_MethodHandle::type(h());
+ if (!java_lang_invoke_MethodType::equals(mt1, mt2)) {
+ if (PrintMiscellaneous && (Verbose || WizardMode)) {
+ tty->print_cr("ciMethodHandle::get_adapter: types not equal");
+ mt1->print(); mt2->print();
+ }
+ return NULL;
+ }
// We catch all exceptions here that could happen in the method
// handle compiler and stop the VM.
MethodHandleCompiler mhc(h, callee->name(), callee->signature(), _profile.count(), is_invokedynamic, THREAD);
@@ -53,7 +63,7 @@
if (PrintMiscellaneous && (Verbose || WizardMode)) {
tty->print("*** ciMethodHandle::get_adapter => ");
PENDING_EXCEPTION->print();
- tty->print("*** get_adapter (%s): ", is_invokedynamic ? "indy" : "mh"); ((ciObject*)this)->print(); //@@
+ tty->print("*** get_adapter (%s): ", is_invokedynamic ? "indy" : "mh"); ((ciObject*)this)->print();
}
CLEAR_PENDING_EXCEPTION;
return NULL;
--- a/hotspot/src/share/vm/ci/ciObjArrayKlass.cpp Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/ci/ciObjArrayKlass.cpp Thu Jun 23 17:14:06 2011 -0700
@@ -93,6 +93,7 @@
// element klass by name.
_element_klass = CURRENT_THREAD_ENV->get_klass_by_name_impl(
this,
+ constantPoolHandle(),
construct_array_name(base_element_klass()->name(),
dimension() - 1),
false);
--- a/hotspot/src/share/vm/ci/ciSignature.cpp Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/ci/ciSignature.cpp Thu Jun 23 17:14:06 2011 -0700
@@ -35,7 +35,7 @@
// ------------------------------------------------------------------
// ciSignature::ciSignature
-ciSignature::ciSignature(ciKlass* accessing_klass, ciSymbol* symbol) {
+ciSignature::ciSignature(ciKlass* accessing_klass, constantPoolHandle cpool, ciSymbol* symbol) {
ASSERT_IN_VM;
EXCEPTION_CONTEXT;
_accessing_klass = accessing_klass;
@@ -64,7 +64,7 @@
CLEAR_PENDING_EXCEPTION;
} else {
ciSymbol* klass_name = env->get_symbol(name);
- type = env->get_klass_by_name_impl(_accessing_klass, klass_name, false);
+ type = env->get_klass_by_name_impl(_accessing_klass, cpool, klass_name, false);
}
}
_types->append(type);
--- a/hotspot/src/share/vm/ci/ciSignature.hpp Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/ci/ciSignature.hpp Thu Jun 23 17:14:06 2011 -0700
@@ -44,7 +44,7 @@
friend class ciMethod;
- ciSignature(ciKlass* accessing_klass, ciSymbol* signature);
+ ciSignature(ciKlass* accessing_klass, constantPoolHandle cpool, ciSymbol* signature);
void get_all_klasses();
--- a/hotspot/src/share/vm/classfile/javaClasses.cpp Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/classfile/javaClasses.cpp Thu Jun 23 17:14:06 2011 -0700
@@ -2574,6 +2574,18 @@
return name;
}
+bool java_lang_invoke_MethodType::equals(oop mt1, oop mt2) {
+ if (rtype(mt1) != rtype(mt2))
+ return false;
+ if (ptype_count(mt1) != ptype_count(mt2))
+ return false;
+ for (int i = ptype_count(mt1) - 1; i >= 0; i--) {
+ if (ptype(mt1, i) != ptype(mt2, i))
+ return false;
+ }
+ return true;
+}
+
oop java_lang_invoke_MethodType::rtype(oop mt) {
assert(is_instance(mt), "must be a MethodType");
return mt->obj_field(_rtype_offset);
--- a/hotspot/src/share/vm/classfile/javaClasses.hpp Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/classfile/javaClasses.hpp Thu Jun 23 17:14:06 2011 -0700
@@ -1079,6 +1079,8 @@
return obj != NULL && obj->klass() == SystemDictionary::MethodType_klass();
}
+ static bool equals(oop mt1, oop mt2);
+
// Accessors for code generation:
static int rtype_offset_in_bytes() { return _rtype_offset; }
static int ptypes_offset_in_bytes() { return _ptypes_offset; }
--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp Thu Jun 23 17:14:06 2011 -0700
@@ -2367,6 +2367,8 @@
// Link m to his method type, if it is suitably generic.
oop mtform = java_lang_invoke_MethodType::form(mt());
if (mtform != NULL && mt() == java_lang_invoke_MethodTypeForm::erasedType(mtform)
+ // vmlayout must be an invokeExact:
+ && name_id == vmSymbols::VM_SYMBOL_ENUM_NAME(invokeExact_name)
&& java_lang_invoke_MethodTypeForm::vmlayout_offset_in_bytes() > 0) {
java_lang_invoke_MethodTypeForm::init_vmlayout(mtform, m());
}
--- a/hotspot/src/share/vm/interpreter/linkResolver.cpp Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp Thu Jun 23 17:14:06 2011 -0700
@@ -294,6 +294,16 @@
Symbol* method_signature = pool->signature_ref_at(index);
KlassHandle current_klass(THREAD, pool->pool_holder());
+ if (pool->has_preresolution()
+ || (resolved_klass() == SystemDictionary::MethodHandle_klass() &&
+ methodOopDesc::is_method_handle_invoke_name(method_name))) {
+ methodOop result_oop = constantPoolOopDesc::method_at_if_loaded(pool, index);
+ if (result_oop != NULL) {
+ resolved_method = methodHandle(THREAD, result_oop);
+ return;
+ }
+ }
+
resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, CHECK);
}
--- a/hotspot/src/share/vm/oops/constantPoolKlass.cpp Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/oops/constantPoolKlass.cpp Thu Jun 23 17:14:06 2011 -0700
@@ -310,10 +310,14 @@
st->print(" - flags: 0x%x", cp->flags());
if (cp->has_pseudo_string()) st->print(" has_pseudo_string");
if (cp->has_invokedynamic()) st->print(" has_invokedynamic");
+ if (cp->has_preresolution()) st->print(" has_preresolution");
st->cr();
}
+ if (cp->pool_holder() != NULL) {
+ bool extra = (instanceKlass::cast(cp->pool_holder())->constants() != cp);
+ st->print_cr(" - holder: " INTPTR_FORMAT "%s", cp->pool_holder(), (extra? " (extra)" : ""));
+ }
st->print_cr(" - cache: " INTPTR_FORMAT, cp->cache());
-
for (int index = 1; index < cp->length(); index++) { // Index 0 is unused
st->print(" - %3d : ", index);
cp->tag_at(index).print_on(st);
@@ -414,10 +418,15 @@
st->print("constant pool [%d]", cp->length());
if (cp->has_pseudo_string()) st->print("/pseudo_string");
if (cp->has_invokedynamic()) st->print("/invokedynamic");
+ if (cp->has_preresolution()) st->print("/preresolution");
if (cp->operands() != NULL) st->print("/operands[%d]", cp->operands()->length());
cp->print_address_on(st);
st->print(" for ");
cp->pool_holder()->print_value_on(st);
+ if (cp->pool_holder() != NULL) {
+ bool extra = (instanceKlass::cast(cp->pool_holder())->constants() != cp);
+ if (extra) st->print(" (extra)");
+ }
if (cp->cache() != NULL) {
st->print(" cache=" PTR_FORMAT, cp->cache());
}
--- a/hotspot/src/share/vm/oops/constantPoolOop.cpp Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/oops/constantPoolOop.cpp Thu Jun 23 17:14:06 2011 -0700
@@ -266,6 +266,29 @@
}
+methodOop constantPoolOopDesc::method_at_if_loaded(constantPoolHandle cpool,
+ int which, Bytecodes::Code invoke_code) {
+ assert(!constantPoolCacheOopDesc::is_secondary_index(which), "no indy instruction here");
+ if (cpool->cache() == NULL) return false; // nothing to load yet
+ int cache_index = which - CPCACHE_INDEX_TAG;
+ if (!(cache_index >= 0 && cache_index < cpool->cache()->length())) {
+ if (PrintMiscellaneous && (Verbose||WizardMode)) {
+ tty->print_cr("bad operand %d for %d in:", which, invoke_code); cpool->print();
+ }
+ return NULL;
+ }
+ ConstantPoolCacheEntry* e = cpool->cache()->entry_at(cache_index);
+ if (invoke_code != Bytecodes::_illegal)
+ return e->get_method_if_resolved(invoke_code, cpool);
+ Bytecodes::Code bc;
+ if ((bc = e->bytecode_1()) != (Bytecodes::Code)0)
+ return e->get_method_if_resolved(bc, cpool);
+ if ((bc = e->bytecode_2()) != (Bytecodes::Code)0)
+ return e->get_method_if_resolved(bc, cpool);
+ return NULL;
+}
+
+
Symbol* constantPoolOopDesc::impl_name_ref_at(int which, bool uncached) {
int name_index = name_ref_index_at(impl_name_and_type_ref_index_at(which, uncached));
return symbol_at(name_index);
--- a/hotspot/src/share/vm/oops/constantPoolOop.hpp Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/oops/constantPoolOop.hpp Thu Jun 23 17:14:06 2011 -0700
@@ -103,7 +103,8 @@
enum FlagBit {
FB_has_invokedynamic = 1,
- FB_has_pseudo_string = 2
+ FB_has_pseudo_string = 2,
+ FB_has_preresolution = 3
};
int flags() const { return _flags; }
@@ -179,8 +180,10 @@
bool has_pseudo_string() const { return flag_at(FB_has_pseudo_string); }
bool has_invokedynamic() const { return flag_at(FB_has_invokedynamic); }
+ bool has_preresolution() const { return flag_at(FB_has_preresolution); }
void set_pseudo_string() { set_flag_at(FB_has_pseudo_string); }
void set_invokedynamic() { set_flag_at(FB_has_invokedynamic); }
+ void set_preresolution() { set_flag_at(FB_has_preresolution); }
// Klass holding pool
klassOop pool_holder() const { return _pool_holder; }
@@ -663,6 +666,8 @@
friend class SystemDictionary;
// Used by compiler to prevent classloading.
+ static methodOop method_at_if_loaded (constantPoolHandle this_oop, int which,
+ Bytecodes::Code bc = Bytecodes::_illegal);
static klassOop klass_at_if_loaded (constantPoolHandle this_oop, int which);
static klassOop klass_ref_at_if_loaded (constantPoolHandle this_oop, int which);
// Same as above - but does LinkResolving.
--- a/hotspot/src/share/vm/oops/cpCacheOop.cpp Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/oops/cpCacheOop.cpp Thu Jun 23 17:14:06 2011 -0700
@@ -295,6 +295,50 @@
}
+methodOop ConstantPoolCacheEntry::get_method_if_resolved(Bytecodes::Code invoke_code, constantPoolHandle cpool) {
+ assert(invoke_code > (Bytecodes::Code)0, "bad query");
+ if (is_secondary_entry()) {
+ return cpool->cache()->entry_at(main_entry_index())->get_method_if_resolved(invoke_code, cpool);
+ }
+ // Decode the action of set_method and set_interface_call
+ if (bytecode_1() == invoke_code) {
+ oop f1 = _f1;
+ if (f1 != NULL) {
+ switch (invoke_code) {
+ case Bytecodes::_invokeinterface:
+ assert(f1->is_klass(), "");
+ return klassItable::method_for_itable_index(klassOop(f1), (int) f2());
+ case Bytecodes::_invokestatic:
+ case Bytecodes::_invokespecial:
+ assert(f1->is_method(), "");
+ return methodOop(f1);
+ }
+ }
+ }
+ if (bytecode_2() == invoke_code) {
+ switch (invoke_code) {
+ case Bytecodes::_invokevirtual:
+ if (is_vfinal()) {
+ // invokevirtual
+ methodOop m = methodOop((intptr_t) f2());
+ assert(m->is_method(), "");
+ return m;
+ } else {
+ int holder_index = cpool->uncached_klass_ref_index_at(constant_pool_index());
+ if (cpool->tag_at(holder_index).is_klass()) {
+ klassOop klass = cpool->resolved_klass_at(holder_index);
+ if (!Klass::cast(klass)->oop_is_instance())
+ klass = SystemDictionary::Object_klass();
+ return instanceKlass::cast(klass)->method_at_vtable((int) f2());
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+
+
class LocalOopClosure: public OopClosure {
private:
void (*_f)(oop*);
--- a/hotspot/src/share/vm/oops/cpCacheOop.hpp Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/oops/cpCacheOop.hpp Thu Jun 23 17:14:06 2011 -0700
@@ -194,6 +194,8 @@
methodHandle signature_invoker // determines signature information
);
+ methodOop get_method_if_resolved(Bytecodes::Code invoke_code, constantPoolHandle cpool);
+
// For JVM_CONSTANT_InvokeDynamic cache entries:
void initialize_bootstrap_method_index_in_cache(int bsm_cache_index);
int bootstrap_method_index_in_cache();
--- a/hotspot/src/share/vm/oops/methodOop.cpp Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/oops/methodOop.cpp Thu Jun 23 17:14:06 2011 -0700
@@ -928,14 +928,40 @@
name->increment_refcount();
signature->increment_refcount();
+ // record non-BCP method types in the constant pool
+ GrowableArray<KlassHandle>* extra_klasses = NULL;
+ for (int i = -1, len = java_lang_invoke_MethodType::ptype_count(method_type()); i < len; i++) {
+ oop ptype = (i == -1
+ ? java_lang_invoke_MethodType::rtype(method_type())
+ : java_lang_invoke_MethodType::ptype(method_type(), i));
+ klassOop klass = check_non_bcp_klass(java_lang_Class::as_klassOop(ptype));
+ if (klass != NULL) {
+ if (extra_klasses == NULL)
+ extra_klasses = new GrowableArray<KlassHandle>(len+1);
+ bool dup = false;
+ for (int j = 0; j < extra_klasses->length(); j++) {
+ if (extra_klasses->at(j) == klass) { dup = true; break; }
+ }
+ if (!dup)
+ extra_klasses->append(KlassHandle(THREAD, klass));
+ }
+ }
+
+ int extra_klass_count = (extra_klasses == NULL ? 0 : extra_klasses->length());
+ int cp_length = _imcp_limit + extra_klass_count;
constantPoolHandle cp;
{
- constantPoolOop cp_oop = oopFactory::new_constantPool(_imcp_limit, IsSafeConc, CHECK_(empty));
+ constantPoolOop cp_oop = oopFactory::new_constantPool(cp_length, IsSafeConc, CHECK_(empty));
cp = constantPoolHandle(THREAD, cp_oop);
}
cp->symbol_at_put(_imcp_invoke_name, name);
cp->symbol_at_put(_imcp_invoke_signature, signature);
cp->string_at_put(_imcp_method_type_value, Universe::the_null_string());
+ for (int j = 0; j < extra_klass_count; j++) {
+ KlassHandle klass = extra_klasses->at(j);
+ cp->klass_at_put(_imcp_limit + j, klass());
+ }
+ cp->set_preresolution();
cp->set_pool_holder(holder());
// set up the fancy stuff:
@@ -984,6 +1010,14 @@
return m;
}
+klassOop methodOopDesc::check_non_bcp_klass(klassOop klass) {
+ if (klass != NULL && Klass::cast(klass)->class_loader() != NULL) {
+ if (Klass::cast(klass)->oop_is_objArray())
+ klass = objArrayKlass::cast(klass)->bottom_klass();
+ return klass;
+ }
+ return NULL;
+}
methodHandle methodOopDesc:: clone_with_new_data(methodHandle m, u_char* new_code, int new_code_length,
--- a/hotspot/src/share/vm/oops/methodOop.hpp Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/oops/methodOop.hpp Thu Jun 23 17:14:06 2011 -0700
@@ -600,6 +600,7 @@
Symbol* signature, //anything at all
Handle method_type,
TRAPS);
+ static klassOop check_non_bcp_klass(klassOop klass);
// these operate only on invoke methods:
oop method_handle_type() const;
static jint* method_type_offsets_chain(); // series of pointer-offsets, terminated by -1
--- a/hotspot/src/share/vm/prims/methodHandleWalk.cpp Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/prims/methodHandleWalk.cpp Thu Jun 23 17:14:06 2011 -0700
@@ -425,6 +425,8 @@
ArgToken arg = _outgoing.at(arg_slot);
assert(dest == arg.basic_type(), "");
arg = make_conversion(T_OBJECT, dest_klass, Bytecodes::_checkcast, arg, CHECK_(empty));
+ // replace the object by the result of the cast, to make the compiler happy:
+ change_argument(T_OBJECT, arg_slot, T_OBJECT, arg);
debug_only(dest_klass = (klassOop)badOop);
break;
}
@@ -467,7 +469,7 @@
ArgToken arglist[2];
arglist[0] = arg; // outgoing 'this'
arglist[1] = ArgToken(); // sentinel
- arg = make_invoke(NULL, unboxer, Bytecodes::_invokevirtual, false, 1, &arglist[0], CHECK_(empty));
+ arg = make_invoke(methodHandle(), unboxer, Bytecodes::_invokevirtual, false, 1, &arglist[0], CHECK_(empty));
change_argument(T_OBJECT, arg_slot, dest, arg);
break;
}
@@ -483,7 +485,7 @@
ArgToken arglist[2];
arglist[0] = arg; // outgoing value
arglist[1] = ArgToken(); // sentinel
- arg = make_invoke(NULL, boxer, Bytecodes::_invokestatic, false, 1, &arglist[0], CHECK_(empty));
+ arg = make_invoke(methodHandle(), boxer, Bytecodes::_invokestatic, false, 1, &arglist[0], CHECK_(empty));
change_argument(src, arg_slot, T_OBJECT, arg);
break;
}
@@ -599,8 +601,9 @@
lose("bad vmlayout slot", CHECK_(empty));
}
// FIXME: consider inlining the invokee at the bytecode level
- ArgToken ret = make_invoke(methodOop(invoker), vmIntrinsics::_none,
+ ArgToken ret = make_invoke(methodHandle(THREAD, methodOop(invoker)), vmIntrinsics::_invokeGeneric,
Bytecodes::_invokevirtual, false, 1+argc, &arglist[0], CHECK_(empty));
+ // The iid = _invokeGeneric really means to adjust reference types as needed.
DEBUG_ONLY(invoker = NULL);
if (rtype == T_OBJECT) {
klassOop rklass = java_lang_Class::as_klassOop( java_lang_invoke_MethodType::rtype(recursive_mtype()) );
@@ -657,7 +660,7 @@
arglist[0] = array_arg; // value to check
arglist[1] = length_arg; // length to check
arglist[2] = ArgToken(); // sentinel
- make_invoke(NULL, vmIntrinsics::_checkSpreadArgument,
+ make_invoke(methodHandle(), vmIntrinsics::_checkSpreadArgument,
Bytecodes::_invokestatic, false, 2, &arglist[0], CHECK_(empty));
// Spread out the array elements.
@@ -680,7 +683,7 @@
ArgToken offset_arg = make_prim_constant(T_INT, &offset_jvalue, CHECK_(empty));
ArgToken element_arg = make_fetch(element_type, element_klass(), aload_op, array_arg, offset_arg, CHECK_(empty));
change_argument(T_VOID, ap, element_type, element_arg);
- ap += type2size[element_type];
+ //ap += type2size[element_type]; // don't do this; insert next arg to *right* of previous
}
break;
}
@@ -731,7 +734,7 @@
}
assert(ap == _outgoing_argc, "");
arglist[ap] = ArgToken(); // add a sentinel, for the sake of asserts
- return make_invoke(chain().last_method_oop(),
+ return make_invoke(chain().last_method(),
vmIntrinsics::_none,
chain().last_invoke_code(), true,
ap, arglist, THREAD);
@@ -853,7 +856,6 @@
if (src != dst) {
if (MethodHandles::same_basic_type_for_returns(src, dst, /*raw*/ true)) {
if (MethodHandles::is_float_fixed_reinterpretation_cast(src, dst)) {
- if (for_return) Untested("MHW return raw conversion"); // still untested
vmIntrinsics::ID iid = vmIntrinsics::for_raw_conversion(src, dst);
if (iid == vmIntrinsics::_none) {
lose("no raw conversion method", CHECK);
@@ -865,18 +867,24 @@
assert(arg.token_type() >= tt_symbolic || src == arg.basic_type(), "sanity");
arglist[0] = arg; // outgoing 'this'
arglist[1] = ArgToken(); // sentinel
- arg = make_invoke(NULL, iid, Bytecodes::_invokestatic, false, 1, &arglist[0], CHECK);
+ arg = make_invoke(methodHandle(), iid, Bytecodes::_invokestatic, false, 1, &arglist[0], CHECK);
change_argument(src, slot, dst, arg);
} else {
// return type conversion
- klassOop arg_klass = NULL;
- arglist[0] = make_parameter(src, arg_klass, -1, CHECK); // return value
- arglist[1] = ArgToken(); // sentinel
- (void) make_invoke(NULL, iid, Bytecodes::_invokestatic, false, 1, &arglist[0], CHECK);
+ if (_return_conv == vmIntrinsics::_none) {
+ _return_conv = iid;
+ } else if (_return_conv == vmIntrinsics::for_raw_conversion(dst, src)) {
+ _return_conv = vmIntrinsics::_none;
+ } else if (_return_conv != zero_return_conv()) {
+ lose(err_msg("requested raw return conversion not allowed: %s -> %s (before %s)", type2name(src), type2name(dst), vmIntrinsics::name_at(_return_conv)), CHECK);
+ }
}
} else {
// Nothing to do.
}
+ } else if (for_return && (!is_subword_type(src) || !is_subword_type(dst))) {
+ // This can occur in exception-throwing MHs, which have a fictitious return value encoded as Void or Empty.
+ _return_conv = zero_return_conv();
} else if (src == T_OBJECT && is_java_primitive(dst)) {
// ref-to-prim: discard ref, push zero
lose("requested ref-to-prim conversion not expected", CHECK);
@@ -896,6 +904,7 @@
_thread(THREAD),
_bytecode(THREAD, 50),
_constants(THREAD, 10),
+ _non_bcp_klasses(THREAD, 5),
_cur_stack(0),
_max_stack(0),
_rtype(T_ILLEGAL)
@@ -908,6 +917,15 @@
_name_index = cpool_symbol_put(name);
_signature_index = cpool_symbol_put(signature);
+ // To make the resulting methods more recognizable by
+ // stack walkers and compiler heuristics,
+ // we put them in holder class MethodHandle.
+ // See klass_is_method_handle_adapter_holder
+ // and methodOopDesc::is_method_handle_adapter.
+ _target_klass = SystemDictionaryHandles::MethodHandle_klass();
+
+ check_non_bcp_klasses(java_lang_invoke_MethodHandle::type(root()), CHECK);
+
// Get return type klass.
Handle first_mtype(THREAD, chain().method_type_oop());
// _rklass is NULL for primitives.
@@ -929,6 +947,7 @@
assert(_thread == THREAD, "must be same thread");
methodHandle nullHandle;
(void) walk(CHECK_(nullHandle));
+ record_non_bcp_klasses();
return get_method_oop(CHECK_(nullHandle));
}
@@ -1197,10 +1216,18 @@
}
case T_OBJECT: {
Handle value = arg.object();
- if (value.is_null())
+ if (value.is_null()) {
emit_bc(Bytecodes::_aconst_null);
- else
- emit_bc(Bytecodes::_ldc, cpool_object_put(value));
+ break;
+ }
+ if (java_lang_Class::is_instance(value())) {
+ klassOop k = java_lang_Class::as_klassOop(value());
+ if (k != NULL) {
+ emit_bc(Bytecodes::_ldc, cpool_klass_put(k));
+ break;
+ }
+ }
+ emit_bc(Bytecodes::_ldc, cpool_object_put(value));
break;
}
default:
@@ -1260,6 +1287,7 @@
index = src.index();
}
emit_bc(op, cpool_klass_put(tk));
+ check_non_bcp_klass(tk, CHECK_(src));
// Allocate a new local for the type so that we don't hide the
// previous type from the verifier.
index = new_local_index(type);
@@ -1292,15 +1320,15 @@
// Emit bytecodes for the given invoke instruction.
MethodHandleWalker::ArgToken
-MethodHandleCompiler::make_invoke(methodOop m, vmIntrinsics::ID iid,
+MethodHandleCompiler::make_invoke(methodHandle m, vmIntrinsics::ID iid,
Bytecodes::Code op, bool tailcall,
int argc, MethodHandleWalker::ArgToken* argv,
TRAPS) {
ArgToken zero;
- if (m == NULL) {
+ if (m.is_null()) {
// Get the intrinsic methodOop.
- m = vmIntrinsics::method_for(iid);
- if (m == NULL) {
+ m = methodHandle(THREAD, vmIntrinsics::method_for(iid));
+ if (m.is_null()) {
lose(vmIntrinsics::name_at(iid), CHECK_(zero));
}
}
@@ -1309,18 +1337,46 @@
Symbol* name = m->name();
Symbol* signature = m->signature();
+ if (iid == vmIntrinsics::_invokeGeneric &&
+ argc >= 1 && argv[0].token_type() == tt_constant) {
+ assert(m->intrinsic_id() == vmIntrinsics::_invokeExact, "");
+ Handle receiver = argv[0].object();
+ Handle rtype(THREAD, java_lang_invoke_MethodHandle::type(receiver()));
+ Handle mtype(THREAD, m->method_handle_type());
+ if (rtype() != mtype()) {
+ assert(java_lang_invoke_MethodType::form(rtype()) ==
+ java_lang_invoke_MethodType::form(mtype()),
+ "must be the same shape");
+ // customize m to the exact required rtype
+ bool has_non_bcp_klass = check_non_bcp_klasses(rtype(), CHECK_(zero));
+ TempNewSymbol sig2 = java_lang_invoke_MethodType::as_signature(rtype(), true, CHECK_(zero));
+ methodHandle m2;
+ if (!has_non_bcp_klass) {
+ methodOop m2_oop = SystemDictionary::find_method_handle_invoke(m->name(), sig2,
+ KlassHandle(), CHECK_(zero));
+ m2 = methodHandle(THREAD, m2_oop);
+ }
+ if (m2.is_null()) {
+ // just build it fresh
+ m2 = methodOopDesc::make_invoke_method(klass, m->name(), sig2, rtype, CHECK_(zero));
+ if (m2.is_null())
+ lose(err_msg("no customized invoker %s", sig2->as_utf8()), CHECK_(zero));
+ }
+ m = m2;
+ signature = m->signature();
+ }
+ }
+
+ check_non_bcp_klass(klass, CHECK_(zero));
+ if (m->is_method_handle_invoke()) {
+ check_non_bcp_klasses(m->method_handle_type(), CHECK_(zero));
+ }
+
// Count the number of arguments, not the size
ArgumentCount asc(signature);
assert(argc == asc.size() + ((op == Bytecodes::_invokestatic || op == Bytecodes::_invokedynamic) ? 0 : 1),
"argc mismatch");
- if (tailcall) {
- // Actually, in order to make these methods more recognizable,
- // let's put them in holder class MethodHandle. That way stack
- // walkers and compiler heuristics can recognize them.
- _target_klass = SystemDictionary::MethodHandle_klass();
- }
-
// Inline the method.
InvocationCounter* ic = m->invocation_counter();
ic->set_carry_flag();
@@ -1353,7 +1409,7 @@
int signature_index = cpool_symbol_put(signature);
int name_and_type_index = cpool_name_and_type_put(name_index, signature_index);
int klass_index = cpool_klass_put(klass);
- int methodref_index = cpool_methodref_put(klass_index, name_and_type_index);
+ int methodref_index = cpool_methodref_put(op, klass_index, name_and_type_index, m);
// Generate invoke.
switch (op) {
@@ -1380,6 +1436,20 @@
stack_push(rbt); // The return value is already pushed onto the stack.
ArgToken ret;
if (tailcall) {
+ if (return_conv() == zero_return_conv()) {
+ rbt = T_VOID; // discard value
+ } else if (return_conv() != vmIntrinsics::_none) {
+ // return value conversion
+ int index = new_local_index(rbt);
+ emit_store(rbt, index);
+ ArgToken arglist[2];
+ arglist[0] = ArgToken(tt_temporary, rbt, index);
+ arglist[1] = ArgToken(); // sentinel
+ ret = make_invoke(methodHandle(), return_conv(), Bytecodes::_invokestatic, false, 1, &arglist[0], CHECK_(zero));
+ set_return_conv(vmIntrinsics::_none);
+ rbt = ret.basic_type();
+ emit_load(rbt, ret.index());
+ }
if (rbt != _rtype) {
if (rbt == T_VOID) {
// push a zero of the right sort
@@ -1425,6 +1495,7 @@
case T_OBJECT:
if (_rklass.not_null() && _rklass() != SystemDictionary::Object_klass() && !Klass::cast(_rklass())->is_interface()) {
emit_bc(Bytecodes::_checkcast, cpool_klass_put(_rklass()));
+ check_non_bcp_klass(_rklass(), CHECK_(zero));
}
emit_bc(Bytecodes::_areturn);
break;
@@ -1525,6 +1596,52 @@
return index;
}
+bool MethodHandleCompiler::check_non_bcp_klasses(Handle method_type, TRAPS) {
+ bool res = false;
+ for (int i = -1, len = java_lang_invoke_MethodType::ptype_count(method_type()); i < len; i++) {
+ oop ptype = (i == -1
+ ? java_lang_invoke_MethodType::rtype(method_type())
+ : java_lang_invoke_MethodType::ptype(method_type(), i));
+ res |= check_non_bcp_klass(java_lang_Class::as_klassOop(ptype), CHECK_(false));
+ }
+ return res;
+}
+
+bool MethodHandleCompiler::check_non_bcp_klass(klassOop klass, TRAPS) {
+ klass = methodOopDesc::check_non_bcp_klass(klass);
+ if (klass != NULL) {
+ Symbol* name = Klass::cast(klass)->name();
+ for (int i = _non_bcp_klasses.length() - 1; i >= 0; i--) {
+ klassOop k2 = _non_bcp_klasses.at(i)();
+ if (Klass::cast(k2)->name() == name) {
+ if (k2 != klass) {
+ lose(err_msg("unsupported klass name alias %s", name->as_utf8()), THREAD);
+ }
+ return true;
+ }
+ }
+ _non_bcp_klasses.append(KlassHandle(THREAD, klass));
+ return true;
+ }
+ return false;
+}
+
+void MethodHandleCompiler::record_non_bcp_klasses() {
+ // Append extra klasses to constant pool, to guide klass lookup.
+ for (int k = 0; k < _non_bcp_klasses.length(); k++) {
+ klassOop non_bcp_klass = _non_bcp_klasses.at(k)();
+ bool add_to_cp = true;
+ for (int j = 1; j < _constants.length(); j++) {
+ ConstantValue* cv = _constants.at(j);
+ if (cv != NULL && cv->tag() == JVM_CONSTANT_Class
+ && cv->klass_oop() == non_bcp_klass) {
+ add_to_cp = false;
+ break;
+ }
+ }
+ if (add_to_cp) cpool_klass_put(non_bcp_klass);
+ }
+}
constantPoolHandle MethodHandleCompiler::get_constant_pool(TRAPS) const {
constantPoolHandle nullHandle;
@@ -1544,6 +1661,8 @@
case JVM_CONSTANT_Double: cpool->double_at_put( i, cv->get_jdouble() ); break;
case JVM_CONSTANT_Class: cpool->klass_at_put( i, cv->klass_oop() ); break;
case JVM_CONSTANT_Methodref: cpool->method_at_put( i, cv->first_index(), cv->second_index()); break;
+ case JVM_CONSTANT_InterfaceMethodref:
+ cpool->interface_method_at_put(i, cv->first_index(), cv->second_index()); break;
case JVM_CONSTANT_NameAndType: cpool->name_and_type_at_put(i, cv->first_index(), cv->second_index()); break;
case JVM_CONSTANT_Object: cpool->object_at_put( i, cv->object_oop() ); break;
default: ShouldNotReachHere();
@@ -1558,6 +1677,8 @@
}
}
+ cpool->set_preresolution();
+
// Set the constant pool holder to the target method's class.
cpool->set_pool_holder(_target_klass());
@@ -1606,6 +1727,33 @@
Rewriter::rewrite(_target_klass(), cpool, methods, CHECK_(empty)); // Use fake class.
Rewriter::relocate_and_link(_target_klass(), methods, CHECK_(empty)); // Use fake class.
+ // Pre-resolve selected CP cache entries, to avoid problems with class loader scoping.
+ constantPoolCacheHandle cpc(THREAD, cpool->cache());
+ for (int i = 0; i < cpc->length(); i++) {
+ ConstantPoolCacheEntry* e = cpc->entry_at(i);
+ assert(!e->is_secondary_entry(), "no indy instructions in here, yet");
+ int constant_pool_index = e->constant_pool_index();
+ ConstantValue* cv = _constants.at(constant_pool_index);
+ if (!cv->has_linkage()) continue;
+ methodHandle m = cv->linkage();
+ int index;
+ switch (cv->tag()) {
+ case JVM_CONSTANT_Methodref:
+ index = m->vtable_index();
+ if (m->is_static()) {
+ e->set_method(Bytecodes::_invokestatic, m, index);
+ } else {
+ e->set_method(Bytecodes::_invokespecial, m, index);
+ e->set_method(Bytecodes::_invokevirtual, m, index);
+ }
+ break;
+ case JVM_CONSTANT_InterfaceMethodref:
+ index = klassItable::compute_itable_index(m());
+ e->set_interface_call(m, index);
+ break;
+ }
+ }
+
// Set the invocation counter's count to the invoke count of the
// original call site.
InvocationCounter* ic = m->invocation_counter();
@@ -1696,6 +1844,9 @@
_param_state(0),
_temp_num(0)
{
+ out->print("MethodHandle:");
+ java_lang_invoke_MethodType::print_signature(java_lang_invoke_MethodHandle::type(root()), out);
+ out->print(" : #");
start_params();
}
virtual ArgToken make_parameter(BasicType type, klassOop tk, int argnum, TRAPS) {
@@ -1759,12 +1910,12 @@
_strbuf.print(")");
return maybe_make_temp("fetch", type, "x");
}
- virtual ArgToken make_invoke(methodOop m, vmIntrinsics::ID iid,
+ virtual ArgToken make_invoke(methodHandle m, vmIntrinsics::ID iid,
Bytecodes::Code op, bool tailcall,
int argc, ArgToken* argv, TRAPS) {
Symbol* name;
Symbol* sig;
- if (m != NULL) {
+ if (m.not_null()) {
name = m->name();
sig = m->signature();
} else {
--- a/hotspot/src/share/vm/prims/methodHandleWalk.hpp Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/prims/methodHandleWalk.hpp Thu Jun 23 17:14:06 2011 -0700
@@ -98,6 +98,7 @@
int bound_arg_slot() { assert(is_bound(), ""); return _arg_slot; }
oop bound_arg_oop() { assert(is_bound(), ""); return BoundMethodHandle_argument_oop(); }
+ methodHandle last_method() { assert(is_last(), ""); return _last_method; }
methodOop last_method_oop() { assert(is_last(), ""); return _last_method(); }
Bytecodes::Code last_invoke_code() { assert(is_last(), ""); return _last_invoke; }
@@ -181,6 +182,8 @@
GrowableArray<ArgToken> _outgoing; // current outgoing parameter slots
int _outgoing_argc; // # non-empty outgoing slots
+ vmIntrinsics::ID _return_conv; // Return conversion required by raw retypes.
+
// Replace a value of type old_type at slot (and maybe slot+1) with the new value.
// If old_type != T_VOID, remove the old argument at that point.
// If new_type != T_VOID, insert the new argument at that point.
@@ -219,7 +222,8 @@
: _chain(root, THREAD),
_for_invokedynamic(for_invokedynamic),
_outgoing(THREAD, 10),
- _outgoing_argc(0)
+ _outgoing_argc(0),
+ _return_conv(vmIntrinsics::_none)
{
_local_index = for_invokedynamic ? 0 : 1;
}
@@ -228,6 +232,10 @@
bool for_invokedynamic() const { return _for_invokedynamic; }
+ vmIntrinsics::ID return_conv() const { return _return_conv; }
+ void set_return_conv(vmIntrinsics::ID c) { _return_conv = c; }
+ static vmIntrinsics::ID zero_return_conv() { return vmIntrinsics::_min; }
+
int new_local_index(BasicType bt) {
//int index = _for_invokedynamic ? _local_index : _local_index - 1;
int index = _local_index;
@@ -243,9 +251,9 @@
virtual ArgToken make_oop_constant(oop con, TRAPS) = 0;
virtual ArgToken make_conversion(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& src, TRAPS) = 0;
virtual ArgToken make_fetch(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& base, const ArgToken& offset, TRAPS) = 0;
- virtual ArgToken make_invoke(methodOop m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS) = 0;
+ virtual ArgToken make_invoke(methodHandle m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS) = 0;
- // For make_invoke, the methodOop can be NULL if the intrinsic ID
+ // For make_invoke, the methodHandle can be NULL if the intrinsic ID
// is something other than vmIntrinsics::_none.
// and in case anyone cares to related the previous actions to the chain:
@@ -280,6 +288,7 @@
JavaValue _value;
Handle _handle;
Symbol* _sym;
+ methodHandle _method; // pre-linkage
public:
// Constructor for oop types.
@@ -328,11 +337,21 @@
jlong get_jlong() const { return _value.get_jlong(); }
jfloat get_jfloat() const { return _value.get_jfloat(); }
jdouble get_jdouble() const { return _value.get_jdouble(); }
+
+ void set_linkage(methodHandle method) {
+ assert(_method.is_null(), "");
+ _method = method;
+ }
+ bool has_linkage() const { return _method.not_null(); }
+ methodHandle linkage() const { return _method; }
};
// Fake constant pool.
GrowableArray<ConstantValue*> _constants;
+ // Non-BCP classes that appear in associated MethodTypes (require special handling).
+ GrowableArray<KlassHandle> _non_bcp_klasses;
+
// Accumulated compiler state:
GrowableArray<unsigned char> _bytecode;
@@ -368,15 +387,20 @@
return _constants.append(cv);
}
- int cpool_oop_reference_put(int tag, int first_index, int second_index) {
+ int cpool_oop_reference_put(int tag, int first_index, int second_index, methodHandle method) {
if (first_index == 0 && second_index == 0) return 0;
assert(first_index != 0 && second_index != 0, "no zero indexes");
ConstantValue* cv = new ConstantValue(tag, first_index, second_index);
+ if (method.not_null()) cv->set_linkage(method);
return _constants.append(cv);
}
int cpool_primitive_put(BasicType type, jvalue* con);
+ bool check_non_bcp_klasses(Handle method_type, TRAPS);
+ bool check_non_bcp_klass(klassOop klass, TRAPS);
+ void record_non_bcp_klasses();
+
int cpool_int_put(jint value) {
jvalue con; con.i = value;
return cpool_primitive_put(T_INT, &con);
@@ -403,11 +427,12 @@
int cpool_klass_put(klassOop klass) {
return cpool_oop_put(JVM_CONSTANT_Class, klass);
}
- int cpool_methodref_put(int class_index, int name_and_type_index) {
- return cpool_oop_reference_put(JVM_CONSTANT_Methodref, class_index, name_and_type_index);
+ int cpool_methodref_put(Bytecodes::Code op, int class_index, int name_and_type_index, methodHandle method) {
+ int tag = (op == Bytecodes::_invokeinterface ? JVM_CONSTANT_InterfaceMethodref : JVM_CONSTANT_Methodref);
+ return cpool_oop_reference_put(tag, class_index, name_and_type_index, method);
}
int cpool_name_and_type_put(int name_index, int signature_index) {
- return cpool_oop_reference_put(JVM_CONSTANT_NameAndType, name_index, signature_index);
+ return cpool_oop_reference_put(JVM_CONSTANT_NameAndType, name_index, signature_index, methodHandle());
}
void emit_bc(Bytecodes::Code op, int index = 0, int args_size = -1);
@@ -428,7 +453,7 @@
virtual ArgToken make_conversion(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& src, TRAPS);
virtual ArgToken make_fetch(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& base, const ArgToken& offset, TRAPS);
- virtual ArgToken make_invoke(methodOop m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS);
+ virtual ArgToken make_invoke(methodHandle m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS);
// Get a real constant pool.
constantPoolHandle get_constant_pool(TRAPS) const;
--- a/hotspot/src/share/vm/prims/methodHandles.cpp Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/prims/methodHandles.cpp Thu Jun 23 17:14:06 2011 -0700
@@ -24,12 +24,14 @@
#include "precompiled.hpp"
#include "classfile/symbolTable.hpp"
+#include "compiler/compileBroker.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/oopMapCache.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/oopFactory.hpp"
#include "prims/methodHandles.hpp"
#include "prims/methodHandleWalk.hpp"
+#include "runtime/compilationPolicy.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/reflection.hpp"
#include "runtime/signature.hpp"
@@ -767,7 +769,9 @@
m = NULL;
// try again with a different class loader...
}
- if (m != NULL) {
+ if (m != NULL &&
+ m->is_method_handle_invoke() &&
+ java_lang_invoke_MethodType::equals(polymorphic_method_type(), m->method_handle_type())) {
int mods = (m->access_flags().as_short() & JVM_RECOGNIZED_METHOD_MODIFIERS);
java_lang_invoke_MemberName::set_vmtarget(mname(), m);
java_lang_invoke_MemberName::set_vmindex(mname(), m->vtable_index());
@@ -986,6 +990,48 @@
// This is for debugging and reflection.
oop MethodHandles::encode_target(Handle mh, int format, TRAPS) {
assert(java_lang_invoke_MethodHandle::is_instance(mh()), "must be a MH");
+ if (format == ETF_FORCE_DIRECT_HANDLE ||
+ format == ETF_COMPILE_DIRECT_HANDLE) {
+ // Internal function for stress testing.
+ Handle mt = java_lang_invoke_MethodHandle::type(mh());
+ int invocation_count = 10000;
+ TempNewSymbol signature = java_lang_invoke_MethodType::as_signature(mt(), true, CHECK_NULL);
+ bool omit_receiver_argument = true;
+ MethodHandleCompiler mhc(mh, vmSymbols::invoke_name(), signature, invocation_count, omit_receiver_argument, CHECK_NULL);
+ methodHandle m = mhc.compile(CHECK_NULL);
+ if (StressMethodHandleWalk && Verbose || PrintMiscellaneous) {
+ tty->print_cr("MethodHandleNatives.getTarget(%s)",
+ format == ETF_FORCE_DIRECT_HANDLE ? "FORCE_DIRECT" : "COMPILE_DIRECT");
+ if (Verbose) {
+ m->print_codes();
+ }
+ }
+ if (StressMethodHandleWalk) {
+ InterpreterOopMap mask;
+ OopMapCache::compute_one_oop_map(m, m->code_size() - 1, &mask);
+ }
+ if ((format == ETF_COMPILE_DIRECT_HANDLE ||
+ CompilationPolicy::must_be_compiled(m))
+ && !instanceKlass::cast(m->method_holder())->is_not_initialized()
+ && CompilationPolicy::can_be_compiled(m)) {
+ // Force compilation
+ CompileBroker::compile_method(m, InvocationEntryBci,
+ CompLevel_initial_compile,
+ methodHandle(), 0, "MethodHandleNatives.getTarget",
+ CHECK_NULL);
+ }
+ // Now wrap m in a DirectMethodHandle.
+ instanceKlassHandle dmh_klass(THREAD, SystemDictionary::DirectMethodHandle_klass());
+ Handle dmh = dmh_klass->allocate_instance_handle(CHECK_NULL);
+ JavaValue ignore_result(T_VOID);
+ Symbol* init_name = vmSymbols::object_initializer_name();
+ Symbol* init_sig = vmSymbols::notifyGenericMethodType_signature();
+ JavaCalls::call_special(&ignore_result, dmh,
+ SystemDictionaryHandles::MethodHandle_klass(), init_name, init_sig,
+ java_lang_invoke_MethodHandle::type(mh()), CHECK_NULL);
+ MethodHandles::init_DirectMethodHandle(dmh, m, false, CHECK_NULL);
+ return dmh();
+ }
if (format == ETF_HANDLE_OR_METHOD_NAME) {
oop target = java_lang_invoke_MethodHandle::vmtarget(mh());
if (target == NULL) {
@@ -1221,6 +1267,12 @@
klassOop aklass_oop = SystemDictionary::resolve_or_null(name, loader, domain, CHECK);
if (aklass_oop != NULL)
aklass = KlassHandle(THREAD, aklass_oop);
+ if (aklass.is_null() &&
+ pklass.not_null() &&
+ loader.is_null() &&
+ pklass->name() == name)
+ // accept name equivalence here, since that's the best we can do
+ aklass = pklass;
}
} else {
// for method handle invokers we don't look at the name in the signature
@@ -2654,6 +2706,17 @@
}
InterpreterOopMap mask;
OopMapCache::compute_one_oop_map(m, m->code_size() - 1, &mask);
+ // compile to object code if -Xcomp or WizardMode
+ if ((WizardMode ||
+ CompilationPolicy::must_be_compiled(m))
+ && !instanceKlass::cast(m->method_holder())->is_not_initialized()
+ && CompilationPolicy::can_be_compiled(m)) {
+ // Force compilation
+ CompileBroker::compile_method(m, InvocationEntryBci,
+ CompLevel_initial_compile,
+ methodHandle(), 0, "StressMethodHandleWalk",
+ CHECK);
+ }
}
}
@@ -2773,7 +2836,12 @@
// Build a BMH on top of a DMH or another BMH:
MethodHandles::init_BoundMethodHandle(mh, target, argnum, CHECK);
}
- stress_method_handle_walk(mh, CHECK);
+
+ if (StressMethodHandleWalk) {
+ if (mh->klass() == SystemDictionary::BoundMethodHandle_klass())
+ stress_method_handle_walk(mh, CHECK);
+ // else don't, since the subclass has not yet initialized its own fields
+ }
}
JVM_END
--- a/hotspot/src/share/vm/prims/methodHandles.hpp Wed Jun 22 14:45:37 2011 -0700
+++ b/hotspot/src/share/vm/prims/methodHandles.hpp Thu Jun 23 17:14:06 2011 -0700
@@ -588,6 +588,8 @@
ETF_DIRECT_HANDLE = 1, // ultimate method handle (will be a DMH, may be self)
ETF_METHOD_NAME = 2, // ultimate method as MemberName
ETF_REFLECT_METHOD = 3, // ultimate method as java.lang.reflect object (sans refClass)
+ ETF_FORCE_DIRECT_HANDLE = 64,
+ ETF_COMPILE_DIRECT_HANDLE = 65,
// ad hoc constants
OP_ROT_ARGS_DOWN_LIMIT_BIAS = -1