OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
7 #if V8_TARGET_ARCH_IA32 | 7 #if V8_TARGET_ARCH_IA32 |
8 | 8 |
9 #include "src/codegen.h" | 9 #include "src/codegen.h" |
10 #include "src/ic-inl.h" | 10 #include "src/ic-inl.h" |
(...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
363 // Put api_function_address in place. | 363 // Put api_function_address in place. |
364 Address function_address = v8::ToCData<Address>(api_call_info->callback()); | 364 Address function_address = v8::ToCData<Address>(api_call_info->callback()); |
365 __ mov(api_function_address, Immediate(function_address)); | 365 __ mov(api_function_address, Immediate(function_address)); |
366 | 366 |
367 // Jump to stub. | 367 // Jump to stub. |
368 CallApiFunctionStub stub(isolate, is_store, call_data_undefined, argc); | 368 CallApiFunctionStub stub(isolate, is_store, call_data_undefined, argc); |
369 __ TailCallStub(&stub); | 369 __ TailCallStub(&stub); |
370 } | 370 } |
371 | 371 |
372 | 372 |
373 void NamedStoreHandlerCompiler::GenerateRestoreName(MacroAssembler* masm, | |
374 Label* label, | |
375 Handle<Name> name) { | |
376 if (!label->is_unused()) { | |
377 __ bind(label); | |
378 __ mov(this->name(), Immediate(name)); | |
379 } | |
380 } | |
381 | |
382 | |
383 // Generate code to check that a global property cell is empty. Create | 373 // Generate code to check that a global property cell is empty. Create |
384 // the property cell at compilation time if no cell exists for the | 374 // the property cell at compilation time if no cell exists for the |
385 // property. | 375 // property. |
386 void PropertyHandlerCompiler::GenerateCheckPropertyCell( | 376 void PropertyHandlerCompiler::GenerateCheckPropertyCell( |
387 MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name, | 377 MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name, |
388 Register scratch, Label* miss) { | 378 Register scratch, Label* miss) { |
389 Handle<PropertyCell> cell = | 379 Handle<PropertyCell> cell = |
390 JSGlobalObject::EnsurePropertyCell(global, name); | 380 JSGlobalObject::EnsurePropertyCell(global, name); |
391 ASSERT(cell->value()->IsTheHole()); | 381 ASSERT(cell->value()->IsTheHole()); |
392 Handle<Oddball> the_hole = masm->isolate()->factory()->the_hole_value(); | 382 Handle<Oddball> the_hole = masm->isolate()->factory()->the_hole_value(); |
393 if (masm->serializer_enabled()) { | 383 if (masm->serializer_enabled()) { |
394 __ mov(scratch, Immediate(cell)); | 384 __ mov(scratch, Immediate(cell)); |
395 __ cmp(FieldOperand(scratch, PropertyCell::kValueOffset), | 385 __ cmp(FieldOperand(scratch, PropertyCell::kValueOffset), |
396 Immediate(the_hole)); | 386 Immediate(the_hole)); |
397 } else { | 387 } else { |
398 __ cmp(Operand::ForCell(cell), Immediate(the_hole)); | 388 __ cmp(Operand::ForCell(cell), Immediate(the_hole)); |
399 } | 389 } |
400 __ j(not_equal, miss); | 390 __ j(not_equal, miss); |
401 } | 391 } |
402 | 392 |
403 | 393 |
| 394 void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm, |
| 395 Handle<Code> code) { |
| 396 __ jmp(code, RelocInfo::CODE_TARGET); |
| 397 } |
| 398 |
| 399 |
| 400 #undef __ |
| 401 #define __ ACCESS_MASM(masm()) |
| 402 |
| 403 |
| 404 void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label, |
| 405 Handle<Name> name) { |
| 406 if (!label->is_unused()) { |
| 407 __ bind(label); |
| 408 __ mov(this->name(), Immediate(name)); |
| 409 } |
| 410 } |
| 411 |
| 412 |
404 void NamedStoreHandlerCompiler::GenerateNegativeHolderLookup( | 413 void NamedStoreHandlerCompiler::GenerateNegativeHolderLookup( |
405 MacroAssembler* masm, Handle<JSObject> holder, Register holder_reg, | 414 Register holder_reg, Handle<Name> name, Label* miss) { |
406 Handle<Name> name, Label* miss) { | 415 if (holder()->IsJSGlobalObject()) { |
407 if (holder->IsJSGlobalObject()) { | 416 GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(holder()), |
408 GenerateCheckPropertyCell( | 417 name, scratch1(), miss); |
409 masm, Handle<JSGlobalObject>::cast(holder), name, scratch1(), miss); | 418 } else if (!holder()->HasFastProperties()) { |
410 } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) { | 419 GenerateDictionaryNegativeLookup(masm(), miss, holder_reg, name, scratch1(), |
411 GenerateDictionaryNegativeLookup( | 420 scratch2()); |
412 masm, miss, holder_reg, name, scratch1(), scratch2()); | |
413 } | 421 } |
414 } | 422 } |
415 | 423 |
416 | 424 |
417 // Receiver_reg is preserved on jumps to miss_label, but may be destroyed if | 425 // Receiver_reg is preserved on jumps to miss_label, but may be destroyed if |
418 // store is successful. | 426 // store is successful. |
419 void NamedStoreHandlerCompiler::GenerateStoreTransition( | 427 void NamedStoreHandlerCompiler::GenerateStoreTransition( |
420 MacroAssembler* masm, LookupResult* lookup, Handle<Map> transition, | 428 Handle<Map> transition, Handle<Name> name, Register receiver_reg, |
421 Handle<Name> name, Register receiver_reg, Register storage_reg, | 429 Register storage_reg, Register value_reg, Register scratch1, |
422 Register value_reg, Register scratch1, Register scratch2, Register unused, | 430 Register scratch2, Register unused, Label* miss_label, Label* slow) { |
423 Label* miss_label, Label* slow) { | |
424 int descriptor = transition->LastAdded(); | 431 int descriptor = transition->LastAdded(); |
425 DescriptorArray* descriptors = transition->instance_descriptors(); | 432 DescriptorArray* descriptors = transition->instance_descriptors(); |
426 PropertyDetails details = descriptors->GetDetails(descriptor); | 433 PropertyDetails details = descriptors->GetDetails(descriptor); |
427 Representation representation = details.representation(); | 434 Representation representation = details.representation(); |
428 ASSERT(!representation.IsNone()); | 435 ASSERT(!representation.IsNone()); |
429 | 436 |
430 if (details.type() == CONSTANT) { | 437 if (details.type() == CONSTANT) { |
431 Handle<Object> constant(descriptors->GetValue(descriptor), masm->isolate()); | 438 Handle<Object> constant(descriptors->GetValue(descriptor), isolate()); |
432 __ CmpObject(value_reg, constant); | 439 __ CmpObject(value_reg, constant); |
433 __ j(not_equal, miss_label); | 440 __ j(not_equal, miss_label); |
434 } else if (representation.IsSmi()) { | 441 } else if (representation.IsSmi()) { |
435 __ JumpIfNotSmi(value_reg, miss_label); | 442 __ JumpIfNotSmi(value_reg, miss_label); |
436 } else if (representation.IsHeapObject()) { | 443 } else if (representation.IsHeapObject()) { |
437 __ JumpIfSmi(value_reg, miss_label); | 444 __ JumpIfSmi(value_reg, miss_label); |
438 HeapType* field_type = descriptors->GetFieldType(descriptor); | 445 HeapType* field_type = descriptors->GetFieldType(descriptor); |
439 HeapType::Iterator<Map> it = field_type->Classes(); | 446 HeapType::Iterator<Map> it = field_type->Classes(); |
440 if (!it.Done()) { | 447 if (!it.Done()) { |
441 Label do_store; | 448 Label do_store; |
(...skipping 12 matching lines...) Expand all Loading... |
454 Label do_store, heap_number; | 461 Label do_store, heap_number; |
455 __ AllocateHeapNumber(storage_reg, scratch1, scratch2, slow, MUTABLE); | 462 __ AllocateHeapNumber(storage_reg, scratch1, scratch2, slow, MUTABLE); |
456 | 463 |
457 __ JumpIfNotSmi(value_reg, &heap_number); | 464 __ JumpIfNotSmi(value_reg, &heap_number); |
458 __ SmiUntag(value_reg); | 465 __ SmiUntag(value_reg); |
459 __ Cvtsi2sd(xmm0, value_reg); | 466 __ Cvtsi2sd(xmm0, value_reg); |
460 __ SmiTag(value_reg); | 467 __ SmiTag(value_reg); |
461 __ jmp(&do_store); | 468 __ jmp(&do_store); |
462 | 469 |
463 __ bind(&heap_number); | 470 __ bind(&heap_number); |
464 __ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(), | 471 __ CheckMap(value_reg, isolate()->factory()->heap_number_map(), miss_label, |
465 miss_label, DONT_DO_SMI_CHECK); | 472 DONT_DO_SMI_CHECK); |
466 __ movsd(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset)); | 473 __ movsd(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset)); |
467 | 474 |
468 __ bind(&do_store); | 475 __ bind(&do_store); |
469 __ movsd(FieldOperand(storage_reg, HeapNumber::kValueOffset), xmm0); | 476 __ movsd(FieldOperand(storage_reg, HeapNumber::kValueOffset), xmm0); |
470 } | 477 } |
471 | 478 |
472 // Stub never generated for objects that require access checks. | 479 // Stub never generated for objects that require access checks. |
473 ASSERT(!transition->is_access_check_needed()); | 480 ASSERT(!transition->is_access_check_needed()); |
474 | 481 |
475 // Perform map transition for the receiver if necessary. | 482 // Perform map transition for the receiver if necessary. |
476 if (details.type() == FIELD && | 483 if (details.type() == FIELD && |
477 Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) { | 484 Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) { |
478 // The properties must be extended before we can store the value. | 485 // The properties must be extended before we can store the value. |
479 // We jump to a runtime call that extends the properties array. | 486 // We jump to a runtime call that extends the properties array. |
480 __ pop(scratch1); // Return address. | 487 __ pop(scratch1); // Return address. |
481 __ push(receiver_reg); | 488 __ push(receiver_reg); |
482 __ push(Immediate(transition)); | 489 __ push(Immediate(transition)); |
483 __ push(value_reg); | 490 __ push(value_reg); |
484 __ push(scratch1); | 491 __ push(scratch1); |
485 __ TailCallExternalReference( | 492 __ TailCallExternalReference( |
486 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), | 493 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), |
487 masm->isolate()), | 494 isolate()), |
488 3, | 495 3, 1); |
489 1); | |
490 return; | 496 return; |
491 } | 497 } |
492 | 498 |
493 // Update the map of the object. | 499 // Update the map of the object. |
494 __ mov(scratch1, Immediate(transition)); | 500 __ mov(scratch1, Immediate(transition)); |
495 __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1); | 501 __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1); |
496 | 502 |
497 // Update the write barrier for the map field. | 503 // Update the write barrier for the map field. |
498 __ RecordWriteField(receiver_reg, | 504 __ RecordWriteField(receiver_reg, |
499 HeapObject::kMapOffset, | 505 HeapObject::kMapOffset, |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
570 | 576 |
571 // Return the value (register eax). | 577 // Return the value (register eax). |
572 ASSERT(value_reg.is(eax)); | 578 ASSERT(value_reg.is(eax)); |
573 __ ret(0); | 579 __ ret(0); |
574 } | 580 } |
575 | 581 |
576 | 582 |
577 // Both name_reg and receiver_reg are preserved on jumps to miss_label, | 583 // Both name_reg and receiver_reg are preserved on jumps to miss_label, |
578 // but may be destroyed if store is successful. | 584 // but may be destroyed if store is successful. |
579 void NamedStoreHandlerCompiler::GenerateStoreField( | 585 void NamedStoreHandlerCompiler::GenerateStoreField( |
580 MacroAssembler* masm, Handle<JSObject> object, LookupResult* lookup, | 586 Handle<JSObject> object, LookupResult* lookup, Register receiver_reg, |
581 Register receiver_reg, Register name_reg, Register value_reg, | 587 Register name_reg, Register value_reg, Register scratch1, Register scratch2, |
582 Register scratch1, Register scratch2, Label* miss_label) { | 588 Label* miss_label) { |
583 // Stub never generated for non-global objects that require access | 589 // Stub never generated for objects that require access checks. |
584 // checks. | 590 ASSERT(!object->IsAccessCheckNeeded()); |
585 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); | 591 ASSERT(!object->IsJSGlobalProxy()); |
586 | 592 |
587 FieldIndex index = lookup->GetFieldIndex(); | 593 FieldIndex index = lookup->GetFieldIndex(); |
588 | 594 |
589 Representation representation = lookup->representation(); | 595 Representation representation = lookup->representation(); |
590 ASSERT(!representation.IsNone()); | 596 ASSERT(!representation.IsNone()); |
591 if (representation.IsSmi()) { | 597 if (representation.IsSmi()) { |
592 __ JumpIfNotSmi(value_reg, miss_label); | 598 __ JumpIfNotSmi(value_reg, miss_label); |
593 } else if (representation.IsHeapObject()) { | 599 } else if (representation.IsHeapObject()) { |
594 __ JumpIfSmi(value_reg, miss_label); | 600 __ JumpIfSmi(value_reg, miss_label); |
595 HeapType* field_type = lookup->GetFieldType(); | 601 HeapType* field_type = lookup->GetFieldType(); |
(...skipping 21 matching lines...) Expand all Loading... |
617 } | 623 } |
618 | 624 |
619 // Store the value into the storage. | 625 // Store the value into the storage. |
620 Label do_store, heap_number; | 626 Label do_store, heap_number; |
621 __ JumpIfNotSmi(value_reg, &heap_number); | 627 __ JumpIfNotSmi(value_reg, &heap_number); |
622 __ SmiUntag(value_reg); | 628 __ SmiUntag(value_reg); |
623 __ Cvtsi2sd(xmm0, value_reg); | 629 __ Cvtsi2sd(xmm0, value_reg); |
624 __ SmiTag(value_reg); | 630 __ SmiTag(value_reg); |
625 __ jmp(&do_store); | 631 __ jmp(&do_store); |
626 __ bind(&heap_number); | 632 __ bind(&heap_number); |
627 __ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(), | 633 __ CheckMap(value_reg, isolate()->factory()->heap_number_map(), miss_label, |
628 miss_label, DONT_DO_SMI_CHECK); | 634 DONT_DO_SMI_CHECK); |
629 __ movsd(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset)); | 635 __ movsd(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset)); |
630 __ bind(&do_store); | 636 __ bind(&do_store); |
631 __ movsd(FieldOperand(scratch1, HeapNumber::kValueOffset), xmm0); | 637 __ movsd(FieldOperand(scratch1, HeapNumber::kValueOffset), xmm0); |
632 // Return the value (register eax). | 638 // Return the value (register eax). |
633 ASSERT(value_reg.is(eax)); | 639 ASSERT(value_reg.is(eax)); |
634 __ ret(0); | 640 __ ret(0); |
635 return; | 641 return; |
636 } | 642 } |
637 | 643 |
638 ASSERT(!representation.IsDouble()); | 644 ASSERT(!representation.IsDouble()); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
674 smi_check); | 680 smi_check); |
675 } | 681 } |
676 } | 682 } |
677 | 683 |
678 // Return the value (register eax). | 684 // Return the value (register eax). |
679 ASSERT(value_reg.is(eax)); | 685 ASSERT(value_reg.is(eax)); |
680 __ ret(0); | 686 __ ret(0); |
681 } | 687 } |
682 | 688 |
683 | 689 |
684 void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm, | |
685 Handle<Code> code) { | |
686 __ jmp(code, RelocInfo::CODE_TARGET); | |
687 } | |
688 | |
689 | |
690 #undef __ | |
691 #define __ ACCESS_MASM(masm()) | |
692 | |
693 | |
694 Register PropertyHandlerCompiler::CheckPrototypes( | 690 Register PropertyHandlerCompiler::CheckPrototypes( |
695 Register object_reg, Register holder_reg, Register scratch1, | 691 Register object_reg, Register holder_reg, Register scratch1, |
696 Register scratch2, Handle<Name> name, Label* miss, | 692 Register scratch2, Handle<Name> name, Label* miss, |
697 PrototypeCheckType check) { | 693 PrototypeCheckType check) { |
698 Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate())); | 694 Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate())); |
699 | 695 |
700 // Make sure there's no overlap between holder and object registers. | 696 // Make sure there's no overlap between holder and object registers. |
701 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); | 697 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); |
702 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg) | 698 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg) |
703 && !scratch2.is(scratch1)); | 699 && !scratch2.is(scratch1)); |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
809 TailCallBuiltin(masm(), MissBuiltin(kind())); | 805 TailCallBuiltin(masm(), MissBuiltin(kind())); |
810 __ bind(&success); | 806 __ bind(&success); |
811 } | 807 } |
812 } | 808 } |
813 | 809 |
814 | 810 |
815 void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { | 811 void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { |
816 if (!miss->is_unused()) { | 812 if (!miss->is_unused()) { |
817 Label success; | 813 Label success; |
818 __ jmp(&success); | 814 __ jmp(&success); |
819 GenerateRestoreName(masm(), miss, name); | 815 GenerateRestoreName(miss, name); |
820 TailCallBuiltin(masm(), MissBuiltin(kind())); | 816 TailCallBuiltin(masm(), MissBuiltin(kind())); |
821 __ bind(&success); | 817 __ bind(&success); |
822 } | 818 } |
823 } | 819 } |
824 | 820 |
825 | 821 |
826 Register NamedLoadHandlerCompiler::CallbackFrontend(Register object_reg, | 822 Register NamedLoadHandlerCompiler::CallbackFrontend(Register object_reg, |
827 Handle<Name> name, | 823 Handle<Name> name, |
828 Handle<Object> callback) { | 824 Handle<Object> callback) { |
829 Label miss; | 825 Label miss; |
(...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1122 // Do tail-call to the runtime system. | 1118 // Do tail-call to the runtime system. |
1123 ExternalReference store_ic_property = ExternalReference( | 1119 ExternalReference store_ic_property = ExternalReference( |
1124 IC_Utility(IC::kStorePropertyWithInterceptor), isolate()); | 1120 IC_Utility(IC::kStorePropertyWithInterceptor), isolate()); |
1125 __ TailCallExternalReference(store_ic_property, 3, 1); | 1121 __ TailCallExternalReference(store_ic_property, 3, 1); |
1126 | 1122 |
1127 // Return the generated code. | 1123 // Return the generated code. |
1128 return GetCode(kind(), Code::FAST, name); | 1124 return GetCode(kind(), Code::FAST, name); |
1129 } | 1125 } |
1130 | 1126 |
1131 | 1127 |
1132 void NamedStoreHandlerCompiler::GenerateStoreArrayLength() { | |
1133 // Prepare tail call to StoreIC_ArrayLength. | |
1134 __ pop(scratch1()); // remove the return address | |
1135 __ push(receiver()); | |
1136 __ push(value()); | |
1137 __ push(scratch1()); // restore return address | |
1138 | |
1139 ExternalReference ref = | |
1140 ExternalReference(IC_Utility(IC::kStoreIC_ArrayLength), | |
1141 masm()->isolate()); | |
1142 __ TailCallExternalReference(ref, 2, 1); | |
1143 } | |
1144 | |
1145 | |
1146 Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic( | 1128 Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic( |
1147 MapHandleList* receiver_maps, CodeHandleList* handler_stubs, | 1129 MapHandleList* receiver_maps, CodeHandleList* handler_stubs, |
1148 MapHandleList* transitioned_maps) { | 1130 MapHandleList* transitioned_maps) { |
1149 Label miss; | 1131 Label miss; |
1150 __ JumpIfSmi(receiver(), &miss, Label::kNear); | 1132 __ JumpIfSmi(receiver(), &miss, Label::kNear); |
1151 __ mov(scratch1(), FieldOperand(receiver(), HeapObject::kMapOffset)); | 1133 __ mov(scratch1(), FieldOperand(receiver(), HeapObject::kMapOffset)); |
1152 for (int i = 0; i < receiver_maps->length(); ++i) { | 1134 for (int i = 0; i < receiver_maps->length(); ++i) { |
1153 __ cmp(scratch1(), receiver_maps->at(i)); | 1135 __ cmp(scratch1(), receiver_maps->at(i)); |
1154 if (transitioned_maps->at(i).is_null()) { | 1136 if (transitioned_maps->at(i).is_null()) { |
1155 __ j(equal, handler_stubs->at(i)); | 1137 __ j(equal, handler_stubs->at(i)); |
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1391 // ----------------------------------- | 1373 // ----------------------------------- |
1392 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); | 1374 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); |
1393 } | 1375 } |
1394 | 1376 |
1395 | 1377 |
1396 #undef __ | 1378 #undef __ |
1397 | 1379 |
1398 } } // namespace v8::internal | 1380 } } // namespace v8::internal |
1399 | 1381 |
1400 #endif // V8_TARGET_ARCH_IA32 | 1382 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |