| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 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_ARM64 | 7 #if V8_TARGET_ARCH_ARM64 |
| 8 | 8 |
| 9 #include "src/ic/call-optimization.h" | 9 #include "src/ic/call-optimization.h" |
| 10 #include "src/ic/handler-compiler.h" | 10 #include "src/ic/handler-compiler.h" |
| (...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 363 | 363 |
| 364 void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label, | 364 void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label, |
| 365 Handle<Name> name) { | 365 Handle<Name> name) { |
| 366 if (!label->is_unused()) { | 366 if (!label->is_unused()) { |
| 367 __ Bind(label); | 367 __ Bind(label); |
| 368 __ Mov(this->name(), Operand(name)); | 368 __ Mov(this->name(), Operand(name)); |
| 369 } | 369 } |
| 370 } | 370 } |
| 371 | 371 |
| 372 | 372 |
| 373 // Generate StoreTransition code, value is passed in x0 register. | 373 void NamedStoreHandlerCompiler::GenerateRestoreNameAndMap( |
| 374 // When leaving generated code after success, the receiver_reg and storage_reg | 374 Handle<Name> name, Handle<Map> transition) { |
| 375 // may be clobbered. Upon branch to miss_label, the receiver and name registers | 375 __ Mov(this->name(), Operand(name)); |
| 376 // have their original values. | 376 __ Mov(StoreTransitionDescriptor::MapRegister(), Operand(transition)); |
| 377 void NamedStoreHandlerCompiler::GenerateStoreTransition( | |
| 378 Handle<Map> transition, Handle<Name> name, Register receiver_reg, | |
| 379 Register storage_reg, Register value_reg, Register scratch1, | |
| 380 Register scratch2, Register scratch3, Label* miss_label, Label* slow) { | |
| 381 Label exit; | |
| 382 | |
| 383 DCHECK(!AreAliased(receiver_reg, storage_reg, value_reg, scratch1, scratch2, | |
| 384 scratch3)); | |
| 385 | |
| 386 // We don't need scratch3. | |
| 387 scratch3 = NoReg; | |
| 388 | |
| 389 int descriptor = transition->LastAdded(); | |
| 390 DescriptorArray* descriptors = transition->instance_descriptors(); | |
| 391 PropertyDetails details = descriptors->GetDetails(descriptor); | |
| 392 Representation representation = details.representation(); | |
| 393 DCHECK(!representation.IsNone()); | |
| 394 | |
| 395 if (details.type() == CONSTANT) { | |
| 396 Handle<Object> constant(descriptors->GetValue(descriptor), isolate()); | |
| 397 __ LoadObject(scratch1, constant); | |
| 398 __ Cmp(value_reg, scratch1); | |
| 399 __ B(ne, miss_label); | |
| 400 } else if (representation.IsSmi()) { | |
| 401 __ JumpIfNotSmi(value_reg, miss_label); | |
| 402 } else if (representation.IsHeapObject()) { | |
| 403 __ JumpIfSmi(value_reg, miss_label); | |
| 404 HeapType* field_type = descriptors->GetFieldType(descriptor); | |
| 405 HeapType::Iterator<Map> it = field_type->Classes(); | |
| 406 if (!it.Done()) { | |
| 407 __ Ldr(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset)); | |
| 408 Label do_store; | |
| 409 while (true) { | |
| 410 __ CompareMap(scratch1, it.Current()); | |
| 411 it.Advance(); | |
| 412 if (it.Done()) { | |
| 413 __ B(ne, miss_label); | |
| 414 break; | |
| 415 } | |
| 416 __ B(eq, &do_store); | |
| 417 } | |
| 418 __ Bind(&do_store); | |
| 419 } | |
| 420 } else if (representation.IsDouble()) { | |
| 421 UseScratchRegisterScope temps(masm()); | |
| 422 DoubleRegister temp_double = temps.AcquireD(); | |
| 423 __ SmiUntagToDouble(temp_double, value_reg, kSpeculativeUntag); | |
| 424 | |
| 425 Label do_store; | |
| 426 __ JumpIfSmi(value_reg, &do_store); | |
| 427 | |
| 428 __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex, miss_label, | |
| 429 DONT_DO_SMI_CHECK); | |
| 430 __ Ldr(temp_double, FieldMemOperand(value_reg, HeapNumber::kValueOffset)); | |
| 431 | |
| 432 __ Bind(&do_store); | |
| 433 __ AllocateHeapNumber(storage_reg, slow, scratch1, scratch2, temp_double, | |
| 434 NoReg, MUTABLE); | |
| 435 } | |
| 436 | |
| 437 // Stub never generated for objects that require access checks. | |
| 438 DCHECK(!transition->is_access_check_needed()); | |
| 439 | |
| 440 // Perform map transition for the receiver if necessary. | |
| 441 if (details.type() == FIELD && | |
| 442 Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) { | |
| 443 // The properties must be extended before we can store the value. | |
| 444 __ Mov(ExtendStorageDescriptor::NameRegister(), Operand(name)); | |
| 445 __ Mov(ExtendStorageDescriptor::MapRegister(), Operand(transition)); | |
| 446 | |
| 447 ExtendStorageStub stub(isolate(), | |
| 448 FieldIndex::ForDescriptor(*transition, descriptor), | |
| 449 representation); | |
| 450 GenerateTailCall(masm(), stub.GetCode()); | |
| 451 return; | |
| 452 } | |
| 453 | |
| 454 // Update the map of the object. | |
| 455 __ Mov(scratch1, Operand(transition)); | |
| 456 __ Str(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); | |
| 457 | |
| 458 // Update the write barrier for the map field. | |
| 459 __ RecordWriteField(receiver_reg, HeapObject::kMapOffset, scratch1, scratch2, | |
| 460 kLRHasNotBeenSaved, kDontSaveFPRegs, OMIT_REMEMBERED_SET, | |
| 461 OMIT_SMI_CHECK); | |
| 462 | |
| 463 if (details.type() == CONSTANT) { | |
| 464 DCHECK(value_reg.is(x0)); | |
| 465 __ Ret(); | |
| 466 return; | |
| 467 } | |
| 468 | |
| 469 int index = transition->instance_descriptors()->GetFieldIndex( | |
| 470 transition->LastAdded()); | |
| 471 | |
| 472 // Adjust for the number of properties stored in the object. Even in the | |
| 473 // face of a transition we can use the old map here because the size of the | |
| 474 // object and the number of in-object properties is not going to change. | |
| 475 index -= transition->inobject_properties(); | |
| 476 | |
| 477 // TODO(verwaest): Share this code as a code stub. | |
| 478 SmiCheck smi_check = | |
| 479 representation.IsTagged() ? INLINE_SMI_CHECK : OMIT_SMI_CHECK; | |
| 480 Register prop_reg = representation.IsDouble() ? storage_reg : value_reg; | |
| 481 if (index < 0) { | |
| 482 // Set the property straight into the object. | |
| 483 int offset = transition->instance_size() + (index * kPointerSize); | |
| 484 __ Str(prop_reg, FieldMemOperand(receiver_reg, offset)); | |
| 485 | |
| 486 if (!representation.IsSmi()) { | |
| 487 // Update the write barrier for the array address. | |
| 488 if (!representation.IsDouble()) { | |
| 489 __ Mov(storage_reg, value_reg); | |
| 490 } | |
| 491 __ RecordWriteField(receiver_reg, offset, storage_reg, scratch1, | |
| 492 kLRHasNotBeenSaved, kDontSaveFPRegs, | |
| 493 EMIT_REMEMBERED_SET, smi_check); | |
| 494 } | |
| 495 } else { | |
| 496 // Write to the properties array. | |
| 497 int offset = index * kPointerSize + FixedArray::kHeaderSize; | |
| 498 // Get the properties array | |
| 499 __ Ldr(scratch1, | |
| 500 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset)); | |
| 501 __ Str(prop_reg, FieldMemOperand(scratch1, offset)); | |
| 502 | |
| 503 if (!representation.IsSmi()) { | |
| 504 // Update the write barrier for the array address. | |
| 505 if (!representation.IsDouble()) { | |
| 506 __ Mov(storage_reg, value_reg); | |
| 507 } | |
| 508 __ RecordWriteField(scratch1, offset, storage_reg, receiver_reg, | |
| 509 kLRHasNotBeenSaved, kDontSaveFPRegs, | |
| 510 EMIT_REMEMBERED_SET, smi_check); | |
| 511 } | |
| 512 } | |
| 513 | |
| 514 __ Bind(&exit); | |
| 515 // Return the value (register x0). | |
| 516 DCHECK(value_reg.is(x0)); | |
| 517 __ Ret(); | |
| 518 } | 377 } |
| 519 | 378 |
| 520 | 379 |
| 521 void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup, | 380 void NamedStoreHandlerCompiler::GenerateConstantCheck(Object* constant, |
| 522 Register value_reg, | 381 Register value_reg, |
| 523 Label* miss_label) { | 382 Label* miss_label) { |
| 524 DCHECK(lookup->representation().IsHeapObject()); | 383 __ LoadObject(scratch1(), handle(constant, isolate())); |
| 525 __ JumpIfSmi(value_reg, miss_label); | 384 __ Cmp(value_reg, scratch1()); |
| 526 HeapType::Iterator<Map> it = lookup->GetFieldType()->Classes(); | 385 __ B(ne, miss_label); |
| 527 __ Ldr(scratch1(), FieldMemOperand(value_reg, HeapObject::kMapOffset)); | |
| 528 Label do_store; | |
| 529 while (true) { | |
| 530 __ CompareMap(scratch1(), it.Current()); | |
| 531 it.Advance(); | |
| 532 if (it.Done()) { | |
| 533 __ B(ne, miss_label); | |
| 534 break; | |
| 535 } | |
| 536 __ B(eq, &do_store); | |
| 537 } | |
| 538 __ Bind(&do_store); | |
| 539 | |
| 540 StoreFieldStub stub(isolate(), lookup->GetFieldIndex(), | |
| 541 lookup->representation()); | |
| 542 GenerateTailCall(masm(), stub.GetCode()); | |
| 543 } | 386 } |
| 544 | 387 |
| 545 | 388 |
| 389 void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(HeapType* field_type, |
| 390 Register value_reg, |
| 391 Label* miss_label) { |
| 392 __ JumpIfSmi(value_reg, miss_label); |
| 393 HeapType::Iterator<Map> it = field_type->Classes(); |
| 394 if (!it.Done()) { |
| 395 __ Ldr(scratch1(), FieldMemOperand(value_reg, HeapObject::kMapOffset)); |
| 396 Label do_store; |
| 397 while (true) { |
| 398 __ CompareMap(scratch1(), it.Current()); |
| 399 it.Advance(); |
| 400 if (it.Done()) { |
| 401 __ B(ne, miss_label); |
| 402 break; |
| 403 } |
| 404 __ B(eq, &do_store); |
| 405 } |
| 406 __ Bind(&do_store); |
| 407 } |
| 408 } |
| 409 |
| 410 |
| 546 Register PropertyHandlerCompiler::CheckPrototypes( | 411 Register PropertyHandlerCompiler::CheckPrototypes( |
| 547 Register object_reg, Register holder_reg, Register scratch1, | 412 Register object_reg, Register holder_reg, Register scratch1, |
| 548 Register scratch2, Handle<Name> name, Label* miss, | 413 Register scratch2, Handle<Name> name, Label* miss, |
| 549 PrototypeCheckType check) { | 414 PrototypeCheckType check) { |
| 550 Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate())); | 415 Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate())); |
| 551 | 416 |
| 552 // object_reg and holder_reg registers can alias. | 417 // object_reg and holder_reg registers can alias. |
| 553 DCHECK(!AreAliased(object_reg, scratch1, scratch2)); | 418 DCHECK(!AreAliased(object_reg, scratch1, scratch2)); |
| 554 DCHECK(!AreAliased(holder_reg, scratch1, scratch2)); | 419 DCHECK(!AreAliased(holder_reg, scratch1, scratch2)); |
| 555 | 420 |
| (...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 838 // Return the generated code. | 703 // Return the generated code. |
| 839 return GetCode(kind(), Code::FAST, name); | 704 return GetCode(kind(), Code::FAST, name); |
| 840 } | 705 } |
| 841 | 706 |
| 842 | 707 |
| 843 #undef __ | 708 #undef __ |
| 844 } | 709 } |
| 845 } // namespace v8::internal | 710 } // namespace v8::internal |
| 846 | 711 |
| 847 #endif // V8_TARGET_ARCH_IA32 | 712 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |