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 #include "src/ic/call-optimization.h" | 7 #include "src/ic/handler-compiler.h" |
8 #include "src/ic/ic-inl.h" | 8 #include "src/ic/ic-inl.h" |
9 #include "src/ic/ic-compiler.h" | 9 #include "src/ic/ic-compiler.h" |
10 | 10 |
11 | 11 |
12 namespace v8 { | 12 namespace v8 { |
13 namespace internal { | 13 namespace internal { |
14 | 14 |
15 | 15 |
16 Handle<Code> PropertyICCompiler::Find(Handle<Name> name, | 16 Handle<Code> PropertyICCompiler::Find(Handle<Name> name, |
17 Handle<Map> stub_holder, Code::Kind kind, | 17 Handle<Map> stub_holder, Code::Kind kind, |
18 ExtraICState extra_state, | 18 ExtraICState extra_state, |
19 CacheHolderFlag cache_holder) { | 19 CacheHolderFlag cache_holder) { |
20 Code::Flags flags = | 20 Code::Flags flags = |
21 Code::ComputeMonomorphicFlags(kind, extra_state, cache_holder); | 21 Code::ComputeMonomorphicFlags(kind, extra_state, cache_holder); |
22 Object* probe = stub_holder->FindInCodeCache(*name, flags); | 22 Object* probe = stub_holder->FindInCodeCache(*name, flags); |
23 if (probe->IsCode()) return handle(Code::cast(probe)); | 23 if (probe->IsCode()) return handle(Code::cast(probe)); |
24 return Handle<Code>::null(); | 24 return Handle<Code>::null(); |
25 } | 25 } |
26 | 26 |
27 | 27 |
28 Handle<Code> PropertyHandlerCompiler::Find(Handle<Name> name, | 28 bool PropertyICCompiler::IncludesNumberType(TypeHandleList* types) { |
29 Handle<Map> stub_holder, | 29 for (int i = 0; i < types->length(); ++i) { |
30 Code::Kind kind, | 30 if (types->at(i)->Is(HeapType::Number())) return true; |
31 CacheHolderFlag cache_holder, | 31 } |
32 Code::StubType type) { | 32 return false; |
33 Code::Flags flags = Code::ComputeHandlerFlags(kind, type, cache_holder); | |
34 Object* probe = stub_holder->FindInCodeCache(*name, flags); | |
35 if (probe->IsCode()) return handle(Code::cast(probe)); | |
36 return Handle<Code>::null(); | |
37 } | 33 } |
38 | 34 |
39 | 35 |
| 36 Handle<Code> PropertyICCompiler::CompileMonomorphic(Handle<HeapType> type, |
| 37 Handle<Code> handler, |
| 38 Handle<Name> name, |
| 39 IcCheckType check) { |
| 40 TypeHandleList types(1); |
| 41 CodeHandleList handlers(1); |
| 42 types.Add(type); |
| 43 handlers.Add(handler); |
| 44 Code::StubType stub_type = handler->type(); |
| 45 return CompilePolymorphic(&types, &handlers, name, stub_type, check); |
| 46 } |
| 47 |
| 48 |
40 Handle<Code> PropertyICCompiler::ComputeMonomorphic( | 49 Handle<Code> PropertyICCompiler::ComputeMonomorphic( |
41 Code::Kind kind, Handle<Name> name, Handle<HeapType> type, | 50 Code::Kind kind, Handle<Name> name, Handle<HeapType> type, |
42 Handle<Code> handler, ExtraICState extra_ic_state) { | 51 Handle<Code> handler, ExtraICState extra_ic_state) { |
43 Isolate* isolate = name->GetIsolate(); | 52 Isolate* isolate = name->GetIsolate(); |
44 if (handler.is_identical_to(isolate->builtins()->LoadIC_Normal()) || | 53 if (handler.is_identical_to(isolate->builtins()->LoadIC_Normal()) || |
45 handler.is_identical_to(isolate->builtins()->StoreIC_Normal())) { | 54 handler.is_identical_to(isolate->builtins()->StoreIC_Normal())) { |
46 name = isolate->factory()->normal_ic_symbol(); | 55 name = isolate->factory()->normal_ic_symbol(); |
47 } | 56 } |
48 | 57 |
49 CacheHolderFlag flag; | 58 CacheHolderFlag flag; |
(...skipping 17 matching lines...) Expand all Loading... |
67 #endif | 76 #endif |
68 | 77 |
69 PropertyICCompiler ic_compiler(isolate, kind, extra_ic_state, flag); | 78 PropertyICCompiler ic_compiler(isolate, kind, extra_ic_state, flag); |
70 ic = ic_compiler.CompileMonomorphic(type, handler, name, PROPERTY); | 79 ic = ic_compiler.CompileMonomorphic(type, handler, name, PROPERTY); |
71 | 80 |
72 if (can_be_cached) Map::UpdateCodeCache(stub_holder, name, ic); | 81 if (can_be_cached) Map::UpdateCodeCache(stub_holder, name, ic); |
73 return ic; | 82 return ic; |
74 } | 83 } |
75 | 84 |
76 | 85 |
77 Handle<Code> NamedLoadHandlerCompiler::ComputeLoadNonexistent( | |
78 Handle<Name> name, Handle<HeapType> type) { | |
79 Isolate* isolate = name->GetIsolate(); | |
80 Handle<Map> receiver_map = IC::TypeToMap(*type, isolate); | |
81 if (receiver_map->prototype()->IsNull()) { | |
82 // TODO(jkummerow/verwaest): If there is no prototype and the property | |
83 // is nonexistent, introduce a builtin to handle this (fast properties | |
84 // -> return undefined, dictionary properties -> do negative lookup). | |
85 return Handle<Code>(); | |
86 } | |
87 CacheHolderFlag flag; | |
88 Handle<Map> stub_holder_map = | |
89 IC::GetHandlerCacheHolder(*type, false, isolate, &flag); | |
90 | |
91 // If no dictionary mode objects are present in the prototype chain, the load | |
92 // nonexistent IC stub can be shared for all names for a given map and we use | |
93 // the empty string for the map cache in that case. If there are dictionary | |
94 // mode objects involved, we need to do negative lookups in the stub and | |
95 // therefore the stub will be specific to the name. | |
96 Handle<Name> cache_name = | |
97 receiver_map->is_dictionary_map() | |
98 ? name | |
99 : Handle<Name>::cast(isolate->factory()->nonexistent_symbol()); | |
100 Handle<Map> current_map = stub_holder_map; | |
101 Handle<JSObject> last(JSObject::cast(receiver_map->prototype())); | |
102 while (true) { | |
103 if (current_map->is_dictionary_map()) cache_name = name; | |
104 if (current_map->prototype()->IsNull()) break; | |
105 last = handle(JSObject::cast(current_map->prototype())); | |
106 current_map = handle(last->map()); | |
107 } | |
108 // Compile the stub that is either shared for all names or | |
109 // name specific if there are global objects involved. | |
110 Handle<Code> handler = PropertyHandlerCompiler::Find( | |
111 cache_name, stub_holder_map, Code::LOAD_IC, flag, Code::FAST); | |
112 if (!handler.is_null()) return handler; | |
113 | |
114 NamedLoadHandlerCompiler compiler(isolate, type, last, flag); | |
115 handler = compiler.CompileLoadNonexistent(cache_name); | |
116 Map::UpdateCodeCache(stub_holder_map, cache_name, handler); | |
117 return handler; | |
118 } | |
119 | |
120 | |
121 Handle<Code> PropertyICCompiler::ComputeKeyedLoadMonomorphic( | 86 Handle<Code> PropertyICCompiler::ComputeKeyedLoadMonomorphic( |
122 Handle<Map> receiver_map) { | 87 Handle<Map> receiver_map) { |
123 Isolate* isolate = receiver_map->GetIsolate(); | 88 Isolate* isolate = receiver_map->GetIsolate(); |
124 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC); | 89 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC); |
125 Handle<Name> name = isolate->factory()->KeyedLoadMonomorphic_string(); | 90 Handle<Name> name = isolate->factory()->KeyedLoadMonomorphic_string(); |
126 | 91 |
127 Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate); | 92 Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate); |
128 if (probe->IsCode()) return Handle<Code>::cast(probe); | 93 if (probe->IsCode()) return Handle<Code>::cast(probe); |
129 | 94 |
130 ElementsKind elements_kind = receiver_map->elements_kind(); | 95 ElementsKind elements_kind = receiver_map->elements_kind(); |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
393 | 358 |
394 | 359 |
395 Handle<Code> PropertyICCompiler::CompileStoreMegamorphic(Code::Flags flags) { | 360 Handle<Code> PropertyICCompiler::CompileStoreMegamorphic(Code::Flags flags) { |
396 StoreIC::GenerateMegamorphic(masm()); | 361 StoreIC::GenerateMegamorphic(masm()); |
397 Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreMegamorphic"); | 362 Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreMegamorphic"); |
398 PROFILE(isolate(), CodeCreateEvent(Logger::STORE_MEGAMORPHIC_TAG, *code, 0)); | 363 PROFILE(isolate(), CodeCreateEvent(Logger::STORE_MEGAMORPHIC_TAG, *code, 0)); |
399 return code; | 364 return code; |
400 } | 365 } |
401 | 366 |
402 | 367 |
403 #define __ ACCESS_MASM(masm()) | |
404 | |
405 | |
406 Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg, | |
407 Handle<Name> name, | |
408 Label* miss) { | |
409 PrototypeCheckType check_type = CHECK_ALL_MAPS; | |
410 int function_index = -1; | |
411 if (type()->Is(HeapType::String())) { | |
412 function_index = Context::STRING_FUNCTION_INDEX; | |
413 } else if (type()->Is(HeapType::Symbol())) { | |
414 function_index = Context::SYMBOL_FUNCTION_INDEX; | |
415 } else if (type()->Is(HeapType::Number())) { | |
416 function_index = Context::NUMBER_FUNCTION_INDEX; | |
417 } else if (type()->Is(HeapType::Boolean())) { | |
418 function_index = Context::BOOLEAN_FUNCTION_INDEX; | |
419 } else { | |
420 check_type = SKIP_RECEIVER; | |
421 } | |
422 | |
423 if (check_type == CHECK_ALL_MAPS) { | |
424 GenerateDirectLoadGlobalFunctionPrototype(masm(), function_index, | |
425 scratch1(), miss); | |
426 Object* function = isolate()->native_context()->get(function_index); | |
427 Object* prototype = JSFunction::cast(function)->instance_prototype(); | |
428 set_type_for_object(handle(prototype, isolate())); | |
429 object_reg = scratch1(); | |
430 } | |
431 | |
432 // Check that the maps starting from the prototype haven't changed. | |
433 return CheckPrototypes(object_reg, scratch1(), scratch2(), scratch3(), name, | |
434 miss, check_type); | |
435 } | |
436 | |
437 | |
438 // Frontend for store uses the name register. It has to be restored before a | |
439 // miss. | |
440 Register NamedStoreHandlerCompiler::FrontendHeader(Register object_reg, | |
441 Handle<Name> name, | |
442 Label* miss) { | |
443 return CheckPrototypes(object_reg, this->name(), scratch1(), scratch2(), name, | |
444 miss, SKIP_RECEIVER); | |
445 } | |
446 | |
447 | |
448 bool PropertyICCompiler::IncludesNumberType(TypeHandleList* types) { | |
449 for (int i = 0; i < types->length(); ++i) { | |
450 if (types->at(i)->Is(HeapType::Number())) return true; | |
451 } | |
452 return false; | |
453 } | |
454 | |
455 | |
456 Register PropertyHandlerCompiler::Frontend(Register object_reg, | |
457 Handle<Name> name) { | |
458 Label miss; | |
459 Register reg = FrontendHeader(object_reg, name, &miss); | |
460 FrontendFooter(name, &miss); | |
461 return reg; | |
462 } | |
463 | |
464 | |
465 void PropertyHandlerCompiler::NonexistentFrontendHeader(Handle<Name> name, | |
466 Label* miss, | |
467 Register scratch1, | |
468 Register scratch2) { | |
469 Register holder_reg; | |
470 Handle<Map> last_map; | |
471 if (holder().is_null()) { | |
472 holder_reg = receiver(); | |
473 last_map = IC::TypeToMap(*type(), isolate()); | |
474 // If |type| has null as its prototype, |holder()| is | |
475 // Handle<JSObject>::null(). | |
476 DCHECK(last_map->prototype() == isolate()->heap()->null_value()); | |
477 } else { | |
478 holder_reg = FrontendHeader(receiver(), name, miss); | |
479 last_map = handle(holder()->map()); | |
480 } | |
481 | |
482 if (last_map->is_dictionary_map()) { | |
483 if (last_map->IsJSGlobalObjectMap()) { | |
484 Handle<JSGlobalObject> global = | |
485 holder().is_null() | |
486 ? Handle<JSGlobalObject>::cast(type()->AsConstant()->Value()) | |
487 : Handle<JSGlobalObject>::cast(holder()); | |
488 GenerateCheckPropertyCell(masm(), global, name, scratch1, miss); | |
489 } else { | |
490 if (!name->IsUniqueName()) { | |
491 DCHECK(name->IsString()); | |
492 name = factory()->InternalizeString(Handle<String>::cast(name)); | |
493 } | |
494 DCHECK(holder().is_null() || | |
495 holder()->property_dictionary()->FindEntry(name) == | |
496 NameDictionary::kNotFound); | |
497 GenerateDictionaryNegativeLookup(masm(), miss, holder_reg, name, scratch1, | |
498 scratch2); | |
499 } | |
500 } | |
501 } | |
502 | |
503 | |
504 Handle<Code> NamedLoadHandlerCompiler::CompileLoadField(Handle<Name> name, | |
505 FieldIndex field) { | |
506 Register reg = Frontend(receiver(), name); | |
507 __ Move(receiver(), reg); | |
508 LoadFieldStub stub(isolate(), field); | |
509 GenerateTailCall(masm(), stub.GetCode()); | |
510 return GetCode(kind(), Code::FAST, name); | |
511 } | |
512 | |
513 | |
514 Handle<Code> NamedLoadHandlerCompiler::CompileLoadConstant(Handle<Name> name, | |
515 int constant_index) { | |
516 Register reg = Frontend(receiver(), name); | |
517 __ Move(receiver(), reg); | |
518 LoadConstantStub stub(isolate(), constant_index); | |
519 GenerateTailCall(masm(), stub.GetCode()); | |
520 return GetCode(kind(), Code::FAST, name); | |
521 } | |
522 | |
523 | |
524 Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent( | |
525 Handle<Name> name) { | |
526 Label miss; | |
527 NonexistentFrontendHeader(name, &miss, scratch2(), scratch3()); | |
528 GenerateLoadConstant(isolate()->factory()->undefined_value()); | |
529 FrontendFooter(name, &miss); | |
530 return GetCode(kind(), Code::FAST, name); | |
531 } | |
532 | |
533 | |
534 Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback( | |
535 Handle<Name> name, Handle<ExecutableAccessorInfo> callback) { | |
536 Register reg = Frontend(receiver(), name); | |
537 GenerateLoadCallback(reg, callback); | |
538 return GetCode(kind(), Code::FAST, name); | |
539 } | |
540 | |
541 | |
542 Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback( | |
543 Handle<Name> name, const CallOptimization& call_optimization) { | |
544 DCHECK(call_optimization.is_simple_api_call()); | |
545 Frontend(receiver(), name); | |
546 Handle<Map> receiver_map = IC::TypeToMap(*type(), isolate()); | |
547 GenerateFastApiCall(masm(), call_optimization, receiver_map, receiver(), | |
548 scratch1(), false, 0, NULL); | |
549 return GetCode(kind(), Code::FAST, name); | |
550 } | |
551 | |
552 | |
553 Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor( | |
554 LookupIterator* it) { | |
555 // So far the most popular follow ups for interceptor loads are FIELD and | |
556 // ExecutableAccessorInfo, so inline only them. Other cases may be added | |
557 // later. | |
558 bool inline_followup = it->state() == LookupIterator::PROPERTY; | |
559 if (inline_followup) { | |
560 switch (it->property_kind()) { | |
561 case LookupIterator::DATA: | |
562 inline_followup = it->property_details().type() == FIELD; | |
563 break; | |
564 case LookupIterator::ACCESSOR: { | |
565 Handle<Object> accessors = it->GetAccessors(); | |
566 inline_followup = accessors->IsExecutableAccessorInfo(); | |
567 if (!inline_followup) break; | |
568 Handle<ExecutableAccessorInfo> info = | |
569 Handle<ExecutableAccessorInfo>::cast(accessors); | |
570 inline_followup = info->getter() != NULL && | |
571 ExecutableAccessorInfo::IsCompatibleReceiverType( | |
572 isolate(), info, type()); | |
573 } | |
574 } | |
575 } | |
576 | |
577 Register reg = Frontend(receiver(), it->name()); | |
578 if (inline_followup) { | |
579 // TODO(368): Compile in the whole chain: all the interceptors in | |
580 // prototypes and ultimate answer. | |
581 GenerateLoadInterceptorWithFollowup(it, reg); | |
582 } else { | |
583 GenerateLoadInterceptor(reg); | |
584 } | |
585 return GetCode(kind(), Code::FAST, it->name()); | |
586 } | |
587 | |
588 | |
589 void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor( | |
590 LookupIterator* it, Register interceptor_reg) { | |
591 Handle<JSObject> real_named_property_holder(it->GetHolder<JSObject>()); | |
592 | |
593 set_type_for_object(holder()); | |
594 set_holder(real_named_property_holder); | |
595 Register reg = Frontend(interceptor_reg, it->name()); | |
596 | |
597 switch (it->property_kind()) { | |
598 case LookupIterator::DATA: { | |
599 DCHECK_EQ(FIELD, it->property_details().type()); | |
600 __ Move(receiver(), reg); | |
601 LoadFieldStub stub(isolate(), it->GetFieldIndex()); | |
602 GenerateTailCall(masm(), stub.GetCode()); | |
603 break; | |
604 } | |
605 case LookupIterator::ACCESSOR: | |
606 Handle<ExecutableAccessorInfo> info = | |
607 Handle<ExecutableAccessorInfo>::cast(it->GetAccessors()); | |
608 DCHECK_NE(NULL, info->getter()); | |
609 GenerateLoadCallback(reg, info); | |
610 } | |
611 } | |
612 | |
613 | |
614 Handle<Code> PropertyICCompiler::CompileMonomorphic(Handle<HeapType> type, | |
615 Handle<Code> handler, | |
616 Handle<Name> name, | |
617 IcCheckType check) { | |
618 TypeHandleList types(1); | |
619 CodeHandleList handlers(1); | |
620 types.Add(type); | |
621 handlers.Add(handler); | |
622 Code::StubType stub_type = handler->type(); | |
623 return CompilePolymorphic(&types, &handlers, name, stub_type, check); | |
624 } | |
625 | |
626 | |
627 Handle<Code> NamedLoadHandlerCompiler::CompileLoadViaGetter( | |
628 Handle<Name> name, Handle<JSFunction> getter) { | |
629 Frontend(receiver(), name); | |
630 GenerateLoadViaGetter(masm(), type(), receiver(), getter); | |
631 return GetCode(kind(), Code::FAST, name); | |
632 } | |
633 | |
634 | |
635 // TODO(verwaest): Cleanup. holder() is actually the receiver. | |
636 Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition( | |
637 Handle<Map> transition, Handle<Name> name) { | |
638 Label miss, slow; | |
639 | |
640 // Ensure no transitions to deprecated maps are followed. | |
641 __ CheckMapDeprecated(transition, scratch1(), &miss); | |
642 | |
643 // Check that we are allowed to write this. | |
644 bool is_nonexistent = holder()->map() == transition->GetBackPointer(); | |
645 if (is_nonexistent) { | |
646 // Find the top object. | |
647 Handle<JSObject> last; | |
648 PrototypeIterator iter(isolate(), holder()); | |
649 while (!iter.IsAtEnd()) { | |
650 last = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); | |
651 iter.Advance(); | |
652 } | |
653 if (!last.is_null()) set_holder(last); | |
654 NonexistentFrontendHeader(name, &miss, scratch1(), scratch2()); | |
655 } else { | |
656 FrontendHeader(receiver(), name, &miss); | |
657 DCHECK(holder()->HasFastProperties()); | |
658 } | |
659 | |
660 GenerateStoreTransition(transition, name, receiver(), this->name(), value(), | |
661 scratch1(), scratch2(), scratch3(), &miss, &slow); | |
662 | |
663 GenerateRestoreName(&miss, name); | |
664 TailCallBuiltin(masm(), MissBuiltin(kind())); | |
665 | |
666 GenerateRestoreName(&slow, name); | |
667 TailCallBuiltin(masm(), SlowBuiltin(kind())); | |
668 return GetCode(kind(), Code::FAST, name); | |
669 } | |
670 | |
671 | |
672 Handle<Code> NamedStoreHandlerCompiler::CompileStoreField(LookupIterator* it) { | |
673 Label miss; | |
674 GenerateStoreField(it, value(), &miss); | |
675 __ bind(&miss); | |
676 TailCallBuiltin(masm(), MissBuiltin(kind())); | |
677 return GetCode(kind(), Code::FAST, it->name()); | |
678 } | |
679 | |
680 | |
681 Handle<Code> NamedStoreHandlerCompiler::CompileStoreViaSetter( | |
682 Handle<JSObject> object, Handle<Name> name, Handle<JSFunction> setter) { | |
683 Frontend(receiver(), name); | |
684 GenerateStoreViaSetter(masm(), type(), receiver(), setter); | |
685 | |
686 return GetCode(kind(), Code::FAST, name); | |
687 } | |
688 | |
689 | |
690 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback( | |
691 Handle<JSObject> object, Handle<Name> name, | |
692 const CallOptimization& call_optimization) { | |
693 Frontend(receiver(), name); | |
694 Register values[] = {value()}; | |
695 GenerateFastApiCall(masm(), call_optimization, handle(object->map()), | |
696 receiver(), scratch1(), true, 1, values); | |
697 return GetCode(kind(), Code::FAST, name); | |
698 } | |
699 | |
700 | |
701 Handle<Code> PropertyICCompiler::CompileKeyedStoreMonomorphic( | |
702 Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) { | |
703 ElementsKind elements_kind = receiver_map->elements_kind(); | |
704 bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE; | |
705 Handle<Code> stub; | |
706 if (receiver_map->has_fast_elements() || | |
707 receiver_map->has_external_array_elements() || | |
708 receiver_map->has_fixed_typed_array_elements()) { | |
709 stub = StoreFastElementStub(isolate(), is_jsarray, elements_kind, | |
710 store_mode).GetCode(); | |
711 } else { | |
712 stub = StoreElementStub(isolate(), is_jsarray, elements_kind, store_mode) | |
713 .GetCode(); | |
714 } | |
715 | |
716 __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK); | |
717 | |
718 TailCallBuiltin(masm(), Builtins::kKeyedStoreIC_Miss); | |
719 | |
720 return GetCode(kind(), Code::NORMAL, factory()->empty_string()); | |
721 } | |
722 | |
723 | |
724 #undef __ | |
725 | |
726 | |
727 Handle<Code> PropertyICCompiler::GetCode(Code::Kind kind, Code::StubType type, | 368 Handle<Code> PropertyICCompiler::GetCode(Code::Kind kind, Code::StubType type, |
728 Handle<Name> name, | 369 Handle<Name> name, |
729 InlineCacheState state) { | 370 InlineCacheState state) { |
730 Code::Flags flags = | 371 Code::Flags flags = |
731 Code::ComputeFlags(kind, state, extra_ic_state_, type, cache_holder()); | 372 Code::ComputeFlags(kind, state, extra_ic_state_, type, cache_holder()); |
732 Handle<Code> code = GetCodeWithFlags(flags, name); | 373 Handle<Code> code = GetCodeWithFlags(flags, name); |
733 IC::RegisterWeakMapDependency(code); | 374 IC::RegisterWeakMapDependency(code); |
734 PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name)); | 375 PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name)); |
735 return code; | 376 return code; |
736 } | 377 } |
737 | 378 |
738 | 379 |
739 Handle<Code> PropertyHandlerCompiler::GetCode(Code::Kind kind, | |
740 Code::StubType type, | |
741 Handle<Name> name) { | |
742 Code::Flags flags = Code::ComputeHandlerFlags(kind, type, cache_holder()); | |
743 Handle<Code> code = GetCodeWithFlags(flags, name); | |
744 PROFILE(isolate(), CodeCreateEvent(Logger::STUB_TAG, *code, *name)); | |
745 return code; | |
746 } | |
747 | |
748 | |
749 void ElementHandlerCompiler::CompileElementHandlers( | |
750 MapHandleList* receiver_maps, CodeHandleList* handlers) { | |
751 for (int i = 0; i < receiver_maps->length(); ++i) { | |
752 Handle<Map> receiver_map = receiver_maps->at(i); | |
753 Handle<Code> cached_stub; | |
754 | |
755 if ((receiver_map->instance_type() & kNotStringTag) == 0) { | |
756 cached_stub = isolate()->builtins()->KeyedLoadIC_String(); | |
757 } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) { | |
758 cached_stub = isolate()->builtins()->KeyedLoadIC_Slow(); | |
759 } else { | |
760 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; | |
761 ElementsKind elements_kind = receiver_map->elements_kind(); | |
762 | |
763 if (IsFastElementsKind(elements_kind) || | |
764 IsExternalArrayElementsKind(elements_kind) || | |
765 IsFixedTypedArrayElementsKind(elements_kind)) { | |
766 cached_stub = LoadFastElementStub(isolate(), is_js_array, elements_kind) | |
767 .GetCode(); | |
768 } else if (elements_kind == SLOPPY_ARGUMENTS_ELEMENTS) { | |
769 cached_stub = isolate()->builtins()->KeyedLoadIC_SloppyArguments(); | |
770 } else { | |
771 DCHECK(elements_kind == DICTIONARY_ELEMENTS); | |
772 cached_stub = LoadDictionaryElementStub(isolate()).GetCode(); | |
773 } | |
774 } | |
775 | |
776 handlers->Add(cached_stub); | |
777 } | |
778 } | |
779 | |
780 | |
781 Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic( | 380 Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic( |
782 MapHandleList* receiver_maps, KeyedAccessStoreMode store_mode) { | 381 MapHandleList* receiver_maps, KeyedAccessStoreMode store_mode) { |
783 // Collect MONOMORPHIC stubs for all |receiver_maps|. | 382 // Collect MONOMORPHIC stubs for all |receiver_maps|. |
784 CodeHandleList handlers(receiver_maps->length()); | 383 CodeHandleList handlers(receiver_maps->length()); |
785 MapHandleList transitioned_maps(receiver_maps->length()); | 384 MapHandleList transitioned_maps(receiver_maps->length()); |
786 for (int i = 0; i < receiver_maps->length(); ++i) { | 385 for (int i = 0; i < receiver_maps->length(); ++i) { |
787 Handle<Map> receiver_map(receiver_maps->at(i)); | 386 Handle<Map> receiver_map(receiver_maps->at(i)); |
788 Handle<Code> cached_stub; | 387 Handle<Code> cached_stub; |
789 Handle<Map> transitioned_map = | 388 Handle<Map> transitioned_map = |
790 receiver_map->FindTransitionedMap(receiver_maps); | 389 receiver_map->FindTransitionedMap(receiver_maps); |
(...skipping 29 matching lines...) Expand all Loading... |
820 } | 419 } |
821 | 420 |
822 Handle<Code> code = CompileKeyedStorePolymorphic(receiver_maps, &handlers, | 421 Handle<Code> code = CompileKeyedStorePolymorphic(receiver_maps, &handlers, |
823 &transitioned_maps); | 422 &transitioned_maps); |
824 isolate()->counters()->keyed_store_polymorphic_stubs()->Increment(); | 423 isolate()->counters()->keyed_store_polymorphic_stubs()->Increment(); |
825 PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, 0)); | 424 PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, 0)); |
826 return code; | 425 return code; |
827 } | 426 } |
828 | 427 |
829 | 428 |
830 void ElementHandlerCompiler::GenerateStoreDictionaryElement( | 429 #define __ ACCESS_MASM(masm()) |
831 MacroAssembler* masm) { | 430 |
832 KeyedStoreIC::GenerateSlow(masm); | 431 |
| 432 Handle<Code> PropertyICCompiler::CompileKeyedStoreMonomorphic( |
| 433 Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) { |
| 434 ElementsKind elements_kind = receiver_map->elements_kind(); |
| 435 bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE; |
| 436 Handle<Code> stub; |
| 437 if (receiver_map->has_fast_elements() || |
| 438 receiver_map->has_external_array_elements() || |
| 439 receiver_map->has_fixed_typed_array_elements()) { |
| 440 stub = StoreFastElementStub(isolate(), is_jsarray, elements_kind, |
| 441 store_mode).GetCode(); |
| 442 } else { |
| 443 stub = StoreElementStub(isolate(), is_jsarray, elements_kind, store_mode) |
| 444 .GetCode(); |
| 445 } |
| 446 |
| 447 __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK); |
| 448 |
| 449 TailCallBuiltin(masm(), Builtins::kKeyedStoreIC_Miss); |
| 450 |
| 451 return GetCode(kind(), Code::NORMAL, factory()->empty_string()); |
833 } | 452 } |
834 | 453 |
835 | 454 |
| 455 #undef __ |
836 } | 456 } |
837 } // namespace v8::internal | 457 } // namespace v8::internal |
OLD | NEW |