| 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_X64 | 7 #if V8_TARGET_ARCH_X64 |
| 8 | 8 |
| 9 #include "src/arguments.h" | 9 #include "src/arguments.h" |
| 10 #include "src/codegen.h" | 10 #include "src/codegen.h" |
| (...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 328 Address function_address = v8::ToCData<Address>(api_call_info->callback()); | 328 Address function_address = v8::ToCData<Address>(api_call_info->callback()); |
| 329 __ Move( | 329 __ Move( |
| 330 api_function_address, function_address, RelocInfo::EXTERNAL_REFERENCE); | 330 api_function_address, function_address, RelocInfo::EXTERNAL_REFERENCE); |
| 331 | 331 |
| 332 // Jump to stub. | 332 // Jump to stub. |
| 333 CallApiFunctionStub stub(isolate, is_store, call_data_undefined, argc); | 333 CallApiFunctionStub stub(isolate, is_store, call_data_undefined, argc); |
| 334 __ TailCallStub(&stub); | 334 __ TailCallStub(&stub); |
| 335 } | 335 } |
| 336 | 336 |
| 337 | 337 |
| 338 void NamedStoreHandlerCompiler::GenerateRestoreName(MacroAssembler* masm, | |
| 339 Label* label, | |
| 340 Handle<Name> name) { | |
| 341 if (!label->is_unused()) { | |
| 342 __ bind(label); | |
| 343 __ Move(this->name(), name); | |
| 344 } | |
| 345 } | |
| 346 | |
| 347 | |
| 348 void PropertyHandlerCompiler::GenerateCheckPropertyCell( | 338 void PropertyHandlerCompiler::GenerateCheckPropertyCell( |
| 349 MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name, | 339 MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name, |
| 350 Register scratch, Label* miss) { | 340 Register scratch, Label* miss) { |
| 351 Handle<PropertyCell> cell = | 341 Handle<PropertyCell> cell = |
| 352 JSGlobalObject::EnsurePropertyCell(global, name); | 342 JSGlobalObject::EnsurePropertyCell(global, name); |
| 353 ASSERT(cell->value()->IsTheHole()); | 343 ASSERT(cell->value()->IsTheHole()); |
| 354 __ Move(scratch, cell); | 344 __ Move(scratch, cell); |
| 355 __ Cmp(FieldOperand(scratch, Cell::kValueOffset), | 345 __ Cmp(FieldOperand(scratch, Cell::kValueOffset), |
| 356 masm->isolate()->factory()->the_hole_value()); | 346 masm->isolate()->factory()->the_hole_value()); |
| 357 __ j(not_equal, miss); | 347 __ j(not_equal, miss); |
| 358 } | 348 } |
| 359 | 349 |
| 360 | 350 |
| 351 void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm, |
| 352 Handle<Code> code) { |
| 353 __ jmp(code, RelocInfo::CODE_TARGET); |
| 354 } |
| 355 |
| 356 |
| 357 #undef __ |
| 358 #define __ ACCESS_MASM((masm())) |
| 359 |
| 360 |
| 361 void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label, |
| 362 Handle<Name> name) { |
| 363 if (!label->is_unused()) { |
| 364 __ bind(label); |
| 365 __ Move(this->name(), name); |
| 366 } |
| 367 } |
| 368 |
| 369 |
| 361 void NamedStoreHandlerCompiler::GenerateNegativeHolderLookup( | 370 void NamedStoreHandlerCompiler::GenerateNegativeHolderLookup( |
| 362 MacroAssembler* masm, Handle<JSObject> holder, Register holder_reg, | 371 Register holder_reg, Handle<Name> name, Label* miss) { |
| 363 Handle<Name> name, Label* miss) { | 372 if (holder()->IsJSGlobalObject()) { |
| 364 if (holder->IsJSGlobalObject()) { | 373 GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(holder()), |
| 365 GenerateCheckPropertyCell( | 374 name, scratch1(), miss); |
| 366 masm, Handle<JSGlobalObject>::cast(holder), name, scratch1(), miss); | 375 } else if (!holder()->HasFastProperties()) { |
| 367 } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) { | 376 GenerateDictionaryNegativeLookup(masm(), miss, holder_reg, name, scratch1(), |
| 368 GenerateDictionaryNegativeLookup( | 377 scratch2()); |
| 369 masm, miss, holder_reg, name, scratch1(), scratch2()); | |
| 370 } | 378 } |
| 371 } | 379 } |
| 372 | 380 |
| 373 | 381 |
| 374 // Receiver_reg is preserved on jumps to miss_label, but may be destroyed if | 382 // Receiver_reg is preserved on jumps to miss_label, but may be destroyed if |
| 375 // store is successful. | 383 // store is successful. |
| 376 void NamedStoreHandlerCompiler::GenerateStoreTransition( | 384 void NamedStoreHandlerCompiler::GenerateStoreTransition( |
| 377 MacroAssembler* masm, LookupResult* lookup, Handle<Map> transition, | 385 Handle<Map> transition, Handle<Name> name, Register receiver_reg, |
| 378 Handle<Name> name, Register receiver_reg, Register storage_reg, | 386 Register storage_reg, Register value_reg, Register scratch1, |
| 379 Register value_reg, Register scratch1, Register scratch2, Register unused, | 387 Register scratch2, Register unused, Label* miss_label, Label* slow) { |
| 380 Label* miss_label, Label* slow) { | |
| 381 int descriptor = transition->LastAdded(); | 388 int descriptor = transition->LastAdded(); |
| 382 DescriptorArray* descriptors = transition->instance_descriptors(); | 389 DescriptorArray* descriptors = transition->instance_descriptors(); |
| 383 PropertyDetails details = descriptors->GetDetails(descriptor); | 390 PropertyDetails details = descriptors->GetDetails(descriptor); |
| 384 Representation representation = details.representation(); | 391 Representation representation = details.representation(); |
| 385 ASSERT(!representation.IsNone()); | 392 ASSERT(!representation.IsNone()); |
| 386 | 393 |
| 387 if (details.type() == CONSTANT) { | 394 if (details.type() == CONSTANT) { |
| 388 Handle<Object> constant(descriptors->GetValue(descriptor), masm->isolate()); | 395 Handle<Object> constant(descriptors->GetValue(descriptor), isolate()); |
| 389 __ Cmp(value_reg, constant); | 396 __ Cmp(value_reg, constant); |
| 390 __ j(not_equal, miss_label); | 397 __ j(not_equal, miss_label); |
| 391 } else if (representation.IsSmi()) { | 398 } else if (representation.IsSmi()) { |
| 392 __ JumpIfNotSmi(value_reg, miss_label); | 399 __ JumpIfNotSmi(value_reg, miss_label); |
| 393 } else if (representation.IsHeapObject()) { | 400 } else if (representation.IsHeapObject()) { |
| 394 __ JumpIfSmi(value_reg, miss_label); | 401 __ JumpIfSmi(value_reg, miss_label); |
| 395 HeapType* field_type = descriptors->GetFieldType(descriptor); | 402 HeapType* field_type = descriptors->GetFieldType(descriptor); |
| 396 HeapType::Iterator<Map> it = field_type->Classes(); | 403 HeapType::Iterator<Map> it = field_type->Classes(); |
| 397 if (!it.Done()) { | 404 if (!it.Done()) { |
| 398 Label do_store; | 405 Label do_store; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 410 } else if (representation.IsDouble()) { | 417 } else if (representation.IsDouble()) { |
| 411 Label do_store, heap_number; | 418 Label do_store, heap_number; |
| 412 __ AllocateHeapNumber(storage_reg, scratch1, slow, MUTABLE); | 419 __ AllocateHeapNumber(storage_reg, scratch1, slow, MUTABLE); |
| 413 | 420 |
| 414 __ JumpIfNotSmi(value_reg, &heap_number); | 421 __ JumpIfNotSmi(value_reg, &heap_number); |
| 415 __ SmiToInteger32(scratch1, value_reg); | 422 __ SmiToInteger32(scratch1, value_reg); |
| 416 __ Cvtlsi2sd(xmm0, scratch1); | 423 __ Cvtlsi2sd(xmm0, scratch1); |
| 417 __ jmp(&do_store); | 424 __ jmp(&do_store); |
| 418 | 425 |
| 419 __ bind(&heap_number); | 426 __ bind(&heap_number); |
| 420 __ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(), | 427 __ CheckMap(value_reg, isolate()->factory()->heap_number_map(), miss_label, |
| 421 miss_label, DONT_DO_SMI_CHECK); | 428 DONT_DO_SMI_CHECK); |
| 422 __ movsd(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset)); | 429 __ movsd(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset)); |
| 423 | 430 |
| 424 __ bind(&do_store); | 431 __ bind(&do_store); |
| 425 __ movsd(FieldOperand(storage_reg, HeapNumber::kValueOffset), xmm0); | 432 __ movsd(FieldOperand(storage_reg, HeapNumber::kValueOffset), xmm0); |
| 426 } | 433 } |
| 427 | 434 |
| 428 // Stub never generated for objects that require access checks. | 435 // Stub never generated for objects that require access checks. |
| 429 ASSERT(!transition->is_access_check_needed()); | 436 ASSERT(!transition->is_access_check_needed()); |
| 430 | 437 |
| 431 // Perform map transition for the receiver if necessary. | 438 // Perform map transition for the receiver if necessary. |
| 432 if (details.type() == FIELD && | 439 if (details.type() == FIELD && |
| 433 Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) { | 440 Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) { |
| 434 // The properties must be extended before we can store the value. | 441 // The properties must be extended before we can store the value. |
| 435 // We jump to a runtime call that extends the properties array. | 442 // We jump to a runtime call that extends the properties array. |
| 436 __ PopReturnAddressTo(scratch1); | 443 __ PopReturnAddressTo(scratch1); |
| 437 __ Push(receiver_reg); | 444 __ Push(receiver_reg); |
| 438 __ Push(transition); | 445 __ Push(transition); |
| 439 __ Push(value_reg); | 446 __ Push(value_reg); |
| 440 __ PushReturnAddressFrom(scratch1); | 447 __ PushReturnAddressFrom(scratch1); |
| 441 __ TailCallExternalReference( | 448 __ TailCallExternalReference( |
| 442 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), | 449 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), |
| 443 masm->isolate()), | 450 isolate()), |
| 444 3, | 451 3, 1); |
| 445 1); | |
| 446 return; | 452 return; |
| 447 } | 453 } |
| 448 | 454 |
| 449 // Update the map of the object. | 455 // Update the map of the object. |
| 450 __ Move(scratch1, transition); | 456 __ Move(scratch1, transition); |
| 451 __ movp(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1); | 457 __ movp(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1); |
| 452 | 458 |
| 453 // Update the write barrier for the map field. | 459 // Update the write barrier for the map field. |
| 454 __ RecordWriteField(receiver_reg, | 460 __ RecordWriteField(receiver_reg, |
| 455 HeapObject::kMapOffset, | 461 HeapObject::kMapOffset, |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 518 | 524 |
| 519 // Return the value (register rax). | 525 // Return the value (register rax). |
| 520 ASSERT(value_reg.is(rax)); | 526 ASSERT(value_reg.is(rax)); |
| 521 __ ret(0); | 527 __ ret(0); |
| 522 } | 528 } |
| 523 | 529 |
| 524 | 530 |
| 525 // Both name_reg and receiver_reg are preserved on jumps to miss_label, | 531 // Both name_reg and receiver_reg are preserved on jumps to miss_label, |
| 526 // but may be destroyed if store is successful. | 532 // but may be destroyed if store is successful. |
| 527 void NamedStoreHandlerCompiler::GenerateStoreField( | 533 void NamedStoreHandlerCompiler::GenerateStoreField( |
| 528 MacroAssembler* masm, Handle<JSObject> object, LookupResult* lookup, | 534 Handle<JSObject> object, LookupResult* lookup, Register receiver_reg, |
| 529 Register receiver_reg, Register name_reg, Register value_reg, | 535 Register name_reg, Register value_reg, Register scratch1, Register scratch2, |
| 530 Register scratch1, Register scratch2, Label* miss_label) { | 536 Label* miss_label) { |
| 531 // Stub never generated for non-global objects that require access | 537 // Stub never generated for objects that require access checks. |
| 532 // checks. | 538 ASSERT(!object->IsAccessCheckNeeded()); |
| 533 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); | 539 ASSERT(!object->IsJSGlobalProxy()); |
| 534 | 540 |
| 535 FieldIndex index = lookup->GetFieldIndex(); | 541 FieldIndex index = lookup->GetFieldIndex(); |
| 536 | 542 |
| 537 Representation representation = lookup->representation(); | 543 Representation representation = lookup->representation(); |
| 538 ASSERT(!representation.IsNone()); | 544 ASSERT(!representation.IsNone()); |
| 539 if (representation.IsSmi()) { | 545 if (representation.IsSmi()) { |
| 540 __ JumpIfNotSmi(value_reg, miss_label); | 546 __ JumpIfNotSmi(value_reg, miss_label); |
| 541 } else if (representation.IsHeapObject()) { | 547 } else if (representation.IsHeapObject()) { |
| 542 __ JumpIfSmi(value_reg, miss_label); | 548 __ JumpIfSmi(value_reg, miss_label); |
| 543 HeapType* field_type = lookup->GetFieldType(); | 549 HeapType* field_type = lookup->GetFieldType(); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 566 } | 572 } |
| 567 | 573 |
| 568 // Store the value into the storage. | 574 // Store the value into the storage. |
| 569 Label do_store, heap_number; | 575 Label do_store, heap_number; |
| 570 __ JumpIfNotSmi(value_reg, &heap_number); | 576 __ JumpIfNotSmi(value_reg, &heap_number); |
| 571 __ SmiToInteger32(scratch2, value_reg); | 577 __ SmiToInteger32(scratch2, value_reg); |
| 572 __ Cvtlsi2sd(xmm0, scratch2); | 578 __ Cvtlsi2sd(xmm0, scratch2); |
| 573 __ jmp(&do_store); | 579 __ jmp(&do_store); |
| 574 | 580 |
| 575 __ bind(&heap_number); | 581 __ bind(&heap_number); |
| 576 __ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(), | 582 __ CheckMap(value_reg, isolate()->factory()->heap_number_map(), miss_label, |
| 577 miss_label, DONT_DO_SMI_CHECK); | 583 DONT_DO_SMI_CHECK); |
| 578 __ movsd(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset)); | 584 __ movsd(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset)); |
| 579 __ bind(&do_store); | 585 __ bind(&do_store); |
| 580 __ movsd(FieldOperand(scratch1, HeapNumber::kValueOffset), xmm0); | 586 __ movsd(FieldOperand(scratch1, HeapNumber::kValueOffset), xmm0); |
| 581 // Return the value (register rax). | 587 // Return the value (register rax). |
| 582 ASSERT(value_reg.is(rax)); | 588 ASSERT(value_reg.is(rax)); |
| 583 __ ret(0); | 589 __ ret(0); |
| 584 return; | 590 return; |
| 585 } | 591 } |
| 586 | 592 |
| 587 // TODO(verwaest): Share this code as a code stub. | 593 // TODO(verwaest): Share this code as a code stub. |
| (...skipping 26 matching lines...) Expand all Loading... |
| 614 EMIT_REMEMBERED_SET, smi_check); | 620 EMIT_REMEMBERED_SET, smi_check); |
| 615 } | 621 } |
| 616 } | 622 } |
| 617 | 623 |
| 618 // Return the value (register rax). | 624 // Return the value (register rax). |
| 619 ASSERT(value_reg.is(rax)); | 625 ASSERT(value_reg.is(rax)); |
| 620 __ ret(0); | 626 __ ret(0); |
| 621 } | 627 } |
| 622 | 628 |
| 623 | 629 |
| 624 void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm, | |
| 625 Handle<Code> code) { | |
| 626 __ jmp(code, RelocInfo::CODE_TARGET); | |
| 627 } | |
| 628 | |
| 629 | |
| 630 #undef __ | |
| 631 #define __ ACCESS_MASM((masm())) | |
| 632 | |
| 633 | |
| 634 Register PropertyHandlerCompiler::CheckPrototypes( | 630 Register PropertyHandlerCompiler::CheckPrototypes( |
| 635 Register object_reg, Register holder_reg, Register scratch1, | 631 Register object_reg, Register holder_reg, Register scratch1, |
| 636 Register scratch2, Handle<Name> name, Label* miss, | 632 Register scratch2, Handle<Name> name, Label* miss, |
| 637 PrototypeCheckType check) { | 633 PrototypeCheckType check) { |
| 638 Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate())); | 634 Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate())); |
| 639 | 635 |
| 640 // Make sure there's no overlap between holder and object registers. | 636 // Make sure there's no overlap between holder and object registers. |
| 641 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); | 637 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); |
| 642 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg) | 638 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg) |
| 643 && !scratch2.is(scratch1)); | 639 && !scratch2.is(scratch1)); |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 750 TailCallBuiltin(masm(), MissBuiltin(kind())); | 746 TailCallBuiltin(masm(), MissBuiltin(kind())); |
| 751 __ bind(&success); | 747 __ bind(&success); |
| 752 } | 748 } |
| 753 } | 749 } |
| 754 | 750 |
| 755 | 751 |
| 756 void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { | 752 void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { |
| 757 if (!miss->is_unused()) { | 753 if (!miss->is_unused()) { |
| 758 Label success; | 754 Label success; |
| 759 __ jmp(&success); | 755 __ jmp(&success); |
| 760 GenerateRestoreName(masm(), miss, name); | 756 GenerateRestoreName(miss, name); |
| 761 TailCallBuiltin(masm(), MissBuiltin(kind())); | 757 TailCallBuiltin(masm(), MissBuiltin(kind())); |
| 762 __ bind(&success); | 758 __ bind(&success); |
| 763 } | 759 } |
| 764 } | 760 } |
| 765 | 761 |
| 766 | 762 |
| 767 Register NamedLoadHandlerCompiler::CallbackFrontend(Register object_reg, | 763 Register NamedLoadHandlerCompiler::CallbackFrontend(Register object_reg, |
| 768 Handle<Name> name, | 764 Handle<Name> name, |
| 769 Handle<Object> callback) { | 765 Handle<Object> callback) { |
| 770 Label miss; | 766 Label miss; |
| (...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1045 // Do tail-call to the runtime system. | 1041 // Do tail-call to the runtime system. |
| 1046 ExternalReference store_ic_property = ExternalReference( | 1042 ExternalReference store_ic_property = ExternalReference( |
| 1047 IC_Utility(IC::kStorePropertyWithInterceptor), isolate()); | 1043 IC_Utility(IC::kStorePropertyWithInterceptor), isolate()); |
| 1048 __ TailCallExternalReference(store_ic_property, 3, 1); | 1044 __ TailCallExternalReference(store_ic_property, 3, 1); |
| 1049 | 1045 |
| 1050 // Return the generated code. | 1046 // Return the generated code. |
| 1051 return GetCode(kind(), Code::FAST, name); | 1047 return GetCode(kind(), Code::FAST, name); |
| 1052 } | 1048 } |
| 1053 | 1049 |
| 1054 | 1050 |
| 1055 void NamedStoreHandlerCompiler::GenerateStoreArrayLength() { | |
| 1056 // Prepare tail call to StoreIC_ArrayLength. | |
| 1057 __ PopReturnAddressTo(scratch1()); | |
| 1058 __ Push(receiver()); | |
| 1059 __ Push(value()); | |
| 1060 __ PushReturnAddressFrom(scratch1()); | |
| 1061 | |
| 1062 ExternalReference ref = | |
| 1063 ExternalReference(IC_Utility(IC::kStoreIC_ArrayLength), | |
| 1064 masm()->isolate()); | |
| 1065 __ TailCallExternalReference(ref, 2, 1); | |
| 1066 } | |
| 1067 | |
| 1068 | |
| 1069 Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic( | 1051 Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic( |
| 1070 MapHandleList* receiver_maps, CodeHandleList* handler_stubs, | 1052 MapHandleList* receiver_maps, CodeHandleList* handler_stubs, |
| 1071 MapHandleList* transitioned_maps) { | 1053 MapHandleList* transitioned_maps) { |
| 1072 Label miss; | 1054 Label miss; |
| 1073 __ JumpIfSmi(receiver(), &miss, Label::kNear); | 1055 __ JumpIfSmi(receiver(), &miss, Label::kNear); |
| 1074 | 1056 |
| 1075 __ movp(scratch1(), FieldOperand(receiver(), HeapObject::kMapOffset)); | 1057 __ movp(scratch1(), FieldOperand(receiver(), HeapObject::kMapOffset)); |
| 1076 int receiver_count = receiver_maps->length(); | 1058 int receiver_count = receiver_maps->length(); |
| 1077 for (int i = 0; i < receiver_count; ++i) { | 1059 for (int i = 0; i < receiver_count; ++i) { |
| 1078 // Check map and tail call if there's a match | 1060 // Check map and tail call if there's a match |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1320 // ----------------------------------- | 1302 // ----------------------------------- |
| 1321 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); | 1303 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); |
| 1322 } | 1304 } |
| 1323 | 1305 |
| 1324 | 1306 |
| 1325 #undef __ | 1307 #undef __ |
| 1326 | 1308 |
| 1327 } } // namespace v8::internal | 1309 } } // namespace v8::internal |
| 1328 | 1310 |
| 1329 #endif // V8_TARGET_ARCH_X64 | 1311 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |