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 |