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); return in_bytes(f1_offset);
} }
// ------------------------------------------------------------------ // ------------------------------------------------------------------
// ciCPCache::print // 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 ciObject;
class ciNullObject; class ciNullObject;
class ciInstance; class ciInstance;
class ciCallSite;
class ciMethodHandle;
class ciMethod; class ciMethod;
class ciMethodData; class ciMethodData;
class ciReceiverTypeData; // part of ciMethodData class ciReceiverTypeData; // part of ciMethodData
@ -79,6 +81,7 @@ friend class ciObjectFactory;
// Any more access must be given explicitly. // Any more access must be given explicitly.
#define CI_PACKAGE_ACCESS_TO \ #define CI_PACKAGE_ACCESS_TO \
friend class ciObjectFactory; \ friend class ciObjectFactory; \
friend class ciCallSite; \
friend class ciConstantPoolCache; \ friend class ciConstantPoolCache; \
friend class ciField; \ friend class ciField; \
friend class ciConstant; \ friend class ciConstant; \
@ -94,6 +97,7 @@ friend class ciNullObject; \
friend class ciInstance; \ friend class ciInstance; \
friend class ciMethod; \ friend class ciMethod; \
friend class ciMethodData; \ friend class ciMethodData; \
friend class ciMethodHandle; \
friend class ciReceiverTypeData; \ friend class ciReceiverTypeData; \
friend class ciSymbol; \ friend class ciSymbol; \
friend class ciArray; \ friend class ciArray; \

View File

