提交 50f0f018 编写于 作者: J jrose

7056328: JSR 292 invocation sometimes fails in adapters for types not on boot class path

Reviewed-by: never
上级 11d5fcaf
......@@ -266,7 +266,7 @@ void TemplateTable::sipush() {
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 @@ void TemplateTable::ldc(bool wide) {
__ 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);
......
......@@ -373,15 +373,17 @@ void TemplateTable::ldc(bool wide) {
__ 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);
......
......@@ -385,6 +385,8 @@ void TemplateTable::ldc(bool wide) {
__ 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);
}
......
......@@ -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 @@ bool ciEnv::check_klass_accessibility(ciKlass* accessing_klass,
// ------------------------------------------------------------------
// 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 @@ ciKlass* ciEnv::get_klass_by_name_impl(ciKlass* accessing_klass,
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 @@ ciKlass* ciEnv::get_klass_by_name_impl(ciKlass* accessing_klass,
// 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 @@ ciKlass* ciEnv::get_klass_by_name_impl(ciKlass* accessing_klass,
}
}
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 @@ ciKlass* ciEnv::get_klass_by_name(ciKlass* accessing_klass,
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 @@ ciKlass* ciEnv::get_klass_by_index_impl(constantPoolHandle cpool,
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 @@ ciConstant ciEnv::get_constant_by_index_impl(constantPoolHandle cpool,
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 @@ ciConstant ciEnv::get_constant_by_index_impl(constantPoolHandle cpool,
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 @@ ciMethod* ciEnv::get_method_by_index_impl(constantPoolHandle cpool,
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 @@ void ciEnv::register_method(ciMethod* target,
// 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);
}
// ------------------------------------------------------------------
......
......@@ -137,6 +137,7 @@ private:
// 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,
......
......@@ -287,7 +287,7 @@ ciType* ciField::compute_type() {
}
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;
......
......@@ -125,7 +125,8 @@ ciMethod::ciMethod(methodHandle h_m) : ciObject(h_m) {
_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 @@ ciMethod::ciMethod(ciInstanceKlass* holder,
// 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;
......
......@@ -41,6 +41,16 @@ ciMethod* ciMethodHandle::get_adapter_impl(bool is_invokedynamic) const {
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 @@ ciMethod* ciMethodHandle::get_adapter_impl(bool is_invokedynamic) const {
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;
......
......@@ -93,6 +93,7 @@ ciKlass* ciObjArrayKlass::element_klass() {
// 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);
......
......@@ -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 @@ ciSignature::ciSignature(ciKlass* accessing_klass, ciSymbol* symbol) {
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);
......
......@@ -44,7 +44,7 @@ private:
friend class ciMethod;
ciSignature(ciKlass* accessing_klass, ciSymbol* signature);
ciSignature(ciKlass* accessing_klass, constantPoolHandle cpool, ciSymbol* signature);
void get_all_klasses();
......
......@@ -2574,6 +2574,18 @@ Symbol* java_lang_invoke_MethodType::as_signature(oop mt, bool intern_if_not_fou
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);
......
......@@ -1079,6 +1079,8 @@ class java_lang_invoke_MethodType: AllStatic {
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; }
......
......@@ -2367,6 +2367,8 @@ methodOop SystemDictionary::find_method_handle_invoke(Symbol* name,
// 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());
}
......
......@@ -294,6 +294,16 @@ void LinkResolver::resolve_method(methodHandle& resolved_method, KlassHandle& re
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);
}
......
......@@ -310,10 +310,14 @@ void constantPoolKlass::oop_print_on(oop obj, outputStream* st) {
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 @@ void constantPoolKlass::oop_print_value_on(oop obj, outputStream* st) {
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());
}
......
......@@ -266,6 +266,29 @@ klassOop constantPoolOopDesc::klass_ref_at_if_loaded_check(constantPoolHandle th
}
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);
......
......@@ -103,7 +103,8 @@ class constantPoolOopDesc : public oopDesc {
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 @@ class constantPoolOopDesc : public oopDesc {
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 @@ class constantPoolOopDesc : public oopDesc {
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.
......
......@@ -295,6 +295,50 @@ void ConstantPoolCacheEntry::set_dynamic_call(Handle call_site, methodHandle sig
}
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*);
......
......@@ -194,6 +194,8 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC {
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();
......
......@@ -928,14 +928,40 @@ methodHandle methodOopDesc::make_invoke_method(KlassHandle holder,
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 @@ methodHandle methodOopDesc::make_invoke_method(KlassHandle holder,
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,
......
......@@ -600,6 +600,7 @@ class methodOopDesc : public oopDesc {
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
......
......@@ -425,6 +425,8 @@ MethodHandleWalker::walk(TRAPS) {
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 @@ MethodHandleWalker::walk(TRAPS) {
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 @@ MethodHandleWalker::walk(TRAPS) {
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 @@ MethodHandleWalker::walk(TRAPS) {
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 @@ MethodHandleWalker::walk(TRAPS) {
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 @@ MethodHandleWalker::walk(TRAPS) {
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 @@ MethodHandleWalker::walk(TRAPS) {
}
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 @@ void MethodHandleWalker::retype_raw_conversion(BasicType src, BasicType dst, boo
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 @@ void MethodHandleWalker::retype_raw_conversion(BasicType src, BasicType dst, boo
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 @@ MethodHandleCompiler::MethodHandleCompiler(Handle root, Symbol* name, Symbol* si
_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 @@ MethodHandleCompiler::MethodHandleCompiler(Handle root, Symbol* name, Symbol* si
_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 @@ methodHandle MethodHandleCompiler::compile(TRAPS) {
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 @@ void MethodHandleCompiler::emit_load_constant(ArgToken arg) {
}
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 @@ MethodHandleCompiler::make_conversion(BasicType type, klassOop tk, Bytecodes::Co
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 @@ jvalue MethodHandleCompiler::one_jvalue = { 1 };
// 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 @@ MethodHandleCompiler::make_invoke(methodOop m, vmIntrinsics::ID iid,
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 @@ MethodHandleCompiler::make_invoke(methodOop m, vmIntrinsics::ID iid,
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 @@ MethodHandleCompiler::make_invoke(methodOop m, vmIntrinsics::ID iid,
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 @@ MethodHandleCompiler::make_invoke(methodOop m, vmIntrinsics::ID iid,
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 @@ int MethodHandleCompiler::cpool_primitive_put(BasicType bt, jvalue* con) {
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 @@ constantPoolHandle MethodHandleCompiler::get_constant_pool(TRAPS) const {
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 @@ constantPoolHandle MethodHandleCompiler::get_constant_pool(TRAPS) const {
}
}
cpool->set_preresolution();
// Set the constant pool holder to the target method's class.
cpool->set_pool_holder(_target_klass());
......@@ -1606,6 +1727,33 @@ methodHandle MethodHandleCompiler::get_method_oop(TRAPS) const {
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 @@ public:
_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 @@ public:
_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 {
......
......@@ -98,6 +98,7 @@ public:
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 @@ private:
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 @@ public:
: _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 @@ public:
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 @@ public:
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 @@ private:
JavaValue _value;
Handle _handle;
Symbol* _sym;
methodHandle _method; // pre-linkage
public:
// Constructor for oop types.
......@@ -328,11 +337,21 @@ private:
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 @@ private:
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 @@ private:
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 @@ private:
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;
......
......@@ -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 @@ void MethodHandles::resolve_MemberName(Handle mname, TRAPS) {
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 @@ instanceKlassHandle MethodHandles::resolve_instance_klass(oop java_mirror_oop, T
// 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 @@ void MethodHandles::verify_method_signature(methodHandle m,
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 @@ static void stress_method_handle_walk_impl(Handle mh, TRAPS) {
}
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 @@ JVM_ENTRY(void, MHN_init_BMH(JNIEnv *env, jobject igcls, jobject mh_jh,
// 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
......
......@@ -588,6 +588,8 @@ class MethodHandles: AllStatic {
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
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册