< prev index next >
src/share/vm/runtime/sharedRuntime.cpp
Print this page
*** 37,47 ****
--- 37,50 ----
#include "gc/shared/gcLocker.inline.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterRuntime.hpp"
#include "logging/log.hpp"
#include "memory/universe.inline.hpp"
+ #include "oops/fieldStreams.hpp"
+ #include "oops/objArrayOop.inline.hpp"
#include "oops/oop.inline.hpp"
+ #include "oops/valueKlass.hpp"
#include "prims/forte.hpp"
#include "prims/jvmtiExport.hpp"
#include "prims/jvmtiRedefineClassesTrace.hpp"
#include "prims/methodHandles.hpp"
#include "prims/nativeLookup.hpp"
*** 1153,1163 ****
bc = bytecode.invoke_code();
}
bool has_receiver = bc != Bytecodes::_invokestatic &&
bc != Bytecodes::_invokedynamic &&
! bc != Bytecodes::_invokehandle;
// Find receiver for non-static call
if (has_receiver) {
// This register map must be update since we need to find the receiver for
// compiled frames. The receiver might be in a register.
--- 1156,1167 ----
bc = bytecode.invoke_code();
}
bool has_receiver = bc != Bytecodes::_invokestatic &&
bc != Bytecodes::_invokedynamic &&
! bc != Bytecodes::_invokehandle &&
! bc != Bytecodes::_invokedirect;
// Find receiver for non-static call
if (has_receiver) {
// This register map must be update since we need to find the receiver for
// compiled frames. The receiver might be in a register.
*** 1365,1377 ****
#ifdef ASSERT
address dest_entry_point = callee_nm == NULL ? 0 : callee_nm->entry_point(); // used below
#endif
if (is_virtual) {
! assert(receiver.not_null() || invoke_code == Bytecodes::_invokehandle, "sanity check");
bool static_bound = call_info.resolved_method()->can_be_statically_bound();
! KlassHandle h_klass(THREAD, invoke_code == Bytecodes::_invokehandle ? NULL : receiver->klass());
CompiledIC::compute_monomorphic_entry(callee_method, h_klass,
is_optimized, static_bound, virtual_call_info,
CHECK_(methodHandle()));
} else {
// static call
--- 1369,1381 ----
#ifdef ASSERT
address dest_entry_point = callee_nm == NULL ? 0 : callee_nm->entry_point(); // used below
#endif
if (is_virtual) {
! assert(receiver.not_null() || invoke_code == Bytecodes::_invokehandle || invoke_code == Bytecodes::_invokedirect, "sanity check");
bool static_bound = call_info.resolved_method()->can_be_statically_bound();
! KlassHandle h_klass(THREAD, (invoke_code == Bytecodes::_invokehandle || invoke_code == Bytecodes::_invokedirect) ? NULL : receiver->klass());
CompiledIC::compute_monomorphic_entry(callee_method, h_klass,
is_optimized, static_bound, virtual_call_info,
CHECK_(methodHandle()));
} else {
// static call
*** 2497,2515 ****
address c2i_entry,
address c2i_unverified_entry) {
return _adapters->new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
}
AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(const methodHandle& method) {
// Use customized signature handler. Need to lock around updates to
// the AdapterHandlerTable (it is not safe for concurrent readers
// and a single writer: this could be fixed if it becomes a
// problem).
ResourceMark rm;
! NOT_PRODUCT(int insts_size);
AdapterBlob* new_adapter = NULL;
AdapterHandlerEntry* entry = NULL;
AdapterFingerPrint* fingerprint = NULL;
{
MutexLocker mu(AdapterHandlerLibrary_lock);
--- 2501,2574 ----
address c2i_entry,
address c2i_unverified_entry) {
return _adapters->new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
}
+ // Value type arguments are not passed by reference, instead each
+ // field of the value type is passed as an argument. This helper
+ // function collects the fields of the value types (including embedded
+ // value type's fields) in a list. Included with the field's type is
+ // the offset of each field in the value type: i2c and c2i adapters
+ // need that to load or store fields. Finally, the list of fields is
+ // sorted in order of increasing offsets: the adapters and the
+ // compiled code need and agreed upon order of fields.
+ //
+ // The list of basic type that is returned starts with a T_VALUETYPE
+ // and ends with an extra T_VOID. T_VALUETYPE/T_VOID are used as
+ // delimiters. Every entry between the two is a field of the value
+ // type. If there's an embedded value type in the list, it also starts
+ // with a T_VALUETYPE and ends with a T_VOID. This is so we can
+ // generate a unique fingerprint for the method's adapters and we can
+ // generate the list of basic types from the interpreter point of view
+ // (value types passed as reference: iterate on the list until a
+ // T_VALUETYPE, drop everything until and including the closing
+ // T_VOID) or the compiler point of view (each field of the value
+ // types is an argument: drop all T_VALUETYPE/T_VOID from the list).
+ static GrowableArray<SigEntry> collect_fields(ValueKlass* vk, int base_off = 0) {
+ GrowableArray<SigEntry> sig;
+ sig.push(SigEntry(T_VALUETYPE, base_off));
+ for (JavaFieldStream fs(vk); !fs.done(); fs.next()) {
+ if (fs.access_flags().is_static()) continue;
+ fieldDescriptor& fd = fs.field_descriptor();
+ BasicType bt = fd.field_type();
+ int offset = base_off + fd.offset() - (base_off > 0 ? vk->first_field_offset() : 0);
+ if (bt == T_VALUETYPE) {
+ Symbol* signature = fd.signature();
+ JavaThread* THREAD = JavaThread::current();
+ oop loader = vk->class_loader();
+ oop protection_domain = vk->protection_domain();
+ Klass* klass = SystemDictionary::resolve_or_null(signature,
+ Handle(THREAD, loader), Handle(THREAD, protection_domain),
+ THREAD);
+ assert(klass != NULL && !HAS_PENDING_EXCEPTION, "lookup shouldn't fail");
+ const GrowableArray<SigEntry>& embedded = collect_fields(ValueKlass::cast(klass), offset);
+ sig.appendAll(&embedded);
+ } else {
+ sig.push(SigEntry(bt, offset));
+ if (bt == T_LONG || bt == T_DOUBLE) {
+ sig.push(SigEntry(T_VOID, offset));
+ }
+ }
+ }
+ int offset = base_off + vk->size_helper()*HeapWordSize - (base_off > 0 ? vk->first_field_offset() : 0);
+ sig.push(SigEntry(T_VOID, offset)); // hack: use T_VOID to mark end of value type fields
+ if (base_off == 0) {
+ sig.sort(SigEntry::compare);
+ }
+ assert(sig.at(0)._bt == T_VALUETYPE && sig.at(sig.length()-1)._bt == T_VOID, "broken structure");
+ return sig;
+ }
+
AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(const methodHandle& method) {
// Use customized signature handler. Need to lock around updates to
// the AdapterHandlerTable (it is not safe for concurrent readers
// and a single writer: this could be fixed if it becomes a
// problem).
ResourceMark rm;
! NOT_PRODUCT(int insts_size = 0);
AdapterBlob* new_adapter = NULL;
AdapterHandlerEntry* entry = NULL;
AdapterFingerPrint* fingerprint = NULL;
{
MutexLocker mu(AdapterHandlerLibrary_lock);
*** 2528,2553 ****
if (method->is_abstract()) {
return _abstract_method_handler;
}
// Fill in the signature array, for the calling-convention call.
! int total_args_passed = method->size_of_parameters(); // All args on stack
- BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_args_passed);
- VMRegPair* regs = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed);
int i = 0;
! if (!method->is_static()) // Pass in receiver first
! sig_bt[i++] = T_OBJECT;
for (SignatureStream ss(method->signature()); !ss.at_return_type(); ss.next()) {
! sig_bt[i++] = ss.type(); // Collect remaining bits of signature
! if (ss.type() == T_LONG || ss.type() == T_DOUBLE)
! sig_bt[i++] = T_VOID; // Longs & doubles take 2 Java slots
}
! assert(i == total_args_passed, "");
// Lookup method signature's fingerprint
! entry = _adapters->lookup(total_args_passed, sig_bt);
#ifdef ASSERT
AdapterHandlerEntry* shared_entry = NULL;
// Start adapter sharing verification only after the VM is booted.
if (VerifyAdapterSharing && (entry != NULL)) {
--- 2587,2668 ----
if (method->is_abstract()) {
return _abstract_method_handler;
}
// Fill in the signature array, for the calling-convention call.
! GrowableArray<SigEntry> sig;
! {
! MutexUnlocker mul(AdapterHandlerLibrary_lock);
! Thread* THREAD = Thread::current();
! Handle class_loader(THREAD, method->method_holder()->class_loader());
! Handle protection_domain(THREAD, method->method_holder()->protection_domain());
! GrowableArray<BasicType> sig_bt_tmp;
! int value_klasses = 0;
int i = 0;
! if (!method->is_static()) { // Pass in receiver first
! Klass* holder = method->method_holder();
! if (ValueTypePassFieldsAsArgs && holder->is_value()) {
! value_klasses++;
! ValueKlass* vk = ValueKlass::cast(holder);
! const GrowableArray<SigEntry>& sig_vk = collect_fields(vk);
! sig.appendAll(&sig_vk);
! } else {
! sig.push(SigEntry(T_OBJECT));
! }
! }
for (SignatureStream ss(method->signature()); !ss.at_return_type(); ss.next()) {
! if (ValueTypePassFieldsAsArgs && ss.type() == T_VALUETYPE) {
! value_klasses++;
! Klass* k = ss.as_klass(class_loader, protection_domain, SignatureStream::ReturnNull, THREAD);
! assert(k != NULL && !HAS_PENDING_EXCEPTION, "");
! ValueKlass* vk = ValueKlass::cast(k);
! const GrowableArray<SigEntry>& sig_vk = collect_fields(vk);
! sig.appendAll(&sig_vk);
! } else {
! sig.push(SigEntry(ss.type()));
! if (ss.type() == T_LONG || ss.type() == T_DOUBLE) {
! sig.push(SigEntry(T_VOID));
! }
! }
! }
}
!
! int values = 0;
! if (ValueTypePassFieldsAsArgs) {
! for (int i = 0; i < sig.length(); i++) {
! if (sig.at(i)._bt == T_VALUETYPE) {
! values++;
! }
! }
! }
! int total_args_passed_cc = sig.length() - 2 * values;
! BasicType* sig_bt_cc = NEW_RESOURCE_ARRAY(BasicType, total_args_passed_cc);
!
! int j = 0;
! for (int i = 0; i < sig.length(); i++) {
! if (!ValueTypePassFieldsAsArgs) {
! sig_bt_cc[j++] = sig.at(i)._bt;
! } else if (sig.at(i)._bt != T_VALUETYPE &&
! (sig.at(i)._bt != T_VOID ||
! sig.at(i-1)._bt == T_LONG ||
! sig.at(i-1)._bt == T_DOUBLE)) {
! sig_bt_cc[j++] = sig.at(i)._bt;
! }
! }
! assert(j == total_args_passed_cc, "");
!
! int total_args_passed_fp = sig.length();
! BasicType* sig_bt_fp = NEW_RESOURCE_ARRAY(BasicType, total_args_passed_fp);
! for (int i = 0; i < sig.length(); i++) {
! sig_bt_fp[i] = sig.at(i)._bt;
! }
!
! VMRegPair* regs = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed_cc);
// Lookup method signature's fingerprint
! entry = _adapters->lookup(total_args_passed_fp, sig_bt_fp);
#ifdef ASSERT
AdapterHandlerEntry* shared_entry = NULL;
// Start adapter sharing verification only after the VM is booted.
if (VerifyAdapterSharing && (entry != NULL)) {
*** 2559,2572 ****
if (entry != NULL) {
return entry;
}
// Get a description of the compiled java calling convention and the largest used (VMReg) stack slot usage
! int comp_args_on_stack = SharedRuntime::java_calling_convention(sig_bt, regs, total_args_passed, false);
// Make a C heap allocated version of the fingerprint to store in the adapter
! fingerprint = new AdapterFingerPrint(total_args_passed, sig_bt);
// StubRoutines::code2() is initialized after this function can be called. As a result,
// VerifyAdapterCalls and VerifyAdapterSharing can fail if we re-use code that generated
// prior to StubRoutines::code2() being set. Checks refer to checks generated in an I2C
// stub that ensure that an I2C stub is called from an interpreter frame.
--- 2674,2687 ----
if (entry != NULL) {
return entry;
}
// Get a description of the compiled java calling convention and the largest used (VMReg) stack slot usage
! int comp_args_on_stack = SharedRuntime::java_calling_convention(sig_bt_cc, regs, total_args_passed_cc, false);
// Make a C heap allocated version of the fingerprint to store in the adapter
! fingerprint = new AdapterFingerPrint(total_args_passed_fp, sig_bt_fp);
// StubRoutines::code2() is initialized after this function can be called. As a result,
// VerifyAdapterCalls and VerifyAdapterSharing can fail if we re-use code that generated
// prior to StubRoutines::code2() being set. Checks refer to checks generated in an I2C
// stub that ensure that an I2C stub is called from an interpreter frame.
*** 2578,2594 ****
CodeBuffer buffer(buf);
short buffer_locs[20];
buffer.insts()->initialize_shared_locs((relocInfo*)buffer_locs,
sizeof(buffer_locs)/sizeof(relocInfo));
MacroAssembler _masm(&buffer);
entry = SharedRuntime::generate_i2c2i_adapters(&_masm,
- total_args_passed,
comp_args_on_stack,
! sig_bt,
regs,
! fingerprint);
#ifdef ASSERT
if (VerifyAdapterSharing) {
if (shared_entry != NULL) {
assert(shared_entry->compare_code(buf->code_begin(), buffer.insts_size()), "code must match");
// Release the one just created and return the original
--- 2693,2710 ----
CodeBuffer buffer(buf);
short buffer_locs[20];
buffer.insts()->initialize_shared_locs((relocInfo*)buffer_locs,
sizeof(buffer_locs)/sizeof(relocInfo));
+
MacroAssembler _masm(&buffer);
entry = SharedRuntime::generate_i2c2i_adapters(&_masm,
comp_args_on_stack,
! sig,
regs,
! fingerprint,
! new_adapter);
#ifdef ASSERT
if (VerifyAdapterSharing) {
if (shared_entry != NULL) {
assert(shared_entry->compare_code(buf->code_begin(), buffer.insts_size()), "code must match");
// Release the one just created and return the original
*** 2598,2608 ****
entry->save_code(buf->code_begin(), buffer.insts_size());
}
}
#endif
- new_adapter = AdapterBlob::create(&buffer);
NOT_PRODUCT(insts_size = buffer.insts_size());
}
if (new_adapter == NULL) {
// CodeCache is full, disable compilation
// Ought to log this but compile log is only per compile thread
--- 2714,2723 ----
*** 3072,3076 ****
--- 3187,3238 ----
}
}
return activation;
}
+ // We are at a compiled code to interpreter call. We need backing
+ // buffers for all value type arguments. Allocate an object array to
+ // hold them (convenient because once we're done with it we don't have
+ // to worry about freeing it).
+ JRT_ENTRY(void, SharedRuntime::allocate_value_types(JavaThread* thread))
+ {
+ assert(ValueTypePassFieldsAsArgs, "no reason to call this");
+ ResourceMark rm;
+ JavaThread* THREAD = thread;
+ vframeStream vfst(thread);
+ methodHandle caller(thread, vfst.method());
+ int bci = vfst.bci();
+ Bytecode_invoke bytecode(caller, bci);
+ methodHandle callee = bytecode.static_target(CHECK);
+
+ int nb_slots = 0;
+ if (!callee->is_static() && callee->method_holder()->is_value()) {
+ nb_slots++;
+ }
+ Handle class_loader(THREAD, callee->method_holder()->class_loader());
+ Handle protection_domain(THREAD, callee->method_holder()->protection_domain());
+ for (SignatureStream ss(callee->signature()); !ss.at_return_type(); ss.next()) {
+ if (ss.type() == T_VALUETYPE) {
+ nb_slots++;
+ }
+ }
+ objArrayHandle array = ObjArrayKlass::cast(Universe::objectArrayKlassObj())->allocate(nb_slots, CHECK);
+ int i = 0;
+ if (!callee->is_static() && callee->method_holder()->is_value()) {
+ ValueKlass* vk = ValueKlass::cast(callee->method_holder());
+ oop res = vk->allocate_instance(CHECK);
+ array->obj_at_put(i, res);
+ i++;
+ }
+ for (SignatureStream ss(callee->signature()); !ss.at_return_type(); ss.next()) {
+ if (ss.type() == T_VALUETYPE) {
+ Klass* k = ss.as_klass(class_loader, protection_domain, SignatureStream::ReturnNull, THREAD);
+ assert(k != NULL && !HAS_PENDING_EXCEPTION, "");
+ ValueKlass* vk = ValueKlass::cast(k);
+ oop res = vk->allocate_instance(CHECK);
+ array->obj_at_put(i, res);
+ i++;
+ }
+ }
+ thread->set_vm_result(array());
+ }
+ JRT_END
< prev index next >