@ -443,12 +443,11 @@ ciKlass* ciEnv::get_klass_by_name(ciKlass* accessing_klass,
// ciEnv::get_klass_by_index_impl // ciEnv::get_klass_by_index_impl
// //
// Implementation of get_klass_by_index. // 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, int index,
bool& is_accessible) { bool& is_accessible,
assert(accessor->get_instanceKlass()->is_linked(), "must be linked before accessing constant pool"); ciInstanceKlass* accessor) {
EXCEPTION_CONTEXT; EXCEPTION_CONTEXT;
constantPoolHandle cpool(THREAD, accessor->get_instanceKlass()->constants());
KlassHandle klass (THREAD, constantPoolOopDesc::klass_at_if_loaded(cpool, index)); KlassHandle klass (THREAD, constantPoolOopDesc::klass_at_if_loaded(cpool, index));
symbolHandle klass_name; symbolHandle klass_name;
if (klass.is_null()) { if (klass.is_null()) {
@ -510,22 +509,21 @@ ciKlass* ciEnv::get_klass_by_index_impl(ciInstanceKlass* accessor,
// ciEnv::get_klass_by_index // ciEnv::get_klass_by_index
// //
// Get a klass from the constant pool. // 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, int index,
bool& is_accessible) { bool& is_accessible,
GUARDED_VM_ENTRY(return get_klass_by_index_impl(accessor, index, is_accessible);) ciInstanceKlass* accessor) {
GUARDED_VM_ENTRY(return get_klass_by_index_impl(cpool, index, is_accessible, accessor);)
} }
// ------------------------------------------------------------------ // ------------------------------------------------------------------
// ciEnv::get_constant_by_index_impl // ciEnv::get_constant_by_index_impl
// //
// Implementation of get_constant_by_index(). // Implementation of get_constant_by_index().
ciConstant ciEnv::get_constant_by_index_impl(ciInstanceKlass* accessor, ciConstant ciEnv::get_constant_by_index_impl(constantPoolHandle cpool,
int index) { int index,
ciInstanceKlass* accessor) {
EXCEPTION_CONTEXT; 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); constantTag tag = cpool->tag_at(index);
if (tag.is_int()) { if (tag.is_int()) {
return ciConstant(T_INT, (jint)cpool->int_at(index)); 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()) { } else if (tag.is_klass() || tag.is_unresolved_klass()) {
// 4881222: allow ldc to take a class type // 4881222: allow ldc to take a class type
bool ignore; 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) { if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION; CLEAR_PENDING_EXCEPTION;
record_out_of_memory_failure(); 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(), assert (klass->is_instance_klass() || klass->is_array_klass(),
"must be an instance or array klass "); "must be an instance or array klass ");
return ciConstant(T_OBJECT, 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 { } else {
ShouldNotReachHere(); ShouldNotReachHere();
return ciConstant(); 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. // Pull a constant out of the constant pool. How appropriate.
// //
// Implementation note: this query is currently in no way cached. // Implementation note: this query is currently in no way cached.
ciConstant ciEnv::get_constant_by_index(ciInstanceKlass* accessor, ciConstant ciEnv::get_constant_by_index(constantPoolHandle cpool,
int index) { int index,
GUARDED_VM_ENTRY(return get_constant_by_index_impl(accessor, index); ) ciInstanceKlass* accessor) {
GUARDED_VM_ENTRY(return get_constant_by_index_impl(cpool, index, accessor);)
} }
// ------------------------------------------------------------------ // ------------------------------------------------------------------
@ -702,15 +706,12 @@ methodOop ciEnv::lookup_method(instanceKlass* accessor,
// ------------------------------------------------------------------ // ------------------------------------------------------------------
// ciEnv::get_method_by_index_impl // ciEnv::get_method_by_index_impl
ciMethod* ciEnv::get_method_by_index_impl(ciInstanceKlass* accessor, ciMethod* ciEnv::get_method_by_index_impl(constantPoolHandle cpool,
int index, Bytecodes::Code bc) { int index, Bytecodes::Code bc,
// Get the method's declared holder. ciInstanceKlass* accessor) {
assert(accessor->get_instanceKlass()->is_linked(), "must be linked before accessing constant pool");
constantPoolHandle cpool = accessor->get_instanceKlass()->constants();
int holder_index = cpool->klass_ref_index_at(index); int holder_index = cpool->klass_ref_index_at(index);
bool holder_is_accessible; 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); ciInstanceKlass* declared_holder = get_instance_klass_for_declared_method_holder(holder);
// Get the method's name and signature. // 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 // 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) { int index, Bytecodes::Code bc) {
assert(bc == Bytecodes::_invokedynamic, "must be invokedynamic"); 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. // Get the CallSite from the constant pool cache.
ConstantPoolCacheEntry* cpc_entry = cpool->cache()->secondary_entry_at(index); 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 // ciEnv::get_method_by_index
ciMethod* ciEnv::get_method_by_index(ciInstanceKlass* accessor, ciMethod* ciEnv::get_method_by_index(constantPoolHandle cpool,
int index, Bytecodes::Code bc) { int index, Bytecodes::Code bc,
ciInstanceKlass* accessor) {
if (bc == Bytecodes::_invokedynamic) { 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 { } 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); bool require_local);
// Constant pool access. // Constant pool access.
ciKlass* get_klass_by_index(ciInstanceKlass* loading_klass, ciKlass* get_klass_by_index(constantPoolHandle cpool,
int klass_index, int klass_index,
bool& is_accessible); bool& is_accessible,
ciConstant get_constant_by_index(ciInstanceKlass* loading_klass, ciInstanceKlass* loading_klass);
int constant_index); ciConstant get_constant_by_index(constantPoolHandle cpool,
int constant_index,
ciInstanceKlass* accessor);
bool is_unresolved_string(ciInstanceKlass* loading_klass, bool is_unresolved_string(ciInstanceKlass* loading_klass,
int constant_index) const; int constant_index) const;
bool is_unresolved_klass(ciInstanceKlass* loading_klass, bool is_unresolved_klass(ciInstanceKlass* loading_klass,
int constant_index) const; int constant_index) const;
ciField* get_field_by_index(ciInstanceKlass* loading_klass, ciField* get_field_by_index(ciInstanceKlass* loading_klass,
int field_index); int field_index);
ciMethod* get_method_by_index(ciInstanceKlass* loading_klass, ciMethod* get_method_by_index(constantPoolHandle cpool,
int method_index, Bytecodes::Code bc); int method_index, Bytecodes::Code bc,
ciInstanceKlass* loading_klass);
// Implementation methods for loading and constant pool access. // Implementation methods for loading and constant pool access.
ciKlass* get_klass_by_name_impl(ciKlass* accessing_klass, ciKlass* get_klass_by_name_impl(ciKlass* accessing_klass,
ciSymbol* klass_name, ciSymbol* klass_name,
bool require_local); bool require_local);
ciKlass* get_klass_by_index_impl(ciInstanceKlass* loading_klass, ciKlass* get_klass_by_index_impl(constantPoolHandle cpool,
int klass_index, int klass_index,
bool& is_accessible); bool& is_accessible,
ciConstant get_constant_by_index_impl(ciInstanceKlass* loading_klass, ciInstanceKlass* loading_klass);
int constant_index); ciConstant get_constant_by_index_impl(constantPoolHandle cpool,
int constant_index,
ciInstanceKlass* loading_klass);
bool is_unresolved_string_impl (instanceKlass* loading_klass, bool is_unresolved_string_impl (instanceKlass* loading_klass,
int constant_index) const; int constant_index) const;
bool is_unresolved_klass_impl (instanceKlass* loading_klass, bool is_unresolved_klass_impl (instanceKlass* loading_klass,
int constant_index) const; int constant_index) const;
ciField* get_field_by_index_impl(ciInstanceKlass* loading_klass, ciField* get_field_by_index_impl(ciInstanceKlass* loading_klass,
int field_index); int field_index);
ciMethod* get_method_by_index_impl(ciInstanceKlass* loading_klass, ciMethod* get_method_by_index_impl(constantPoolHandle cpool,
int method_index, Bytecodes::Code bc); int method_index, Bytecodes::Code bc,
ciMethod* get_fake_invokedynamic_method_impl(ciInstanceKlass* accessor, ciInstanceKlass* loading_klass);
ciMethod* get_fake_invokedynamic_method_impl(constantPoolHandle cpool,
int index, Bytecodes::Code bc); int index, Bytecodes::Code bc);
// Helper methods // 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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. // Get the exception klass that this handler catches.
ciInstanceKlass* ciExceptionHandler::catch_klass() { ciInstanceKlass* ciExceptionHandler::catch_klass() {
VM_ENTRY_MARK;
assert(!is_catch_all(), "bad index"); assert(!is_catch_all(), "bad index");
if (_catch_klass == NULL) { if (_catch_klass == NULL) {
bool will_link; 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, _catch_klass_index,
will_link); will_link,
_loading_klass);
if (!will_link && k->is_loaded()) { if (!will_link && k->is_loaded()) {
GUARDED_VM_ENTRY( GUARDED_VM_ENTRY(
k = CURRENT_ENV->get_unloaded_klass(_loading_klass, k->name()); 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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; bool ignore;
// This is not really a class reference; the index always refers to the // 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. // 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 { } else {
_type = ciType::make(field_type); _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); int holder_index = cpool->klass_ref_index_at(index);
bool holder_is_accessible; bool holder_is_accessible;
ciInstanceKlass* declared_holder = ciInstanceKlass* declared_holder =
ciEnv::current(thread)->get_klass_by_index(klass, holder_index, ciEnv::current(thread)->get_klass_by_index(cpool, holder_index,
holder_is_accessible) holder_is_accessible,
->as_instance_klass(); klass)->as_instance_klass();
// The declared holder of this field may not have been loaded. // The declared holder of this field may not have been loaded.
// Bail out with partial field information. // 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(); _holder = CURRENT_ENV->get_object(fd->field_holder())->as_instance_klass();
// Check to see if the field is constant. // Check to see if the field is constant.
if (_holder->is_initialized() && if (_holder->is_initialized() && this->is_final()) {
this->is_final() && this->is_static()) { 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 // This field just may be constant. The only cases where it will
// not be constant are: // not be constant are:
// //

View File

@ -138,10 +138,18 @@ public:
// Get the constant value of this field. // Get the constant value of this field.
ciConstant constant_value() { ciConstant constant_value() {
assert(is_constant(), "illegal call to constant_value()"); assert(is_static() && is_constant(), "illegal call to constant_value()");
return _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 // Check for link time errors. Accessing a field from a
// certain class via a certain bytecode may or may not be legal. // certain class via a certain bytecode may or may not be legal.
// This call checks to see if an exception may be raised by // 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 // ciInstanceKlass::uses_default_loader
bool ciInstanceKlass::uses_default_loader() { bool ciInstanceKlass::uses_default_loader() {
VM_ENTRY_MARK; // Note: We do not need to resolve the handle or enter the VM
return loader() == NULL; // 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. // be loaded.
class ciInstanceKlass : public ciKlass { class ciInstanceKlass : public ciKlass {
CI_PACKAGE_ACCESS CI_PACKAGE_ACCESS
friend class ciBytecodeStream;
friend class ciEnv; friend class ciEnv;
friend class ciExceptionHandler;
friend class ciMethod; friend class ciMethod;
friend class ciField; friend class ciField;
friend class ciBytecodeStream;
private: private:
jobject _loader; jobject _loader;
@ -78,6 +79,8 @@ protected:
const char* type_string() { return "ciInstanceKlass"; } const char* type_string() { return "ciInstanceKlass"; }
bool is_in_package_impl(const char* packagename, int len);
void print_impl(outputStream* st); void print_impl(outputStream* st);
ciConstantPoolCache* field_cache(); ciConstantPoolCache* field_cache();
@ -196,6 +199,12 @@ public:
bool is_java_lang_Object(); 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? // What kind of ciObject is this?
bool is_instance_klass() { return true; } bool is_instance_klass() { return true; }
bool is_java_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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -69,7 +69,7 @@ public:
ciKlass(KlassHandle k_h); ciKlass(KlassHandle k_h);
// What is the name of this klass? // What is the name of this klass?
ciSymbol* name() { return _name; } ciSymbol* name() const { return _name; }
// What is its layout helper value? // What is its layout helper value?
jint layout_helper() { return _layout_helper; } jint layout_helper() { return _layout_helper; }

View File

@ -38,6 +38,8 @@ class ciMethod : public ciObject {
CI_PACKAGE_ACCESS CI_PACKAGE_ACCESS
friend class ciEnv; friend class ciEnv;
friend class ciExceptionHandlerStream; friend class ciExceptionHandlerStream;
friend class ciBytecodeStream;
friend class ciMethodHandle;
private: private:
// General method information. // General method information.
@ -251,4 +253,10 @@ class ciMethod : public ciObject {
// Print the name of this method in various incarnations. // Print the name of this method in various incarnations.
void print_name(outputStream* st = tty); void print_name(outputStream* st = tty);
void print_short_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? // What kind of ciObject is this?
virtual bool is_null_object() const { return false; } 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_cpcache() const { return false; }
virtual bool is_instance() { return false; } virtual bool is_instance() { return false; }
virtual bool is_method() { return false; } virtual bool is_method() { return false; }
virtual bool is_method_data() { 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_array() { return false; }
virtual bool is_obj_array() { return false; } virtual bool is_obj_array() { return false; }
virtual bool is_type_array() { return false; } virtual bool is_type_array() { return false; }
@ -186,6 +188,10 @@ public:
assert(is_null_object(), "bad cast"); assert(is_null_object(), "bad cast");
return (ciNullObject*)this; return (ciNullObject*)this;
} }
ciCallSite* as_call_site() {
assert(is_call_site(), "bad cast");
return (ciCallSite*) this;
}
ciCPCache* as_cpcache() { ciCPCache* as_cpcache() {
assert(is_cpcache(), "bad cast"); assert(is_cpcache(), "bad cast");
return (ciCPCache*) this; return (ciCPCache*) this;
@ -202,6 +208,10 @@ public:
assert(is_method_data(), "bad cast"); assert(is_method_data(), "bad cast");
return (ciMethodData*)this; return (ciMethodData*)this;
} }
ciMethodHandle* as_method_handle() {
assert(is_method_handle(), "bad cast");
return (ciMethodHandle*) this;
}
ciArray* as_array() { ciArray* as_array() {
assert(is_array(), "bad cast"); assert(is_array(), "bad cast");
return (ciArray*)this; return (ciArray*)this;

View File

@ -337,6 +337,11 @@ ciObject* ciObjectFactory::create_new_object(oop o) {
return new (arena()) ciMethodData(h_md); return new (arena()) ciMethodData(h_md);
} else if (o->is_instance()) { } else if (o->is_instance()) {
instanceHandle h_i(THREAD, (instanceOop)o); instanceHandle h_i(THREAD, (instanceOop)o);
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); return new (arena()) ciInstance(h_i);
} else if (o->is_objArray()) { } else if (o->is_objArray()) {
objArrayHandle h_oa(THREAD, (objArrayOop)o); objArrayHandle h_oa(THREAD, (objArrayOop)o);

View File

@ -186,8 +186,9 @@ int ciBytecodeStream::get_klass_index() const {
// If this bytecode is a new, newarray, multianewarray, instanceof, // If this bytecode is a new, newarray, multianewarray, instanceof,
// or checkcast, get the referenced klass. // or checkcast, get the referenced klass.
ciKlass* ciBytecodeStream::get_klass(bool& will_link) { ciKlass* ciBytecodeStream::get_klass(bool& will_link) {
return CURRENT_ENV->get_klass_by_index(_holder, get_klass_index(), VM_ENTRY_MARK;
will_link); 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 // If this bytecode is one of the ldc variants, get the referenced
// constant. // constant.
ciConstant ciBytecodeStream::get_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 // There is no "will_link" result passed back. The user is responsible
// for checking linkability when retrieving the associated field. // for checking linkability when retrieving the associated field.
ciInstanceKlass* ciBytecodeStream::get_declared_field_holder() { ciInstanceKlass* ciBytecodeStream::get_declared_field_holder() {
VM_ENTRY_MARK;
constantPoolHandle cpool(_method->get_methodOop()->constants());
int holder_index = get_field_holder_index(); int holder_index = get_field_holder_index();
bool ignore; 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(); ->as_instance_klass();
} }
@ -277,9 +282,10 @@ ciInstanceKlass* ciBytecodeStream::get_declared_field_holder() {
// referenced by the current bytecode. Used for generating // referenced by the current bytecode. Used for generating
// deoptimization information. // deoptimization information.
int ciBytecodeStream::get_field_holder_index() { int ciBytecodeStream::get_field_holder_index() {
VM_ENTRY_MARK; GUARDED_VM_ENTRY(
constantPoolOop cpool = _holder->get_instanceKlass()->constants(); constantPoolOop cpool = _holder->get_instanceKlass()->constants();
return cpool->klass_ref_index_at(get_field_index()); 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. // If this is a method invocation bytecode, get the invoked method.
ciMethod* ciBytecodeStream::get_method(bool& will_link) { 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(); will_link = m->is_loaded();
return m; 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 // There is no "will_link" result passed back. The user is responsible
// for checking linkability when retrieving the associated method. // for checking linkability when retrieving the associated method.
ciKlass* ciBytecodeStream::get_declared_method_holder() { ciKlass* ciBytecodeStream::get_declared_method_holder() {
VM_ENTRY_MARK;
constantPoolHandle cpool(_method->get_methodOop()->constants());
bool ignore; bool ignore;
// report as InvokeDynamic for invokedynamic, which is syntactically classless // report as InvokeDynamic for invokedynamic, which is syntactically classless
if (cur_bc() == Bytecodes::_invokedynamic) if (cur_bc() == Bytecodes::_invokedynamic)
return CURRENT_ENV->get_klass_by_name(_holder, ciSymbol::java_dyn_InvokeDynamic(), false); 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 // referenced by the current bytecode. Used for generating
// deoptimization information. // deoptimization information.
int ciBytecodeStream::get_method_holder_index() { int ciBytecodeStream::get_method_holder_index() {
VM_ENTRY_MARK; constantPoolOop cpool = _method->get_methodOop()->constants();
constantPoolOop cpool = _holder->get_instanceKlass()->constants();
return cpool->klass_ref_index_at(get_method_index()); 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(); 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

@ -233,6 +233,7 @@ public:
int get_method_signature_index(); int get_method_signature_index();
ciCPCache* get_cpcache(); ciCPCache* get_cpcache();
ciCallSite* get_call_site();
private: private:
void assert_index_size(int required_size) const { 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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);) 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 // ciSymbol::utf8_length
int 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -28,6 +28,7 @@
// machine. // machine.
class ciSymbol : public ciObject { class ciSymbol : public ciObject {
CI_PACKAGE_ACCESS CI_PACKAGE_ACCESS
// These friends all make direct use of get_symbolOop:
friend class ciEnv; friend class ciEnv;
friend class ciInstanceKlass; friend class ciInstanceKlass;
friend class ciSignature; friend class ciSignature;
@ -38,13 +39,13 @@ private:
ciSymbol(symbolOop s) : ciObject(s) {} ciSymbol(symbolOop s) : ciObject(s) {}
ciSymbol(symbolHandle s); // for use with vmSymbolHandles 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"; } const char* type_string() { return "ciSymbol"; }
void print_impl(outputStream* st); 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(); jbyte* base();
// Make a ciSymbol from a C string (implementation). // Make a ciSymbol from a C string (implementation).
@ -55,6 +56,15 @@ public:
const char* as_utf8(); const char* as_utf8();
int utf8_length(); 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? // What kind of ciObject is this?
bool is_symbol() { return true; } 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); guarantee_property(value_type.is_int(), "Inconsistent constant value type in class file %s", CHECK);
break; break;
case T_OBJECT: 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())), && (value_type.is_string() || value_type.is_unresolved_string())),
"Bad string initial value in class file %s", CHECK); "Bad string initial value in class file %s", CHECK);
break; break;
@ -1718,9 +1718,7 @@ methodHandle ClassFileParser::parse_method(constantPoolHandle cp, bool is_interf
m->set_exception_table(exception_handlers()); m->set_exception_table(exception_handlers());
// Copy byte codes // Copy byte codes
if (code_length > 0) { m->set_code(code_start);
memcpy(m->code_base(), code_start, code_length);
}
// Copy line number table // Copy line number table
if (linenumber_table != NULL) { if (linenumber_table != NULL) {

View File

@ -299,6 +299,20 @@ vmIntrinsics::ID vmIntrinsics::for_unboxing(BasicType type) {
return wrapper_intrinsic(type, true); 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) { methodOop vmIntrinsics::method_for(vmIntrinsics::ID id) {
if (id == _none) return NULL; if (id == _none) return NULL;
symbolOop cname = vmSymbols::symbol_at(class_for(id)); symbolOop cname = vmSymbols::symbol_at(class_for(id));

View File

@ -1084,4 +1084,7 @@ public:
// Wrapper object methods: // Wrapper object methods:
static ID for_boxing(BasicType type); static ID for_boxing(BasicType type);
static ID for_unboxing(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()) { if (!method()->is_native()) {
SimpleScopeDesc ssd(this, fr.pc()); SimpleScopeDesc ssd(this, fr.pc());
Bytecode_invoke* call = Bytecode_invoke_at(ssd.method(), ssd.bci()); 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(); 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 compileLog.hpp
callGenerator.cpp connode.hpp callGenerator.cpp connode.hpp
callGenerator.cpp ciCPCache.hpp callGenerator.cpp ciCPCache.hpp
callGenerator.cpp ciMethodHandle.hpp
callGenerator.cpp javaClasses.hpp
callGenerator.cpp parse.hpp callGenerator.cpp parse.hpp
callGenerator.cpp rootnode.hpp callGenerator.cpp rootnode.hpp
callGenerator.cpp runtime.hpp callGenerator.cpp runtime.hpp
@ -392,6 +394,9 @@ divnode.hpp type.hpp
doCall.cpp addnode.hpp doCall.cpp addnode.hpp
doCall.cpp callGenerator.hpp doCall.cpp callGenerator.hpp
doCall.cpp ciCallSite.hpp
doCall.cpp ciCPCache.hpp
doCall.cpp ciMethodHandle.hpp
doCall.cpp cfgnode.hpp doCall.cpp cfgnode.hpp
doCall.cpp compileLog.hpp doCall.cpp compileLog.hpp
doCall.cpp linkResolver.hpp doCall.cpp linkResolver.hpp

View File

@ -516,6 +516,11 @@ ciArrayKlassKlass.hpp ciKlassKlass.hpp
ciCallProfile.hpp ciClassList.hpp ciCallProfile.hpp ciClassList.hpp
ciCallSite.cpp ciCallSite.hpp
ciCallSite.cpp ciUtilities.hpp
ciCallSite.hpp ciInstance.hpp
ciConstant.cpp allocation.hpp ciConstant.cpp allocation.hpp
ciConstant.cpp allocation.inline.hpp ciConstant.cpp allocation.inline.hpp
ciConstant.cpp ciConstant.hpp ciConstant.cpp ciConstant.hpp
@ -599,6 +604,7 @@ ciField.cpp universe.inline.hpp
ciField.hpp ciClassList.hpp ciField.hpp ciClassList.hpp
ciField.hpp ciConstant.hpp ciField.hpp ciConstant.hpp
ciField.hpp ciFlags.hpp ciField.hpp ciFlags.hpp
ciField.hpp ciInstance.hpp
ciFlags.cpp ciFlags.hpp ciFlags.cpp ciFlags.hpp
@ -685,6 +691,7 @@ ciMethod.hpp ciFlags.hpp
ciMethod.hpp ciInstanceKlass.hpp ciMethod.hpp ciInstanceKlass.hpp
ciMethod.hpp ciObject.hpp ciMethod.hpp ciObject.hpp
ciMethod.hpp ciSignature.hpp ciMethod.hpp ciSignature.hpp
ciMethod.hpp methodHandles.hpp
ciMethod.hpp methodLiveness.hpp ciMethod.hpp methodLiveness.hpp
ciMethodBlocks.cpp bytecode.hpp ciMethodBlocks.cpp bytecode.hpp
@ -716,6 +723,15 @@ ciMethodKlass.cpp ciUtilities.hpp
ciMethodKlass.hpp ciKlass.hpp ciMethodKlass.hpp ciKlass.hpp
ciMethodKlass.hpp ciSymbol.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.cpp ciNullObject.hpp
ciNullObject.hpp ciClassList.hpp ciNullObject.hpp ciClassList.hpp
@ -761,12 +777,14 @@ ciObject.hpp handles.hpp
ciObject.hpp jniHandles.hpp ciObject.hpp jniHandles.hpp
ciObjectFactory.cpp allocation.inline.hpp ciObjectFactory.cpp allocation.inline.hpp
ciObjectFactory.cpp ciCallSite.hpp
ciObjectFactory.cpp ciCPCache.hpp ciObjectFactory.cpp ciCPCache.hpp
ciObjectFactory.cpp ciInstance.hpp ciObjectFactory.cpp ciInstance.hpp
ciObjectFactory.cpp ciInstanceKlass.hpp ciObjectFactory.cpp ciInstanceKlass.hpp
ciObjectFactory.cpp ciInstanceKlassKlass.hpp ciObjectFactory.cpp ciInstanceKlassKlass.hpp
ciObjectFactory.cpp ciMethod.hpp ciObjectFactory.cpp ciMethod.hpp
ciObjectFactory.cpp ciMethodData.hpp ciObjectFactory.cpp ciMethodData.hpp
ciObjectFactory.cpp ciMethodHandle.hpp
ciObjectFactory.cpp ciMethodKlass.hpp ciObjectFactory.cpp ciMethodKlass.hpp
ciObjectFactory.cpp ciNullObject.hpp ciObjectFactory.cpp ciNullObject.hpp
ciObjectFactory.cpp ciObjArray.hpp ciObjectFactory.cpp ciObjArray.hpp
@ -800,6 +818,7 @@ ciSignature.hpp ciSymbol.hpp
ciSignature.hpp globalDefinitions.hpp ciSignature.hpp globalDefinitions.hpp
ciSignature.hpp growableArray.hpp ciSignature.hpp growableArray.hpp
ciStreams.cpp ciCallSite.hpp
ciStreams.cpp ciConstant.hpp ciStreams.cpp ciConstant.hpp
ciStreams.cpp ciField.hpp ciStreams.cpp ciField.hpp
ciStreams.cpp ciStreams.hpp ciStreams.cpp ciStreams.hpp
@ -2824,6 +2843,8 @@ methodDataOop.hpp universe.hpp
methodHandleWalk.hpp methodHandles.hpp methodHandleWalk.hpp methodHandles.hpp
methodHandleWalk.cpp methodHandleWalk.hpp methodHandleWalk.cpp methodHandleWalk.hpp
methodHandleWalk.cpp oopFactory.hpp
methodHandleWalk.cpp rewriter.hpp
methodHandles.hpp frame.inline.hpp methodHandles.hpp frame.inline.hpp
methodHandles.hpp globals.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_invokespecial() const { return adjusted_invoke_code() == Bytecodes::_invokespecial; }
bool is_invokedynamic() const { return adjusted_invoke_code() == Bytecodes::_invokedynamic; } 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 has_giant_index() const { return is_invokedynamic(); }
bool is_valid() const { return is_invokeinterface() || 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()); st->print_cr(" %s", constants->resolved_klass_at(i)->klass_part()->external_name());
} else if (tag.is_unresolved_klass()) { } else if (tag.is_unresolved_klass()) {
st->print_cr(" <unresolved klass at %d>", i); st->print_cr(" <unresolved klass at %d>", i);
} else if (tag.is_object()) {
st->print_cr(" " PTR_FORMAT, constants->object_at(i));
} else { } else {
st->print_cr(" bad tag=%d at %d", tag.value(), i); 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()); methodHandle mh(thread, fr.interpreter_frame_method());
Bytecode_invoke* invoke = Bytecode_invoke_at(mh, bci); Bytecode_invoke* invoke = Bytecode_invoke_at(mh, bci);
ArgumentSizeComputer asc(invoke->signature()); 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, Copy::conjoint_bytes(src_address, dest_address,
size_of_arguments * Interpreter::stackElementSize()); size_of_arguments * Interpreter::stackElementSize());
IRT_END IRT_END

View File

@ -247,15 +247,22 @@ methodHandle Rewriter::rewrite_jsrs(methodHandle method, TRAPS) {
void Rewriter::rewrite(instanceKlassHandle klass, TRAPS) { void Rewriter::rewrite(instanceKlassHandle klass, TRAPS) {
ResourceMark rm(THREAD); ResourceMark rm(THREAD);
Rewriter rw(klass, CHECK); Rewriter rw(klass, klass->constants(), klass->methods(), CHECK);
// (That's all, folks.) // (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), : _klass(klass),
// gather starting points _pool(cpool),
_pool( THREAD, klass->constants()), _methods(methods)
_methods(THREAD, klass->methods())
{ {
assert(_pool->cache() == NULL, "constant pool cache must not be set yet"); 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: // All the work goes in here:
Rewriter(instanceKlassHandle klass, TRAPS); Rewriter(instanceKlassHandle klass, constantPoolHandle cpool, objArrayHandle methods, TRAPS);
void compute_index_maps(); void compute_index_maps();
void make_constant_pool_cache(TRAPS); void make_constant_pool_cache(TRAPS);
@ -70,6 +70,7 @@ class Rewriter: public StackObj {
public: public:
// Driver routine: // Driver routine:
static void rewrite(instanceKlassHandle klass, TRAPS); static void rewrite(instanceKlassHandle klass, TRAPS);
static void rewrite(instanceKlassHandle klass, constantPoolHandle cpool, objArrayHandle methods, TRAPS);
enum { enum {
_secondary_entry_tag = nth_bit(30) _secondary_entry_tag = nth_bit(30)

View File

@ -258,6 +258,11 @@ public:
LocalVariableTableElement* localvariable_table_start() const; LocalVariableTableElement* localvariable_table_start() const;
// byte codes // 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_base() const { return (address) (this+1); }
address code_end() const { return code_base() + code_size(); } address code_end() const { return code_base() + code_size(); }
bool contains(address bcp) const { return code_base() <= bcp 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 // For temporary use while constructing constant pool
void string_index_at_put(int which, int string_index) { void string_index_at_put(int which, int string_index) {
tag_at_put(which, JVM_CONSTANT_StringIndex); tag_at_put(which, JVM_CONSTANT_StringIndex);
@ -228,7 +238,8 @@ class constantPoolOopDesc : public oopDesc {
tag.is_unresolved_klass() || tag.is_unresolved_klass() ||
tag.is_symbol() || tag.is_symbol() ||
tag.is_unresolved_string() || tag.is_unresolved_string() ||
tag.is_string(); tag.is_string() ||
tag.is_object();
} }
// Fetching constants // Fetching constants
@ -291,6 +302,11 @@ class constantPoolOopDesc : public oopDesc {
return string_at_impl(h_this, which, CHECK_NULL); 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 "pseudo-string" is an non-string oop that has found is way into
// a String entry. // a String entry.
// Under AnonymousClasses this can happen if the user patches a live // Under AnonymousClasses this can happen if the user patches a live

View File

@ -1831,11 +1831,7 @@ void GenerateOopMap::do_jsr(int targ_bci) {
void GenerateOopMap::do_ldc(int idx, int bci) { void GenerateOopMap::do_ldc(int idx, int bci) {
constantPoolOop cp = method()->constants(); constantPoolOop cp = method()->constants();
constantTag tag = cp->tag_at(idx); CellTypeState cts = cp->is_pointer_entry(idx) ? CellTypeState::make_line_ref(bci) : valCTS;
CellTypeState cts = (tag.is_string() || tag.is_unresolved_string() ||
tag.is_klass() || tag.is_unresolved_klass())
? CellTypeState::make_line_ref(bci) : valCTS;
ppush1(cts); ppush1(cts);
} }

View File

@ -365,6 +365,7 @@ class methodOopDesc : public oopDesc {
#endif #endif
// byte codes // byte codes
void set_code(address code) { return constMethod()->set_code(code); }
address code_base() const { return constMethod()->code_base(); } address code_base() const { return constMethod()->code_base(); }
bool contains(address bcp) const { return constMethod()->contains(bcp); } 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -25,6 +25,11 @@
# include "incls/_precompiled.incl" # include "incls/_precompiled.incl"
# include "incls/_symbolOop.cpp.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 { bool symbolOopDesc::equals(const char* str, int len) const {
int l = utf8_length(); int l = utf8_length();
if (l != len) return false; if (l != len) return false;
@ -36,6 +41,48 @@ bool symbolOopDesc::equals(const char* str, int len) const {
return true; 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 { char* symbolOopDesc::as_C_string(char* buf, int size) const {
if (size > 0) { if (size > 0) {
int len = MIN2(size - 1, utf8_length()); 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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; } 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, 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 // Three-way compare for sorting; returns -1/0/1 if receiver is </==/> than arg
// note that the ordering is not alfabetical // note that the ordering is not alfabetical

View File

@ -180,6 +180,10 @@ const char* InlineTree::shouldNotInline(ciMethod *callee_method, ciMethod* calle
return NULL; 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 // First check all inlining restrictions which are required for correctness
if (callee_method->is_abstract()) return "abstract method"; if (callee_method->is_abstract()) return "abstract method";
// note: we allow ik->is_abstract() // note: we allow ik->is_abstract()

View File

@ -148,7 +148,7 @@ JVMState* DirectCallGenerator::generate(JVMState* jvms) {
} }
//---------------------------DynamicCallGenerator----------------------------- //---------------------------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 { class DynamicCallGenerator : public CallGenerator {
public: public:
DynamicCallGenerator(ciMethod* method) DynamicCallGenerator(ciMethod* method)
@ -179,25 +179,25 @@ JVMState* DynamicCallGenerator::generate(JVMState* jvms) {
// Load the CallSite object from the constant pool cache. // Load the CallSite object from the constant pool cache.
const TypeOopPtr* cpcache_ptr = TypeOopPtr::make_from_constant(cpcache); const TypeOopPtr* cpcache_ptr = TypeOopPtr::make_from_constant(cpcache);
Node* cpc = kit.makecon(cpcache_ptr); Node* cpcache_adr = kit.makecon(cpcache_ptr);
Node* adr = kit.basic_plus_adr(cpc, cpc, call_site_offset); Node* call_site_adr = kit.basic_plus_adr(cpcache_adr, cpcache_adr, call_site_offset);
Node* call_site = kit.make_load(kit.control(), adr, TypeInstPtr::BOTTOM, T_OBJECT, Compile::AliasIdxRaw); 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. // Load the target MethodHandle from the CallSite object.
Node* mh_adr = kit.basic_plus_adr(call_site, call_site, java_dyn_CallSite::target_offset_in_bytes()); Node* target_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); 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. // invokedynamic is treated as an optimized invokevirtual.
call->set_optimized_virtual(true); call->set_optimized_virtual(true);
// Take extra care (in the presence of argument motion) not to trash the SP: // Take extra care (in the presence of argument motion) not to trash the SP:
call->set_method_handle_invoke(true); call->set_method_handle_invoke(true);
// Pass the MethodHandle as first argument and shift the other // Pass the target MethodHandle as first argument and shift the
// arguments. // other arguments.
call->init_req(0 + TypeFunc::Parms, mh); call->init_req(0 + TypeFunc::Parms, target_mh);
uint nargs = call->method()->arg_size(); uint nargs = call->method()->arg_size();
for (uint i = 1; i < nargs; i++) { for (uint i = 1; i < nargs; i++) {
Node* arg = kit.argument(i - 1); 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----------------------------- //-------------------------UncommonTrapCallGenerator-----------------------------
// Internal class which handles all out-of-line calls checking receiver type. // Internal class which handles all out-of-line calls checking receiver type.
class UncommonTrapCallGenerator : public CallGenerator { class UncommonTrapCallGenerator : public CallGenerator {

View File

@ -117,6 +117,12 @@ class CallGenerator : public ResourceObj {
CallGenerator* if_hit, CallGenerator* if_hit,
float hit_prob); 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: // How to make a call that gives up and goes back to the interpreter:
static CallGenerator* for_uncommon_trap(ciMethod* m, static CallGenerator* for_uncommon_trap(ciMethod* m,
Deoptimization::DeoptReason reason, 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. // There was no special inlining tactic, or it bailed out.
// Use a more generic tactic, like a simple call. // Use a more generic tactic, like a simple call.
if (call_is_virtual) { if (call_is_virtual) {
return CallGenerator::for_virtual_call(call_method, vtable_index); 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 { } else {
// Class Hierarchy Analysis or Type Profile reveals a unique target, // Class Hierarchy Analysis or Type Profile reveals a unique target,
// or it is a static or special call. // 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) { 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. // 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(); ciType* field_klass = field->type();
bool is_vol = field->is_volatile(); 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()) { if (!field->type()->is_loaded()) {
type = TypeInstPtr::BOTTOM; type = TypeInstPtr::BOTTOM;
must_assert_null = true; 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. // This can happen if the constant oop is non-perm.
ciObject* con = field->constant_value().as_object(); ciObject* con = field->constant_value().as_object();
// Do not "join" in the previous type; it doesn't add value, // 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; } Handle method_handle() { return _method_handle; }
oop method_handle_oop() { return _method_handle(); } oop method_handle_oop() { return _method_handle(); }
oop method_type_oop() { return MethodHandle_type_oop(); } oop method_type_oop() { return MethodHandle_type_oop(); }
oop vmtarget_oop() { return MethodHandle_vmtarget_oop(); }
jint adapter_conversion() { assert(is_adapter(), ""); return _conversion; } jint adapter_conversion() { assert(is_adapter(), ""); return _conversion; }
int adapter_conversion_op() { return MethodHandles::adapter_conversion_op(adapter_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. // You supply the tokens shuffled by the abstract interpretation.
class MethodHandleWalker : StackObj { class MethodHandleWalker : StackObj {
public: public:
struct _ArgToken { }; // dummy struct // Stack values:
typedef _ArgToken* ArgToken; 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: // Abstract interpretation state:
struct SlotState { struct SlotState {
@ -118,6 +156,8 @@ public:
private: private:
MethodHandleChain _chain; 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 int _outgoing_argc; // # non-empty outgoing slots
@ -126,7 +166,7 @@ private:
// If old_type != T_VOID, remove the old argument at that point. // If old_type != T_VOID, remove the old argument at that point.
// If new_type != T_VOID, insert the new 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. // 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) { SlotState* slot_state(int slot) {
if (slot < 0 || slot >= _outgoing.length()) if (slot < 0 || slot >= _outgoing.length())
@ -153,20 +193,34 @@ private:
void walk_incoming_state(TRAPS); void walk_incoming_state(TRAPS);
public: public:
MethodHandleWalker(Handle root, TRAPS) MethodHandleWalker(Handle root, bool for_invokedynamic, TRAPS)
: _chain(root, THREAD), : _chain(root, THREAD),
_for_invokedynamic(for_invokedynamic),
_outgoing(THREAD, 10), _outgoing(THREAD, 10),
_outgoing_argc(0) _outgoing_argc(0)
{ } {
_local_index = for_invokedynamic ? 0 : 1;
}
MethodHandleChain& chain() { return _chain; } 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: // plug-in abstract interpretation steps:
virtual ArgToken make_parameter( BasicType type, klassOop tk, int argnum, TRAPS ) = 0; 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_prim_constant( BasicType type, jvalue* con, TRAPS ) = 0;
virtual ArgToken make_oop_constant( oop 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_conversion( BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& src, TRAPS ) = 0;
virtual ArgToken make_fetch( BasicType type, klassOop tk, Bytecodes::Code op, ArgToken base, ArgToken offset, 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( 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 // For make_invoke, the methodOop can be NULL if the intrinsic ID
@ -187,83 +241,167 @@ public:
// The IR happens to be JVM bytecodes. // The IR happens to be JVM bytecodes.
class MethodHandleCompiler : public MethodHandleWalker { class MethodHandleCompiler : public MethodHandleWalker {
private: private:
methodHandle _callee;
KlassHandle _rklass; // Return type for casting.
BasicType _rtype;
KlassHandle _target_klass;
Thread* _thread; Thread* _thread;
struct PrimCon { // Fake constant pool entry.
BasicType _type; class ConstantValue {
jvalue _value; 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: // Accumulated compiler state:
stringStream _bytes; GrowableArray<unsigned char> _bytecode;
GrowableArray<Handle> _constant_oops;
GrowableArray<PrimCon*> _constant_prims; int _cur_stack;
int _max_stack; int _max_stack;
int _num_params; int _num_params;
int _max_locals;
int _name_index; int _name_index;
int _signature_index; int _signature_index;
// Stack values: void stack_push(BasicType bt) {
enum TokenType { _cur_stack += type2size[bt];
tt_void, if (_cur_stack > _max_stack) _max_stack = _cur_stack;
tt_parameter, }
tt_temporary, void stack_pop(BasicType bt) {
tt_constant _cur_stack -= type2size[bt];
}; assert(_cur_stack >= 0, "sanity");
ArgToken make_stack_value(TokenType tt, BasicType type, int id) {
return ArgToken( ((intptr_t)id << 8) | ((intptr_t)type << 4) | (intptr_t)tt );
} }
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) { 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) { 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) { 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); 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); // Get a real constant pool.
int find_prim_constant(BasicType type, jvalue* con); constantPoolHandle get_constant_pool(TRAPS) const;
// Get a real methodOop.
methodHandle get_method_oop(TRAPS) const;
public: public:
MethodHandleCompiler(Handle root, TRAPS) MethodHandleCompiler(Handle root, methodHandle call_method, bool for_invokedynamic, 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);
}
// Compile the given MH chain into bytecode. // 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; return m;
} else { } else {
decode_flags_result |= MethodHandles::_dmf_does_dispatch;
assert(vmtarget->is_klass(), "must be class or interface"); 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; receiver_limit_result = (klassOop)vmtarget;
Klass* tk = Klass::cast((klassOop)vmtarget); Klass* tk = Klass::cast((klassOop)vmtarget);
if (tk->is_interface()) { if (tk->is_interface()) {
@ -179,8 +180,10 @@ methodOop MethodHandles::decode_BoundMethodHandle(oop mh, klassOop& receiver_lim
// short-circuits directly to the methodOop. // short-circuits directly to the methodOop.
// (It might be another argument besides a receiver also.) // (It might be another argument besides a receiver also.)
assert(target->is_method(), "must be a simple method"); assert(target->is_method(), "must be a simple method");
methodOop m = (methodOop) target;
decode_flags_result |= MethodHandles::_dmf_binds_method; decode_flags_result |= MethodHandles::_dmf_binds_method;
methodOop m = (methodOop) target;
if (!m->is_static())
decode_flags_result |= MethodHandles::_dmf_has_receiver;
return m; return m;
} }
} }
@ -233,8 +236,8 @@ methodOop MethodHandles::decode_methodOop(methodOop m, int& decode_flags_result)
BasicType recv_bt = char2type(sig->byte_at(1)); BasicType recv_bt = char2type(sig->byte_at(1));
// Note: recv_bt might be T_ILLEGAL if byte_at(2) is ')' // Note: recv_bt might be T_ILLEGAL if byte_at(2) is ')'
assert(sig->byte_at(0) == '(', "must be method sig"); assert(sig->byte_at(0) == '(', "must be method sig");
if (recv_bt == T_OBJECT || recv_bt == T_ARRAY) // if (recv_bt == T_OBJECT || recv_bt == T_ARRAY)
decode_flags_result |= _dmf_has_receiver; // decode_flags_result |= _dmf_has_receiver;
} else { } else {
// non-static method // non-static method
decode_flags_result |= _dmf_has_receiver; decode_flags_result |= _dmf_has_receiver;
@ -818,7 +821,7 @@ static bool is_always_null_type(klassOop klass) {
for (int i = 0; ; i++) { for (int i = 0; ; i++) {
const char* test_name = always_null_names[i]; const char* test_name = always_null_names[i];
if (test_name == NULL) break; if (test_name == NULL) break;
if (name->equals(test_name, (int) strlen(test_name))) if (name->equals(test_name))
return true; return true;
} }
return false; return false;
@ -1487,8 +1490,9 @@ void MethodHandles::verify_BoundMethodHandle(Handle mh, Handle target, int argnu
int target_pushes = decode_MethodHandle_stack_pushes(target()); int target_pushes = decode_MethodHandle_stack_pushes(target());
assert(this_pushes == slots_pushed + target_pushes, "BMH stack motion must be correct"); 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 // do not blow the stack; use a Java-based adapter if this limit is exceeded
if (slots_pushed + target_pushes > MethodHandlePushLimit) // FIXME
err = "too many bound parameters"; // 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); 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, // If (a) the target is a direct non-dispatched method handle,
// or (b) the target is a dispatched direct method handle and we // or (b) the target is a dispatched direct method handle and we
// are binding the receiver, cut out the middle-man. // 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; int decode_flags = 0; klassOop receiver_limit_oop = NULL;
methodHandle m(THREAD, decode_method(target(), receiver_limit_oop, decode_flags)); 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"); } 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"); assert(sun_dyn_BoundMethodHandle::vmslots(mh()) == m_vmslots, "type w/ m sig");
if (argnum == 0 && (decode_flags & _dmf_has_receiver) != 0) { if (argnum == 0 && (decode_flags & _dmf_has_receiver) != 0) {
KlassHandle receiver_limit(THREAD, receiver_limit_oop); 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? // 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; MethodHandleEntry* me = NULL;
if (ptype == T_OBJECT) { if (ptype == T_OBJECT) {
if (direct_to_method) me = MethodHandles::entry(_bound_ref_direct_mh); 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -771,7 +771,7 @@ class InterpretedArgumentOopFinder: public SignatureInfo {
private: private:
OopClosure* _f; // Closure to invoke OopClosure* _f; // Closure to invoke
int _offset; // TOS-relative offset, decremented with each argument int _offset; // TOS-relative offset, decremented with each argument
bool _is_static; // true if the callee is a static method bool _has_receiver; // true if the callee has a receiver
frame* _fr; frame* _fr;
void set(int size, BasicType type) { void set(int size, BasicType type) {
@ -786,9 +786,9 @@ class InterpretedArgumentOopFinder: public SignatureInfo {
} }
public: 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 // 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() || assert(!fr->is_interpreted_frame() ||
args_size <= fr->interpreter_frame_expression_stack_size(), args_size <= fr->interpreter_frame_expression_stack_size(),
"args cannot be on stack anymore"); "args cannot be on stack anymore");
@ -796,11 +796,10 @@ class InterpretedArgumentOopFinder: public SignatureInfo {
_f = f; _f = f;
_fr = fr; _fr = fr;
_offset = args_size; _offset = args_size;
_is_static = is_static;
} }
void oops_do() { void oops_do() {
if (!_is_static) { if (_has_receiver) {
--_offset; --_offset;
oop_offset_do(); 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(); int max_locals = m->is_native() ? m->size_of_parameters() : m->max_locals();
symbolHandle signature; symbolHandle signature;
bool is_static = false; bool has_receiver = false;
// Process a callee's arguments if we are at a call site // Process a callee's arguments if we are at a call site
// (i.e., if we are at an invoke bytecode) // (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); Bytecode_invoke *call = Bytecode_invoke_at_check(m, bci);
if (call != NULL) { if (call != NULL) {
signature = symbolHandle(thread, call->signature()); signature = symbolHandle(thread, call->signature());
is_static = call->is_invokestatic(); has_receiver = call->has_receiver();
if (map->include_argument_oops() && if (map->include_argument_oops() &&
interpreter_frame_expression_stack_size() > 0) { interpreter_frame_expression_stack_size() > 0) {
ResourceMark rm(thread); // is this right ??? 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 // code in the interpreter calls a blocking runtime
// routine which can cause this code to be executed). // routine which can cause this code to be executed).
// (was bug gri 7/27/98) // (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; mask = &oopmap_mask;
#endif // ASSERT #endif // ASSERT
oops_interpreted_locals_do(f, max_locals, mask); 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(), m->max_stack(),
max_locals, mask); max_locals, mask);
} else { } else {
@ -992,7 +991,7 @@ void frame::oops_interpreted_locals_do(OopClosure *f,
void frame::oops_interpreted_expressions_do(OopClosure *f, void frame::oops_interpreted_expressions_do(OopClosure *f,
symbolHandle signature, symbolHandle signature,
bool is_static, bool has_receiver,
int max_stack, int max_stack,
int max_locals, int max_locals,
InterpreterOopMap *mask) { InterpreterOopMap *mask) {
@ -1005,7 +1004,7 @@ void frame::oops_interpreted_expressions_do(OopClosure *f,
// arguments in callee's locals. // arguments in callee's locals.
int args_size = 0; int args_size = 0;
if (!signature.is_null()) { 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); 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) { void frame::oops_interpreted_arguments_do(symbolHandle signature, bool has_receiver, OopClosure* f) {
InterpretedArgumentOopFinder finder(signature, is_static, this, f); InterpretedArgumentOopFinder finder(signature, has_receiver, this, f);
finder.oops_do(); finder.oops_do();
} }
@ -1067,7 +1066,7 @@ class CompiledArgumentOopFinder: public SignatureInfo {
protected: protected:
OopClosure* _f; OopClosure* _f;
int _offset; // the current offset, incremented with each argument int _offset; // the current offset, incremented with each argument
bool _is_static; // true if the callee is a static method bool _has_receiver; // true if the callee has a receiver
frame _fr; frame _fr;
RegisterMap* _reg_map; RegisterMap* _reg_map;
int _arg_size; int _arg_size;
@ -1087,24 +1086,24 @@ class CompiledArgumentOopFinder: public SignatureInfo {
} }
public: 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) { : SignatureInfo(signature) {
// initialize CompiledArgumentOopFinder // initialize CompiledArgumentOopFinder
_f = f; _f = f;
_offset = 0; _offset = 0;
_is_static = is_static; _has_receiver = has_receiver;
_fr = fr; _fr = fr;
_reg_map = (RegisterMap*)reg_map; _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; 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"); assert(arg_size == _arg_size, "wrong arg size");
} }
void oops_do() { void oops_do() {
if (!_is_static) { if (_has_receiver) {
handle_oop_offset(); handle_oop_offset();
_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; ResourceMark rm;
CompiledArgumentOopFinder finder(signature, is_static, f, *this, reg_map); CompiledArgumentOopFinder finder(signature, has_receiver, f, *this, reg_map);
finder.oops_do(); 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; oop* oopmapreg_to_location(VMReg reg, const RegisterMap* regmap) const;
// Oops-do's // 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); void oops_interpreted_do(OopClosure* f, const RegisterMap* map, bool query_oop_map_cache = true);
private: private:
@ -379,9 +379,9 @@ class frame VALUE_OBJ_CLASS_SPEC {
int max_locals, int max_locals,
InterpreterOopMap *mask); InterpreterOopMap *mask);
void oops_interpreted_expressions_do(OopClosure *f, symbolHandle signature, 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); 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 // Iteration of oops
void oops_do_internal(OopClosure* f, CodeBlobClosure* cf, RegisterMap* map, bool use_interpreter_oop_map_cache); 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(); 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 // This method is returning a data structure allocating as a
// ResourceObject, so do not put any ResourceMarks in here. // ResourceObject, so do not put any ResourceMarks in here.
char *s = sig->as_C_string(); 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 ); BasicType *sig_bt = NEW_RESOURCE_ARRAY( BasicType, 256 );
VMRegPair *regs = NEW_RESOURCE_ARRAY( VMRegPair, 256 ); VMRegPair *regs = NEW_RESOURCE_ARRAY( VMRegPair, 256 );
int cnt = 0; int cnt = 0;
if (!is_static) { if (has_receiver) {
sig_bt[cnt++] = T_OBJECT; // Receiver is argument 0; not in signature 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 // Convert a sig into a calling convention register layout
// and find interesting things about it. // 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(); static VMReg name_for_receiver();
// "Top of Stack" slots that may be unused by the calling convention but must // "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_UnresolvedString = 102, // Temporary tag until actual use
JVM_CONSTANT_StringIndex = 103, // Temporary tag while constructing constant pool JVM_CONSTANT_StringIndex = 103, // Temporary tag while constructing constant pool
JVM_CONSTANT_UnresolvedClassInError = 104, // Error tag due to resolution error 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_unresolved_string() const { return _tag == JVM_CONSTANT_UnresolvedString; }
bool is_string_index() const { return _tag == JVM_CONSTANT_StringIndex; } 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_reference() const { return is_klass_index() || is_unresolved_klass(); }
bool is_klass_or_reference() const{ return is_klass() || is_klass_reference(); } 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(); } bool is_field_or_method() const { return is_field() || is_method() || is_interface_method(); }