| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 412 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 423 Label* miss) { | 423 Label* miss) { |
| 424 Handle<Cell> cell = GlobalObject::EnsurePropertyCell(global, name); | 424 Handle<Cell> cell = GlobalObject::EnsurePropertyCell(global, name); |
| 425 ASSERT(cell->value()->IsTheHole()); | 425 ASSERT(cell->value()->IsTheHole()); |
| 426 __ Mov(scratch, Operand(cell)); | 426 __ Mov(scratch, Operand(cell)); |
| 427 __ Ldr(scratch, FieldMemOperand(scratch, Cell::kValueOffset)); | 427 __ Ldr(scratch, FieldMemOperand(scratch, Cell::kValueOffset)); |
| 428 __ Cmp(scratch, the_hole); | 428 __ Cmp(scratch, the_hole); |
| 429 __ B(ne, miss); | 429 __ B(ne, miss); |
| 430 } | 430 } |
| 431 | 431 |
| 432 | 432 |
| 433 void BaseStoreStubCompiler::GenerateNegativeHolderLookup( |
| 434 MacroAssembler* masm, |
| 435 Handle<JSObject> holder, |
| 436 Register holder_reg, |
| 437 Handle<Name> name, |
| 438 Label* miss) { |
| 439 if (holder->IsJSGlobalObject()) { |
| 440 __ LoadRoot(scratch2(), Heap::kTheHoleValueRootIndex); |
| 441 GenerateCheckPropertyCell( |
| 442 masm, Handle<GlobalObject>::cast(holder), name, |
| 443 scratch1(), scratch2(), miss); |
| 444 } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) { |
| 445 GenerateDictionaryNegativeLookup( |
| 446 masm, miss, holder_reg, name, scratch1(), scratch2()); |
| 447 } |
| 448 } |
| 449 |
| 450 |
| 433 // Generate StoreTransition code, value is passed in x0 register. | 451 // Generate StoreTransition code, value is passed in x0 register. |
| 434 // When leaving generated code after success, the receiver_reg and name_reg may | 452 // When leaving generated code after success, the receiver_reg and storage_reg |
| 435 // be clobbered. Upon branch to miss_label, the receiver and name registers have | 453 // may be clobbered. Upon branch to miss_label, the receiver and name registers |
| 436 // their original values. | 454 // have their original values. |
| 437 void StubCompiler::GenerateStoreTransition(MacroAssembler* masm, | 455 void BaseStoreStubCompiler::GenerateStoreTransition(MacroAssembler* masm, |
| 438 Handle<JSObject> object, | 456 Handle<JSObject> object, |
| 439 LookupResult* lookup, | 457 LookupResult* lookup, |
| 440 Handle<Map> transition, | 458 Handle<Map> transition, |
| 441 Handle<Name> name, | 459 Handle<Name> name, |
| 442 Register receiver_reg, | 460 Register receiver_reg, |
| 443 Register name_reg, | 461 Register storage_reg, |
| 444 Register value_reg, | 462 Register value_reg, |
| 445 Register scratch1, | 463 Register scratch1, |
| 446 Register scratch2, | 464 Register scratch2, |
| 447 Register scratch3, | 465 Register scratch3, |
| 448 Label* miss_label, | 466 Label* miss_label, |
| 449 Label* miss_restore_name, | 467 Label* slow) { |
| 450 Label* slow) { | |
| 451 Label exit; | 468 Label exit; |
| 452 | 469 |
| 453 ASSERT(!AreAliased(receiver_reg, name_reg, value_reg, | 470 ASSERT(!AreAliased(receiver_reg, storage_reg, value_reg, |
| 454 scratch1, scratch2, scratch3)); | 471 scratch1, scratch2, scratch3)); |
| 455 | 472 |
| 456 // We don't need scratch3. | 473 // We don't need scratch3. |
| 457 scratch3 = NoReg; | 474 scratch3 = NoReg; |
| 458 | 475 |
| 459 // Check that the map of the object hasn't changed. | |
| 460 __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label, | |
| 461 DO_SMI_CHECK); | |
| 462 | |
| 463 // Perform global security token check if needed. | |
| 464 if (object->IsJSGlobalProxy()) { | |
| 465 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label); | |
| 466 } | |
| 467 | |
| 468 int descriptor = transition->LastAdded(); | 476 int descriptor = transition->LastAdded(); |
| 469 DescriptorArray* descriptors = transition->instance_descriptors(); | 477 DescriptorArray* descriptors = transition->instance_descriptors(); |
| 470 PropertyDetails details = descriptors->GetDetails(descriptor); | 478 PropertyDetails details = descriptors->GetDetails(descriptor); |
| 471 Representation representation = details.representation(); | 479 Representation representation = details.representation(); |
| 472 ASSERT(!representation.IsNone()); | 480 ASSERT(!representation.IsNone()); |
| 473 | 481 |
| 474 // Ensure no transitions to deprecated maps are followed. | |
| 475 __ CheckMapDeprecated(transition, scratch1, miss_label); | |
| 476 | |
| 477 // Check that we are allowed to write this. | |
| 478 if (object->GetPrototype()->IsJSObject()) { | |
| 479 JSObject* holder; | |
| 480 // holder == object indicates that no property was found. | |
| 481 if (lookup->holder() != *object) { | |
| 482 holder = lookup->holder(); | |
| 483 } else { | |
| 484 // Find the top object. | |
| 485 holder = *object; | |
| 486 do { | |
| 487 holder = JSObject::cast(holder->GetPrototype()); | |
| 488 } while (holder->GetPrototype()->IsJSObject()); | |
| 489 } | |
| 490 Register holder_reg = CheckPrototypes( | |
| 491 object, receiver_reg, Handle<JSObject>(holder), name_reg, | |
| 492 scratch1, scratch2, name, miss_restore_name, SKIP_RECEIVER); | |
| 493 // If no property was found, and the holder (the last object in the | |
| 494 // prototype chain) is in slow mode, we need to do a negative lookup on the | |
| 495 // holder. | |
| 496 if (lookup->holder() == *object) { | |
| 497 if (holder->IsJSGlobalObject()) { | |
| 498 __ LoadRoot(scratch2, Heap::kTheHoleValueRootIndex); | |
| 499 GenerateCheckPropertyCell( | |
| 500 masm, | |
| 501 Handle<GlobalObject>(GlobalObject::cast(holder)), | |
| 502 name, | |
| 503 scratch1, | |
| 504 scratch2, // The hole. | |
| 505 miss_restore_name); | |
| 506 } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) { | |
| 507 GenerateDictionaryNegativeLookup( | |
| 508 masm, miss_restore_name, holder_reg, name, scratch1, scratch2); | |
| 509 } | |
| 510 } | |
| 511 } | |
| 512 | |
| 513 // We've possibly already clobbered name_reg at this point, so use it for | |
| 514 // storage_reg. | |
| 515 Register storage_reg = name_reg; | |
| 516 | |
| 517 if (details.type() == CONSTANT_FUNCTION) { | 482 if (details.type() == CONSTANT_FUNCTION) { |
| 518 Handle<HeapObject> constant( | 483 Handle<HeapObject> constant( |
| 519 HeapObject::cast(descriptors->GetValue(descriptor))); | 484 HeapObject::cast(descriptors->GetValue(descriptor))); |
| 520 __ LoadHeapObject(scratch1, constant); | 485 __ LoadHeapObject(scratch1, constant); |
| 521 __ Cmp(value_reg, scratch1); | 486 __ Cmp(value_reg, scratch1); |
| 522 __ B(ne, miss_restore_name); | 487 __ B(ne, miss_label); |
| 523 } else if (FLAG_track_fields && representation.IsSmi()) { | 488 } else if (FLAG_track_fields && representation.IsSmi()) { |
| 524 __ JumpIfNotSmi(value_reg, miss_restore_name); | 489 __ JumpIfNotSmi(value_reg, miss_label); |
| 525 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) { | 490 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) { |
| 526 __ JumpIfSmi(value_reg, miss_restore_name); | 491 __ JumpIfSmi(value_reg, miss_label); |
| 527 } else if (FLAG_track_double_fields && representation.IsDouble()) { | 492 } else if (FLAG_track_double_fields && representation.IsDouble()) { |
| 528 Label do_store, heap_number; | 493 Label do_store, heap_number; |
| 529 __ AllocateHeapNumber(storage_reg, slow, scratch1, scratch2); | 494 __ AllocateHeapNumber(storage_reg, slow, scratch1, scratch2); |
| 530 | 495 |
| 531 // TODO(jbramley): Is fp_scratch the most appropriate FP scratch register? | 496 // TODO(jbramley): Is fp_scratch the most appropriate FP scratch register? |
| 532 // It's only used in Fcmp, but it's not really safe to use it like this. | 497 // It's only used in Fcmp, but it's not really safe to use it like this. |
| 533 __ JumpIfNotSmi(value_reg, &heap_number); | 498 __ JumpIfNotSmi(value_reg, &heap_number); |
| 534 __ SmiUntagToDouble(fp_scratch, value_reg); | 499 __ SmiUntagToDouble(fp_scratch, value_reg); |
| 535 __ B(&do_store); | 500 __ B(&do_store); |
| 536 | 501 |
| 537 __ Bind(&heap_number); | 502 __ Bind(&heap_number); |
| 538 __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex, | 503 __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex, |
| 539 miss_restore_name, DONT_DO_SMI_CHECK); | 504 miss_label, DONT_DO_SMI_CHECK); |
| 540 __ Ldr(fp_scratch, FieldMemOperand(value_reg, HeapNumber::kValueOffset)); | 505 __ Ldr(fp_scratch, FieldMemOperand(value_reg, HeapNumber::kValueOffset)); |
| 541 | 506 |
| 542 __ Bind(&do_store); | 507 __ Bind(&do_store); |
| 543 __ Str(fp_scratch, FieldMemOperand(storage_reg, HeapNumber::kValueOffset)); | 508 __ Str(fp_scratch, FieldMemOperand(storage_reg, HeapNumber::kValueOffset)); |
| 544 } | 509 } |
| 545 | 510 |
| 546 // Stub never generated for non-global objects that require access checks. | 511 // Stub never generated for non-global objects that require access checks. |
| 547 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); | 512 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); |
| 548 | 513 |
| 549 // Perform map transition for the receiver if necessary. | 514 // Perform map transition for the receiver if necessary. |
| 550 if ((details.type() == FIELD) && | 515 if ((details.type() == FIELD) && |
| 551 (object->map()->unused_property_fields() == 0)) { | 516 (object->map()->unused_property_fields() == 0)) { |
| 552 // The properties must be extended before we can store the value. | 517 // The properties must be extended before we can store the value. |
| 553 // We jump to a runtime call that extends the properties array. | 518 // We jump to a runtime call that extends the properties array. |
| 554 __ Mov(scratch1, Operand(transition)); | 519 __ Mov(scratch1, Operand(transition)); |
| 555 __ Push(receiver_reg, scratch1, value_reg); | 520 __ Push(receiver_reg, scratch1, value_reg); |
| 556 __ TailCallExternalReference( | 521 __ TailCallExternalReference( |
| 557 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), | 522 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), |
| 558 masm->isolate()), | 523 masm->isolate()), |
| 559 3, | 524 3, |
| 560 1); | 525 1); |
| 561 return; | 526 return; |
| 562 } | 527 } |
| 563 | 528 |
| 564 // Update the map of the object. | 529 // Update the map of the object. |
| 565 __ Mov(scratch1, Operand(transition)); | 530 __ Mov(scratch1, Operand(transition)); |
| 566 __ Str(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); | 531 __ Str(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); |
| 567 | 532 |
| 568 // Update the write barrier for the map field and pass the now unused | 533 // Update the write barrier for the map field. |
| 569 // name_reg as scratch register. | |
| 570 __ RecordWriteField(receiver_reg, | 534 __ RecordWriteField(receiver_reg, |
| 571 HeapObject::kMapOffset, | 535 HeapObject::kMapOffset, |
| 572 scratch1, | 536 scratch1, |
| 573 scratch2, | 537 scratch2, |
| 574 kLRHasNotBeenSaved, | 538 kLRHasNotBeenSaved, |
| 575 kDontSaveFPRegs, | 539 kDontSaveFPRegs, |
| 576 OMIT_REMEMBERED_SET, | 540 OMIT_REMEMBERED_SET, |
| 577 OMIT_SMI_CHECK); | 541 OMIT_SMI_CHECK); |
| 578 | 542 |
| 579 if (details.type() == CONSTANT_FUNCTION) { | 543 if (details.type() == CONSTANT_FUNCTION) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 598 int offset = object->map()->instance_size() + (index * kPointerSize); | 562 int offset = object->map()->instance_size() + (index * kPointerSize); |
| 599 // TODO(jbramley): This construct appears in several places in this | 563 // TODO(jbramley): This construct appears in several places in this |
| 600 // function. Try to clean it up, perhaps using a result_reg. | 564 // function. Try to clean it up, perhaps using a result_reg. |
| 601 if (FLAG_track_double_fields && representation.IsDouble()) { | 565 if (FLAG_track_double_fields && representation.IsDouble()) { |
| 602 __ Str(storage_reg, FieldMemOperand(receiver_reg, offset)); | 566 __ Str(storage_reg, FieldMemOperand(receiver_reg, offset)); |
| 603 } else { | 567 } else { |
| 604 __ Str(value_reg, FieldMemOperand(receiver_reg, offset)); | 568 __ Str(value_reg, FieldMemOperand(receiver_reg, offset)); |
| 605 } | 569 } |
| 606 | 570 |
| 607 if (!FLAG_track_fields || !representation.IsSmi()) { | 571 if (!FLAG_track_fields || !representation.IsSmi()) { |
| 608 // Skip updating write barrier if storing a smi. | |
| 609 __ JumpIfSmi(value_reg, &exit); | |
| 610 | |
| 611 // Update the write barrier for the array address. | 572 // Update the write barrier for the array address. |
| 612 // Pass the now unused name_reg as a scratch register. | |
| 613 if (!FLAG_track_double_fields || !representation.IsDouble()) { | 573 if (!FLAG_track_double_fields || !representation.IsDouble()) { |
| 614 __ Mov(name_reg, value_reg); | 574 __ Mov(storage_reg, value_reg); |
| 615 } else { | |
| 616 ASSERT(storage_reg.is(name_reg)); | |
| 617 } | 575 } |
| 618 __ RecordWriteField(receiver_reg, | 576 __ RecordWriteField(receiver_reg, |
| 619 offset, | 577 offset, |
| 620 name_reg, | 578 storage_reg, |
| 621 scratch1, | 579 scratch1, |
| 622 kLRHasNotBeenSaved, | 580 kLRHasNotBeenSaved, |
| 623 kDontSaveFPRegs, | 581 kDontSaveFPRegs, |
| 624 EMIT_REMEMBERED_SET, | 582 EMIT_REMEMBERED_SET, |
| 625 smi_check); | 583 smi_check); |
| 626 } | 584 } |
| 627 } else { | 585 } else { |
| 628 // Write to the properties array. | 586 // Write to the properties array. |
| 629 int offset = index * kPointerSize + FixedArray::kHeaderSize; | 587 int offset = index * kPointerSize + FixedArray::kHeaderSize; |
| 630 // Get the properties array | 588 // Get the properties array |
| 631 __ Ldr(scratch1, | 589 __ Ldr(scratch1, |
| 632 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset)); | 590 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset)); |
| 633 if (FLAG_track_double_fields && representation.IsDouble()) { | 591 if (FLAG_track_double_fields && representation.IsDouble()) { |
| 634 __ Str(storage_reg, FieldMemOperand(scratch1, offset)); | 592 __ Str(storage_reg, FieldMemOperand(scratch1, offset)); |
| 635 } else { | 593 } else { |
| 636 __ Str(value_reg, FieldMemOperand(scratch1, offset)); | 594 __ Str(value_reg, FieldMemOperand(scratch1, offset)); |
| 637 } | 595 } |
| 638 | 596 |
| 639 if (!FLAG_track_fields || !representation.IsSmi()) { | 597 if (!FLAG_track_fields || !representation.IsSmi()) { |
| 640 // Skip updating write barrier if storing a smi. | |
| 641 __ JumpIfSmi(value_reg, &exit); | |
| 642 | |
| 643 // Update the write barrier for the array address. | 598 // Update the write barrier for the array address. |
| 644 // Ok to clobber receiver_reg and name_reg, since we return. | |
| 645 if (!FLAG_track_double_fields || !representation.IsDouble()) { | 599 if (!FLAG_track_double_fields || !representation.IsDouble()) { |
| 646 __ Mov(name_reg, value_reg); | 600 __ Mov(storage_reg, value_reg); |
| 647 } else { | |
| 648 ASSERT(storage_reg.is(name_reg)); | |
| 649 } | 601 } |
| 650 __ RecordWriteField(scratch1, | 602 __ RecordWriteField(scratch1, |
| 651 offset, | 603 offset, |
| 652 name_reg, | 604 storage_reg, |
| 653 receiver_reg, | 605 receiver_reg, |
| 654 kLRHasNotBeenSaved, | 606 kLRHasNotBeenSaved, |
| 655 kDontSaveFPRegs, | 607 kDontSaveFPRegs, |
| 656 EMIT_REMEMBERED_SET, | 608 EMIT_REMEMBERED_SET, |
| 657 smi_check); | 609 smi_check); |
| 658 } | 610 } |
| 659 } | 611 } |
| 660 | 612 |
| 661 __ Bind(&exit); | 613 __ Bind(&exit); |
| 662 // Return the value (register x0). | 614 // Return the value (register x0). |
| 663 ASSERT(value_reg.is(x0)); | 615 ASSERT(value_reg.is(x0)); |
| 664 __ Ret(); | 616 __ Ret(); |
| 665 } | 617 } |
| 666 | 618 |
| 667 | 619 |
| 668 // Generate StoreField code, value is passed in x0 register. | 620 // Generate StoreField code, value is passed in x0 register. |
| 669 // When leaving generated code after success, the receiver_reg and name_reg may | 621 // When leaving generated code after success, the receiver_reg and name_reg may |
| 670 // be clobbered. Upon branch to miss_label, the receiver and name registers have | 622 // be clobbered. Upon branch to miss_label, the receiver and name registers have |
| 671 // their original values. | 623 // their original values. |
| 672 void StubCompiler::GenerateStoreField(MacroAssembler* masm, | 624 void BaseStoreStubCompiler::GenerateStoreField(MacroAssembler* masm, |
| 673 Handle<JSObject> object, | 625 Handle<JSObject> object, |
| 674 LookupResult* lookup, | 626 LookupResult* lookup, |
| 675 Register receiver_reg, | 627 Register receiver_reg, |
| 676 Register name_reg, | 628 Register name_reg, |
| 677 Register value_reg, | 629 Register value_reg, |
| 678 Register scratch1, | 630 Register scratch1, |
| 679 Register scratch2, | 631 Register scratch2, |
| 680 Label* miss_label) { | 632 Label* miss_label) { |
| 681 // x0 : value | 633 // x0 : value |
| 682 Label exit; | 634 Label exit; |
| 683 | 635 |
| 684 // Check that the map of the object hasn't changed. | |
| 685 __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label, | |
| 686 DO_SMI_CHECK); | |
| 687 | |
| 688 // Perform global security token check if needed. | |
| 689 if (object->IsJSGlobalProxy()) { | |
| 690 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label); | |
| 691 } | |
| 692 | |
| 693 // Stub never generated for non-global objects that require access | 636 // Stub never generated for non-global objects that require access |
| 694 // checks. | 637 // checks. |
| 695 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); | 638 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); |
| 696 | 639 |
| 697 int index = lookup->GetFieldIndex().field_index(); | 640 int index = lookup->GetFieldIndex().field_index(); |
| 698 | 641 |
| 699 // Adjust for the number of properties stored in the object. Even in the | 642 // Adjust for the number of properties stored in the object. Even in the |
| 700 // face of a transition we can use the old map here because the size of the | 643 // face of a transition we can use the old map here because the size of the |
| 701 // object and the number of in-object properties is not going to change. | 644 // object and the number of in-object properties is not going to change. |
| 702 index -= object->map()->inobject_properties(); | 645 index -= object->map()->inobject_properties(); |
| (...skipping 656 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1359 // their maps haven't changed. We also need to check that the property | 1302 // their maps haven't changed. We also need to check that the property |
| 1360 // cell for the property is still empty. | 1303 // cell for the property is still empty. |
| 1361 GenerateCheckPropertyCells(masm(), object, holder, name, | 1304 GenerateCheckPropertyCells(masm(), object, holder, name, |
| 1362 scratch1, scratch2, miss); | 1305 scratch1, scratch2, miss); |
| 1363 | 1306 |
| 1364 // Return the register containing the holder. | 1307 // Return the register containing the holder. |
| 1365 return reg; | 1308 return reg; |
| 1366 } | 1309 } |
| 1367 | 1310 |
| 1368 | 1311 |
| 1369 void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success, | 1312 void BaseLoadStubCompiler::HandlerFrontendFooter(Handle<Name> name, |
| 1313 Label* success, |
| 1370 Label* miss) { | 1314 Label* miss) { |
| 1371 if (!miss->is_unused()) { | 1315 if (!miss->is_unused()) { |
| 1372 __ B(success); | 1316 __ B(success); |
| 1373 __ Bind(miss); | 1317 __ Bind(miss); |
| 1374 TailCallBuiltin(masm(), MissBuiltin(kind())); | 1318 TailCallBuiltin(masm(), MissBuiltin(kind())); |
| 1375 } | 1319 } |
| 1376 } | 1320 } |
| 1377 | 1321 |
| 1378 | 1322 |
| 1323 void BaseStoreStubCompiler::HandlerFrontendFooter(Handle<Name> name, |
| 1324 Label* success, |
| 1325 Label* miss) { |
| 1326 if (!miss->is_unused()) { |
| 1327 __ B(success); |
| 1328 GenerateRestoreName(masm(), miss, name); |
| 1329 TailCallBuiltin(masm(), MissBuiltin(kind())); |
| 1330 } |
| 1331 } |
| 1332 |
| 1333 |
| 1379 Register BaseLoadStubCompiler::CallbackHandlerFrontend( | 1334 Register BaseLoadStubCompiler::CallbackHandlerFrontend( |
| 1380 Handle<JSObject> object, | 1335 Handle<JSObject> object, |
| 1381 Register object_reg, | 1336 Register object_reg, |
| 1382 Handle<JSObject> holder, | 1337 Handle<JSObject> holder, |
| 1383 Handle<Name> name, | 1338 Handle<Name> name, |
| 1384 Label* success, | 1339 Label* success, |
| 1385 Handle<ExecutableAccessorInfo> callback) { | 1340 Handle<ExecutableAccessorInfo> callback) { |
| 1386 Label miss; | 1341 Label miss; |
| 1387 | 1342 |
| 1388 Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss); | 1343 Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1413 // pointer into the dictionary. Check that the value is the callback. | 1368 // pointer into the dictionary. Check that the value is the callback. |
| 1414 Register pointer = scratch3(); | 1369 Register pointer = scratch3(); |
| 1415 const int kElementsStartOffset = NameDictionary::kHeaderSize + | 1370 const int kElementsStartOffset = NameDictionary::kHeaderSize + |
| 1416 NameDictionary::kElementsStartIndex * kPointerSize; | 1371 NameDictionary::kElementsStartIndex * kPointerSize; |
| 1417 const int kValueOffset = kElementsStartOffset + kPointerSize; | 1372 const int kValueOffset = kElementsStartOffset + kPointerSize; |
| 1418 __ Ldr(scratch2(), FieldMemOperand(pointer, kValueOffset)); | 1373 __ Ldr(scratch2(), FieldMemOperand(pointer, kValueOffset)); |
| 1419 __ Cmp(scratch2(), Operand(callback)); | 1374 __ Cmp(scratch2(), Operand(callback)); |
| 1420 __ B(ne, &miss); | 1375 __ B(ne, &miss); |
| 1421 } | 1376 } |
| 1422 | 1377 |
| 1423 HandlerFrontendFooter(success, &miss); | 1378 HandlerFrontendFooter(name, success, &miss); |
| 1424 return reg; | 1379 return reg; |
| 1425 } | 1380 } |
| 1426 | 1381 |
| 1427 | 1382 |
| 1428 void BaseLoadStubCompiler::NonexistentHandlerFrontend( | 1383 void BaseLoadStubCompiler::NonexistentHandlerFrontend( |
| 1429 Handle<JSObject> object, | 1384 Handle<JSObject> object, |
| 1430 Handle<JSObject> last, | 1385 Handle<JSObject> last, |
| 1431 Handle<Name> name, | 1386 Handle<Name> name, |
| 1432 Label* success, | 1387 Label* success, |
| 1433 Handle<GlobalObject> global) { | 1388 Handle<GlobalObject> global) { |
| 1434 Label miss; | 1389 Label miss; |
| 1435 | 1390 |
| 1436 HandlerFrontendHeader(object, receiver(), last, name, &miss); | 1391 HandlerFrontendHeader(object, receiver(), last, name, &miss); |
| 1437 | 1392 |
| 1438 // If the last object in the prototype chain is a global object, | 1393 // If the last object in the prototype chain is a global object, |
| 1439 // check that the global property cell is empty. | 1394 // check that the global property cell is empty. |
| 1440 if (!global.is_null()) { | 1395 if (!global.is_null()) { |
| 1441 GenerateCheckPropertyCell(masm(), global, name, | 1396 GenerateCheckPropertyCell(masm(), global, name, |
| 1442 scratch1(), scratch2(), &miss); | 1397 scratch1(), scratch2(), &miss); |
| 1443 } | 1398 } |
| 1444 | 1399 |
| 1445 HandlerFrontendFooter(success, &miss); | 1400 HandlerFrontendFooter(name, success, &miss); |
| 1446 } | 1401 } |
| 1447 | 1402 |
| 1448 | 1403 |
| 1449 void BaseLoadStubCompiler::GenerateLoadField(Register reg, | 1404 void BaseLoadStubCompiler::GenerateLoadField(Register reg, |
| 1450 Handle<JSObject> holder, | 1405 Handle<JSObject> holder, |
| 1451 PropertyIndex field, | 1406 PropertyIndex field, |
| 1452 Representation representation) { | 1407 Representation representation) { |
| 1453 __ Mov(receiver(), reg); | 1408 __ Mov(receiver(), reg); |
| 1454 if (kind() == Code::LOAD_IC) { | 1409 if (kind() == Code::LOAD_IC) { |
| 1455 LoadFieldStub stub(field.is_inobject(holder), | 1410 LoadFieldStub stub(field.is_inobject(holder), |
| (...skipping 337 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1793 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, x3, x0, | 1748 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, x3, x0, |
| 1794 x4, name, &miss); | 1749 x4, name, &miss); |
| 1795 } else { | 1750 } else { |
| 1796 ASSERT(cell->value() == *function); | 1751 ASSERT(cell->value() == *function); |
| 1797 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name, | 1752 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name, |
| 1798 &miss); | 1753 &miss); |
| 1799 GenerateLoadFunctionFromCell(cell, function, &miss); | 1754 GenerateLoadFunctionFromCell(cell, function, &miss); |
| 1800 } | 1755 } |
| 1801 | 1756 |
| 1802 Handle<AllocationSite> site = isolate()->factory()->NewAllocationSite(); | 1757 Handle<AllocationSite> site = isolate()->factory()->NewAllocationSite(); |
| 1803 site->set_payload(Smi::FromInt(GetInitialFastElementsKind())); | 1758 site->set_transition_info(Smi::FromInt(GetInitialFastElementsKind())); |
| 1804 Handle<Cell> site_feedback_cell = isolate()->factory()->NewCell(site); | 1759 Handle<Cell> site_feedback_cell = isolate()->factory()->NewCell(site); |
| 1805 __ Mov(x0, argc); | 1760 __ Mov(x0, argc); |
| 1806 __ Mov(x1, Operand(function)); | 1761 __ Mov(x1, Operand(function)); |
| 1807 __ Mov(x2, Operand(site_feedback_cell)); | 1762 __ Mov(x2, Operand(site_feedback_cell)); |
| 1808 | 1763 |
| 1809 ArrayConstructorStub stub(isolate()); | 1764 ArrayConstructorStub stub(isolate()); |
| 1810 __ TailCallStub(&stub); | 1765 __ TailCallStub(&stub); |
| 1811 | 1766 |
| 1812 __ Bind(&miss); | 1767 __ Bind(&miss); |
| 1813 GenerateMissBranch(); | 1768 GenerateMissBranch(); |
| (...skipping 1104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2918 __ Bind(&miss); | 2873 __ Bind(&miss); |
| 2919 __ IncrementCounter(counters->call_global_inline_miss(), 1, x1, x3); | 2874 __ IncrementCounter(counters->call_global_inline_miss(), 1, x1, x3); |
| 2920 GenerateMissBranch(); | 2875 GenerateMissBranch(); |
| 2921 | 2876 |
| 2922 // Return the generated code. | 2877 // Return the generated code. |
| 2923 return GetCode(Code::NORMAL, name); | 2878 return GetCode(Code::NORMAL, name); |
| 2924 } | 2879 } |
| 2925 | 2880 |
| 2926 | 2881 |
| 2927 Handle<Code> StoreStubCompiler::CompileStoreCallback( | 2882 Handle<Code> StoreStubCompiler::CompileStoreCallback( |
| 2928 Handle<Name> name, | |
| 2929 Handle<JSObject> object, | 2883 Handle<JSObject> object, |
| 2930 Handle<JSObject> holder, | 2884 Handle<JSObject> holder, |
| 2885 Handle<Name> name, |
| 2931 Handle<ExecutableAccessorInfo> callback) { | 2886 Handle<ExecutableAccessorInfo> callback) { |
| 2932 Label miss; | |
| 2933 | |
| 2934 ASM_LOCATION("StoreStubCompiler::CompileStoreCallback"); | 2887 ASM_LOCATION("StoreStubCompiler::CompileStoreCallback"); |
| 2935 | 2888 |
| 2936 // Check that the maps haven't changed. | 2889 Label success; |
| 2937 __ JumpIfSmi(receiver(), &miss); | 2890 HandlerFrontend(object, receiver(), holder, name, &success); |
| 2938 CheckPrototypes(object, receiver(), holder, | 2891 __ Bind(&success); |
| 2939 scratch1(), scratch2(), scratch3(), name, &miss); | |
| 2940 | 2892 |
| 2941 // Stub never generated for non-global objects that require access checks. | 2893 // Stub never generated for non-global objects that require access checks. |
| 2942 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded()); | 2894 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded()); |
| 2943 | 2895 |
| 2944 __ Mov(scratch1(), Operand(callback)); | 2896 __ Mov(scratch1(), Operand(callback)); |
| 2945 __ Push(receiver(), scratch1(), this->name(), value()); | 2897 __ Mov(scratch2(), Operand(name)); |
| 2898 __ Push(receiver(), scratch1(), scratch2(), value()); |
| 2946 | 2899 |
| 2947 // Do tail-call to the runtime system. | 2900 // Do tail-call to the runtime system. |
| 2948 ExternalReference store_callback_property = | 2901 ExternalReference store_callback_property = |
| 2949 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate()); | 2902 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate()); |
| 2950 __ TailCallExternalReference(store_callback_property, 4, 1); | 2903 __ TailCallExternalReference(store_callback_property, 4, 1); |
| 2951 | 2904 |
| 2952 // Handle store cache miss. | |
| 2953 __ Bind(&miss); | |
| 2954 TailCallBuiltin(masm(), MissBuiltin(kind())); | |
| 2955 | |
| 2956 // Return the generated code. | 2905 // Return the generated code. |
| 2957 return GetICCode(kind(), Code::CALLBACKS, name); | 2906 return GetCode(kind(), Code::CALLBACKS, name); |
| 2958 } | 2907 } |
| 2959 | 2908 |
| 2960 | 2909 |
| 2961 #undef __ | 2910 #undef __ |
| 2962 #define __ ACCESS_MASM(masm) | 2911 #define __ ACCESS_MASM(masm) |
| 2963 | 2912 |
| 2964 | 2913 |
| 2965 void StoreStubCompiler::GenerateStoreViaSetter( | 2914 void StoreStubCompiler::GenerateStoreViaSetter( |
| 2966 MacroAssembler* masm, | 2915 MacroAssembler* masm, |
| 2967 Handle<JSFunction> setter) { | 2916 Handle<JSFunction> setter) { |
| (...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3208 | 3157 |
| 3209 // Get the value from the cell. | 3158 // Get the value from the cell. |
| 3210 __ Mov(x3, Operand(cell)); | 3159 __ Mov(x3, Operand(cell)); |
| 3211 __ Ldr(x4, FieldMemOperand(x3, Cell::kValueOffset)); | 3160 __ Ldr(x4, FieldMemOperand(x3, Cell::kValueOffset)); |
| 3212 | 3161 |
| 3213 // Check for deleted property if property can actually be deleted. | 3162 // Check for deleted property if property can actually be deleted. |
| 3214 if (!is_dont_delete) { | 3163 if (!is_dont_delete) { |
| 3215 __ JumpIfRoot(x4, Heap::kTheHoleValueRootIndex, &miss); | 3164 __ JumpIfRoot(x4, Heap::kTheHoleValueRootIndex, &miss); |
| 3216 } | 3165 } |
| 3217 | 3166 |
| 3218 HandlerFrontendFooter(&success, &miss); | 3167 HandlerFrontendFooter(name, &success, &miss); |
| 3219 __ bind(&success); | 3168 __ Bind(&success); |
| 3220 | 3169 |
| 3221 Counters* counters = isolate()->counters(); | 3170 Counters* counters = isolate()->counters(); |
| 3222 __ IncrementCounter(counters->named_load_global_stub(), 1, x1, x3); | 3171 __ IncrementCounter(counters->named_load_global_stub(), 1, x1, x3); |
| 3223 __ Mov(x0, x4); | 3172 __ Mov(x0, x4); |
| 3224 __ Ret(); | 3173 __ Ret(); |
| 3225 | 3174 |
| 3226 // Return the generated code. | 3175 // Return the generated code. |
| 3227 return GetICCode(kind(), Code::NORMAL, name); | 3176 return GetICCode(kind(), Code::NORMAL, name); |
| 3228 } | 3177 } |
| 3229 | 3178 |
| 3230 | 3179 |
| 3231 Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC( | 3180 Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC( |
| 3232 MapHandleList* receiver_maps, | 3181 MapHandleList* receiver_maps, |
| 3233 CodeHandleList* handlers, | 3182 CodeHandleList* handlers, |
| 3234 Handle<Name> name, | 3183 Handle<Name> name, |
| 3235 Code::StubType type, | 3184 Code::StubType type, |
| 3236 IcCheckType check) { | 3185 IcCheckType check) { |
| 3237 Label miss; | 3186 Label miss; |
| 3238 | 3187 |
| 3239 if (check == PROPERTY) { | 3188 if (check == PROPERTY) { |
| 3240 GenerateNameCheck(name, this->name(), &miss); | 3189 GenerateNameCheck(name, this->name(), &miss); |
| 3241 } | 3190 } |
| (...skipping 565 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3807 // ----------- S t a t e ------------- | 3756 // ----------- S t a t e ------------- |
| 3808 | 3757 |
| 3809 GenerateStoreFastSmiOrDoubleElement(masm, is_js_array, FAST_DOUBLE_ELEMENTS, | 3758 GenerateStoreFastSmiOrDoubleElement(masm, is_js_array, FAST_DOUBLE_ELEMENTS, |
| 3810 store_mode, true); | 3759 store_mode, true); |
| 3811 } | 3760 } |
| 3812 | 3761 |
| 3813 | 3762 |
| 3814 } } // namespace v8::internal | 3763 } } // namespace v8::internal |
| 3815 | 3764 |
| 3816 #endif // V8_TARGET_ARCH_A64 | 3765 #endif // V8_TARGET_ARCH_A64 |
| OLD | NEW |