6893268: additional dynamic language related optimizations in C2

C2 needs some additional optimizations to be able to handle MethodHandle invokes and invokedynamic instructions at the best performance.

Reviewed-by: kvn, never
This commit is contained in:
Christian Thalinger 2010-01-05 15:21:25 +01:00
parent 375527d84e
commit 47f2433a58
52 changed files with 1781 additions and 342 deletions

View File

@ -39,6 +39,7 @@ size_t ciCPCache::get_f1_offset(int index) {
return in_bytes(f1_offset);
}
// ------------------------------------------------------------------
// ciCPCache::print
//

View File

@ -0,0 +1,46 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
#include "incls/_precompiled.incl"
#include "incls/_ciCallSite.cpp.incl"
// ciCallSite
// ------------------------------------------------------------------
// ciCallSite::get_target
//
// Return the target MethodHandle of this CallSite.
ciMethodHandle* ciCallSite::get_target() const {
VM_ENTRY_MARK;
oop method_handle_oop = java_dyn_CallSite::target(get_oop());
return CURRENT_ENV->get_object(method_handle_oop)->as_method_handle();
}
// ------------------------------------------------------------------
// ciCallSite::print
//
// Print debugging information about the CallSite.
void ciCallSite::print() {
Unimplemented();
}

View File

@ -0,0 +1,39 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
// ciCallSite
//
// The class represents a java.dyn.CallSite object.
class ciCallSite : public ciInstance {
public:
ciCallSite(instanceHandle h_i) : ciInstance(h_i) {}
// What kind of ciObject is this?
bool is_call_site() const { return true; }
// Return the target MethodHandle of this CallSite.
ciMethodHandle* get_target() const;
void print();
};

View File

@ -43,6 +43,8 @@ class ciTypeFlow;
class ciObject;
class ciNullObject;
class ciInstance;
class ciCallSite;
class ciMethodHandle;
class ciMethod;
class ciMethodData;
class ciReceiverTypeData; // part of ciMethodData
@ -79,6 +81,7 @@ friend class ciObjectFactory;
// Any more access must be given explicitly.
#define CI_PACKAGE_ACCESS_TO \
friend class ciObjectFactory; \
friend class ciCallSite; \
friend class ciConstantPoolCache; \
friend class ciField; \
friend class ciConstant; \
@ -94,6 +97,7 @@ friend class ciNullObject; \
friend class ciInstance; \
friend class ciMethod; \
friend class ciMethodData; \
friend class ciMethodHandle; \
friend class ciReceiverTypeData; \
friend class ciSymbol; \
friend class ciArray; \

View File

@ -443,12 +443,11 @@ ciKlass* ciEnv::get_klass_by_name(ciKlass* accessing_klass,
// ciEnv::get_klass_by_index_impl
//
// Implementation of get_klass_by_index.
ciKlass* ciEnv::get_klass_by_index_impl(ciInstanceKlass* accessor,
ciKlass* ciEnv::get_klass_by_index_impl(constantPoolHandle cpool,
int index,
bool& is_accessible) {
assert(accessor->get_instanceKlass()->is_linked(), "must be linked before accessing constant pool");
bool& is_accessible,
ciInstanceKlass* accessor) {
EXCEPTION_CONTEXT;
constantPoolHandle cpool(THREAD, accessor->get_instanceKlass()->constants());
KlassHandle klass (THREAD, constantPoolOopDesc::klass_at_if_loaded(cpool, index));
symbolHandle klass_name;
if (klass.is_null()) {
@ -510,22 +509,21 @@ ciKlass* ciEnv::get_klass_by_index_impl(ciInstanceKlass* accessor,
// ciEnv::get_klass_by_index
//
// Get a klass from the constant pool.
ciKlass* ciEnv::get_klass_by_index(ciInstanceKlass* accessor,
ciKlass* ciEnv::get_klass_by_index(constantPoolHandle cpool,
int index,
bool& is_accessible) {
GUARDED_VM_ENTRY(return get_klass_by_index_impl(accessor, index, is_accessible);)
bool& is_accessible,
ciInstanceKlass* accessor) {
GUARDED_VM_ENTRY(return get_klass_by_index_impl(cpool, index, is_accessible, accessor);)
}
// ------------------------------------------------------------------
// ciEnv::get_constant_by_index_impl
//
// Implementation of get_constant_by_index().
ciConstant ciEnv::get_constant_by_index_impl(ciInstanceKlass* accessor,
int index) {
ciConstant ciEnv::get_constant_by_index_impl(constantPoolHandle cpool,
int index,
ciInstanceKlass* accessor) {
EXCEPTION_CONTEXT;
instanceKlass* ik_accessor = accessor->get_instanceKlass();
assert(ik_accessor->is_linked(), "must be linked before accessing constant pool");
constantPoolOop cpool = ik_accessor->constants();
constantTag tag = cpool->tag_at(index);
if (tag.is_int()) {
return ciConstant(T_INT, (jint)cpool->int_at(index));
@ -553,7 +551,7 @@ ciConstant ciEnv::get_constant_by_index_impl(ciInstanceKlass* accessor,
} else if (tag.is_klass() || tag.is_unresolved_klass()) {
// 4881222: allow ldc to take a class type
bool ignore;
ciKlass* klass = get_klass_by_index_impl(accessor, index, ignore);
ciKlass* klass = get_klass_by_index_impl(cpool, index, ignore, accessor);
if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION;
record_out_of_memory_failure();
@ -562,6 +560,11 @@ ciConstant ciEnv::get_constant_by_index_impl(ciInstanceKlass* accessor,
assert (klass->is_instance_klass() || klass->is_array_klass(),
"must be an instance or array klass ");
return ciConstant(T_OBJECT, klass);
} else if (tag.is_object()) {
oop obj = cpool->object_at(index);
assert(obj->is_instance(), "must be an instance");
ciObject* ciobj = get_object(obj);
return ciConstant(T_OBJECT, ciobj);
} else {
ShouldNotReachHere();
return ciConstant();
@ -598,9 +601,10 @@ bool ciEnv::is_unresolved_klass_impl(instanceKlass* accessor, int index) const {
// Pull a constant out of the constant pool. How appropriate.
//
// Implementation note: this query is currently in no way cached.
ciConstant ciEnv::get_constant_by_index(ciInstanceKlass* accessor,
int index) {
GUARDED_VM_ENTRY(return get_constant_by_index_impl(accessor, index); )
ciConstant ciEnv::get_constant_by_index(constantPoolHandle cpool,
int index,
ciInstanceKlass* accessor) {
GUARDED_VM_ENTRY(return get_constant_by_index_impl(cpool, index, accessor);)
}
// ------------------------------------------------------------------
@ -610,7 +614,7 @@ ciConstant ciEnv::get_constant_by_index(ciInstanceKlass* accessor,
//
// Implementation note: this query is currently in no way cached.
bool ciEnv::is_unresolved_string(ciInstanceKlass* accessor,
int index) const {
int index) const {
GUARDED_VM_ENTRY(return is_unresolved_string_impl(accessor->get_instanceKlass(), index); )
}
@ -621,7 +625,7 @@ bool ciEnv::is_unresolved_string(ciInstanceKlass* accessor,
//
// Implementation note: this query is currently in no way cached.
bool ciEnv::is_unresolved_klass(ciInstanceKlass* accessor,
int index) const {
int index) const {
GUARDED_VM_ENTRY(return is_unresolved_klass_impl(accessor->get_instanceKlass(), index); )
}
@ -702,15 +706,12 @@ methodOop ciEnv::lookup_method(instanceKlass* accessor,
// ------------------------------------------------------------------
// ciEnv::get_method_by_index_impl
ciMethod* ciEnv::get_method_by_index_impl(ciInstanceKlass* accessor,
int index, Bytecodes::Code bc) {
// Get the method's declared holder.
assert(accessor->get_instanceKlass()->is_linked(), "must be linked before accessing constant pool");
constantPoolHandle cpool = accessor->get_instanceKlass()->constants();
ciMethod* ciEnv::get_method_by_index_impl(constantPoolHandle cpool,
int index, Bytecodes::Code bc,
ciInstanceKlass* accessor) {
int holder_index = cpool->klass_ref_index_at(index);
bool holder_is_accessible;
ciKlass* holder = get_klass_by_index_impl(accessor, holder_index, holder_is_accessible);
ciKlass* holder = get_klass_by_index_impl(cpool, holder_index, holder_is_accessible, accessor);
ciInstanceKlass* declared_holder = get_instance_klass_for_declared_method_holder(holder);
// Get the method's name and signature.
@ -738,11 +739,9 @@ ciMethod* ciEnv::get_method_by_index_impl(ciInstanceKlass* accessor,
// ------------------------------------------------------------------
// ciEnv::get_fake_invokedynamic_method_impl
ciMethod* ciEnv::get_fake_invokedynamic_method_impl(ciInstanceKlass* accessor,
ciMethod* ciEnv::get_fake_invokedynamic_method_impl(constantPoolHandle cpool,
int index, Bytecodes::Code bc) {
assert(bc == Bytecodes::_invokedynamic, "must be invokedynamic");
assert(accessor->get_instanceKlass()->is_linked(), "must be linked before accessing constant pool");
constantPoolHandle cpool = accessor->get_instanceKlass()->constants();
// Get the CallSite from the constant pool cache.
ConstantPoolCacheEntry* cpc_entry = cpool->cache()->secondary_entry_at(index);
@ -789,12 +788,13 @@ ciInstanceKlass* ciEnv::get_instance_klass_for_declared_method_holder(ciKlass* m
// ------------------------------------------------------------------
// ciEnv::get_method_by_index
ciMethod* ciEnv::get_method_by_index(ciInstanceKlass* accessor,
int index, Bytecodes::Code bc) {
ciMethod* ciEnv::get_method_by_index(constantPoolHandle cpool,
int index, Bytecodes::Code bc,
ciInstanceKlass* accessor) {
if (bc == Bytecodes::_invokedynamic) {
GUARDED_VM_ENTRY(return get_fake_invokedynamic_method_impl(accessor, index, bc);)
GUARDED_VM_ENTRY(return get_fake_invokedynamic_method_impl(cpool, index, bc);)
} else {
GUARDED_VM_ENTRY(return get_method_by_index_impl(accessor, index, bc);)
GUARDED_VM_ENTRY(return get_method_by_index_impl(cpool, index, bc, accessor);)
}
}

View File

@ -121,38 +121,44 @@ private:
bool require_local);
// Constant pool access.
ciKlass* get_klass_by_index(ciInstanceKlass* loading_klass,
ciKlass* get_klass_by_index(constantPoolHandle cpool,
int klass_index,
bool& is_accessible);
ciConstant get_constant_by_index(ciInstanceKlass* loading_klass,
int constant_index);
bool& is_accessible,
ciInstanceKlass* loading_klass);
ciConstant get_constant_by_index(constantPoolHandle cpool,
int constant_index,
ciInstanceKlass* accessor);
bool is_unresolved_string(ciInstanceKlass* loading_klass,
int constant_index) const;
bool is_unresolved_klass(ciInstanceKlass* loading_klass,
int constant_index) const;
ciField* get_field_by_index(ciInstanceKlass* loading_klass,
int field_index);
ciMethod* get_method_by_index(ciInstanceKlass* loading_klass,
int method_index, Bytecodes::Code bc);
ciMethod* get_method_by_index(constantPoolHandle cpool,
int method_index, Bytecodes::Code bc,
ciInstanceKlass* loading_klass);
// Implementation methods for loading and constant pool access.
ciKlass* get_klass_by_name_impl(ciKlass* accessing_klass,
ciSymbol* klass_name,
bool require_local);
ciKlass* get_klass_by_index_impl(ciInstanceKlass* loading_klass,
ciKlass* get_klass_by_index_impl(constantPoolHandle cpool,
int klass_index,
bool& is_accessible);
ciConstant get_constant_by_index_impl(ciInstanceKlass* loading_klass,
int constant_index);
bool& is_accessible,
ciInstanceKlass* loading_klass);
ciConstant get_constant_by_index_impl(constantPoolHandle cpool,
int constant_index,
ciInstanceKlass* loading_klass);
bool is_unresolved_string_impl (instanceKlass* loading_klass,
int constant_index) const;
bool is_unresolved_klass_impl (instanceKlass* loading_klass,
int constant_index) const;
ciField* get_field_by_index_impl(ciInstanceKlass* loading_klass,
int field_index);
ciMethod* get_method_by_index_impl(ciInstanceKlass* loading_klass,
int method_index, Bytecodes::Code bc);
ciMethod* get_fake_invokedynamic_method_impl(ciInstanceKlass* accessor,
ciMethod* get_method_by_index_impl(constantPoolHandle cpool,
int method_index, Bytecodes::Code bc,
ciInstanceKlass* loading_klass);
ciMethod* get_fake_invokedynamic_method_impl(constantPoolHandle cpool,
int index, Bytecodes::Code bc);
// Helper methods

View File

@ -1,5 +1,5 @@
/*
* Copyright 1999-2003 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -34,12 +34,16 @@
//
// Get the exception klass that this handler catches.
ciInstanceKlass* ciExceptionHandler::catch_klass() {
VM_ENTRY_MARK;
assert(!is_catch_all(), "bad index");
if (_catch_klass == NULL) {
bool will_link;
ciKlass* k = CURRENT_ENV->get_klass_by_index(_loading_klass,
assert(_loading_klass->get_instanceKlass()->is_linked(), "must be linked before accessing constant pool");
constantPoolHandle cpool(_loading_klass->get_instanceKlass()->constants());
ciKlass* k = CURRENT_ENV->get_klass_by_index(cpool,
_catch_klass_index,
will_link);
will_link,
_loading_klass);
if (!will_link && k->is_loaded()) {
GUARDED_VM_ENTRY(
k = CURRENT_ENV->get_unloaded_klass(_loading_klass, k->name());

View File

@ -1,5 +1,5 @@
/*
* Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -86,7 +86,7 @@ ciField::ciField(ciInstanceKlass* klass, int index): _known_to_link_with(NULL) {
bool ignore;
// This is not really a class reference; the index always refers to the
// field's type signature, as a symbol. Linkage checks do not apply.
_type = ciEnv::current(thread)->get_klass_by_index(klass, sig_index, ignore);
_type = ciEnv::current(thread)->get_klass_by_index(cpool, sig_index, ignore, klass);
} else {
_type = ciType::make(field_type);
}
@ -100,9 +100,9 @@ ciField::ciField(ciInstanceKlass* klass, int index): _known_to_link_with(NULL) {
int holder_index = cpool->klass_ref_index_at(index);
bool holder_is_accessible;
ciInstanceKlass* declared_holder =
ciEnv::current(thread)->get_klass_by_index(klass, holder_index,
holder_is_accessible)
->as_instance_klass();
ciEnv::current(thread)->get_klass_by_index(cpool, holder_index,
holder_is_accessible,
klass)->as_instance_klass();
// The declared holder of this field may not have been loaded.
// Bail out with partial field information.
@ -168,8 +168,18 @@ void ciField::initialize_from(fieldDescriptor* fd) {
_holder = CURRENT_ENV->get_object(fd->field_holder())->as_instance_klass();
// Check to see if the field is constant.
if (_holder->is_initialized() &&
this->is_final() && this->is_static()) {
if (_holder->is_initialized() && this->is_final()) {
if (!this->is_static()) {
// A field can be constant if it's a final static field or if it's
// a final non-static field of a trusted class ({java,sun}.dyn).
if (_holder->is_in_package("java/dyn") || _holder->is_in_package("sun/dyn")) {
_is_constant = true;
return;
}
_is_constant = false;
return;
}
// This field just may be constant. The only cases where it will
// not be constant are:
//

View File

@ -138,10 +138,18 @@ public:
// Get the constant value of this field.
ciConstant constant_value() {
assert(is_constant(), "illegal call to constant_value()");
assert(is_static() && is_constant(), "illegal call to constant_value()");
return _constant_value;
}
// Get the constant value of non-static final field in the given
// object.
ciConstant constant_value_of(ciObject* object) {
assert(!is_static() && is_constant(), "only if field is non-static constant");
assert(object->is_instance(), "must be instance");
return object->as_instance()->field_value(this);
}
// Check for link time errors. Accessing a field from a
// certain class via a certain bytecode may or may not be legal.
// This call checks to see if an exception may be raised by

View File

@ -232,8 +232,48 @@ bool ciInstanceKlass::is_java_lang_Object() {
// ------------------------------------------------------------------
// ciInstanceKlass::uses_default_loader
bool ciInstanceKlass::uses_default_loader() {
VM_ENTRY_MARK;
return loader() == NULL;
// Note: We do not need to resolve the handle or enter the VM
// in order to test null-ness.
return _loader == NULL;
}
// ------------------------------------------------------------------
// ciInstanceKlass::is_in_package
//
// Is this klass in the given package?
bool ciInstanceKlass::is_in_package(const char* packagename, int len) {
// To avoid class loader mischief, this test always rejects application classes.
if (!uses_default_loader())
return false;
GUARDED_VM_ENTRY(
return is_in_package_impl(packagename, len);
)
}
bool ciInstanceKlass::is_in_package_impl(const char* packagename, int len) {
ASSERT_IN_VM;
// If packagename contains trailing '/' exclude it from the
// prefix-test since we test for it explicitly.
if (packagename[len - 1] == '/')
len--;
if (!name()->starts_with(packagename, len))
return false;
// Test if the class name is something like "java/lang".
if ((len + 1) > name()->utf8_length())
return false;
// Test for trailing '/'
if ((char) name()->byte_at(len) != '/')
return false;
// Make sure it's not actually in a subpackage:
if (name()->index_of_at(len+1, "/", 1) >= 0)
return false;
return true;
}
// ------------------------------------------------------------------

View File

@ -29,10 +29,11 @@
// be loaded.
class ciInstanceKlass : public ciKlass {
CI_PACKAGE_ACCESS
friend class ciBytecodeStream;
friend class ciEnv;
friend class ciExceptionHandler;
friend class ciMethod;
friend class ciField;
friend class ciBytecodeStream;
private:
jobject _loader;
@ -78,6 +79,8 @@ protected:
const char* type_string() { return "ciInstanceKlass"; }
bool is_in_package_impl(const char* packagename, int len);
void print_impl(outputStream* st);
ciConstantPoolCache* field_cache();
@ -196,6 +199,12 @@ public:
bool is_java_lang_Object();
// Is this klass in the given package?
bool is_in_package(const char* packagename) {
return is_in_package(packagename, (int) strlen(packagename));
}
bool is_in_package(const char* packagename, int len);
// What kind of ciObject is this?
bool is_instance_klass() { return true; }
bool is_java_klass() { return true; }

View File

@ -1,5 +1,5 @@
/*
* Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it

View File

@ -1,5 +1,5 @@
/*
* Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -69,7 +69,7 @@ public:
ciKlass(KlassHandle k_h);
// What is the name of this klass?
ciSymbol* name() { return _name; }
ciSymbol* name() const { return _name; }
// What is its layout helper value?
jint layout_helper() { return _layout_helper; }

View File

@ -38,6 +38,8 @@ class ciMethod : public ciObject {
CI_PACKAGE_ACCESS
friend class ciEnv;
friend class ciExceptionHandlerStream;
friend class ciBytecodeStream;
friend class ciMethodHandle;
private:
// General method information.
@ -251,4 +253,10 @@ class ciMethod : public ciObject {
// Print the name of this method in various incarnations.
void print_name(outputStream* st = tty);
void print_short_name(outputStream* st = tty);
methodOop get_method_handle_target() {
klassOop receiver_limit_oop = NULL;
int flags = 0;
return MethodHandles::decode_method(get_oop(), receiver_limit_oop, flags);
}
};

View File

@ -0,0 +1,52 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
#include "incls/_precompiled.incl"
#include "incls/_ciMethodHandle.cpp.incl"
// ciMethodHandle
// ------------------------------------------------------------------
// ciMethodHandle::get_adapter
//
// Return an adapter for this MethodHandle.
ciMethod* ciMethodHandle::get_adapter(bool is_invokedynamic) const {
VM_ENTRY_MARK;
Handle h(get_oop());
methodHandle callee(_callee->get_methodOop());
MethodHandleCompiler mhc(h, callee, is_invokedynamic, THREAD);
methodHandle m = mhc.compile(CHECK_NULL);
return CURRENT_ENV->get_object(m())->as_method();
}
// ------------------------------------------------------------------
// ciMethodHandle::print_impl
//
// Implementation of the print method.
void ciMethodHandle::print_impl(outputStream* st) {
st->print(" type=");
get_oop()->print();
}

View File

@ -0,0 +1,56 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
// ciMethodHandle
//
// The class represents a java.dyn.MethodHandle object.
class ciMethodHandle : public ciInstance {
private:
ciMethod* _callee;
// Return an adapter for this MethodHandle.
ciMethod* get_adapter(bool is_invokedynamic) const;
protected:
void print_impl(outputStream* st);
public:
ciMethodHandle(instanceHandle h_i) : ciInstance(h_i) {};
// What kind of ciObject is this?
bool is_method_handle() const { return true; }
ciMethod* callee() const { return _callee; }
void set_callee(ciMethod* m) { _callee = m; }
// Return an adapter for a MethodHandle call.
ciMethod* get_method_handle_adapter() const {
return get_adapter(false);
}
// Return an adapter for an invokedynamic call.
ciMethod* get_invokedynamic_adapter() const {
return get_adapter(true);
}
};

View File

@ -131,10 +131,12 @@ public:
// What kind of ciObject is this?
virtual bool is_null_object() const { return false; }
virtual bool is_call_site() const { return false; }
virtual bool is_cpcache() const { return false; }
virtual bool is_instance() { return false; }
virtual bool is_method() { return false; }
virtual bool is_method_data() { return false; }
virtual bool is_method_handle() const { return false; }
virtual bool is_array() { return false; }
virtual bool is_obj_array() { return false; }
virtual bool is_type_array() { return false; }
@ -186,6 +188,10 @@ public:
assert(is_null_object(), "bad cast");
return (ciNullObject*)this;
}
ciCallSite* as_call_site() {
assert(is_call_site(), "bad cast");
return (ciCallSite*) this;
}
ciCPCache* as_cpcache() {
assert(is_cpcache(), "bad cast");
return (ciCPCache*) this;
@ -202,6 +208,10 @@ public:
assert(is_method_data(), "bad cast");
return (ciMethodData*)this;
}
ciMethodHandle* as_method_handle() {
assert(is_method_handle(), "bad cast");
return (ciMethodHandle*) this;
}
ciArray* as_array() {
assert(is_array(), "bad cast");
return (ciArray*)this;

View File

@ -337,7 +337,12 @@ ciObject* ciObjectFactory::create_new_object(oop o) {
return new (arena()) ciMethodData(h_md);
} else if (o->is_instance()) {
instanceHandle h_i(THREAD, (instanceOop)o);
return new (arena()) ciInstance(h_i);
if (java_dyn_CallSite::is_instance(o))
return new (arena()) ciCallSite(h_i);
else if (java_dyn_MethodHandle::is_instance(o))
return new (arena()) ciMethodHandle(h_i);
else
return new (arena()) ciInstance(h_i);
} else if (o->is_objArray()) {
objArrayHandle h_oa(THREAD, (objArrayOop)o);
return new (arena()) ciObjArray(h_oa);

View File

@ -186,8 +186,9 @@ int ciBytecodeStream::get_klass_index() const {
// If this bytecode is a new, newarray, multianewarray, instanceof,
// or checkcast, get the referenced klass.
ciKlass* ciBytecodeStream::get_klass(bool& will_link) {
return CURRENT_ENV->get_klass_by_index(_holder, get_klass_index(),
will_link);
VM_ENTRY_MARK;
constantPoolHandle cpool(_method->get_methodOop()->constants());
return CURRENT_ENV->get_klass_by_index(cpool, get_klass_index(), will_link, _holder);
}
// ------------------------------------------------------------------
@ -213,7 +214,9 @@ int ciBytecodeStream::get_constant_index() const {
// If this bytecode is one of the ldc variants, get the referenced
// constant.
ciConstant ciBytecodeStream::get_constant() {
return CURRENT_ENV->get_constant_by_index(_holder, get_constant_index());
VM_ENTRY_MARK;
constantPoolHandle cpool(_method->get_methodOop()->constants());
return CURRENT_ENV->get_constant_by_index(cpool, get_constant_index(), _holder);
}
// ------------------------------------------------------------------
@ -264,9 +267,11 @@ ciField* ciBytecodeStream::get_field(bool& will_link) {
// There is no "will_link" result passed back. The user is responsible
// for checking linkability when retrieving the associated field.
ciInstanceKlass* ciBytecodeStream::get_declared_field_holder() {
VM_ENTRY_MARK;
constantPoolHandle cpool(_method->get_methodOop()->constants());
int holder_index = get_field_holder_index();
bool ignore;
return CURRENT_ENV->get_klass_by_index(_holder, holder_index, ignore)
return CURRENT_ENV->get_klass_by_index(cpool, holder_index, ignore, _holder)
->as_instance_klass();
}
@ -277,9 +282,10 @@ ciInstanceKlass* ciBytecodeStream::get_declared_field_holder() {
// referenced by the current bytecode. Used for generating
// deoptimization information.
int ciBytecodeStream::get_field_holder_index() {
VM_ENTRY_MARK;
constantPoolOop cpool = _holder->get_instanceKlass()->constants();
return cpool->klass_ref_index_at(get_field_index());
GUARDED_VM_ENTRY(
constantPoolOop cpool = _holder->get_instanceKlass()->constants();
return cpool->klass_ref_index_at(get_field_index());
)
}
// ------------------------------------------------------------------
@ -321,7 +327,9 @@ int ciBytecodeStream::get_method_index() {
//
// If this is a method invocation bytecode, get the invoked method.
ciMethod* ciBytecodeStream::get_method(bool& will_link) {
ciMethod* m = CURRENT_ENV->get_method_by_index(_holder, get_method_index(), cur_bc());
VM_ENTRY_MARK;
constantPoolHandle cpool(_method->get_methodOop()->constants());
ciMethod* m = CURRENT_ENV->get_method_by_index(cpool, get_method_index(), cur_bc(), _holder);
will_link = m->is_loaded();
return m;
}
@ -338,11 +346,13 @@ ciMethod* ciBytecodeStream::get_method(bool& will_link) {
// There is no "will_link" result passed back. The user is responsible
// for checking linkability when retrieving the associated method.
ciKlass* ciBytecodeStream::get_declared_method_holder() {
VM_ENTRY_MARK;
constantPoolHandle cpool(_method->get_methodOop()->constants());
bool ignore;
// report as InvokeDynamic for invokedynamic, which is syntactically classless
if (cur_bc() == Bytecodes::_invokedynamic)
return CURRENT_ENV->get_klass_by_name(_holder, ciSymbol::java_dyn_InvokeDynamic(), false);
return CURRENT_ENV->get_klass_by_index(_holder, get_method_holder_index(), ignore);
return CURRENT_ENV->get_klass_by_index(cpool, get_method_holder_index(), ignore, _holder);
}
// ------------------------------------------------------------------
@ -352,8 +362,7 @@ ciKlass* ciBytecodeStream::get_declared_method_holder() {
// referenced by the current bytecode. Used for generating
// deoptimization information.
int ciBytecodeStream::get_method_holder_index() {
VM_ENTRY_MARK;
constantPoolOop cpool = _holder->get_instanceKlass()->constants();
constantPoolOop cpool = _method->get_methodOop()->constants();
return cpool->klass_ref_index_at(get_method_index());
}
@ -381,3 +390,20 @@ ciCPCache* ciBytecodeStream::get_cpcache() {
return CURRENT_ENV->get_object(cpcache)->as_cpcache();
}
// ------------------------------------------------------------------
// ciBytecodeStream::get_call_site
ciCallSite* ciBytecodeStream::get_call_site() {
VM_ENTRY_MARK;
// Get the constant pool.
constantPoolOop cpool = _holder->get_instanceKlass()->constants();
constantPoolCacheOop cpcache = cpool->cache();
// Get the CallSite from the constant pool cache.
int method_index = get_method_index();
ConstantPoolCacheEntry* cpcache_entry = cpcache->secondary_entry_at(method_index);
oop call_site_oop = cpcache_entry->f1();
// Create a CallSite object and return it.
return CURRENT_ENV->get_object(call_site_oop)->as_call_site();
}

View File

@ -232,7 +232,8 @@ public:
int get_method_holder_index();
int get_method_signature_index();
ciCPCache* get_cpcache();
ciCPCache* get_cpcache();
ciCallSite* get_call_site();
private:
void assert_index_size(int required_size) const {

View File

@ -1,5 +1,5 @@
/*
* Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -59,6 +59,22 @@ int ciSymbol::byte_at(int i) {
GUARDED_VM_ENTRY(return get_symbolOop()->byte_at(i);)
}
// ------------------------------------------------------------------
// ciSymbol::starts_with
//
// Tests if the symbol starts with the given prefix.
bool ciSymbol::starts_with(const char* prefix, int len) const {
GUARDED_VM_ENTRY(return get_symbolOop()->starts_with(prefix, len);)
}
// ------------------------------------------------------------------
// ciSymbol::index_of
//
// Determines where the symbol contains the given substring.
int ciSymbol::index_of_at(int i, const char* str, int len) const {
GUARDED_VM_ENTRY(return get_symbolOop()->index_of_at(i, str, len);)
}
// ------------------------------------------------------------------
// ciSymbol::utf8_length
int ciSymbol::utf8_length() {

View File

@ -1,5 +1,5 @@
/*
* Copyright 1999-2001 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -28,6 +28,7 @@
// machine.
class ciSymbol : public ciObject {
CI_PACKAGE_ACCESS
// These friends all make direct use of get_symbolOop:
friend class ciEnv;
friend class ciInstanceKlass;
friend class ciSignature;
@ -38,13 +39,13 @@ private:
ciSymbol(symbolOop s) : ciObject(s) {}
ciSymbol(symbolHandle s); // for use with vmSymbolHandles
symbolOop get_symbolOop() { return (symbolOop)get_oop(); }
symbolOop get_symbolOop() const { return (symbolOop)get_oop(); }
const char* type_string() { return "ciSymbol"; }
void print_impl(outputStream* st);
int byte_at(int i);
// This is public in symbolOop but private here, because the base can move:
jbyte* base();
// Make a ciSymbol from a C string (implementation).
@ -55,6 +56,15 @@ public:
const char* as_utf8();
int utf8_length();
// Return the i-th utf8 byte, where i < utf8_length
int byte_at(int i);
// Tests if the symbol starts with the given prefix.
bool starts_with(const char* prefix, int len) const;
// Determines where the symbol contains the given substring.
int index_of_at(int i, const char* str, int len) const;
// What kind of ciObject is this?
bool is_symbol() { return true; }

View File

@ -643,7 +643,7 @@ void ClassFileParser::verify_constantvalue(int constantvalue_index, int signatur
guarantee_property(value_type.is_int(), "Inconsistent constant value type in class file %s", CHECK);
break;
case T_OBJECT:
guarantee_property((cp->symbol_at(signature_index)->equals("Ljava/lang/String;", 18)
guarantee_property((cp->symbol_at(signature_index)->equals("Ljava/lang/String;")
&& (value_type.is_string() || value_type.is_unresolved_string())),
"Bad string initial value in class file %s", CHECK);
break;
@ -1718,9 +1718,7 @@ methodHandle ClassFileParser::parse_method(constantPoolHandle cp, bool is_interf
m->set_exception_table(exception_handlers());
// Copy byte codes
if (code_length > 0) {
memcpy(m->code_base(), code_start, code_length);
}
m->set_code(code_start);
// Copy line number table
if (linenumber_table != NULL) {

View File

@ -299,6 +299,20 @@ vmIntrinsics::ID vmIntrinsics::for_unboxing(BasicType type) {
return wrapper_intrinsic(type, true);
}
vmIntrinsics::ID vmIntrinsics::for_raw_conversion(BasicType src, BasicType dest) {
#define SRC_DEST(s,d) (((int)(s) << 4) + (int)(d))
switch (SRC_DEST(src, dest)) {
case SRC_DEST(T_INT, T_FLOAT): return vmIntrinsics::_intBitsToFloat;
case SRC_DEST(T_FLOAT, T_INT): return vmIntrinsics::_floatToRawIntBits;
case SRC_DEST(T_LONG, T_DOUBLE): return vmIntrinsics::_longBitsToDouble;
case SRC_DEST(T_DOUBLE, T_LONG): return vmIntrinsics::_doubleToRawLongBits;
}
#undef SRC_DEST
return vmIntrinsics::_none;
}
methodOop vmIntrinsics::method_for(vmIntrinsics::ID id) {
if (id == _none) return NULL;
symbolOop cname = vmSymbols::symbol_at(class_for(id));

View File

@ -1084,4 +1084,7 @@ public:
// Wrapper object methods:
static ID for_boxing(BasicType type);
static ID for_unboxing(BasicType type);
// Raw conversion:
static ID for_raw_conversion(BasicType src, BasicType dest);
};

View File

@ -1724,9 +1724,9 @@ void nmethod::preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map
if (!method()->is_native()) {
SimpleScopeDesc ssd(this, fr.pc());
Bytecode_invoke* call = Bytecode_invoke_at(ssd.method(), ssd.bci());
bool is_static = call->is_invokestatic();
bool has_receiver = call->has_receiver();
symbolOop signature = call->signature();
fr.oops_compiled_arguments_do(signature, is_static, reg_map, f);
fr.oops_compiled_arguments_do(signature, has_receiver, reg_map, f);
}
}

View File

@ -156,6 +156,8 @@ callGenerator.cpp cfgnode.hpp
callGenerator.cpp compileLog.hpp
callGenerator.cpp connode.hpp
callGenerator.cpp ciCPCache.hpp
callGenerator.cpp ciMethodHandle.hpp
callGenerator.cpp javaClasses.hpp
callGenerator.cpp parse.hpp
callGenerator.cpp rootnode.hpp
callGenerator.cpp runtime.hpp
@ -392,6 +394,9 @@ divnode.hpp type.hpp
doCall.cpp addnode.hpp
doCall.cpp callGenerator.hpp
doCall.cpp ciCallSite.hpp
doCall.cpp ciCPCache.hpp
doCall.cpp ciMethodHandle.hpp
doCall.cpp cfgnode.hpp
doCall.cpp compileLog.hpp
doCall.cpp linkResolver.hpp

View File

@ -516,6 +516,11 @@ ciArrayKlassKlass.hpp ciKlassKlass.hpp
ciCallProfile.hpp ciClassList.hpp
ciCallSite.cpp ciCallSite.hpp
ciCallSite.cpp ciUtilities.hpp
ciCallSite.hpp ciInstance.hpp
ciConstant.cpp allocation.hpp
ciConstant.cpp allocation.inline.hpp
ciConstant.cpp ciConstant.hpp
@ -599,6 +604,7 @@ ciField.cpp universe.inline.hpp
ciField.hpp ciClassList.hpp
ciField.hpp ciConstant.hpp
ciField.hpp ciFlags.hpp
ciField.hpp ciInstance.hpp
ciFlags.cpp ciFlags.hpp
@ -685,6 +691,7 @@ ciMethod.hpp ciFlags.hpp
ciMethod.hpp ciInstanceKlass.hpp
ciMethod.hpp ciObject.hpp
ciMethod.hpp ciSignature.hpp
ciMethod.hpp methodHandles.hpp
ciMethod.hpp methodLiveness.hpp
ciMethodBlocks.cpp bytecode.hpp
@ -716,6 +723,15 @@ ciMethodKlass.cpp ciUtilities.hpp
ciMethodKlass.hpp ciKlass.hpp
ciMethodKlass.hpp ciSymbol.hpp
ciMethodHandle.cpp ciClassList.hpp
ciMethodHandle.cpp ciInstance.hpp
ciMethodHandle.cpp ciMethodHandle.hpp
ciMethodHandle.cpp ciUtilities.hpp
ciMethodHandle.cpp methodHandles.hpp
ciMethodHandle.cpp methodHandleWalk.hpp
ciMethodHandle.hpp methodHandles.hpp
ciNullObject.cpp ciNullObject.hpp
ciNullObject.hpp ciClassList.hpp
@ -761,12 +777,14 @@ ciObject.hpp handles.hpp
ciObject.hpp jniHandles.hpp
ciObjectFactory.cpp allocation.inline.hpp
ciObjectFactory.cpp ciCallSite.hpp
ciObjectFactory.cpp ciCPCache.hpp
ciObjectFactory.cpp ciInstance.hpp
ciObjectFactory.cpp ciInstanceKlass.hpp
ciObjectFactory.cpp ciInstanceKlassKlass.hpp
ciObjectFactory.cpp ciMethod.hpp
ciObjectFactory.cpp ciMethodData.hpp
ciObjectFactory.cpp ciMethodHandle.hpp
ciObjectFactory.cpp ciMethodKlass.hpp
ciObjectFactory.cpp ciNullObject.hpp
ciObjectFactory.cpp ciObjArray.hpp
@ -800,6 +818,7 @@ ciSignature.hpp ciSymbol.hpp
ciSignature.hpp globalDefinitions.hpp
ciSignature.hpp growableArray.hpp
ciStreams.cpp ciCallSite.hpp
ciStreams.cpp ciConstant.hpp
ciStreams.cpp ciField.hpp
ciStreams.cpp ciStreams.hpp
@ -2824,6 +2843,8 @@ methodDataOop.hpp universe.hpp
methodHandleWalk.hpp methodHandles.hpp
methodHandleWalk.cpp methodHandleWalk.hpp
methodHandleWalk.cpp oopFactory.hpp
methodHandleWalk.cpp rewriter.hpp
methodHandles.hpp frame.inline.hpp
methodHandles.hpp globals.hpp

View File

@ -205,6 +205,7 @@ class Bytecode_invoke: public ResourceObj {
bool is_invokespecial() const { return adjusted_invoke_code() == Bytecodes::_invokespecial; }
bool is_invokedynamic() const { return adjusted_invoke_code() == Bytecodes::_invokedynamic; }
bool has_receiver() const { return !is_invokestatic() && !is_invokedynamic(); }
bool has_giant_index() const { return is_invokedynamic(); }
bool is_valid() const { return is_invokeinterface() ||

View File

@ -270,6 +270,8 @@ void BytecodePrinter::print_constant(int i, outputStream* st) {
st->print_cr(" %s", constants->resolved_klass_at(i)->klass_part()->external_name());
} else if (tag.is_unresolved_klass()) {
st->print_cr(" <unresolved klass at %d>", i);
} else if (tag.is_object()) {
st->print_cr(" " PTR_FORMAT, constants->object_at(i));
} else {
st->print_cr(" bad tag=%d at %d", tag.value(), i);
}

View File

@ -1250,7 +1250,7 @@ IRT_LEAF(void, InterpreterRuntime::popframe_move_outgoing_args(JavaThread* threa
methodHandle mh(thread, fr.interpreter_frame_method());
Bytecode_invoke* invoke = Bytecode_invoke_at(mh, bci);
ArgumentSizeComputer asc(invoke->signature());
int size_of_arguments = (asc.size() + (invoke->is_invokestatic() ? 0 : 1)); // receiver
int size_of_arguments = (asc.size() + (invoke->has_receiver() ? 1 : 0)); // receiver
Copy::conjoint_bytes(src_address, dest_address,
size_of_arguments * Interpreter::stackElementSize());
IRT_END

View File

@ -247,15 +247,22 @@ methodHandle Rewriter::rewrite_jsrs(methodHandle method, TRAPS) {
void Rewriter::rewrite(instanceKlassHandle klass, TRAPS) {
ResourceMark rm(THREAD);
Rewriter rw(klass, CHECK);
Rewriter rw(klass, klass->constants(), klass->methods(), CHECK);
// (That's all, folks.)
}
Rewriter::Rewriter(instanceKlassHandle klass, TRAPS)
void Rewriter::rewrite(instanceKlassHandle klass, constantPoolHandle cpool, objArrayHandle methods, TRAPS) {
ResourceMark rm(THREAD);
Rewriter rw(klass, cpool, methods, CHECK);
// (That's all, folks.)
}
Rewriter::Rewriter(instanceKlassHandle klass, constantPoolHandle cpool, objArrayHandle methods, TRAPS)
: _klass(klass),
// gather starting points
_pool( THREAD, klass->constants()),
_methods(THREAD, klass->methods())
_pool(cpool),
_methods(methods)
{
assert(_pool->cache() == NULL, "constant pool cache must not be set yet");

View File

@ -57,7 +57,7 @@ class Rewriter: public StackObj {
}
// All the work goes in here:
Rewriter(instanceKlassHandle klass, TRAPS);
Rewriter(instanceKlassHandle klass, constantPoolHandle cpool, objArrayHandle methods, TRAPS);
void compute_index_maps();
void make_constant_pool_cache(TRAPS);
@ -70,6 +70,7 @@ class Rewriter: public StackObj {
public:
// Driver routine:
static void rewrite(instanceKlassHandle klass, TRAPS);
static void rewrite(instanceKlassHandle klass, constantPoolHandle cpool, objArrayHandle methods, TRAPS);
enum {
_secondary_entry_tag = nth_bit(30)

View File

@ -258,6 +258,11 @@ public:
LocalVariableTableElement* localvariable_table_start() const;
// byte codes
void set_code(address code) {
if (code_size() > 0) {
memcpy(code_base(), code, code_size());
}
}
address code_base() const { return (address) (this+1); }
address code_end() const { return code_base() + code_size(); }
bool contains(address bcp) const { return code_base() <= bcp

View File

@ -191,6 +191,16 @@ class constantPoolOopDesc : public oopDesc {
}
}
void object_at_put(int which, oop str) {
oop_store((volatile oop*) obj_at_addr(which), str);
release_tag_at_put(which, JVM_CONSTANT_Object);
if (UseConcMarkSweepGC) {
// In case the earlier card-mark was consumed by a concurrent
// marking thread before the tag was updated, redirty the card.
oop_store_without_check((volatile oop*) obj_at_addr(which), str);
}
}
// For temporary use while constructing constant pool
void string_index_at_put(int which, int string_index) {
tag_at_put(which, JVM_CONSTANT_StringIndex);
@ -228,7 +238,8 @@ class constantPoolOopDesc : public oopDesc {
tag.is_unresolved_klass() ||
tag.is_symbol() ||
tag.is_unresolved_string() ||
tag.is_string();
tag.is_string() ||
tag.is_object();
}
// Fetching constants
@ -291,6 +302,11 @@ class constantPoolOopDesc : public oopDesc {
return string_at_impl(h_this, which, CHECK_NULL);
}
oop object_at(int which) {
assert(tag_at(which).is_object(), "Corrupted constant pool");
return *obj_at_addr(which);
}
// A "pseudo-string" is an non-string oop that has found is way into
// a String entry.
// Under AnonymousClasses this can happen if the user patches a live

View File

@ -1556,13 +1556,13 @@ void GenerateOopMap::interp1(BytecodeStream *itr) {
case Bytecodes::_getfield: do_field(true, false, itr->get_index_big(), itr->bci()); break;
case Bytecodes::_putfield: do_field(false, false, itr->get_index_big(), itr->bci()); break;
case Bytecodes::_invokevirtual:
case Bytecodes::_invokespecial: do_method(false, false, itr->get_index_big(), itr->bci()); break;
case Bytecodes::_invokestatic: do_method(true, false, itr->get_index_big(), itr->bci()); break;
case Bytecodes::_invokevirtual:
case Bytecodes::_invokespecial: do_method(false, false, itr->get_index_big(), itr->bci()); break;
case Bytecodes::_invokestatic: do_method(true, false, itr->get_index_big(), itr->bci()); break;
case Bytecodes::_invokedynamic: do_method(true, false, itr->get_index_int(), itr->bci()); break;
case Bytecodes::_invokeinterface: do_method(false, true, itr->get_index_big(), itr->bci()); break;
case Bytecodes::_newarray:
case Bytecodes::_anewarray: pp_new_ref(vCTS, itr->bci()); break;
case Bytecodes::_invokeinterface: do_method(false, true, itr->get_index_big(), itr->bci()); break;
case Bytecodes::_newarray:
case Bytecodes::_anewarray: pp_new_ref(vCTS, itr->bci()); break;
case Bytecodes::_checkcast: do_checkcast(); break;
case Bytecodes::_arraylength:
case Bytecodes::_instanceof: pp(rCTS, vCTS); break;
@ -1830,12 +1830,8 @@ void GenerateOopMap::do_jsr(int targ_bci) {
void GenerateOopMap::do_ldc(int idx, int bci) {
constantPoolOop cp = method()->constants();
constantTag tag = cp->tag_at(idx);
CellTypeState cts = (tag.is_string() || tag.is_unresolved_string() ||
tag.is_klass() || tag.is_unresolved_klass())
? CellTypeState::make_line_ref(bci) : valCTS;
constantPoolOop cp = method()->constants();
CellTypeState cts = cp->is_pointer_entry(idx) ? CellTypeState::make_line_ref(bci) : valCTS;
ppush1(cts);
}

View File

@ -365,6 +365,7 @@ class methodOopDesc : public oopDesc {
#endif
// byte codes
void set_code(address code) { return constMethod()->set_code(code); }
address code_base() const { return constMethod()->code_base(); }
bool contains(address bcp) const { return constMethod()->contains(bcp); }

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,6 +25,11 @@
# include "incls/_precompiled.incl"
# include "incls/_symbolOop.cpp.incl"
// ------------------------------------------------------------------
// symbolOopDesc::equals
//
// Compares the symbol with a string of the given length.
bool symbolOopDesc::equals(const char* str, int len) const {
int l = utf8_length();
if (l != len) return false;
@ -36,6 +41,48 @@ bool symbolOopDesc::equals(const char* str, int len) const {
return true;
}
// ------------------------------------------------------------------
// symbolOopDesc::starts_with
//
// Tests if the symbol starts with the specified prefix of the given
// length.
bool symbolOopDesc::starts_with(const char* prefix, int len) const {
if (len > utf8_length()) return false;
while (len-- > 0) {
if (prefix[len] != (char) byte_at(len))
return false;
}
assert(len == -1, "we should be at the beginning");
return true;
}
// ------------------------------------------------------------------
// symbolOopDesc::index_of
//
// Finds if the given string is a substring of this symbol's utf8 bytes.
// Return -1 on failure. Otherwise return the first index where str occurs.
int symbolOopDesc::index_of_at(int i, const char* str, int len) const {
assert(i >= 0 && i <= utf8_length(), "oob");
if (len <= 0) return 0;
char first_char = str[0];
address bytes = (address) ((symbolOopDesc*)this)->base();
address limit = bytes + utf8_length() - len; // inclusive limit
address scan = bytes + i;
if (scan > limit)
return -1;
for (;;) {
scan = (address) memchr(scan, first_char, (limit + 1 - scan));
if (scan == NULL)
return -1; // not found
assert(scan >= bytes+i && scan <= limit, "scan oob");
if (memcmp(scan, str, len) == 0)
return (int)(scan - bytes);
}
}
char* symbolOopDesc::as_C_string(char* buf, int size) const {
if (size > 0) {
int len = MIN2(size - 1, utf8_length());

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -70,8 +70,21 @@ class symbolOopDesc : public oopDesc {
void set_utf8_length(int len) { _length = len; }
// Compares the symbol with a string
// Compares the symbol with a string.
bool equals(const char* str, int len) const;
bool equals(const char* str) const { return equals(str, (int) strlen(str)); }
// Tests if the symbol starts with the given prefix.
bool starts_with(const char* prefix, int len) const;
bool starts_with(const char* prefix) const {
return starts_with(prefix, (int) strlen(prefix));
}
// Tests if the symbol starts with the given prefix.
int index_of_at(int i, const char* str, int len) const;
int index_of_at(int i, const char* str) const {
return index_of_at(i, str, (int) strlen(str));
}
// Three-way compare for sorting; returns -1/0/1 if receiver is </==/> than arg
// note that the ordering is not alfabetical

View File

@ -180,6 +180,10 @@ const char* InlineTree::shouldNotInline(ciMethod *callee_method, ciMethod* calle
return NULL;
}
// Always inline MethodHandle methods.
if (callee_method->is_method_handle_invoke())
return NULL;
// First check all inlining restrictions which are required for correctness
if (callee_method->is_abstract()) return "abstract method";
// note: we allow ik->is_abstract()

View File

@ -148,7 +148,7 @@ JVMState* DirectCallGenerator::generate(JVMState* jvms) {
}
//---------------------------DynamicCallGenerator-----------------------------
// Internal class which handles all out-of-line dynamic calls.
// Internal class which handles all out-of-line invokedynamic calls.
class DynamicCallGenerator : public CallGenerator {
public:
DynamicCallGenerator(ciMethod* method)
@ -179,25 +179,25 @@ JVMState* DynamicCallGenerator::generate(JVMState* jvms) {
// Load the CallSite object from the constant pool cache.
const TypeOopPtr* cpcache_ptr = TypeOopPtr::make_from_constant(cpcache);
Node* cpc = kit.makecon(cpcache_ptr);
Node* adr = kit.basic_plus_adr(cpc, cpc, call_site_offset);
Node* call_site = kit.make_load(kit.control(), adr, TypeInstPtr::BOTTOM, T_OBJECT, Compile::AliasIdxRaw);
Node* cpcache_adr = kit.makecon(cpcache_ptr);
Node* call_site_adr = kit.basic_plus_adr(cpcache_adr, cpcache_adr, call_site_offset);
Node* call_site = kit.make_load(kit.control(), call_site_adr, TypeInstPtr::BOTTOM, T_OBJECT, Compile::AliasIdxRaw);
// Load the MethodHandle (target) from the CallSite object.
Node* mh_adr = kit.basic_plus_adr(call_site, call_site, java_dyn_CallSite::target_offset_in_bytes());
Node* mh = kit.make_load(kit.control(), mh_adr, TypeInstPtr::BOTTOM, T_OBJECT);
// Load the target MethodHandle from the CallSite object.
Node* target_mh_adr = kit.basic_plus_adr(call_site, call_site, java_dyn_CallSite::target_offset_in_bytes());
Node* target_mh = kit.make_load(kit.control(), target_mh_adr, TypeInstPtr::BOTTOM, T_OBJECT);
address stub = SharedRuntime::get_resolve_opt_virtual_call_stub();
address resolve_stub = SharedRuntime::get_resolve_opt_virtual_call_stub();
CallStaticJavaNode *call = new (kit.C, tf()->domain()->cnt()) CallStaticJavaNode(tf(), stub, method(), kit.bci());
CallStaticJavaNode *call = new (kit.C, tf()->domain()->cnt()) CallStaticJavaNode(tf(), resolve_stub, method(), kit.bci());
// invokedynamic is treated as an optimized invokevirtual.
call->set_optimized_virtual(true);
// Take extra care (in the presence of argument motion) not to trash the SP:
call->set_method_handle_invoke(true);
// Pass the MethodHandle as first argument and shift the other
// arguments.
call->init_req(0 + TypeFunc::Parms, mh);
// Pass the target MethodHandle as first argument and shift the
// other arguments.
call->init_req(0 + TypeFunc::Parms, target_mh);
uint nargs = call->method()->arg_size();
for (uint i = 1; i < nargs; i++) {
Node* arg = kit.argument(i - 1);
@ -647,6 +647,155 @@ JVMState* PredictedCallGenerator::generate(JVMState* jvms) {
}
//------------------------PredictedDynamicCallGenerator-----------------------
// Internal class which handles all out-of-line calls checking receiver type.
class PredictedDynamicCallGenerator : public CallGenerator {
ciMethodHandle* _predicted_method_handle;
CallGenerator* _if_missed;
CallGenerator* _if_hit;
float _hit_prob;
public:
PredictedDynamicCallGenerator(ciMethodHandle* predicted_method_handle,
CallGenerator* if_missed,
CallGenerator* if_hit,
float hit_prob)
: CallGenerator(if_missed->method()),
_predicted_method_handle(predicted_method_handle),
_if_missed(if_missed),
_if_hit(if_hit),
_hit_prob(hit_prob)
{}
virtual bool is_inline() const { return _if_hit->is_inline(); }
virtual bool is_deferred() const { return _if_hit->is_deferred(); }
virtual JVMState* generate(JVMState* jvms);
};
CallGenerator* CallGenerator::for_predicted_dynamic_call(ciMethodHandle* predicted_method_handle,
CallGenerator* if_missed,
CallGenerator* if_hit,
float hit_prob) {
return new PredictedDynamicCallGenerator(predicted_method_handle, if_missed, if_hit, hit_prob);
}
JVMState* PredictedDynamicCallGenerator::generate(JVMState* jvms) {
GraphKit kit(jvms);
PhaseGVN& gvn = kit.gvn();
CompileLog* log = kit.C->log();
if (log != NULL) {
log->elem("predicted_dynamic_call bci='%d'", jvms->bci());
}
// Get the constant pool cache from the caller class.
ciMethod* caller_method = jvms->method();
ciBytecodeStream str(caller_method);
str.force_bci(jvms->bci()); // Set the stream to the invokedynamic bci.
ciCPCache* cpcache = str.get_cpcache();
// Get the offset of the CallSite from the constant pool cache
// pointer.
int index = str.get_method_index();
size_t call_site_offset = cpcache->get_f1_offset(index);
// Load the CallSite object from the constant pool cache.
const TypeOopPtr* cpcache_ptr = TypeOopPtr::make_from_constant(cpcache);
Node* cpcache_adr = kit.makecon(cpcache_ptr);
Node* call_site_adr = kit.basic_plus_adr(cpcache_adr, cpcache_adr, call_site_offset);
Node* call_site = kit.make_load(kit.control(), call_site_adr, TypeInstPtr::BOTTOM, T_OBJECT, Compile::AliasIdxRaw);
// Load the target MethodHandle from the CallSite object.
Node* target_adr = kit.basic_plus_adr(call_site, call_site, java_dyn_CallSite::target_offset_in_bytes());
Node* target_mh = kit.make_load(kit.control(), target_adr, TypeInstPtr::BOTTOM, T_OBJECT);
// Check if the MethodHandle is still the same.
const TypeOopPtr* predicted_mh_ptr = TypeOopPtr::make_from_constant(_predicted_method_handle, true);
Node* predicted_mh = kit.makecon(predicted_mh_ptr);
Node* cmp = gvn.transform(new(kit.C, 3) CmpPNode(target_mh, predicted_mh));
Node* bol = gvn.transform(new(kit.C, 2) BoolNode(cmp, BoolTest::eq) );
IfNode* iff = kit.create_and_xform_if(kit.control(), bol, _hit_prob, COUNT_UNKNOWN);
kit.set_control( gvn.transform(new(kit.C, 1) IfTrueNode (iff)));
Node* slow_ctl = gvn.transform(new(kit.C, 1) IfFalseNode(iff));
SafePointNode* slow_map = NULL;
JVMState* slow_jvms;
{ PreserveJVMState pjvms(&kit);
kit.set_control(slow_ctl);
if (!kit.stopped()) {
slow_jvms = _if_missed->generate(kit.sync_jvms());
assert(slow_jvms != NULL, "miss path must not fail to generate");
kit.add_exception_states_from(slow_jvms);
kit.set_map(slow_jvms->map());
if (!kit.stopped())
slow_map = kit.stop();
}
}
if (kit.stopped()) {
// Instance exactly does not matches the desired type.
kit.set_jvms(slow_jvms);
return kit.transfer_exceptions_into_jvms();
}
// Make the hot call:
JVMState* new_jvms = _if_hit->generate(kit.sync_jvms());
if (new_jvms == NULL) {
// Inline failed, so make a direct call.
assert(_if_hit->is_inline(), "must have been a failed inline");
CallGenerator* cg = CallGenerator::for_direct_call(_if_hit->method());
new_jvms = cg->generate(kit.sync_jvms());
}
kit.add_exception_states_from(new_jvms);
kit.set_jvms(new_jvms);
// Need to merge slow and fast?
if (slow_map == NULL) {
// The fast path is the only path remaining.
return kit.transfer_exceptions_into_jvms();
}
if (kit.stopped()) {
// Inlined method threw an exception, so it's just the slow path after all.
kit.set_jvms(slow_jvms);
return kit.transfer_exceptions_into_jvms();
}
// Finish the diamond.
kit.C->set_has_split_ifs(true); // Has chance for split-if optimization
RegionNode* region = new (kit.C, 3) RegionNode(3);
region->init_req(1, kit.control());
region->init_req(2, slow_map->control());
kit.set_control(gvn.transform(region));
Node* iophi = PhiNode::make(region, kit.i_o(), Type::ABIO);
iophi->set_req(2, slow_map->i_o());
kit.set_i_o(gvn.transform(iophi));
kit.merge_memory(slow_map->merged_memory(), region, 2);
uint tos = kit.jvms()->stkoff() + kit.sp();
uint limit = slow_map->req();
for (uint i = TypeFunc::Parms; i < limit; i++) {
// Skip unused stack slots; fast forward to monoff();
if (i == tos) {
i = kit.jvms()->monoff();
if( i >= limit ) break;
}
Node* m = kit.map()->in(i);
Node* n = slow_map->in(i);
if (m != n) {
const Type* t = gvn.type(m)->meet(gvn.type(n));
Node* phi = PhiNode::make(region, m, t);
phi->set_req(2, n);
kit.map()->set_req(i, gvn.transform(phi));
}
}
return kit.transfer_exceptions_into_jvms();
}
//-------------------------UncommonTrapCallGenerator-----------------------------
// Internal class which handles all out-of-line calls checking receiver type.
class UncommonTrapCallGenerator : public CallGenerator {

View File

@ -117,6 +117,12 @@ class CallGenerator : public ResourceObj {
CallGenerator* if_hit,
float hit_prob);
// How to make a call that optimistically assumes a MethodHandle target:
static CallGenerator* for_predicted_dynamic_call(ciMethodHandle* predicted_method_handle,
CallGenerator* if_missed,
CallGenerator* if_hit,
float hit_prob);
// How to make a call that gives up and goes back to the interpreter:
static CallGenerator* for_uncommon_trap(ciMethod* m,
Deoptimization::DeoptReason reason,

View File

@ -224,16 +224,61 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index,
}
}
// Do MethodHandle calls.
if (call_method->is_method_handle_invoke()) {
if (jvms->method()->java_code_at_bci(jvms->bci()) != Bytecodes::_invokedynamic) {
GraphKit kit(jvms);
Node* n = kit.argument(0);
if (n->Opcode() == Op_ConP) {
const TypeOopPtr* oop_ptr = n->bottom_type()->is_oopptr();
ciObject* const_oop = oop_ptr->const_oop();
ciMethodHandle* method_handle = const_oop->as_method_handle();
// Set the actually called method to have access to the class
// and signature in the MethodHandleCompiler.
method_handle->set_callee(call_method);
// Get an adapter for the MethodHandle.
ciMethod* target_method = method_handle->get_method_handle_adapter();
CallGenerator* hit_cg = this->call_generator(target_method, vtable_index, false, jvms, true, prof_factor);
if (hit_cg != NULL && hit_cg->is_inline())
return hit_cg;
}
return CallGenerator::for_direct_call(call_method);
}
else {
// Get the MethodHandle from the CallSite.
ciMethod* caller_method = jvms->method();
ciBytecodeStream str(caller_method);
str.force_bci(jvms->bci()); // Set the stream to the invokedynamic bci.
ciCallSite* call_site = str.get_call_site();
ciMethodHandle* method_handle = call_site->get_target();
// Set the actually called method to have access to the class
// and signature in the MethodHandleCompiler.
method_handle->set_callee(call_method);
// Get an adapter for the MethodHandle.
ciMethod* target_method = method_handle->get_invokedynamic_adapter();
CallGenerator* hit_cg = this->call_generator(target_method, vtable_index, false, jvms, true, prof_factor);
if (hit_cg != NULL && hit_cg->is_inline()) {
CallGenerator* miss_cg = CallGenerator::for_dynamic_call(call_method);
return CallGenerator::for_predicted_dynamic_call(method_handle, miss_cg, hit_cg, prof_factor);
}
// If something failed, generate a normal dynamic call.
return CallGenerator::for_dynamic_call(call_method);
}
}
// There was no special inlining tactic, or it bailed out.
// Use a more generic tactic, like a simple call.
if (call_is_virtual) {
return CallGenerator::for_virtual_call(call_method, vtable_index);
} else if (call_method->is_method_handle_invoke()) {
if (jvms->method()->java_code_at_bci(jvms->bci()) == Bytecodes::_invokedynamic)
return CallGenerator::for_dynamic_call(call_method);
else
// %%% if the target MH is a compile-time constant, we should try to inline it
return CallGenerator::for_direct_call(call_method);
} else {
// Class Hierarchy Analysis or Type Profile reveals a unique target,
// or it is a static or special call.

View File

@ -125,7 +125,25 @@ void Parse::do_field_access(bool is_get, bool is_field) {
void Parse::do_get_xxx(const TypePtr* obj_type, Node* obj, ciField* field, bool is_field) {
// Does this field have a constant value? If so, just push the value.
if (field->is_constant() && push_constant(field->constant_value())) return;
if (field->is_constant()) {
if (field->is_static()) {
// final static field
if (push_constant(field->constant_value()))
return;
}
else {
// final non-static field of a trusted class ({java,sun}.dyn
// classes).
if (obj->is_Con()) {
const TypeOopPtr* oop_ptr = obj->bottom_type()->isa_oopptr();
ciObject* constant_oop = oop_ptr->const_oop();
ciConstant constant = field->constant_value_of(constant_oop);
if (push_constant(constant, true))
return;
}
}
}
ciType* field_klass = field->type();
bool is_vol = field->is_volatile();
@ -145,7 +163,7 @@ void Parse::do_get_xxx(const TypePtr* obj_type, Node* obj, ciField* field, bool
if (!field->type()->is_loaded()) {
type = TypeInstPtr::BOTTOM;
must_assert_null = true;
} else if (field->is_constant()) {
} else if (field->is_constant() && field->is_static()) {
// This can happen if the constant oop is non-perm.
ciObject* con = field->constant_value().as_object();
// Do not "join" in the previous type; it doesn't add value,

File diff suppressed because it is too large Load Diff

View File

@ -68,6 +68,7 @@ public:
Handle method_handle() { return _method_handle; }
oop method_handle_oop() { return _method_handle(); }
oop method_type_oop() { return MethodHandle_type_oop(); }
oop vmtarget_oop() { return MethodHandle_vmtarget_oop(); }
jint adapter_conversion() { assert(is_adapter(), ""); return _conversion; }
int adapter_conversion_op() { return MethodHandles::adapter_conversion_op(adapter_conversion()); }
@ -101,8 +102,45 @@ public:
// You supply the tokens shuffled by the abstract interpretation.
class MethodHandleWalker : StackObj {
public:
struct _ArgToken { }; // dummy struct
typedef _ArgToken* ArgToken;
// Stack values:
enum TokenType {
tt_void,
tt_parameter,
tt_temporary,
tt_constant,
tt_illegal
};
// Argument token:
class ArgToken {
private:
TokenType _tt;
BasicType _bt;
jvalue _value;
Handle _handle;
public:
ArgToken(TokenType tt = tt_illegal) : _tt(tt) {}
ArgToken(TokenType tt, BasicType bt, jvalue value) : _tt(tt), _bt(bt), _value(value) {}
ArgToken(TokenType tt, BasicType bt, int index) : _tt(tt), _bt(bt) {
_value.i = index;
}
ArgToken(TokenType tt, BasicType bt, Handle value) : _tt(tt), _bt(bt) {
_handle = value;
}
TokenType token_type() const { return _tt; }
BasicType basic_type() const { return _bt; }
int index() const { return _value.i; }
Handle object() const { return _handle; }
jint get_jint() const { return _value.i; }
jlong get_jlong() const { return _value.j; }
jfloat get_jfloat() const { return _value.f; }
jdouble get_jdouble() const { return _value.d; }
};
// Abstract interpretation state:
struct SlotState {
@ -118,15 +156,17 @@ public:
private:
MethodHandleChain _chain;
bool _for_invokedynamic;
int _local_index;
GrowableArray<SlotState> _outgoing; // current outgoing parameter slots
GrowableArray<SlotState> _outgoing; // current outgoing parameter slots
int _outgoing_argc; // # non-empty outgoing slots
// 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.
// Insert or delete a second empty slot as needed.
void change_argument(BasicType old_type, int slot, BasicType new_type, ArgToken new_arg);
void change_argument(BasicType old_type, int slot, BasicType new_type, const ArgToken& new_arg);
SlotState* slot_state(int slot) {
if (slot < 0 || slot >= _outgoing.length())
@ -153,20 +193,34 @@ private:
void walk_incoming_state(TRAPS);
public:
MethodHandleWalker(Handle root, TRAPS)
MethodHandleWalker(Handle root, bool for_invokedynamic, TRAPS)
: _chain(root, THREAD),
_for_invokedynamic(for_invokedynamic),
_outgoing(THREAD, 10),
_outgoing_argc(0)
{ }
{
_local_index = for_invokedynamic ? 0 : 1;
}
MethodHandleChain& chain() { return _chain; }
bool for_invokedynamic() const { return _for_invokedynamic; }
int new_local_index(BasicType bt) {
//int index = _for_invokedynamic ? _local_index : _local_index - 1;
int index = _local_index;
_local_index += type2size[bt];
return index;
}
int max_locals() const { return _local_index; }
// plug-in abstract interpretation steps:
virtual ArgToken make_parameter( BasicType type, klassOop tk, int argnum, TRAPS ) = 0;
virtual ArgToken make_prim_constant( BasicType type, jvalue* con, TRAPS ) = 0;
virtual ArgToken make_oop_constant( oop con, TRAPS ) = 0;
virtual ArgToken make_conversion( BasicType type, klassOop tk, Bytecodes::Code op, ArgToken src, TRAPS ) = 0;
virtual ArgToken make_fetch( BasicType type, klassOop tk, Bytecodes::Code op, ArgToken base, ArgToken offset, 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;
// For make_invoke, the methodOop can be NULL if the intrinsic ID
@ -187,83 +241,167 @@ public:
// The IR happens to be JVM bytecodes.
class MethodHandleCompiler : public MethodHandleWalker {
private:
Thread* _thread;
methodHandle _callee;
KlassHandle _rklass; // Return type for casting.
BasicType _rtype;
KlassHandle _target_klass;
Thread* _thread;
struct PrimCon {
BasicType _type;
jvalue _value;
// Fake constant pool entry.
class ConstantValue {
private:
int _tag; // Constant pool tag type.
JavaValue _value;
Handle _handle;
public:
// Constructor for oop types.
ConstantValue(int tag, Handle con) : _tag(tag), _handle(con) {
assert(tag == JVM_CONSTANT_Utf8 ||
tag == JVM_CONSTANT_Class ||
tag == JVM_CONSTANT_String ||
tag == JVM_CONSTANT_Object, "must be oop type");
}
// Constructor for oop reference types.
ConstantValue(int tag, int index) : _tag(tag) {
assert(JVM_CONSTANT_Fieldref <= tag && tag <= JVM_CONSTANT_NameAndType, "must be ref type");
_value.set_jint(index);
}
ConstantValue(int tag, int first_index, int second_index) : _tag(tag) {
assert(JVM_CONSTANT_Fieldref <= tag && tag <= JVM_CONSTANT_NameAndType, "must be ref type");
_value.set_jint(first_index << 16 | second_index);
}
// Constructor for primitive types.
ConstantValue(BasicType bt, jvalue con) {
_value.set_type(bt);
switch (bt) {
case T_INT: _tag = JVM_CONSTANT_Integer; _value.set_jint( con.i); break;
case T_LONG: _tag = JVM_CONSTANT_Long; _value.set_jlong( con.j); break;
case T_FLOAT: _tag = JVM_CONSTANT_Float; _value.set_jfloat( con.f); break;
case T_DOUBLE: _tag = JVM_CONSTANT_Double; _value.set_jdouble(con.d); break;
default: ShouldNotReachHere();
}
}
int tag() const { return _tag; }
symbolOop symbol_oop() const { return (symbolOop) _handle(); }
klassOop klass_oop() const { return (klassOop) _handle(); }
oop object_oop() const { return _handle(); }
int index() const { return _value.get_jint(); }
int first_index() const { return _value.get_jint() >> 16; }
int second_index() const { return _value.get_jint() & 0x0000FFFF; }
bool is_primitive() const { return is_java_primitive(_value.get_type()); }
jint get_jint() const { return _value.get_jint(); }
jlong get_jlong() const { return _value.get_jlong(); }
jfloat get_jfloat() const { return _value.get_jfloat(); }
jdouble get_jdouble() const { return _value.get_jdouble(); }
};
// Fake constant pool.
GrowableArray<ConstantValue*> _constants;
// Accumulated compiler state:
stringStream _bytes;
GrowableArray<Handle> _constant_oops;
GrowableArray<PrimCon*> _constant_prims;
GrowableArray<unsigned char> _bytecode;
int _cur_stack;
int _max_stack;
int _num_params;
int _max_locals;
int _name_index;
int _signature_index;
// Stack values:
enum TokenType {
tt_void,
tt_parameter,
tt_temporary,
tt_constant
};
ArgToken make_stack_value(TokenType tt, BasicType type, int id) {
return ArgToken( ((intptr_t)id << 8) | ((intptr_t)type << 4) | (intptr_t)tt );
void stack_push(BasicType bt) {
_cur_stack += type2size[bt];
if (_cur_stack > _max_stack) _max_stack = _cur_stack;
}
void stack_pop(BasicType bt) {
_cur_stack -= type2size[bt];
assert(_cur_stack >= 0, "sanity");
}
public:
unsigned char* bytecode() const { return _bytecode.adr_at(0); }
int bytecode_length() const { return _bytecode.length(); }
// Fake constant pool.
int cpool_oop_put(int tag, Handle con) {
if (con.is_null()) return 0;
ConstantValue* cv = new ConstantValue(tag, con);
return _constants.append(cv);
}
int cpool_oop_reference_put(int tag, int first_index, int second_index) {
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);
return _constants.append(cv);
}
int cpool_primitive_put(BasicType type, jvalue* con);
int cpool_int_put(jint value) {
jvalue con; con.i = value;
return cpool_primitive_put(T_INT, &con);
}
int cpool_long_put(jlong value) {
jvalue con; con.j = value;
return cpool_primitive_put(T_LONG, &con);
}
int cpool_float_put(jfloat value) {
jvalue con; con.f = value;
return cpool_primitive_put(T_FLOAT, &con);
}
int cpool_double_put(jdouble value) {
jvalue con; con.d = value;
return cpool_primitive_put(T_DOUBLE, &con);
}
int cpool_object_put(Handle obj) {
return cpool_oop_put(JVM_CONSTANT_Object, obj);
}
int cpool_symbol_put(symbolOop sym) {
return cpool_oop_put(JVM_CONSTANT_Utf8, sym);
}
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_name_and_type_put(int name_index, int signature_index) {
return cpool_oop_reference_put(JVM_CONSTANT_NameAndType, name_index, signature_index);
}
void emit_bc(Bytecodes::Code op, int index = 0);
void emit_load(BasicType bt, int index);
void emit_store(BasicType bt, int index);
void emit_load_constant(ArgToken arg);
virtual ArgToken make_parameter(BasicType type, klassOop tk, int argnum, TRAPS) {
return make_stack_value(tt_parameter, type, argnum);
return ArgToken(tt_parameter, type, argnum);
}
virtual ArgToken make_oop_constant(oop con, TRAPS) {
return make_stack_value(tt_constant, T_OBJECT, find_oop_constant(con));
Handle h(THREAD, con);
return ArgToken(tt_constant, T_OBJECT, h);
}
virtual ArgToken make_prim_constant(BasicType type, jvalue* con, TRAPS) {
return make_stack_value(tt_constant, type, find_prim_constant(type, con));
return ArgToken(tt_constant, type, *con);
}
virtual ArgToken make_conversion(BasicType type, klassOop tk, Bytecodes::Code op, ArgToken src, TRAPS);
virtual ArgToken make_fetch(BasicType type, klassOop tk, Bytecodes::Code op, ArgToken base, ArgToken offset, TRAPS);
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);
int find_oop_constant(oop con);
int find_prim_constant(BasicType type, jvalue* con);
// Get a real constant pool.
constantPoolHandle get_constant_pool(TRAPS) const;
// Get a real methodOop.
methodHandle get_method_oop(TRAPS) const;
public:
MethodHandleCompiler(Handle root, TRAPS)
: MethodHandleWalker(root, THREAD),
_thread(THREAD),
_bytes(50),
_constant_oops(THREAD, 10),
_constant_prims(THREAD, 10),
_max_stack(0), _max_locals(0),
_name_index(0), _signature_index(0)
{ }
const char* bytes() { return _bytes.as_string(); }
int constant_length() { return _constant_oops.length(); }
int max_stack() { return _max_stack; }
int max_locals() { return _max_locals; }
int name_index() { return _name_index; }
int signature_index() { return _signature_index; }
symbolHandle name() { return symbolHandle(_thread, (symbolOop)constant_oop_at(_name_index)()); }
symbolHandle signature() { return symbolHandle(_thread, (symbolOop)constant_oop_at(_signature_index)()); }
bool constant_is_oop_at(int i) {
return (_constant_prims.at(i) == NULL);
}
Handle constant_oop_at(int i) {
assert(constant_is_oop_at(i), "");
return _constant_oops.at(i);
}
PrimCon* constant_prim_at(int i) {
assert(!constant_is_oop_at(i), "");
return _constant_prims.at(i);
}
MethodHandleCompiler(Handle root, methodHandle call_method, bool for_invokedynamic, TRAPS);
// Compile the given MH chain into bytecode.
void compile(TRAPS);
methodHandle compile(TRAPS);
};

View File

@ -132,8 +132,9 @@ methodOop MethodHandles::decode_vmtarget(oop vmtarget, int vmindex, oop mtype,
}
return m;
} else {
decode_flags_result |= MethodHandles::_dmf_does_dispatch;
assert(vmtarget->is_klass(), "must be class or interface");
decode_flags_result |= MethodHandles::_dmf_does_dispatch;
decode_flags_result |= MethodHandles::_dmf_has_receiver;
receiver_limit_result = (klassOop)vmtarget;
Klass* tk = Klass::cast((klassOop)vmtarget);
if (tk->is_interface()) {
@ -179,8 +180,10 @@ methodOop MethodHandles::decode_BoundMethodHandle(oop mh, klassOop& receiver_lim
// short-circuits directly to the methodOop.
// (It might be another argument besides a receiver also.)
assert(target->is_method(), "must be a simple method");
methodOop m = (methodOop) target;
decode_flags_result |= MethodHandles::_dmf_binds_method;
methodOop m = (methodOop) target;
if (!m->is_static())
decode_flags_result |= MethodHandles::_dmf_has_receiver;
return m;
}
}
@ -233,8 +236,8 @@ methodOop MethodHandles::decode_methodOop(methodOop m, int& decode_flags_result)
BasicType recv_bt = char2type(sig->byte_at(1));
// Note: recv_bt might be T_ILLEGAL if byte_at(2) is ')'
assert(sig->byte_at(0) == '(', "must be method sig");
if (recv_bt == T_OBJECT || recv_bt == T_ARRAY)
decode_flags_result |= _dmf_has_receiver;
// if (recv_bt == T_OBJECT || recv_bt == T_ARRAY)
// decode_flags_result |= _dmf_has_receiver;
} else {
// non-static method
decode_flags_result |= _dmf_has_receiver;
@ -818,7 +821,7 @@ static bool is_always_null_type(klassOop klass) {
for (int i = 0; ; i++) {
const char* test_name = always_null_names[i];
if (test_name == NULL) break;
if (name->equals(test_name, (int) strlen(test_name)))
if (name->equals(test_name))
return true;
}
return false;
@ -1487,8 +1490,9 @@ void MethodHandles::verify_BoundMethodHandle(Handle mh, Handle target, int argnu
int target_pushes = decode_MethodHandle_stack_pushes(target());
assert(this_pushes == slots_pushed + target_pushes, "BMH stack motion must be correct");
// do not blow the stack; use a Java-based adapter if this limit is exceeded
if (slots_pushed + target_pushes > MethodHandlePushLimit)
err = "too many bound parameters";
// FIXME
// if (slots_pushed + target_pushes > MethodHandlePushLimit)
// err = "too many bound parameters";
}
}
@ -1518,6 +1522,11 @@ void MethodHandles::init_BoundMethodHandle(Handle mh, Handle target, int argnum,
verify_vmslots(mh, CHECK);
}
// Get bound type and required slots.
oop ptype_oop = java_dyn_MethodType::ptype(java_dyn_MethodHandle::type(target()), argnum);
BasicType ptype = java_lang_Class::as_BasicType(ptype_oop);
int slots_pushed = type2size[ptype];
// If (a) the target is a direct non-dispatched method handle,
// or (b) the target is a dispatched direct method handle and we
// are binding the receiver, cut out the middle-man.
@ -1529,7 +1538,7 @@ void MethodHandles::init_BoundMethodHandle(Handle mh, Handle target, int argnum,
int decode_flags = 0; klassOop receiver_limit_oop = NULL;
methodHandle m(THREAD, decode_method(target(), receiver_limit_oop, decode_flags));
if (m.is_null()) { THROW_MSG(vmSymbols::java_lang_InternalError(), "DMH failed to decode"); }
DEBUG_ONLY(int m_vmslots = m->size_of_parameters() - 1); // pos. of 1st arg.
DEBUG_ONLY(int m_vmslots = m->size_of_parameters() - slots_pushed); // pos. of 1st arg.
assert(sun_dyn_BoundMethodHandle::vmslots(mh()) == m_vmslots, "type w/ m sig");
if (argnum == 0 && (decode_flags & _dmf_has_receiver) != 0) {
KlassHandle receiver_limit(THREAD, receiver_limit_oop);
@ -1554,10 +1563,6 @@ void MethodHandles::init_BoundMethodHandle(Handle mh, Handle target, int argnum,
}
// Next question: Is this a ref, int, or long bound value?
oop ptype_oop = java_dyn_MethodType::ptype(java_dyn_MethodHandle::type(target()), argnum);
BasicType ptype = java_lang_Class::as_BasicType(ptype_oop);
int slots_pushed = type2size[ptype];
MethodHandleEntry* me = NULL;
if (ptype == T_OBJECT) {
if (direct_to_method) me = MethodHandles::entry(_bound_ref_direct_mh);

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -769,9 +769,9 @@ class InterpreterFrameClosure : public OffsetClosure {
class InterpretedArgumentOopFinder: public SignatureInfo {
private:
OopClosure* _f; // Closure to invoke
int _offset; // TOS-relative offset, decremented with each argument
bool _is_static; // true if the callee is a static method
OopClosure* _f; // Closure to invoke
int _offset; // TOS-relative offset, decremented with each argument
bool _has_receiver; // true if the callee has a receiver
frame* _fr;
void set(int size, BasicType type) {
@ -786,9 +786,9 @@ class InterpretedArgumentOopFinder: public SignatureInfo {
}
public:
InterpretedArgumentOopFinder(symbolHandle signature, bool is_static, frame* fr, OopClosure* f) : SignatureInfo(signature) {
InterpretedArgumentOopFinder(symbolHandle signature, bool has_receiver, frame* fr, OopClosure* f) : SignatureInfo(signature), _has_receiver(has_receiver) {
// compute size of arguments
int args_size = ArgumentSizeComputer(signature).size() + (is_static ? 0 : 1);
int args_size = ArgumentSizeComputer(signature).size() + (has_receiver ? 1 : 0);
assert(!fr->is_interpreted_frame() ||
args_size <= fr->interpreter_frame_expression_stack_size(),
"args cannot be on stack anymore");
@ -796,11 +796,10 @@ class InterpretedArgumentOopFinder: public SignatureInfo {
_f = f;
_fr = fr;
_offset = args_size;
_is_static = is_static;
}
void oops_do() {
if (!_is_static) {
if (_has_receiver) {
--_offset;
oop_offset_do();
}
@ -912,7 +911,7 @@ void frame::oops_interpreted_do(OopClosure* f, const RegisterMap* map, bool quer
int max_locals = m->is_native() ? m->size_of_parameters() : m->max_locals();
symbolHandle signature;
bool is_static = false;
bool has_receiver = false;
// Process a callee's arguments if we are at a call site
// (i.e., if we are at an invoke bytecode)
@ -922,7 +921,7 @@ void frame::oops_interpreted_do(OopClosure* f, const RegisterMap* map, bool quer
Bytecode_invoke *call = Bytecode_invoke_at_check(m, bci);
if (call != NULL) {
signature = symbolHandle(thread, call->signature());
is_static = call->is_invokestatic();
has_receiver = call->has_receiver();
if (map->include_argument_oops() &&
interpreter_frame_expression_stack_size() > 0) {
ResourceMark rm(thread); // is this right ???
@ -936,7 +935,7 @@ void frame::oops_interpreted_do(OopClosure* f, const RegisterMap* map, bool quer
// code in the interpreter calls a blocking runtime
// routine which can cause this code to be executed).
// (was bug gri 7/27/98)
oops_interpreted_arguments_do(signature, is_static, f);
oops_interpreted_arguments_do(signature, has_receiver, f);
}
}
}
@ -950,7 +949,7 @@ void frame::oops_interpreted_do(OopClosure* f, const RegisterMap* map, bool quer
mask = &oopmap_mask;
#endif // ASSERT
oops_interpreted_locals_do(f, max_locals, mask);
oops_interpreted_expressions_do(f, signature, is_static,
oops_interpreted_expressions_do(f, signature, has_receiver,
m->max_stack(),
max_locals, mask);
} else {
@ -992,7 +991,7 @@ void frame::oops_interpreted_locals_do(OopClosure *f,
void frame::oops_interpreted_expressions_do(OopClosure *f,
symbolHandle signature,
bool is_static,
bool has_receiver,
int max_stack,
int max_locals,
InterpreterOopMap *mask) {
@ -1005,7 +1004,7 @@ void frame::oops_interpreted_expressions_do(OopClosure *f,
// arguments in callee's locals.
int args_size = 0;
if (!signature.is_null()) {
args_size = ArgumentSizeComputer(signature).size() + (is_static ? 0 : 1);
args_size = ArgumentSizeComputer(signature).size() + (has_receiver ? 1 : 0);
}
intptr_t *tos_addr = interpreter_frame_tos_at(args_size);
@ -1038,8 +1037,8 @@ void frame::oops_interpreted_expressions_do(OopClosure *f,
}
}
void frame::oops_interpreted_arguments_do(symbolHandle signature, bool is_static, OopClosure* f) {
InterpretedArgumentOopFinder finder(signature, is_static, this, f);
void frame::oops_interpreted_arguments_do(symbolHandle signature, bool has_receiver, OopClosure* f) {
InterpretedArgumentOopFinder finder(signature, has_receiver, this, f);
finder.oops_do();
}
@ -1066,8 +1065,8 @@ void frame::oops_code_blob_do(OopClosure* f, CodeBlobClosure* cf, const Register
class CompiledArgumentOopFinder: public SignatureInfo {
protected:
OopClosure* _f;
int _offset; // the current offset, incremented with each argument
bool _is_static; // true if the callee is a static method
int _offset; // the current offset, incremented with each argument
bool _has_receiver; // true if the callee has a receiver
frame _fr;
RegisterMap* _reg_map;
int _arg_size;
@ -1087,24 +1086,24 @@ class CompiledArgumentOopFinder: public SignatureInfo {
}
public:
CompiledArgumentOopFinder(symbolHandle signature, bool is_static, OopClosure* f, frame fr, const RegisterMap* reg_map)
CompiledArgumentOopFinder(symbolHandle signature, bool has_receiver, OopClosure* f, frame fr, const RegisterMap* reg_map)
: SignatureInfo(signature) {
// initialize CompiledArgumentOopFinder
_f = f;
_offset = 0;
_is_static = is_static;
_has_receiver = has_receiver;
_fr = fr;
_reg_map = (RegisterMap*)reg_map;
_arg_size = ArgumentSizeComputer(signature).size() + (is_static ? 0 : 1);
_arg_size = ArgumentSizeComputer(signature).size() + (has_receiver ? 1 : 0);
int arg_size;
_regs = SharedRuntime::find_callee_arguments(signature(), is_static, &arg_size);
_regs = SharedRuntime::find_callee_arguments(signature(), has_receiver, &arg_size);
assert(arg_size == _arg_size, "wrong arg size");
}
void oops_do() {
if (!_is_static) {
if (_has_receiver) {
handle_oop_offset();
_offset++;
}
@ -1112,9 +1111,9 @@ class CompiledArgumentOopFinder: public SignatureInfo {
}
};
void frame::oops_compiled_arguments_do(symbolHandle signature, bool is_static, const RegisterMap* reg_map, OopClosure* f) {
void frame::oops_compiled_arguments_do(symbolHandle signature, bool has_receiver, const RegisterMap* reg_map, OopClosure* f) {
ResourceMark rm;
CompiledArgumentOopFinder finder(signature, is_static, f, *this, reg_map);
CompiledArgumentOopFinder finder(signature, has_receiver, f, *this, reg_map);
finder.oops_do();
}

View File

@ -371,7 +371,7 @@ class frame VALUE_OBJ_CLASS_SPEC {
oop* oopmapreg_to_location(VMReg reg, const RegisterMap* regmap) const;
// Oops-do's
void oops_compiled_arguments_do(symbolHandle signature, bool is_static, const RegisterMap* reg_map, OopClosure* f);
void oops_compiled_arguments_do(symbolHandle signature, bool has_receiver, const RegisterMap* reg_map, OopClosure* f);
void oops_interpreted_do(OopClosure* f, const RegisterMap* map, bool query_oop_map_cache = true);
private:
@ -379,9 +379,9 @@ class frame VALUE_OBJ_CLASS_SPEC {
int max_locals,
InterpreterOopMap *mask);
void oops_interpreted_expressions_do(OopClosure *f, symbolHandle signature,
bool is_static, int max_stack, int max_locals,
bool has_receiver, int max_stack, int max_locals,
InterpreterOopMap *mask);
void oops_interpreted_arguments_do(symbolHandle signature, bool is_static, OopClosure* f);
void oops_interpreted_arguments_do(symbolHandle signature, bool has_receiver, OopClosure* f);
// Iteration of oops
void oops_do_internal(OopClosure* f, CodeBlobClosure* cf, RegisterMap* map, bool use_interpreter_oop_map_cache);

View File

@ -2145,7 +2145,7 @@ VMReg SharedRuntime::name_for_receiver() {
return regs.first();
}
VMRegPair *SharedRuntime::find_callee_arguments(symbolOop sig, bool is_static, int* arg_size) {
VMRegPair *SharedRuntime::find_callee_arguments(symbolOop sig, bool has_receiver, int* arg_size) {
// This method is returning a data structure allocating as a
// ResourceObject, so do not put any ResourceMarks in here.
char *s = sig->as_C_string();
@ -2157,7 +2157,7 @@ VMRegPair *SharedRuntime::find_callee_arguments(symbolOop sig, bool is_static, i
BasicType *sig_bt = NEW_RESOURCE_ARRAY( BasicType, 256 );
VMRegPair *regs = NEW_RESOURCE_ARRAY( VMRegPair, 256 );
int cnt = 0;
if (!is_static) {
if (has_receiver) {
sig_bt[cnt++] = T_OBJECT; // Receiver is argument 0; not in signature
}

View File

@ -357,7 +357,7 @@ class SharedRuntime: AllStatic {
// Convert a sig into a calling convention register layout
// and find interesting things about it.
static VMRegPair* find_callee_arguments(symbolOop sig, bool is_static, int *arg_size);
static VMRegPair* find_callee_arguments(symbolOop sig, bool has_receiver, int *arg_size);
static VMReg name_for_receiver();
// "Top of Stack" slots that may be unused by the calling convention but must

View File

@ -36,7 +36,8 @@ enum {
JVM_CONSTANT_UnresolvedString = 102, // Temporary tag until actual use
JVM_CONSTANT_StringIndex = 103, // Temporary tag while constructing constant pool
JVM_CONSTANT_UnresolvedClassInError = 104, // Error tag due to resolution error
JVM_CONSTANT_InternalMax = 104 // Last implementation tag
JVM_CONSTANT_Object = 105, // Required for BoundMethodHandle arguments.
JVM_CONSTANT_InternalMax = 105 // Last implementation tag
};
@ -70,6 +71,8 @@ class constantTag VALUE_OBJ_CLASS_SPEC {
bool is_unresolved_string() const { return _tag == JVM_CONSTANT_UnresolvedString; }
bool is_string_index() const { return _tag == JVM_CONSTANT_StringIndex; }
bool is_object() const { return _tag == JVM_CONSTANT_Object; }
bool is_klass_reference() const { return is_klass_index() || is_unresolved_klass(); }
bool is_klass_or_reference() const{ return is_klass() || is_klass_reference(); }
bool is_field_or_method() const { return is_field() || is_method() || is_interface_method(); }