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 417 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
428 | 428 |
429 | 429 |
430 // Generate StoreField code, value is passed in r0 register. | 430 // Generate StoreField code, value is passed in r0 register. |
431 // When leaving generated code after success, the receiver_reg and name_reg | 431 // When leaving generated code after success, the receiver_reg and name_reg |
432 // may be clobbered. Upon branch to miss_label, the receiver and name | 432 // may be clobbered. Upon branch to miss_label, the receiver and name |
433 // registers have their original values. | 433 // registers have their original values. |
434 void StubCompiler::GenerateStoreField(MacroAssembler* masm, | 434 void StubCompiler::GenerateStoreField(MacroAssembler* masm, |
435 Handle<JSObject> object, | 435 Handle<JSObject> object, |
436 int index, | 436 int index, |
437 Handle<Map> transition, | 437 Handle<Map> transition, |
438 Handle<String> name, | |
439 Register receiver_reg, | 438 Register receiver_reg, |
440 Register name_reg, | 439 Register name_reg, |
441 Register scratch1, | 440 Register scratch, |
442 Register scratch2, | |
443 Label* miss_label) { | 441 Label* miss_label) { |
444 // r0 : value | 442 // r0 : value |
445 Label exit; | 443 Label exit; |
446 | 444 |
447 LookupResult lookup(masm->isolate()); | |
448 object->Lookup(*name, &lookup); | |
449 if (lookup.IsFound() && (lookup.IsReadOnly() || !lookup.IsCacheable())) { | |
450 // In sloppy mode, we could just return the value and be done. However, we | |
451 // might be in strict mode, where we have to throw. Since we cannot tell, | |
452 // go into slow case unconditionally. | |
453 __ jmp(miss_label); | |
454 return; | |
455 } | |
456 | |
457 // Check that the map of the object hasn't changed. | 445 // Check that the map of the object hasn't changed. |
458 CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS | 446 CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS |
459 : REQUIRE_EXACT_MAP; | 447 : REQUIRE_EXACT_MAP; |
460 __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label, | 448 __ CheckMap(receiver_reg, scratch, Handle<Map>(object->map()), miss_label, |
461 DO_SMI_CHECK, mode); | 449 DO_SMI_CHECK, mode); |
462 | 450 |
463 // Perform global security token check if needed. | 451 // Perform global security token check if needed. |
464 if (object->IsJSGlobalProxy()) { | 452 if (object->IsJSGlobalProxy()) { |
465 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label); | 453 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label); |
466 } | |
467 | |
468 // Check that we are allowed to write this. | |
469 if (!transition.is_null() && object->GetPrototype()->IsJSObject()) { | |
470 JSObject* holder; | |
471 if (lookup.IsFound()) { | |
472 holder = lookup.holder(); | |
473 } else { | |
474 // Find the top object. | |
475 holder = *object; | |
476 do { | |
477 holder = JSObject::cast(holder->GetPrototype()); | |
478 } while (holder->GetPrototype()->IsJSObject()); | |
479 } | |
480 // We need an extra register, push | |
481 __ push(name_reg); | |
482 Label miss_pop, done_check; | |
483 CheckPrototypes(object, receiver_reg, Handle<JSObject>(holder), name_reg, | |
484 scratch1, scratch2, name, &miss_pop); | |
485 __ jmp(&done_check); | |
486 __ bind(&miss_pop); | |
487 __ pop(name_reg); | |
488 __ jmp(miss_label); | |
489 __ bind(&done_check); | |
490 __ pop(name_reg); | |
491 } | 454 } |
492 | 455 |
493 // Stub never generated for non-global objects that require access | 456 // Stub never generated for non-global objects that require access |
494 // checks. | 457 // checks. |
495 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); | 458 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); |
496 | 459 |
497 // Perform map transition for the receiver if necessary. | 460 // Perform map transition for the receiver if necessary. |
498 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) { | 461 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) { |
499 // The properties must be extended before we can store the value. | 462 // The properties must be extended before we can store the value. |
500 // We jump to a runtime call that extends the properties array. | 463 // We jump to a runtime call that extends the properties array. |
501 __ push(receiver_reg); | 464 __ push(receiver_reg); |
502 __ mov(r2, Operand(transition)); | 465 __ mov(r2, Operand(transition)); |
503 __ Push(r2, r0); | 466 __ Push(r2, r0); |
504 __ TailCallExternalReference( | 467 __ TailCallExternalReference( |
505 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), | 468 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), |
506 masm->isolate()), | 469 masm->isolate()), |
507 3, | 470 3, |
508 1); | 471 1); |
509 return; | 472 return; |
510 } | 473 } |
511 | 474 |
512 if (!transition.is_null()) { | 475 if (!transition.is_null()) { |
513 // Update the map of the object. | 476 // Update the map of the object. |
514 __ mov(scratch1, Operand(transition)); | 477 __ mov(scratch, Operand(transition)); |
515 __ str(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); | 478 __ str(scratch, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); |
516 | 479 |
517 // Update the write barrier for the map field and pass the now unused | 480 // Update the write barrier for the map field and pass the now unused |
518 // name_reg as scratch register. | 481 // name_reg as scratch register. |
519 __ RecordWriteField(receiver_reg, | 482 __ RecordWriteField(receiver_reg, |
520 HeapObject::kMapOffset, | 483 HeapObject::kMapOffset, |
521 scratch1, | 484 scratch, |
522 name_reg, | 485 name_reg, |
523 kLRHasNotBeenSaved, | 486 kLRHasNotBeenSaved, |
524 kDontSaveFPRegs, | 487 kDontSaveFPRegs, |
525 OMIT_REMEMBERED_SET, | 488 OMIT_REMEMBERED_SET, |
526 OMIT_SMI_CHECK); | 489 OMIT_SMI_CHECK); |
527 } | 490 } |
528 | 491 |
529 // Adjust for the number of properties stored in the object. Even in the | 492 // Adjust for the number of properties stored in the object. Even in the |
530 // face of a transition we can use the old map here because the size of the | 493 // face of a transition we can use the old map here because the size of the |
531 // object and the number of in-object properties is not going to change. | 494 // object and the number of in-object properties is not going to change. |
532 index -= object->map()->inobject_properties(); | 495 index -= object->map()->inobject_properties(); |
533 | 496 |
534 if (index < 0) { | 497 if (index < 0) { |
535 // Set the property straight into the object. | 498 // Set the property straight into the object. |
536 int offset = object->map()->instance_size() + (index * kPointerSize); | 499 int offset = object->map()->instance_size() + (index * kPointerSize); |
537 __ str(r0, FieldMemOperand(receiver_reg, offset)); | 500 __ str(r0, FieldMemOperand(receiver_reg, offset)); |
538 | 501 |
539 // Skip updating write barrier if storing a smi. | 502 // Skip updating write barrier if storing a smi. |
540 __ JumpIfSmi(r0, &exit); | 503 __ JumpIfSmi(r0, &exit); |
541 | 504 |
542 // Update the write barrier for the array address. | 505 // Update the write barrier for the array address. |
543 // Pass the now unused name_reg as a scratch register. | 506 // Pass the now unused name_reg as a scratch register. |
544 __ mov(name_reg, r0); | 507 __ mov(name_reg, r0); |
545 __ RecordWriteField(receiver_reg, | 508 __ RecordWriteField(receiver_reg, |
546 offset, | 509 offset, |
547 name_reg, | 510 name_reg, |
548 scratch1, | 511 scratch, |
549 kLRHasNotBeenSaved, | 512 kLRHasNotBeenSaved, |
550 kDontSaveFPRegs); | 513 kDontSaveFPRegs); |
551 } else { | 514 } else { |
552 // Write to the properties array. | 515 // Write to the properties array. |
553 int offset = index * kPointerSize + FixedArray::kHeaderSize; | 516 int offset = index * kPointerSize + FixedArray::kHeaderSize; |
554 // Get the properties array | 517 // Get the properties array |
555 __ ldr(scratch1, | 518 __ ldr(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset)); |
556 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset)); | 519 __ str(r0, FieldMemOperand(scratch, offset)); |
557 __ str(r0, FieldMemOperand(scratch1, offset)); | |
558 | 520 |
559 // Skip updating write barrier if storing a smi. | 521 // Skip updating write barrier if storing a smi. |
560 __ JumpIfSmi(r0, &exit); | 522 __ JumpIfSmi(r0, &exit); |
561 | 523 |
562 // Update the write barrier for the array address. | 524 // Update the write barrier for the array address. |
563 // Ok to clobber receiver_reg and name_reg, since we return. | 525 // Ok to clobber receiver_reg and name_reg, since we return. |
564 __ mov(name_reg, r0); | 526 __ mov(name_reg, r0); |
565 __ RecordWriteField(scratch1, | 527 __ RecordWriteField(scratch, |
566 offset, | 528 offset, |
567 name_reg, | 529 name_reg, |
568 receiver_reg, | 530 receiver_reg, |
569 kLRHasNotBeenSaved, | 531 kLRHasNotBeenSaved, |
570 kDontSaveFPRegs); | 532 kDontSaveFPRegs); |
571 } | 533 } |
572 | 534 |
573 // Return the value (register r0). | 535 // Return the value (register r0). |
574 __ bind(&exit); | 536 __ bind(&exit); |
575 __ Ret(); | 537 __ Ret(); |
(...skipping 2023 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2599 Handle<Map> transition, | 2561 Handle<Map> transition, |
2600 Handle<String> name) { | 2562 Handle<String> name) { |
2601 // ----------- S t a t e ------------- | 2563 // ----------- S t a t e ------------- |
2602 // -- r0 : value | 2564 // -- r0 : value |
2603 // -- r1 : receiver | 2565 // -- r1 : receiver |
2604 // -- r2 : name | 2566 // -- r2 : name |
2605 // -- lr : return address | 2567 // -- lr : return address |
2606 // ----------------------------------- | 2568 // ----------------------------------- |
2607 Label miss; | 2569 Label miss; |
2608 | 2570 |
2609 GenerateStoreField(masm(), | 2571 GenerateStoreField(masm(), object, index, transition, r1, r2, r3, &miss); |
2610 object, | |
2611 index, | |
2612 transition, | |
2613 name, | |
2614 r1, r2, r3, r4, | |
2615 &miss); | |
2616 __ bind(&miss); | 2572 __ bind(&miss); |
2617 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss(); | 2573 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss(); |
2618 __ Jump(ic, RelocInfo::CODE_TARGET); | 2574 __ Jump(ic, RelocInfo::CODE_TARGET); |
2619 | 2575 |
2620 // Return the generated code. | 2576 // Return the generated code. |
2621 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name); | 2577 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name); |
2622 } | 2578 } |
2623 | 2579 |
2624 | 2580 |
2625 Handle<Code> StoreStubCompiler::CompileStoreCallback( | 2581 Handle<Code> StoreStubCompiler::CompileStoreCallback( |
(...skipping 525 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3151 | 3107 |
3152 Counters* counters = masm()->isolate()->counters(); | 3108 Counters* counters = masm()->isolate()->counters(); |
3153 __ IncrementCounter(counters->keyed_store_field(), 1, r3, r4); | 3109 __ IncrementCounter(counters->keyed_store_field(), 1, r3, r4); |
3154 | 3110 |
3155 // Check that the name has not changed. | 3111 // Check that the name has not changed. |
3156 __ cmp(r1, Operand(name)); | 3112 __ cmp(r1, Operand(name)); |
3157 __ b(ne, &miss); | 3113 __ b(ne, &miss); |
3158 | 3114 |
3159 // r3 is used as scratch register. r1 and r2 keep their values if a jump to | 3115 // r3 is used as scratch register. r1 and r2 keep their values if a jump to |
3160 // the miss label is generated. | 3116 // the miss label is generated. |
3161 GenerateStoreField(masm(), | 3117 GenerateStoreField(masm(), object, index, transition, r2, r1, r3, &miss); |
3162 object, | |
3163 index, | |
3164 transition, | |
3165 name, | |
3166 r2, r1, r3, r4, | |
3167 &miss); | |
3168 __ bind(&miss); | 3118 __ bind(&miss); |
3169 | 3119 |
3170 __ DecrementCounter(counters->keyed_store_field(), 1, r3, r4); | 3120 __ DecrementCounter(counters->keyed_store_field(), 1, r3, r4); |
3171 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss(); | 3121 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss(); |
3172 __ Jump(ic, RelocInfo::CODE_TARGET); | 3122 __ Jump(ic, RelocInfo::CODE_TARGET); |
3173 | 3123 |
3174 // Return the generated code. | 3124 // Return the generated code. |
3175 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name); | 3125 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name); |
3176 } | 3126 } |
3177 | 3127 |
(...skipping 1413 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4591 __ Jump(ic_slow, RelocInfo::CODE_TARGET); | 4541 __ Jump(ic_slow, RelocInfo::CODE_TARGET); |
4592 } | 4542 } |
4593 } | 4543 } |
4594 | 4544 |
4595 | 4545 |
4596 #undef __ | 4546 #undef __ |
4597 | 4547 |
4598 } } // namespace v8::internal | 4548 } } // namespace v8::internal |
4599 | 4549 |
4600 #endif // V8_TARGET_ARCH_ARM | 4550 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |