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:
parent
375527d84e
commit
47f2433a58
@ -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
|
||||||
//
|
//
|
||||||
|
46
hotspot/src/share/vm/ci/ciCallSite.cpp
Normal file
46
hotspot/src/share/vm/ci/ciCallSite.cpp
Normal 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();
|
||||||
|
}
|
39
hotspot/src/share/vm/ci/ciCallSite.hpp
Normal file
39
hotspot/src/share/vm/ci/ciCallSite.hpp
Normal 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();
|
||||||
|
};
|
@ -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; \
|
||||||
|
@ -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);)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
@ -610,7 +614,7 @@ ciConstant ciEnv::get_constant_by_index(ciInstanceKlass* accessor,
|
|||||||
//
|
//
|
||||||
// Implementation note: this query is currently in no way cached.
|
// Implementation note: this query is currently in no way cached.
|
||||||
bool ciEnv::is_unresolved_string(ciInstanceKlass* accessor,
|
bool ciEnv::is_unresolved_string(ciInstanceKlass* accessor,
|
||||||
int index) const {
|
int index) const {
|
||||||
GUARDED_VM_ENTRY(return is_unresolved_string_impl(accessor->get_instanceKlass(), index); )
|
GUARDED_VM_ENTRY(return is_unresolved_string_impl(accessor->get_instanceKlass(), index); )
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -621,7 +625,7 @@ bool ciEnv::is_unresolved_string(ciInstanceKlass* accessor,
|
|||||||
//
|
//
|
||||||
// Implementation note: this query is currently in no way cached.
|
// Implementation note: this query is currently in no way cached.
|
||||||
bool ciEnv::is_unresolved_klass(ciInstanceKlass* accessor,
|
bool ciEnv::is_unresolved_klass(ciInstanceKlass* accessor,
|
||||||
int index) const {
|
int index) const {
|
||||||
GUARDED_VM_ENTRY(return is_unresolved_klass_impl(accessor->get_instanceKlass(), index); )
|
GUARDED_VM_ENTRY(return is_unresolved_klass_impl(accessor->get_instanceKlass(), index); )
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -702,15 +706,12 @@ methodOop ciEnv::lookup_method(instanceKlass* accessor,
|
|||||||
|
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
// ciEnv::get_method_by_index_impl
|
// 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);)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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());
|
||||||
|
@ -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:
|
||||||
//
|
//
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
|
@ -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; }
|
||||||
|
@ -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
|
||||||
|
@ -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; }
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
52
hotspot/src/share/vm/ci/ciMethodHandle.cpp
Normal file
52
hotspot/src/share/vm/ci/ciMethodHandle.cpp
Normal 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();
|
||||||
|
}
|
56
hotspot/src/share/vm/ci/ciMethodHandle.hpp
Normal file
56
hotspot/src/share/vm/ci/ciMethodHandle.hpp
Normal 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);
|
||||||
|
}
|
||||||
|
};
|
@ -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;
|
||||||
|
@ -337,7 +337,12 @@ 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);
|
||||||
return new (arena()) ciInstance(h_i);
|
if (java_dyn_CallSite::is_instance(o))
|
||||||
|
return new (arena()) ciCallSite(h_i);
|
||||||
|
else if (java_dyn_MethodHandle::is_instance(o))
|
||||||
|
return new (arena()) ciMethodHandle(h_i);
|
||||||
|
else
|
||||||
|
return new (arena()) ciInstance(h_i);
|
||||||
} else if (o->is_objArray()) {
|
} else if (o->is_objArray()) {
|
||||||
objArrayHandle h_oa(THREAD, (objArrayOop)o);
|
objArrayHandle h_oa(THREAD, (objArrayOop)o);
|
||||||
return new (arena()) ciObjArray(h_oa);
|
return new (arena()) ciObjArray(h_oa);
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
@ -232,7 +232,8 @@ public:
|
|||||||
int get_method_holder_index();
|
int get_method_holder_index();
|
||||||
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 {
|
||||||
|
@ -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() {
|
||||||
|
@ -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; }
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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));
|
||||||
|
@ -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);
|
||||||
};
|
};
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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() ||
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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");
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -1556,13 +1556,13 @@ void GenerateOopMap::interp1(BytecodeStream *itr) {
|
|||||||
case Bytecodes::_getfield: do_field(true, false, itr->get_index_big(), itr->bci()); break;
|
case Bytecodes::_getfield: do_field(true, false, itr->get_index_big(), itr->bci()); break;
|
||||||
case Bytecodes::_putfield: do_field(false, false, itr->get_index_big(), itr->bci()); break;
|
case Bytecodes::_putfield: do_field(false, false, itr->get_index_big(), itr->bci()); break;
|
||||||
|
|
||||||
case Bytecodes::_invokevirtual:
|
case Bytecodes::_invokevirtual:
|
||||||
case Bytecodes::_invokespecial: do_method(false, false, itr->get_index_big(), itr->bci()); break;
|
case Bytecodes::_invokespecial: do_method(false, false, itr->get_index_big(), itr->bci()); break;
|
||||||
case Bytecodes::_invokestatic: do_method(true, false, itr->get_index_big(), itr->bci()); break;
|
case Bytecodes::_invokestatic: do_method(true, false, itr->get_index_big(), itr->bci()); break;
|
||||||
case Bytecodes::_invokedynamic: do_method(true, false, itr->get_index_int(), itr->bci()); break;
|
case Bytecodes::_invokedynamic: do_method(true, false, itr->get_index_int(), itr->bci()); break;
|
||||||
case Bytecodes::_invokeinterface: do_method(false, true, itr->get_index_big(), itr->bci()); break;
|
case Bytecodes::_invokeinterface: do_method(false, true, itr->get_index_big(), itr->bci()); break;
|
||||||
case Bytecodes::_newarray:
|
case Bytecodes::_newarray:
|
||||||
case Bytecodes::_anewarray: pp_new_ref(vCTS, itr->bci()); break;
|
case Bytecodes::_anewarray: pp_new_ref(vCTS, itr->bci()); break;
|
||||||
case Bytecodes::_checkcast: do_checkcast(); break;
|
case Bytecodes::_checkcast: do_checkcast(); break;
|
||||||
case Bytecodes::_arraylength:
|
case Bytecodes::_arraylength:
|
||||||
case Bytecodes::_instanceof: pp(rCTS, vCTS); break;
|
case Bytecodes::_instanceof: pp(rCTS, vCTS); break;
|
||||||
@ -1830,12 +1830,8 @@ void GenerateOopMap::do_jsr(int targ_bci) {
|
|||||||
|
|
||||||
|
|
||||||
void GenerateOopMap::do_ldc(int idx, int bci) {
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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); }
|
||||||
|
|
||||||
|
@ -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());
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
|
@ -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 {
|
||||||
|
@ -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,
|
||||||
|
@ -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.
|
||||||
|
@ -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
@ -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,15 +156,17 @@ 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
|
||||||
|
|
||||||
// Replace a value of type old_type at slot (and maybe slot+1) with the new value.
|
// Replace a value of type old_type at slot (and maybe slot+1) with the new value.
|
||||||
// If old_type != T_VOID, remove the old argument at that point.
|
// If 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:
|
||||||
Thread* _thread;
|
methodHandle _callee;
|
||||||
|
KlassHandle _rklass; // Return type for casting.
|
||||||
|
BasicType _rtype;
|
||||||
|
KlassHandle _target_klass;
|
||||||
|
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);
|
||||||
};
|
};
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
@ -769,9 +769,9 @@ class InterpreterFrameClosure : public OffsetClosure {
|
|||||||
|
|
||||||
class InterpretedArgumentOopFinder: public SignatureInfo {
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1066,8 +1065,8 @@ void frame::oops_code_blob_do(OopClosure* f, CodeBlobClosure* cf, const Register
|
|||||||
class CompiledArgumentOopFinder: public SignatureInfo {
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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(); }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user