OLD | NEW |
---|---|
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 411 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
422 GlobalObject::EnsurePropertyCell(global, name); | 422 GlobalObject::EnsurePropertyCell(global, name); |
423 ASSERT(cell->value()->IsTheHole()); | 423 ASSERT(cell->value()->IsTheHole()); |
424 __ li(scratch, Operand(cell)); | 424 __ li(scratch, Operand(cell)); |
425 __ lw(scratch, | 425 __ lw(scratch, |
426 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset)); | 426 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset)); |
427 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); | 427 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); |
428 __ Branch(miss, ne, scratch, Operand(at)); | 428 __ Branch(miss, ne, scratch, Operand(at)); |
429 } | 429 } |
430 | 430 |
431 | 431 |
432 // Generate StoreField code, value is passed in a0 register. | 432 // Generate StoreTransition code, value is passed in a0 register. |
433 // After executing generated code, the receiver_reg and name_reg | 433 // After executing generated code, the receiver_reg and name_reg |
434 // may be clobbered. | 434 // may be clobbered. |
435 void StubCompiler::GenerateStoreField(MacroAssembler* masm, | 435 void StubCompiler::GenerateStoreTransition(MacroAssembler* masm, |
436 Handle<JSObject> object, | 436 Handle<JSObject> object, |
437 LookupResult* lookup, | 437 LookupResult* lookup, |
438 Handle<Map> transition, | 438 Handle<Map> transition, |
439 Handle<Name> name, | 439 Handle<Name> name, |
440 Register receiver_reg, | 440 Register receiver_reg, |
441 Register name_reg, | 441 Register name_reg, |
442 Register value_reg, | 442 Register value_reg, |
443 Register scratch1, | 443 Register scratch1, |
444 Register scratch2, | 444 Register scratch2, |
445 Label* miss_label, | 445 Label* miss_label, |
446 Label* miss_restore_name) { | 446 Label* miss_restore_name) { |
447 // a0 : value. | 447 // a0 : value. |
448 Label exit; | 448 Label exit; |
449 | 449 |
450 // Check that the map of the object hasn't changed. | 450 // Check that the map of the object hasn't changed. |
451 CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS | |
452 : REQUIRE_EXACT_MAP; | |
453 __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label, | 451 __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label, |
454 DO_SMI_CHECK, mode); | 452 DO_SMI_CHECK, REQUIRE_EXACT_MAP); |
455 | 453 |
456 // Perform global security token check if needed. | 454 // Perform global security token check if needed. |
457 if (object->IsJSGlobalProxy()) { | 455 if (object->IsJSGlobalProxy()) { |
458 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label); | 456 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label); |
459 } | 457 } |
460 | 458 |
461 // Check that we are allowed to write this. | 459 // Check that we are allowed to write this. |
462 if (!transition.is_null() && object->GetPrototype()->IsJSObject()) { | 460 if (object->GetPrototype()->IsJSObject()) { |
463 JSObject* holder; | 461 JSObject* holder; |
464 // holder == object indicates that no property was found. | 462 // holder == object indicates that no property was found. |
465 if (lookup->holder() != *object) { | 463 if (lookup->holder() != *object) { |
466 holder = lookup->holder(); | 464 holder = lookup->holder(); |
467 } else { | 465 } else { |
468 // Find the top object. | 466 // Find the top object. |
469 holder = *object; | 467 holder = *object; |
470 do { | 468 do { |
471 holder = JSObject::cast(holder->GetPrototype()); | 469 holder = JSObject::cast(holder->GetPrototype()); |
472 } while (holder->GetPrototype()->IsJSObject()); | 470 } while (holder->GetPrototype()->IsJSObject()); |
(...skipping 17 matching lines...) Expand all Loading... | |
490 masm, miss_restore_name, holder_reg, name, scratch1, scratch2); | 488 masm, miss_restore_name, holder_reg, name, scratch1, scratch2); |
491 } | 489 } |
492 } | 490 } |
493 } | 491 } |
494 | 492 |
495 // Stub never generated for non-global objects that require access | 493 // Stub never generated for non-global objects that require access |
496 // checks. | 494 // checks. |
497 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); | 495 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); |
498 | 496 |
499 // Perform map transition for the receiver if necessary. | 497 // Perform map transition for the receiver if necessary. |
500 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) { | 498 if (object->map()->unused_property_fields() == 0) { |
501 // The properties must be extended before we can store the value. | 499 // The properties must be extended before we can store the value. |
502 // We jump to a runtime call that extends the properties array. | 500 // We jump to a runtime call that extends the properties array. |
503 __ push(receiver_reg); | 501 __ push(receiver_reg); |
504 __ li(a2, Operand(transition)); | 502 __ li(a2, Operand(transition)); |
505 __ Push(a2, a0); | 503 __ Push(a2, a0); |
506 __ TailCallExternalReference( | 504 __ TailCallExternalReference( |
507 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), | 505 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), |
508 masm->isolate()), | 506 masm->isolate()), |
509 3, 1); | 507 3, 1); |
510 return; | 508 return; |
511 } | 509 } |
512 | 510 |
513 int index; | 511 // Update the map of the object. |
514 if (!transition.is_null()) { | 512 __ li(scratch1, Operand(transition)); |
515 // Update the map of the object. | 513 __ sw(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); |
516 __ li(scratch1, Operand(transition)); | |
517 __ sw(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); | |
518 | 514 |
519 // Update the write barrier for the map field and pass the now unused | 515 // Update the write barrier for the map field and pass the now unused |
520 // name_reg as scratch register. | 516 // name_reg as scratch register. |
521 __ RecordWriteField(receiver_reg, | 517 __ RecordWriteField(receiver_reg, |
522 HeapObject::kMapOffset, | 518 HeapObject::kMapOffset, |
523 scratch1, | 519 scratch1, |
524 name_reg, | 520 name_reg, |
525 kRAHasNotBeenSaved, | 521 kRAHasNotBeenSaved, |
526 kDontSaveFPRegs, | 522 kDontSaveFPRegs, |
527 OMIT_REMEMBERED_SET, | 523 OMIT_REMEMBERED_SET, |
528 OMIT_SMI_CHECK); | 524 OMIT_SMI_CHECK); |
529 index = transition->instance_descriptors()->GetFieldIndex( | 525 |
530 transition->LastAdded()); | 526 int index = transition->instance_descriptors()->GetFieldIndex( |
531 } else { | 527 transition->LastAdded()); |
532 index = lookup->GetFieldIndex().field_index(); | |
533 } | |
534 | 528 |
535 // Adjust for the number of properties stored in the object. Even in the | 529 // Adjust for the number of properties stored in the object. Even in the |
536 // face of a transition we can use the old map here because the size of the | 530 // face of a transition we can use the old map here because the size of the |
537 // object and the number of in-object properties is not going to change. | 531 // object and the number of in-object properties is not going to change. |
538 index -= object->map()->inobject_properties(); | 532 index -= object->map()->inobject_properties(); |
539 | 533 |
534 // TODO(verwaest): Share this code as a code stub. | |
540 if (index < 0) { | 535 if (index < 0) { |
541 // Set the property straight into the object. | 536 // Set the property straight into the object. |
542 int offset = object->map()->instance_size() + (index * kPointerSize); | 537 int offset = object->map()->instance_size() + (index * kPointerSize); |
538 __ sw(value_reg, FieldMemOperand(receiver_reg, offset)); | |
539 | |
540 // Skip updating write barrier if storing a smi. | |
541 __ JumpIfSmi(value_reg, &exit); | |
542 | |
543 // Update the write barrier for the array address. | |
544 // Pass the now unused name_reg as a scratch register. | |
545 __ mov(name_reg, value_reg); | |
546 __ RecordWriteField(receiver_reg, | |
547 offset, | |
548 name_reg, | |
549 scratch1, | |
550 kRAHasNotBeenSaved, | |
551 kDontSaveFPRegs); | |
552 } else { | |
553 // Write to the properties array. | |
554 int offset = index * kPointerSize + FixedArray::kHeaderSize; | |
555 // Get the properties array | |
556 __ lw(scratch1, | |
557 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset)); | |
558 __ sw(value_reg, FieldMemOperand(scratch1, offset)); | |
559 | |
560 // Skip updating write barrier if storing a smi. | |
561 __ JumpIfSmi(value_reg, &exit); | |
562 | |
563 // Update the write barrier for the array address. | |
564 // Ok to clobber receiver_reg and name_reg, since we return. | |
565 __ mov(name_reg, value_reg); | |
566 __ RecordWriteField(scratch1, | |
567 offset, | |
568 name_reg, | |
569 receiver_reg, | |
570 kRAHasNotBeenSaved, | |
571 kDontSaveFPRegs); | |
572 } | |
573 | |
574 // Return the value (register v0). | |
575 ASSERT(value_reg.is(a0)); | |
576 __ bind(&exit); | |
577 __ mov(v0, a0); | |
578 __ Ret(); | |
Paul Lind
2013/04/11 23:09:15
Please note (for the future) that this is a small
| |
579 } | |
580 | |
581 | |
582 // Generate StoreField code, value is passed in a0 register. | |
583 // When leaving generated code after success, the receiver_reg and name_reg | |
584 // may be clobbered. Upon branch to miss_label, the receiver and name | |
585 // registers have their original values. | |
586 void StubCompiler::GenerateStoreField(MacroAssembler* masm, | |
587 Handle<JSObject> object, | |
588 LookupResult* lookup, | |
589 Register receiver_reg, | |
590 Register name_reg, | |
591 Register value_reg, | |
592 Register scratch1, | |
593 Register scratch2, | |
594 Label* miss_label) { | |
595 // a0 : value | |
596 Label exit; | |
597 | |
598 // Check that the map of the object hasn't changed. | |
599 __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label, | |
600 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS); | |
601 | |
602 // Perform global security token check if needed. | |
603 if (object->IsJSGlobalProxy()) { | |
604 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label); | |
605 } | |
606 | |
607 // Stub never generated for non-global objects that require access | |
608 // checks. | |
609 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); | |
610 | |
611 int index = lookup->GetFieldIndex().field_index(); | |
612 | |
613 // Adjust for the number of properties stored in the object. Even in the | |
614 // face of a transition we can use the old map here because the size of the | |
615 // object and the number of in-object properties is not going to change. | |
616 index -= object->map()->inobject_properties(); | |
617 | |
618 // TODO(verwaest): Share this code as a code stub. | |
619 if (index < 0) { | |
620 // Set the property straight into the object. | |
621 int offset = object->map()->instance_size() + (index * kPointerSize); | |
543 __ sw(value_reg, FieldMemOperand(receiver_reg, offset)); | 622 __ sw(value_reg, FieldMemOperand(receiver_reg, offset)); |
544 | 623 |
545 // Skip updating write barrier if storing a smi. | 624 // Skip updating write barrier if storing a smi. |
546 __ JumpIfSmi(value_reg, &exit); | 625 __ JumpIfSmi(value_reg, &exit); |
547 | 626 |
548 // Update the write barrier for the array address. | 627 // Update the write barrier for the array address. |
549 // Pass the now unused name_reg as a scratch register. | 628 // Pass the now unused name_reg as a scratch register. |
550 __ mov(name_reg, value_reg); | 629 __ mov(name_reg, value_reg); |
551 __ RecordWriteField(receiver_reg, | 630 __ RecordWriteField(receiver_reg, |
552 offset, | 631 offset, |
(...skipping 3396 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3949 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow); | 4028 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow); |
3950 } | 4029 } |
3951 } | 4030 } |
3952 | 4031 |
3953 | 4032 |
3954 #undef __ | 4033 #undef __ |
3955 | 4034 |
3956 } } // namespace v8::internal | 4035 } } // namespace v8::internal |
3957 | 4036 |
3958 #endif // V8_TARGET_ARCH_MIPS | 4037 #endif // V8_TARGET_ARCH_MIPS |
OLD | NEW |