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 |