| 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_ARM | 7 #if V8_TARGET_ARCH_ARM |
| 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 308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 319 | 319 |
| 320 void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label, | 320 void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label, |
| 321 Handle<Name> name) { | 321 Handle<Name> name) { |
| 322 if (!label->is_unused()) { | 322 if (!label->is_unused()) { |
| 323 __ bind(label); | 323 __ bind(label); |
| 324 __ mov(this->name(), Operand(name)); | 324 __ mov(this->name(), Operand(name)); |
| 325 } | 325 } |
| 326 } | 326 } |
| 327 | 327 |
| 328 | 328 |
| 329 // Generate StoreTransition code, value is passed in r0 register. | 329 void NamedStoreHandlerCompiler::GenerateRestoreNameAndMap( |
| 330 // When leaving generated code after success, the receiver_reg and name_reg | 330 Handle<Name> name, Handle<Map> transition) { |
| 331 // may be clobbered. Upon branch to miss_label, the receiver and name | 331 __ mov(this->name(), Operand(name)); |
| 332 // registers have their original values. | 332 __ mov(StoreTransitionDescriptor::MapRegister(), Operand(transition)); |
| 333 void NamedStoreHandlerCompiler::GenerateStoreTransition( | |
| 334 Handle<Map> transition, Handle<Name> name, Register receiver_reg, | |
| 335 Register storage_reg, Register value_reg, Register scratch1, | |
| 336 Register scratch2, Register scratch3, Label* miss_label, Label* slow) { | |
| 337 // r0 : value | |
| 338 Label exit; | |
| 339 | |
| 340 int descriptor = transition->LastAdded(); | |
| 341 DescriptorArray* descriptors = transition->instance_descriptors(); | |
| 342 PropertyDetails details = descriptors->GetDetails(descriptor); | |
| 343 Representation representation = details.representation(); | |
| 344 DCHECK(!representation.IsNone()); | |
| 345 | |
| 346 if (details.type() == CONSTANT) { | |
| 347 Handle<Object> constant(descriptors->GetValue(descriptor), isolate()); | |
| 348 __ Move(scratch1, constant); | |
| 349 __ cmp(value_reg, scratch1); | |
| 350 __ b(ne, miss_label); | |
| 351 } else if (representation.IsSmi()) { | |
| 352 __ JumpIfNotSmi(value_reg, miss_label); | |
| 353 } else if (representation.IsHeapObject()) { | |
| 354 __ JumpIfSmi(value_reg, miss_label); | |
| 355 HeapType* field_type = descriptors->GetFieldType(descriptor); | |
| 356 HeapType::Iterator<Map> it = field_type->Classes(); | |
| 357 if (!it.Done()) { | |
| 358 __ ldr(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset)); | |
| 359 Label do_store; | |
| 360 while (true) { | |
| 361 __ CompareMap(scratch1, it.Current(), &do_store); | |
| 362 it.Advance(); | |
| 363 if (it.Done()) { | |
| 364 __ b(ne, miss_label); | |
| 365 break; | |
| 366 } | |
| 367 __ b(eq, &do_store); | |
| 368 } | |
| 369 __ bind(&do_store); | |
| 370 } | |
| 371 } else if (representation.IsDouble()) { | |
| 372 Label do_store, heap_number; | |
| 373 __ LoadRoot(scratch3, Heap::kMutableHeapNumberMapRootIndex); | |
| 374 __ AllocateHeapNumber(storage_reg, scratch1, scratch2, scratch3, slow, | |
| 375 TAG_RESULT, MUTABLE); | |
| 376 | |
| 377 __ JumpIfNotSmi(value_reg, &heap_number); | |
| 378 __ SmiUntag(scratch1, value_reg); | |
| 379 __ vmov(s0, scratch1); | |
| 380 __ vcvt_f64_s32(d0, s0); | |
| 381 __ jmp(&do_store); | |
| 382 | |
| 383 __ bind(&heap_number); | |
| 384 __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex, miss_label, | |
| 385 DONT_DO_SMI_CHECK); | |
| 386 __ vldr(d0, FieldMemOperand(value_reg, HeapNumber::kValueOffset)); | |
| 387 | |
| 388 __ bind(&do_store); | |
| 389 __ vstr(d0, FieldMemOperand(storage_reg, HeapNumber::kValueOffset)); | |
| 390 } | |
| 391 | |
| 392 // Stub never generated for objects that require access checks. | |
| 393 DCHECK(!transition->is_access_check_needed()); | |
| 394 | |
| 395 // Perform map transition for the receiver if necessary. | |
| 396 if (details.type() == FIELD && | |
| 397 Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) { | |
| 398 // The properties must be extended before we can store the value. | |
| 399 __ mov(ExtendStorageDescriptor::NameRegister(), Operand(name)); | |
| 400 __ mov(ExtendStorageDescriptor::MapRegister(), Operand(transition)); | |
| 401 | |
| 402 ExtendStorageStub stub(isolate(), | |
| 403 FieldIndex::ForDescriptor(*transition, descriptor), | |
| 404 representation); | |
| 405 GenerateTailCall(masm(), stub.GetCode()); | |
| 406 return; | |
| 407 } | |
| 408 | |
| 409 // Update the map of the object. | |
| 410 __ mov(scratch1, Operand(transition)); | |
| 411 __ str(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); | |
| 412 | |
| 413 // Update the write barrier for the map field. | |
| 414 __ RecordWriteField(receiver_reg, HeapObject::kMapOffset, scratch1, scratch2, | |
| 415 kLRHasNotBeenSaved, kDontSaveFPRegs, OMIT_REMEMBERED_SET, | |
| 416 OMIT_SMI_CHECK); | |
| 417 | |
| 418 if (details.type() == CONSTANT) { | |
| 419 DCHECK(value_reg.is(r0)); | |
| 420 __ Ret(); | |
| 421 return; | |
| 422 } | |
| 423 | |
| 424 int index = transition->instance_descriptors()->GetFieldIndex( | |
| 425 transition->LastAdded()); | |
| 426 | |
| 427 // Adjust for the number of properties stored in the object. Even in the | |
| 428 // face of a transition we can use the old map here because the size of the | |
| 429 // object and the number of in-object properties is not going to change. | |
| 430 index -= transition->inobject_properties(); | |
| 431 | |
| 432 // TODO(verwaest): Share this code as a code stub. | |
| 433 SmiCheck smi_check = | |
| 434 representation.IsTagged() ? INLINE_SMI_CHECK : OMIT_SMI_CHECK; | |
| 435 if (index < 0) { | |
| 436 // Set the property straight into the object. | |
| 437 int offset = transition->instance_size() + (index * kPointerSize); | |
| 438 if (representation.IsDouble()) { | |
| 439 __ str(storage_reg, FieldMemOperand(receiver_reg, offset)); | |
| 440 } else { | |
| 441 __ str(value_reg, FieldMemOperand(receiver_reg, offset)); | |
| 442 } | |
| 443 | |
| 444 if (!representation.IsSmi()) { | |
| 445 // Update the write barrier for the array address. | |
| 446 if (!representation.IsDouble()) { | |
| 447 __ mov(storage_reg, value_reg); | |
| 448 } | |
| 449 __ RecordWriteField(receiver_reg, offset, storage_reg, scratch1, | |
| 450 kLRHasNotBeenSaved, kDontSaveFPRegs, | |
| 451 EMIT_REMEMBERED_SET, smi_check); | |
| 452 } | |
| 453 } else { | |
| 454 // Write to the properties array. | |
| 455 int offset = index * kPointerSize + FixedArray::kHeaderSize; | |
| 456 // Get the properties array | |
| 457 __ ldr(scratch1, | |
| 458 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset)); | |
| 459 if (representation.IsDouble()) { | |
| 460 __ str(storage_reg, FieldMemOperand(scratch1, offset)); | |
| 461 } else { | |
| 462 __ str(value_reg, FieldMemOperand(scratch1, offset)); | |
| 463 } | |
| 464 | |
| 465 if (!representation.IsSmi()) { | |
| 466 // Update the write barrier for the array address. | |
| 467 if (!representation.IsDouble()) { | |
| 468 __ mov(storage_reg, value_reg); | |
| 469 } | |
| 470 __ RecordWriteField(scratch1, offset, storage_reg, receiver_reg, | |
| 471 kLRHasNotBeenSaved, kDontSaveFPRegs, | |
| 472 EMIT_REMEMBERED_SET, smi_check); | |
| 473 } | |
| 474 } | |
| 475 | |
| 476 // Return the value (register r0). | |
| 477 DCHECK(value_reg.is(r0)); | |
| 478 __ bind(&exit); | |
| 479 __ Ret(); | |
| 480 } | 333 } |
| 481 | 334 |
| 482 | 335 |
| 483 void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup, | 336 void NamedStoreHandlerCompiler::GenerateConstantCheck(Object* constant, |
| 484 Register value_reg, | 337 Register value_reg, |
| 485 Label* miss_label) { | 338 Label* miss_label) { |
| 486 DCHECK(lookup->representation().IsHeapObject()); | 339 __ Move(scratch1(), handle(constant, isolate())); |
| 487 __ JumpIfSmi(value_reg, miss_label); | 340 __ cmp(value_reg, scratch1()); |
| 488 HeapType::Iterator<Map> it = lookup->GetFieldType()->Classes(); | 341 __ b(ne, miss_label); |
| 489 __ ldr(scratch1(), FieldMemOperand(value_reg, HeapObject::kMapOffset)); | |
| 490 Label do_store; | |
| 491 while (true) { | |
| 492 __ CompareMap(scratch1(), it.Current(), &do_store); | |
| 493 it.Advance(); | |
| 494 if (it.Done()) { | |
| 495 __ b(ne, miss_label); | |
| 496 break; | |
| 497 } | |
| 498 __ b(eq, &do_store); | |
| 499 } | |
| 500 __ bind(&do_store); | |
| 501 | |
| 502 StoreFieldStub stub(isolate(), lookup->GetFieldIndex(), | |
| 503 lookup->representation()); | |
| 504 GenerateTailCall(masm(), stub.GetCode()); | |
| 505 } | 342 } |
| 506 | 343 |
| 507 | 344 |
| 345 void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(HeapType* field_type, |
| 346 Register value_reg, |
| 347 Label* miss_label) { |
| 348 __ JumpIfSmi(value_reg, miss_label); |
| 349 HeapType::Iterator<Map> it = field_type->Classes(); |
| 350 if (!it.Done()) { |
| 351 __ ldr(scratch1(), FieldMemOperand(value_reg, HeapObject::kMapOffset)); |
| 352 Label do_store; |
| 353 while (true) { |
| 354 __ CompareMap(scratch1(), it.Current(), &do_store); |
| 355 it.Advance(); |
| 356 if (it.Done()) { |
| 357 __ b(ne, miss_label); |
| 358 break; |
| 359 } |
| 360 __ b(eq, &do_store); |
| 361 } |
| 362 __ bind(&do_store); |
| 363 } |
| 364 } |
| 365 |
| 366 |
| 508 Register PropertyHandlerCompiler::CheckPrototypes( | 367 Register PropertyHandlerCompiler::CheckPrototypes( |
| 509 Register object_reg, Register holder_reg, Register scratch1, | 368 Register object_reg, Register holder_reg, Register scratch1, |
| 510 Register scratch2, Handle<Name> name, Label* miss, | 369 Register scratch2, Handle<Name> name, Label* miss, |
| 511 PrototypeCheckType check) { | 370 PrototypeCheckType check) { |
| 512 Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate())); | 371 Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate())); |
| 513 | 372 |
| 514 // Make sure there's no overlap between holder and object registers. | 373 // Make sure there's no overlap between holder and object registers. |
| 515 DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); | 374 DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); |
| 516 DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) && | 375 DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) && |
| 517 !scratch2.is(scratch1)); | 376 !scratch2.is(scratch1)); |
| (...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 830 // Return the generated code. | 689 // Return the generated code. |
| 831 return GetCode(kind(), Code::NORMAL, name); | 690 return GetCode(kind(), Code::NORMAL, name); |
| 832 } | 691 } |
| 833 | 692 |
| 834 | 693 |
| 835 #undef __ | 694 #undef __ |
| 836 } | 695 } |
| 837 } // namespace v8::internal | 696 } // namespace v8::internal |
| 838 | 697 |
| 839 #endif // V8_TARGET_ARCH_ARM | 698 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |