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, |
438 Register receiver_reg, | 439 Register receiver_reg, |
439 Register name_reg, | 440 Register name_reg, |
440 Register scratch, | 441 Register scratch1, |
| 442 Register scratch2, |
441 Label* miss_label) { | 443 Label* miss_label) { |
442 // r0 : value | 444 // r0 : value |
443 Label exit; | 445 Label exit; |
444 | 446 |
| 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 |
445 // Check that the map of the object hasn't changed. | 457 // Check that the map of the object hasn't changed. |
446 CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS | 458 CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS |
447 : REQUIRE_EXACT_MAP; | 459 : REQUIRE_EXACT_MAP; |
448 __ CheckMap(receiver_reg, scratch, Handle<Map>(object->map()), miss_label, | 460 __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label, |
449 DO_SMI_CHECK, mode); | 461 DO_SMI_CHECK, mode); |
450 | 462 |
451 // Perform global security token check if needed. | 463 // Perform global security token check if needed. |
452 if (object->IsJSGlobalProxy()) { | 464 if (object->IsJSGlobalProxy()) { |
453 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label); | 465 __ CheckAccessGlobalProxy(receiver_reg, scratch1, 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); |
454 } | 491 } |
455 | 492 |
456 // Stub never generated for non-global objects that require access | 493 // Stub never generated for non-global objects that require access |
457 // checks. | 494 // checks. |
458 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); | 495 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); |
459 | 496 |
460 // Perform map transition for the receiver if necessary. | 497 // Perform map transition for the receiver if necessary. |
461 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) { | 498 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) { |
462 // The properties must be extended before we can store the value. | 499 // The properties must be extended before we can store the value. |
463 // We jump to a runtime call that extends the properties array. | 500 // We jump to a runtime call that extends the properties array. |
(...skipping 27 matching lines...) Expand all Loading... |
491 | 528 |
492 // Skip updating write barrier if storing a smi. | 529 // Skip updating write barrier if storing a smi. |
493 __ JumpIfSmi(r0, &exit); | 530 __ JumpIfSmi(r0, &exit); |
494 | 531 |
495 // Update the write barrier for the array address. | 532 // Update the write barrier for the array address. |
496 // Pass the now unused name_reg as a scratch register. | 533 // Pass the now unused name_reg as a scratch register. |
497 __ mov(name_reg, r0); | 534 __ mov(name_reg, r0); |
498 __ RecordWriteField(receiver_reg, | 535 __ RecordWriteField(receiver_reg, |
499 offset, | 536 offset, |
500 name_reg, | 537 name_reg, |
501 scratch, | 538 scratch1, |
502 kLRHasNotBeenSaved, | 539 kLRHasNotBeenSaved, |
503 kDontSaveFPRegs); | 540 kDontSaveFPRegs); |
504 } else { | 541 } else { |
505 // Write to the properties array. | 542 // Write to the properties array. |
506 int offset = index * kPointerSize + FixedArray::kHeaderSize; | 543 int offset = index * kPointerSize + FixedArray::kHeaderSize; |
507 // Get the properties array | 544 // Get the properties array |
508 __ ldr(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset)); | 545 __ ldr(scratch1, |
509 __ str(r0, FieldMemOperand(scratch, offset)); | 546 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset)); |
| 547 __ str(r0, FieldMemOperand(scratch1, offset)); |
510 | 548 |
511 // Skip updating write barrier if storing a smi. | 549 // Skip updating write barrier if storing a smi. |
512 __ JumpIfSmi(r0, &exit); | 550 __ JumpIfSmi(r0, &exit); |
513 | 551 |
514 // Update the write barrier for the array address. | 552 // Update the write barrier for the array address. |
515 // Ok to clobber receiver_reg and name_reg, since we return. | 553 // Ok to clobber receiver_reg and name_reg, since we return. |
516 __ mov(name_reg, r0); | 554 __ mov(name_reg, r0); |
517 __ RecordWriteField(scratch, | 555 __ RecordWriteField(scratch1, |
518 offset, | 556 offset, |
519 name_reg, | 557 name_reg, |
520 receiver_reg, | 558 receiver_reg, |
521 kLRHasNotBeenSaved, | 559 kLRHasNotBeenSaved, |
522 kDontSaveFPRegs); | 560 kDontSaveFPRegs); |
523 } | 561 } |
524 | 562 |
525 // Return the value (register r0). | 563 // Return the value (register r0). |
526 __ bind(&exit); | 564 __ bind(&exit); |
527 __ Ret(); | 565 __ Ret(); |
(...skipping 2010 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2538 Handle<Map> transition, | 2576 Handle<Map> transition, |
2539 Handle<String> name) { | 2577 Handle<String> name) { |
2540 // ----------- S t a t e ------------- | 2578 // ----------- S t a t e ------------- |
2541 // -- r0 : value | 2579 // -- r0 : value |
2542 // -- r1 : receiver | 2580 // -- r1 : receiver |
2543 // -- r2 : name | 2581 // -- r2 : name |
2544 // -- lr : return address | 2582 // -- lr : return address |
2545 // ----------------------------------- | 2583 // ----------------------------------- |
2546 Label miss; | 2584 Label miss; |
2547 | 2585 |
2548 GenerateStoreField(masm(), object, index, transition, r1, r2, r3, &miss); | 2586 GenerateStoreField(masm(), |
| 2587 object, |
| 2588 index, |
| 2589 transition, |
| 2590 name, |
| 2591 r1, r2, r3, r4, |
| 2592 &miss); |
2549 __ bind(&miss); | 2593 __ bind(&miss); |
2550 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss(); | 2594 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss(); |
2551 __ Jump(ic, RelocInfo::CODE_TARGET); | 2595 __ Jump(ic, RelocInfo::CODE_TARGET); |
2552 | 2596 |
2553 // Return the generated code. | 2597 // Return the generated code. |
2554 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name); | 2598 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name); |
2555 } | 2599 } |
2556 | 2600 |
2557 | 2601 |
2558 Handle<Code> StoreStubCompiler::CompileStoreCallback( | 2602 Handle<Code> StoreStubCompiler::CompileStoreCallback( |
(...skipping 525 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3084 | 3128 |
3085 Counters* counters = masm()->isolate()->counters(); | 3129 Counters* counters = masm()->isolate()->counters(); |
3086 __ IncrementCounter(counters->keyed_store_field(), 1, r3, r4); | 3130 __ IncrementCounter(counters->keyed_store_field(), 1, r3, r4); |
3087 | 3131 |
3088 // Check that the name has not changed. | 3132 // Check that the name has not changed. |
3089 __ cmp(r1, Operand(name)); | 3133 __ cmp(r1, Operand(name)); |
3090 __ b(ne, &miss); | 3134 __ b(ne, &miss); |
3091 | 3135 |
3092 // r3 is used as scratch register. r1 and r2 keep their values if a jump to | 3136 // r3 is used as scratch register. r1 and r2 keep their values if a jump to |
3093 // the miss label is generated. | 3137 // the miss label is generated. |
3094 GenerateStoreField(masm(), object, index, transition, r2, r1, r3, &miss); | 3138 GenerateStoreField(masm(), |
| 3139 object, |
| 3140 index, |
| 3141 transition, |
| 3142 name, |
| 3143 r2, r1, r3, r4, |
| 3144 &miss); |
3095 __ bind(&miss); | 3145 __ bind(&miss); |
3096 | 3146 |
3097 __ DecrementCounter(counters->keyed_store_field(), 1, r3, r4); | 3147 __ DecrementCounter(counters->keyed_store_field(), 1, r3, r4); |
3098 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss(); | 3148 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss(); |
3099 __ Jump(ic, RelocInfo::CODE_TARGET); | 3149 __ Jump(ic, RelocInfo::CODE_TARGET); |
3100 | 3150 |
3101 // Return the generated code. | 3151 // Return the generated code. |
3102 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name); | 3152 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name); |
3103 } | 3153 } |
3104 | 3154 |
(...skipping 1398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4503 __ Jump(ic_slow, RelocInfo::CODE_TARGET); | 4553 __ Jump(ic_slow, RelocInfo::CODE_TARGET); |
4504 } | 4554 } |
4505 } | 4555 } |
4506 | 4556 |
4507 | 4557 |
4508 #undef __ | 4558 #undef __ |
4509 | 4559 |
4510 } } // namespace v8::internal | 4560 } } // namespace v8::internal |
4511 | 4561 |
4512 #endif // V8_TARGET_ARCH_ARM | 4562 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |