< prev index next >

src/hotspot/share/oops/valueKlass.cpp

Print this page




 250       while (map != end) {
 251         address doop_address = dst_oop_addr + map->offset();
 252         bs->write_ref_array((HeapWord*) doop_address, map->count());
 253         map++;
 254       }
 255     } else { // Buffered value case
 256       raw_field_copy(src, dst, raw_byte_size);
 257     }
 258   } else {   // Primitive-only case...
 259     raw_field_copy(src, dst, raw_byte_size);
 260   }
 261 }
 262 
 263 // Value type arguments are not passed by reference, instead each
 264 // field of the value type is passed as an argument. This helper
 265 // function collects the fields of the value types (including embedded
 266 // value type's fields) in a list. Included with the field's type is
 267 // the offset of each field in the value type: i2c and c2i adapters
 268 // need that to load or store fields. Finally, the list of fields is
 269 // sorted in order of increasing offsets: the adapters and the
 270 // compiled code need and agreed upon order of fields.
 271 //
 272 // The list of basic types that is returned starts with a T_VALUETYPE
 273 // and ends with an extra T_VOID. T_VALUETYPE/T_VOID are used as
 274 // delimiters. Every entry between the two is a field of the value
 275 // type. If there's an embedded value type in the list, it also starts
 276 // with a T_VALUETYPE and ends with a T_VOID. This is so we can
 277 // generate a unique fingerprint for the method's adapters and we can
 278 // generate the list of basic types from the interpreter point of view
 279 // (value types passed as reference: iterate on the list until a
 280 // T_VALUETYPE, drop everything until and including the closing
 281 // T_VOID) or the compiler point of view (each field of the value
 282 // types is an argument: drop all T_VALUETYPE/T_VOID from the list).
 283 GrowableArray<SigEntry> ValueKlass::collect_fields(int base_off) const {
 284   GrowableArray<SigEntry> sig_extended;
 285   sig_extended.push(SigEntry(T_VALUETYPE, base_off));
 286   for (JavaFieldStream fs(this); !fs.done(); fs.next()) {
 287     if (fs.access_flags().is_static()) continue;
 288     fieldDescriptor& fd = fs.field_descriptor();
 289     BasicType bt = fd.field_type();
 290     int offset = base_off + fd.offset() - (base_off > 0 ? first_field_offset() : 0);
 291     if (bt == T_VALUETYPE) {
 292       if (fd.is_flattened()) {
 293         Symbol* signature = fd.signature();
 294         JavaThread* THREAD = JavaThread::current();
 295         oop loader = class_loader();
 296         oop domain = protection_domain();
 297         ResetNoHandleMark rnhm;
 298         HandleMark hm;
 299         NoSafepointVerifier nsv;
 300         Klass* klass = SystemDictionary::resolve_or_null(signature,
 301                                                          Handle(THREAD, loader), Handle(THREAD, domain),
 302                                                          THREAD);
 303         assert(klass != NULL && !HAS_PENDING_EXCEPTION, "lookup shouldn't fail");
 304         const GrowableArray<SigEntry>& embedded = ValueKlass::cast(klass)->collect_fields(offset);
 305         sig_extended.appendAll(&embedded);
 306       } else {
 307         sig_extended.push(SigEntry(T_VALUETYPEPTR, offset));
 308       }
 309     } else {
 310       sig_extended.push(SigEntry(bt, offset));
 311       if (bt == T_LONG || bt == T_DOUBLE) {
 312         sig_extended.push(SigEntry(T_VOID, offset));
 313       }


 314     }
 315   }
 316   int offset = base_off + size_helper()*HeapWordSize - (base_off > 0 ? first_field_offset() : 0);
 317   sig_extended.push(SigEntry(T_VOID, offset)); // hack: use T_VOID to mark end of value type fields
 318   if (base_off == 0) {
 319     sig_extended.sort(SigEntry::compare);
 320   }
 321   assert(sig_extended.at(0)._bt == T_VALUETYPE && sig_extended.at(sig_extended.length()-1)._bt == T_VOID, "broken structure");
 322   return sig_extended;
 323 }
 324 
 325 void ValueKlass::initialize_calling_convention() {
 326   // Because the pack and unpack handler addresses need to be loadable from generated code,
 327   // they are stored at a fixed offset in the klass metadata. Since value type klasses do
 328   // not have a vtable, the vtable offset is used to store these addresses.
 329   //guarantee(vtable_length() == 0, "vtables are not supported in value klasses");
 330   if (ValueTypeReturnedAsFields || ValueTypePassFieldsAsArgs) {
 331     Thread* THREAD = Thread::current();
 332     assert(!HAS_PENDING_EXCEPTION, "should have no exception");
 333     ResourceMark rm;
 334     const GrowableArray<SigEntry>& sig_vk = collect_fields();
 335     int nb_fields = SigEntry::count_fields(sig_vk)+1;
 336     Array<SigEntry>* extended_sig = MetadataFactory::new_array<SigEntry>(class_loader_data(), sig_vk.length(), CHECK_AND_CLEAR);
 337     *((Array<SigEntry>**)adr_extended_sig()) = extended_sig;
 338     for (int i = 0; i < sig_vk.length(); i++) {
 339       extended_sig->at_put(i, sig_vk.at(i));
 340     }
 341 
 342     if (ValueTypeReturnedAsFields) {

 343       BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType, nb_fields);
 344       sig_bt[0] = T_METADATA;
 345       SigEntry::fill_sig_bt(sig_vk, sig_bt+1, nb_fields-1, true);
 346       VMRegPair* regs = NEW_RESOURCE_ARRAY(VMRegPair, nb_fields);
 347       int total = SharedRuntime::java_return_convention(sig_bt, regs, nb_fields);
 348 
 349       if (total > 0) {
 350         Array<VMRegPair>* return_regs = MetadataFactory::new_array<VMRegPair>(class_loader_data(), nb_fields, CHECK_AND_CLEAR);
 351         *((Array<VMRegPair>**)adr_return_regs()) = return_regs;
 352         for (int i = 0; i < nb_fields; i++) {
 353           return_regs->at_put(i, regs[i]);
 354         }
 355 
 356         BufferedValueTypeBlob* buffered_blob = SharedRuntime::generate_buffered_value_type_adapter(this);
 357         *((address*)adr_pack_handler()) = buffered_blob->pack_fields();
 358         *((address*)adr_unpack_handler()) = buffered_blob->unpack_fields();
 359         assert(CodeCache::find_blob(pack_handler()) == buffered_blob, "lost track of blob");
 360       }
 361     }
 362   }
 363 }
 364 
 365 void ValueKlass::deallocate_contents(ClassLoaderData* loader_data) {
 366   if (extended_sig() != NULL) {
 367     MetadataFactory::free_array<SigEntry>(loader_data, extended_sig());
 368   }
 369   if (return_regs() != NULL) {
 370     MetadataFactory::free_array<VMRegPair>(loader_data, return_regs());


 384     BufferBlob::free((BufferBlob*)buffered_blob);
 385     *((address*)adr_pack_handler()) = NULL;
 386     *((address*)adr_unpack_handler()) = NULL;
 387   }
 388 }
 389 
 390 // Can this value type be returned as multiple values?
 391 bool ValueKlass::can_be_returned_as_fields() const {
 392   return return_regs() != NULL;
 393 }
 394 
 395 // Create handles for all oop fields returned in registers that are going to be live across a safepoint
 396 void ValueKlass::save_oop_fields(const RegisterMap& reg_map, GrowableArray<Handle>& handles) const {
 397   Thread* thread = Thread::current();
 398   const Array<SigEntry>* sig_vk = extended_sig();
 399   const Array<VMRegPair>* regs = return_regs();
 400   int j = 1;
 401 
 402   for (int i = 0; i < sig_vk->length(); i++) {
 403     BasicType bt = sig_vk->at(i)._bt;
 404     if (bt == T_OBJECT || bt == T_VALUETYPEPTR || bt == T_ARRAY) {
 405       int off = sig_vk->at(i)._offset;
 406       VMRegPair pair = regs->at(j);
 407       address loc = reg_map.location(pair.first());
 408       oop v = *(oop*)loc;
 409       assert(v == NULL || oopDesc::is_oop(v), "not an oop?");
 410       assert(Universe::heap()->is_in_or_null(v), "must be heap pointer");
 411       handles.push(Handle(thread, v));
 412     }
 413     if (bt == T_VALUETYPE) {
 414       continue;
 415     }
 416     if (bt == T_VOID &&
 417         sig_vk->at(i-1)._bt != T_LONG &&
 418         sig_vk->at(i-1)._bt != T_DOUBLE) {
 419       continue;
 420     }
 421     j++;
 422   }
 423   assert(j == regs->length(), "missed a field?");
 424 }
 425 
 426 // Update oop fields in registers from handles after a safepoint
 427 void ValueKlass::restore_oop_results(RegisterMap& reg_map, GrowableArray<Handle>& handles) const {
 428   assert(ValueTypeReturnedAsFields, "inconsistent");
 429   const Array<SigEntry>* sig_vk = extended_sig();
 430   const Array<VMRegPair>* regs = return_regs();
 431   assert(regs != NULL, "inconsistent");
 432 
 433   int j = 1;
 434   for (int i = 0, k = 0; i < sig_vk->length(); i++) {
 435     BasicType bt = sig_vk->at(i)._bt;
 436     if (bt == T_OBJECT || bt == T_ARRAY) {
 437       int off = sig_vk->at(i)._offset;
 438       VMRegPair pair = regs->at(j);
 439       address loc = reg_map.location(pair.first());
 440       *(oop*)loc = handles.at(k++)();
 441     }
 442     if (bt == T_VALUETYPE) {
 443       continue;
 444     }
 445     if (bt == T_VOID &&
 446         sig_vk->at(i-1)._bt != T_LONG &&
 447         sig_vk->at(i-1)._bt != T_DOUBLE) {
 448       continue;
 449     }
 450     j++;
 451   }
 452   assert(j == regs->length(), "missed a field?");
 453 }
 454 
 455 // Fields are in registers. Create an instance of the value type and
 456 // initialize it with the values of the fields.
 457 oop ValueKlass::realloc_result(const RegisterMap& reg_map, const GrowableArray<Handle>& handles, TRAPS) {
 458 
 459   oop new_vt = allocate_instance(CHECK_NULL);
 460   const Array<SigEntry>* sig_vk = extended_sig();
 461   const Array<VMRegPair>* regs = return_regs();
 462 
 463   int j = 1;
 464   int k = 0;
 465   for (int i = 0; i < sig_vk->length(); i++) {
 466     BasicType bt = sig_vk->at(i)._bt;
 467     if (bt == T_VALUETYPE) {
 468       continue;
 469     }
 470     if (bt == T_VOID) {
 471       if (sig_vk->at(i-1)._bt == T_LONG ||
 472           sig_vk->at(i-1)._bt == T_DOUBLE) {
 473         j++;
 474       }
 475       continue;
 476     }
 477     int off = sig_vk->at(i)._offset;

 478     VMRegPair pair = regs->at(j);
 479     address loc = reg_map.location(pair.first());
 480     switch(bt) {
 481     case T_BOOLEAN: {
 482       jboolean v = *(intptr_t*)loc;
 483       *(jboolean*)((address)new_vt + off) = v;
 484       break;
 485     }
 486     case T_CHAR: {
 487       jchar v = *(intptr_t*)loc;
 488       *(jchar*)((address)new_vt + off) = v;
 489       break;
 490     }
 491     case T_BYTE: {
 492       jbyte v = *(intptr_t*)loc;
 493       *(jbyte*)((address)new_vt + off) = v;
 494       break;
 495     }
 496     case T_SHORT: {
 497       jshort v = *(intptr_t*)loc;
 498       *(jshort*)((address)new_vt + off) = v;
 499       break;
 500     }
 501     case T_INT: {
 502       jint v = *(intptr_t*)loc;
 503       *(jint*)((address)new_vt + off) = v;
 504       break;
 505     }
 506     case T_LONG: {
 507 #ifdef _LP64
 508       jlong v = *(intptr_t*)loc;
 509       *(jlong*)((address)new_vt + off) = v;
 510 #else
 511       Unimplemented();
 512 #endif
 513       break;
 514     }
 515     case T_OBJECT:
 516     case T_VALUETYPEPTR:
 517     case T_ARRAY: {
 518       Handle handle = handles.at(k++);
 519       HeapAccess<>::oop_store_at(new_vt, off, handle());
 520       break;
 521     }
 522     case T_FLOAT: {
 523       jfloat v = *(jfloat*)loc;
 524       *(jfloat*)((address)new_vt + off) = v;
 525       break;
 526     }
 527     case T_DOUBLE: {
 528       jdouble v = *(jdouble*)loc;
 529       *(jdouble*)((address)new_vt + off) = v;
 530       break;
 531     }
 532     default:
 533       ShouldNotReachHere();
 534     }
 535     *(intptr_t*)loc = 0xDEAD;
 536     j++;
 537   }
 538   assert(j == regs->length(), "missed a field?");
 539   assert(k == handles.length(), "missed an oop?");
 540   return new_vt;
 541 }
 542 
 543 // Check the return register for a ValueKlass oop
 544 ValueKlass* ValueKlass::returned_value_klass(const RegisterMap& map) {
 545   BasicType bt = T_METADATA;
 546   VMRegPair pair;
 547   int nb = SharedRuntime::java_return_convention(&bt, &pair, 1);
 548   assert(nb == 1, "broken");
 549 




 250       while (map != end) {
 251         address doop_address = dst_oop_addr + map->offset();
 252         bs->write_ref_array((HeapWord*) doop_address, map->count());
 253         map++;
 254       }
 255     } else { // Buffered value case
 256       raw_field_copy(src, dst, raw_byte_size);
 257     }
 258   } else {   // Primitive-only case...
 259     raw_field_copy(src, dst, raw_byte_size);
 260   }
 261 }
 262 
 263 // Value type arguments are not passed by reference, instead each
 264 // field of the value type is passed as an argument. This helper
 265 // function collects the fields of the value types (including embedded
 266 // value type's fields) in a list. Included with the field's type is
 267 // the offset of each field in the value type: i2c and c2i adapters
 268 // need that to load or store fields. Finally, the list of fields is
 269 // sorted in order of increasing offsets: the adapters and the
 270 // compiled code need to agree upon the order of fields.
 271 //
 272 // The list of basic types that is returned starts with a T_VALUETYPE
 273 // and ends with an extra T_VOID. T_VALUETYPE/T_VOID pairs are used as
 274 // delimiters. Every entry between the two is a field of the value
 275 // type. If there's an embedded value type in the list, it also starts
 276 // with a T_VALUETYPE and ends with a T_VOID. This is so we can
 277 // generate a unique fingerprint for the method's adapters and we can
 278 // generate the list of basic types from the interpreter point of view
 279 // (value types passed as reference: iterate on the list until a
 280 // T_VALUETYPE, drop everything until and including the closing
 281 // T_VOID) or the compiler point of view (each field of the value
 282 // types is an argument: drop all T_VALUETYPE/T_VOID from the list).
 283 int ValueKlass::collect_fields(GrowableArray<SigEntry>* sig, int base_off) const {
 284   int count = 0;
 285   SigEntry::add_entry(sig, T_VALUETYPE, base_off);
 286   for (JavaFieldStream fs(this); !fs.done(); fs.next()) {
 287     if (fs.access_flags().is_static()) continue;
 288     int offset = base_off + fs.offset() - (base_off > 0 ? first_field_offset() : 0);
 289     if (fs.is_flattened()) {
 290       // Resolve klass of flattened value type field and recursively collect fields
 291       Klass* vk = get_value_field_klass(fs.index());
 292       count += ValueKlass::cast(vk)->collect_fields(sig, offset);
















 293     } else {
 294       BasicType bt = FieldType::basic_type(fs.signature());
 295       if (bt == T_VALUETYPE) {
 296         bt = T_OBJECT;
 297       }
 298       SigEntry::add_entry(sig, bt, offset);
 299       count += type2size[bt];
 300     }
 301   }
 302   int offset = base_off + size_helper()*HeapWordSize - (base_off > 0 ? first_field_offset() : 0);
 303   SigEntry::add_entry(sig, T_VOID, offset);
 304   if (base_off == 0) {
 305     sig->sort(SigEntry::compare);
 306   }
 307   assert(sig->at(0)._bt == T_VALUETYPE && sig->at(sig->length()-1)._bt == T_VOID, "broken structure");
 308   return count;
 309 }
 310 
 311 void ValueKlass::initialize_calling_convention(TRAPS) {
 312   // Because the pack and unpack handler addresses need to be loadable from generated code,
 313   // they are stored at a fixed offset in the klass metadata. Since value type klasses do
 314   // not have a vtable, the vtable offset is used to store these addresses.

 315   if (ValueTypeReturnedAsFields || ValueTypePassFieldsAsArgs) {


 316     ResourceMark rm;
 317     GrowableArray<SigEntry> sig_vk;
 318     int nb_fields = collect_fields(&sig_vk);
 319     Array<SigEntry>* extended_sig = MetadataFactory::new_array<SigEntry>(class_loader_data(), sig_vk.length(), CHECK);
 320     *((Array<SigEntry>**)adr_extended_sig()) = extended_sig;
 321     for (int i = 0; i < sig_vk.length(); i++) {
 322       extended_sig->at_put(i, sig_vk.at(i));
 323     }
 324 
 325     if (ValueTypeReturnedAsFields) {
 326       nb_fields++;
 327       BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType, nb_fields);
 328       sig_bt[0] = T_METADATA;
 329       SigEntry::fill_sig_bt(&sig_vk, sig_bt+1);
 330       VMRegPair* regs = NEW_RESOURCE_ARRAY(VMRegPair, nb_fields);
 331       int total = SharedRuntime::java_return_convention(sig_bt, regs, nb_fields);
 332 
 333       if (total > 0) {
 334         Array<VMRegPair>* return_regs = MetadataFactory::new_array<VMRegPair>(class_loader_data(), nb_fields, CHECK);
 335         *((Array<VMRegPair>**)adr_return_regs()) = return_regs;
 336         for (int i = 0; i < nb_fields; i++) {
 337           return_regs->at_put(i, regs[i]);
 338         }
 339 
 340         BufferedValueTypeBlob* buffered_blob = SharedRuntime::generate_buffered_value_type_adapter(this);
 341         *((address*)adr_pack_handler()) = buffered_blob->pack_fields();
 342         *((address*)adr_unpack_handler()) = buffered_blob->unpack_fields();
 343         assert(CodeCache::find_blob(pack_handler()) == buffered_blob, "lost track of blob");
 344       }
 345     }
 346   }
 347 }
 348 
 349 void ValueKlass::deallocate_contents(ClassLoaderData* loader_data) {
 350   if (extended_sig() != NULL) {
 351     MetadataFactory::free_array<SigEntry>(loader_data, extended_sig());
 352   }
 353   if (return_regs() != NULL) {
 354     MetadataFactory::free_array<VMRegPair>(loader_data, return_regs());


 368     BufferBlob::free((BufferBlob*)buffered_blob);
 369     *((address*)adr_pack_handler()) = NULL;
 370     *((address*)adr_unpack_handler()) = NULL;
 371   }
 372 }
 373 
 374 // Can this value type be returned as multiple values?
 375 bool ValueKlass::can_be_returned_as_fields() const {
 376   return return_regs() != NULL;
 377 }
 378 
 379 // Create handles for all oop fields returned in registers that are going to be live across a safepoint
 380 void ValueKlass::save_oop_fields(const RegisterMap& reg_map, GrowableArray<Handle>& handles) const {
 381   Thread* thread = Thread::current();
 382   const Array<SigEntry>* sig_vk = extended_sig();
 383   const Array<VMRegPair>* regs = return_regs();
 384   int j = 1;
 385 
 386   for (int i = 0; i < sig_vk->length(); i++) {
 387     BasicType bt = sig_vk->at(i)._bt;
 388     if (bt == T_OBJECT || bt == T_ARRAY) {

 389       VMRegPair pair = regs->at(j);
 390       address loc = reg_map.location(pair.first());
 391       oop v = *(oop*)loc;
 392       assert(v == NULL || oopDesc::is_oop(v), "not an oop?");
 393       assert(Universe::heap()->is_in_or_null(v), "must be heap pointer");
 394       handles.push(Handle(thread, v));
 395     }
 396     if (bt == T_VALUETYPE) {
 397       continue;
 398     }
 399     if (bt == T_VOID &&
 400         sig_vk->at(i-1)._bt != T_LONG &&
 401         sig_vk->at(i-1)._bt != T_DOUBLE) {
 402       continue;
 403     }
 404     j++;
 405   }
 406   assert(j == regs->length(), "missed a field?");
 407 }
 408 
 409 // Update oop fields in registers from handles after a safepoint
 410 void ValueKlass::restore_oop_results(RegisterMap& reg_map, GrowableArray<Handle>& handles) const {
 411   assert(ValueTypeReturnedAsFields, "inconsistent");
 412   const Array<SigEntry>* sig_vk = extended_sig();
 413   const Array<VMRegPair>* regs = return_regs();
 414   assert(regs != NULL, "inconsistent");
 415 
 416   int j = 1;
 417   for (int i = 0, k = 0; i < sig_vk->length(); i++) {
 418     BasicType bt = sig_vk->at(i)._bt;
 419     if (bt == T_OBJECT || bt == T_ARRAY) {

 420       VMRegPair pair = regs->at(j);
 421       address loc = reg_map.location(pair.first());
 422       *(oop*)loc = handles.at(k++)();
 423     }
 424     if (bt == T_VALUETYPE) {
 425       continue;
 426     }
 427     if (bt == T_VOID &&
 428         sig_vk->at(i-1)._bt != T_LONG &&
 429         sig_vk->at(i-1)._bt != T_DOUBLE) {
 430       continue;
 431     }
 432     j++;
 433   }
 434   assert(j == regs->length(), "missed a field?");
 435 }
 436 
 437 // Fields are in registers. Create an instance of the value type and
 438 // initialize it with the values of the fields.
 439 oop ValueKlass::realloc_result(const RegisterMap& reg_map, const GrowableArray<Handle>& handles, TRAPS) {

 440   oop new_vt = allocate_instance(CHECK_NULL);
 441   const Array<SigEntry>* sig_vk = extended_sig();
 442   const Array<VMRegPair>* regs = return_regs();
 443 
 444   int j = 1;
 445   int k = 0;
 446   for (int i = 0; i < sig_vk->length(); i++) {
 447     BasicType bt = sig_vk->at(i)._bt;
 448     if (bt == T_VALUETYPE) {
 449       continue;
 450     }
 451     if (bt == T_VOID) {
 452       if (sig_vk->at(i-1)._bt == T_LONG ||
 453           sig_vk->at(i-1)._bt == T_DOUBLE) {
 454         j++;
 455       }
 456       continue;
 457     }
 458     int off = sig_vk->at(i)._offset;
 459     assert(off > 0, "offset in object should be positive");
 460     VMRegPair pair = regs->at(j);
 461     address loc = reg_map.location(pair.first());
 462     switch(bt) {
 463     case T_BOOLEAN: {
 464       new_vt->bool_field_put(off, *(jboolean*)loc);

 465       break;
 466     }
 467     case T_CHAR: {
 468       new_vt->char_field_put(off, *(jchar*)loc);

 469       break;
 470     }
 471     case T_BYTE: {
 472       new_vt->byte_field_put(off, *(jbyte*)loc);

 473       break;
 474     }
 475     case T_SHORT: {
 476       new_vt->short_field_put(off, *(jshort*)loc);

 477       break;
 478     }
 479     case T_INT: {
 480       new_vt->int_field_put(off, *(jint*)loc);

 481       break;
 482     }
 483     case T_LONG: {
 484 #ifdef _LP64
 485       new_vt->double_field_put(off,  *(jdouble*)loc);

 486 #else
 487       Unimplemented();
 488 #endif
 489       break;
 490     }
 491     case T_OBJECT:

 492     case T_ARRAY: {
 493       Handle handle = handles.at(k++);
 494       new_vt->obj_field_put(off, handle());
 495       break;
 496     }
 497     case T_FLOAT: {
 498       new_vt->float_field_put(off,  *(jfloat*)loc);

 499       break;
 500     }
 501     case T_DOUBLE: {
 502       new_vt->double_field_put(off, *(jdouble*)loc);

 503       break;
 504     }
 505     default:
 506       ShouldNotReachHere();
 507     }
 508     *(intptr_t*)loc = 0xDEAD;
 509     j++;
 510   }
 511   assert(j == regs->length(), "missed a field?");
 512   assert(k == handles.length(), "missed an oop?");
 513   return new_vt;
 514 }
 515 
 516 // Check the return register for a ValueKlass oop
 517 ValueKlass* ValueKlass::returned_value_klass(const RegisterMap& map) {
 518   BasicType bt = T_METADATA;
 519   VMRegPair pair;
 520   int nb = SharedRuntime::java_return_convention(&bt, &pair, 1);
 521   assert(nb == 1, "broken");
 522 


< prev index next >