| 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 |