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/ic/handler-compiler.h" | 5 #include "src/ic/handler-compiler.h" |
6 | 6 |
7 #include "src/field-type.h" | 7 #include "src/field-type.h" |
8 #include "src/ic/call-optimization.h" | 8 #include "src/ic/call-optimization.h" |
9 #include "src/ic/handler-configuration-inl.h" | 9 #include "src/ic/handler-configuration-inl.h" |
10 #include "src/ic/ic-inl.h" | 10 #include "src/ic/ic-inl.h" |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
186 } | 186 } |
187 DCHECK(holder().is_null() || | 187 DCHECK(holder().is_null() || |
188 holder()->property_dictionary()->FindEntry(name) == | 188 holder()->property_dictionary()->FindEntry(name) == |
189 NameDictionary::kNotFound); | 189 NameDictionary::kNotFound); |
190 GenerateDictionaryNegativeLookup(masm(), miss, holder_reg, name, scratch1, | 190 GenerateDictionaryNegativeLookup(masm(), miss, holder_reg, name, scratch1, |
191 scratch2); | 191 scratch2); |
192 } | 192 } |
193 } | 193 } |
194 } | 194 } |
195 | 195 |
196 | |
197 Handle<Code> NamedLoadHandlerCompiler::CompileLoadField(Handle<Name> name, | |
198 FieldIndex field) { | |
199 Register reg = Frontend(name); | |
200 __ Move(receiver(), reg); | |
201 LoadFieldStub stub(isolate(), field); | |
202 GenerateTailCall(masm(), stub.GetCode()); | |
203 return GetCode(kind(), name); | |
204 } | |
205 | |
206 | |
207 Handle<Code> NamedLoadHandlerCompiler::CompileLoadConstant(Handle<Name> name, | |
208 int constant_index) { | |
209 Register reg = Frontend(name); | |
210 __ Move(receiver(), reg); | |
211 LoadConstantStub stub(isolate(), constant_index); | |
212 GenerateTailCall(masm(), stub.GetCode()); | |
213 return GetCode(kind(), name); | |
214 } | |
215 | |
216 | |
217 Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent( | 196 Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent( |
218 Handle<Name> name) { | 197 Handle<Name> name) { |
219 Label miss; | 198 Label miss; |
220 if (IC::ShouldPushPopSlotAndVector(kind())) { | 199 if (IC::ShouldPushPopSlotAndVector(kind())) { |
221 DCHECK(kind() == Code::LOAD_IC); | 200 DCHECK(kind() == Code::LOAD_IC); |
222 PushVectorAndSlot(); | 201 PushVectorAndSlot(); |
223 } | 202 } |
224 NonexistentFrontendHeader(name, &miss, scratch2(), scratch3()); | 203 NonexistentFrontendHeader(name, &miss, scratch2(), scratch3()); |
225 if (IC::ShouldPushPopSlotAndVector(kind())) { | 204 if (IC::ShouldPushPopSlotAndVector(kind())) { |
226 DiscardVectorAndSlot(); | 205 DiscardVectorAndSlot(); |
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
433 } | 412 } |
434 | 413 |
435 Handle<Code> NamedLoadHandlerCompiler::CompileLoadViaGetter( | 414 Handle<Code> NamedLoadHandlerCompiler::CompileLoadViaGetter( |
436 Handle<Name> name, int accessor_index, int expected_arguments) { | 415 Handle<Name> name, int accessor_index, int expected_arguments) { |
437 Register holder = Frontend(name); | 416 Register holder = Frontend(name); |
438 GenerateLoadViaGetter(masm(), map(), receiver(), holder, accessor_index, | 417 GenerateLoadViaGetter(masm(), map(), receiver(), holder, accessor_index, |
439 expected_arguments, scratch2()); | 418 expected_arguments, scratch2()); |
440 return GetCode(kind(), name); | 419 return GetCode(kind(), name); |
441 } | 420 } |
442 | 421 |
443 | |
444 // TODO(verwaest): Cleanup. holder() is actually the receiver. | |
445 Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition( | |
446 Handle<Map> transition, Handle<Name> name) { | |
447 Label miss; | |
448 | |
449 // Ensure that the StoreTransitionStub we are going to call has the same | |
450 // number of stack arguments. This means that we don't have to adapt them | |
451 // if we decide to call the transition or miss stub. | |
452 STATIC_ASSERT(Descriptor::kStackArgumentsCount == | |
453 StoreTransitionDescriptor::kStackArgumentsCount); | |
454 STATIC_ASSERT(Descriptor::kStackArgumentsCount == 0 || | |
455 Descriptor::kStackArgumentsCount == 3); | |
456 STATIC_ASSERT(Descriptor::kParameterCount - Descriptor::kValue == | |
457 StoreTransitionDescriptor::kParameterCount - | |
458 StoreTransitionDescriptor::kValue); | |
459 STATIC_ASSERT(Descriptor::kParameterCount - Descriptor::kSlot == | |
460 StoreTransitionDescriptor::kParameterCount - | |
461 StoreTransitionDescriptor::kSlot); | |
462 STATIC_ASSERT(Descriptor::kParameterCount - Descriptor::kVector == | |
463 StoreTransitionDescriptor::kParameterCount - | |
464 StoreTransitionDescriptor::kVector); | |
465 | |
466 if (Descriptor::kPassLastArgsOnStack) { | |
467 __ LoadParameterFromStack<Descriptor>(value(), Descriptor::kValue); | |
468 } | |
469 | |
470 bool need_save_restore = IC::ShouldPushPopSlotAndVector(kind()); | |
471 if (need_save_restore) { | |
472 PushVectorAndSlot(); | |
473 } | |
474 | |
475 // Check that we are allowed to write this. | |
476 bool is_nonexistent = holder()->map() == transition->GetBackPointer(); | |
477 if (is_nonexistent) { | |
478 // Find the top object. | |
479 Handle<JSObject> last; | |
480 PrototypeIterator::WhereToEnd end = | |
481 name->IsPrivate() ? PrototypeIterator::END_AT_NON_HIDDEN | |
482 : PrototypeIterator::END_AT_NULL; | |
483 PrototypeIterator iter(isolate(), holder(), kStartAtPrototype, end); | |
484 while (!iter.IsAtEnd()) { | |
485 last = PrototypeIterator::GetCurrent<JSObject>(iter); | |
486 iter.Advance(); | |
487 } | |
488 if (!last.is_null()) set_holder(last); | |
489 NonexistentFrontendHeader(name, &miss, scratch1(), scratch2()); | |
490 } else { | |
491 FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING); | |
492 DCHECK(holder()->HasFastProperties()); | |
493 } | |
494 | |
495 int descriptor = transition->LastAdded(); | |
496 Handle<DescriptorArray> descriptors(transition->instance_descriptors()); | |
497 PropertyDetails details = descriptors->GetDetails(descriptor); | |
498 Representation representation = details.representation(); | |
499 DCHECK(!representation.IsNone()); | |
500 | |
501 // Stub is never generated for objects that require access checks. | |
502 DCHECK(!transition->is_access_check_needed()); | |
503 | |
504 // Call to respective StoreTransitionStub. | |
505 Register map_reg = StoreTransitionDescriptor::MapRegister(); | |
506 | |
507 if (details.type() == DATA_CONSTANT) { | |
508 DCHECK(descriptors->GetValue(descriptor)->IsJSFunction()); | |
509 GenerateRestoreMap(transition, map_reg, scratch1(), &miss); | |
510 GenerateConstantCheck(map_reg, descriptor, value(), scratch1(), &miss); | |
511 if (need_save_restore) { | |
512 PopVectorAndSlot(); | |
513 } | |
514 GenerateRestoreName(name); | |
515 StoreMapStub stub(isolate()); | |
516 GenerateTailCall(masm(), stub.GetCode()); | |
517 | |
518 } else { | |
519 if (representation.IsHeapObject()) { | |
520 GenerateFieldTypeChecks(descriptors->GetFieldType(descriptor), value(), | |
521 &miss); | |
522 } | |
523 StoreTransitionStub::StoreMode store_mode = | |
524 Map::cast(transition->GetBackPointer())->unused_property_fields() == 0 | |
525 ? StoreTransitionStub::ExtendStorageAndStoreMapAndValue | |
526 : StoreTransitionStub::StoreMapAndValue; | |
527 GenerateRestoreMap(transition, map_reg, scratch1(), &miss); | |
528 if (need_save_restore) { | |
529 PopVectorAndSlot(); | |
530 } | |
531 // We need to pass name on the stack. | |
532 PopReturnAddress(this->name()); | |
533 __ Push(name); | |
534 PushReturnAddress(this->name()); | |
535 | |
536 FieldIndex index = FieldIndex::ForDescriptor(*transition, descriptor); | |
537 __ Move(StoreNamedTransitionDescriptor::FieldOffsetRegister(), | |
538 Smi::FromInt(index.index() << kPointerSizeLog2)); | |
539 | |
540 StoreTransitionStub stub(isolate(), index.is_inobject(), representation, | |
541 store_mode); | |
542 GenerateTailCall(masm(), stub.GetCode()); | |
543 } | |
544 | |
545 __ bind(&miss); | |
546 if (need_save_restore) { | |
547 PopVectorAndSlot(); | |
548 } | |
549 GenerateRestoreName(name); | |
550 TailCallBuiltin(masm(), MissBuiltin(kind())); | |
551 | |
552 return GetCode(kind(), name); | |
553 } | |
554 | |
555 bool NamedStoreHandlerCompiler::RequiresFieldTypeChecks( | 422 bool NamedStoreHandlerCompiler::RequiresFieldTypeChecks( |
556 FieldType* field_type) const { | 423 FieldType* field_type) const { |
557 return field_type->IsClass(); | 424 return field_type->IsClass(); |
558 } | 425 } |
559 | 426 |
560 | |
561 Handle<Code> NamedStoreHandlerCompiler::CompileStoreField(LookupIterator* it) { | |
562 Label miss; | |
563 DCHECK(it->representation().IsHeapObject()); | |
564 | |
565 FieldType* field_type = *it->GetFieldType(); | |
566 bool need_save_restore = false; | |
567 if (RequiresFieldTypeChecks(field_type)) { | |
568 need_save_restore = IC::ShouldPushPopSlotAndVector(kind()); | |
569 if (Descriptor::kPassLastArgsOnStack) { | |
570 __ LoadParameterFromStack<Descriptor>(value(), Descriptor::kValue); | |
571 } | |
572 if (need_save_restore) PushVectorAndSlot(); | |
573 GenerateFieldTypeChecks(field_type, value(), &miss); | |
574 if (need_save_restore) PopVectorAndSlot(); | |
575 } | |
576 | |
577 StoreFieldStub stub(isolate(), it->GetFieldIndex(), it->representation()); | |
578 GenerateTailCall(masm(), stub.GetCode()); | |
579 | |
580 __ bind(&miss); | |
581 if (need_save_restore) PopVectorAndSlot(); | |
582 TailCallBuiltin(masm(), MissBuiltin(kind())); | |
583 return GetCode(kind(), it->name()); | |
584 } | |
585 | |
586 | |
587 Handle<Code> NamedStoreHandlerCompiler::CompileStoreViaSetter( | 427 Handle<Code> NamedStoreHandlerCompiler::CompileStoreViaSetter( |
588 Handle<JSObject> object, Handle<Name> name, int accessor_index, | 428 Handle<JSObject> object, Handle<Name> name, int accessor_index, |
589 int expected_arguments) { | 429 int expected_arguments) { |
590 Register holder = Frontend(name); | 430 Register holder = Frontend(name); |
591 GenerateStoreViaSetter(masm(), map(), receiver(), holder, accessor_index, | 431 GenerateStoreViaSetter(masm(), map(), receiver(), holder, accessor_index, |
592 expected_arguments, scratch2()); | 432 expected_arguments, scratch2()); |
593 | 433 |
594 return GetCode(kind(), name); | 434 return GetCode(kind(), name); |
595 } | 435 } |
596 | 436 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
655 } | 495 } |
656 | 496 |
657 void ElementHandlerCompiler::CompileElementHandlers( | 497 void ElementHandlerCompiler::CompileElementHandlers( |
658 MapHandleList* receiver_maps, List<Handle<Object>>* handlers) { | 498 MapHandleList* receiver_maps, List<Handle<Object>>* handlers) { |
659 for (int i = 0; i < receiver_maps->length(); ++i) { | 499 for (int i = 0; i < receiver_maps->length(); ++i) { |
660 handlers->Add(GetKeyedLoadHandler(receiver_maps->at(i), isolate())); | 500 handlers->Add(GetKeyedLoadHandler(receiver_maps->at(i), isolate())); |
661 } | 501 } |
662 } | 502 } |
663 } // namespace internal | 503 } // namespace internal |
664 } // namespace v8 | 504 } // namespace v8 |
OLD | NEW |