• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #include "src/ic/handler-compiler.h"
6 
7 #include "src/field-type.h"
8 #include "src/ic/call-optimization.h"
9 #include "src/ic/ic-inl.h"
10 #include "src/ic/ic.h"
11 #include "src/isolate-inl.h"
12 
13 namespace v8 {
14 namespace internal {
15 
Find(Handle<Name> name,Handle<Map> stub_holder,Code::Kind kind,CacheHolderFlag cache_holder)16 Handle<Code> PropertyHandlerCompiler::Find(Handle<Name> name,
17                                            Handle<Map> stub_holder,
18                                            Code::Kind kind,
19                                            CacheHolderFlag cache_holder) {
20   Code::Flags flags = Code::ComputeHandlerFlags(kind, cache_holder);
21   Code* code = stub_holder->LookupInCodeCache(*name, flags);
22   if (code == nullptr) return Handle<Code>();
23   return handle(code);
24 }
25 
26 
ComputeLoadNonexistent(Handle<Name> name,Handle<Map> receiver_map)27 Handle<Code> NamedLoadHandlerCompiler::ComputeLoadNonexistent(
28     Handle<Name> name, Handle<Map> receiver_map) {
29   Isolate* isolate = name->GetIsolate();
30   if (receiver_map->prototype()->IsNull(isolate)) {
31     // TODO(jkummerow/verwaest): If there is no prototype and the property
32     // is nonexistent, introduce a builtin to handle this (fast properties
33     // -> return undefined, dictionary properties -> do negative lookup).
34     return Handle<Code>();
35   }
36   CacheHolderFlag flag;
37   Handle<Map> stub_holder_map =
38       IC::GetHandlerCacheHolder(receiver_map, false, isolate, &flag);
39 
40   // If no dictionary mode objects are present in the prototype chain, the load
41   // nonexistent IC stub can be shared for all names for a given map and we use
42   // the empty string for the map cache in that case. If there are dictionary
43   // mode objects involved, we need to do negative lookups in the stub and
44   // therefore the stub will be specific to the name.
45   Handle<Name> cache_name =
46       receiver_map->is_dictionary_map()
47           ? name
48           : Handle<Name>::cast(isolate->factory()->nonexistent_symbol());
49   Handle<Map> current_map = stub_holder_map;
50   Handle<JSObject> last(JSObject::cast(receiver_map->prototype()));
51   while (true) {
52     if (current_map->is_dictionary_map()) cache_name = name;
53     if (current_map->prototype()->IsNull(isolate)) break;
54     if (name->IsPrivate()) {
55       // TODO(verwaest): Use nonexistent_private_symbol.
56       cache_name = name;
57       if (!current_map->has_hidden_prototype()) break;
58     }
59 
60     last = handle(JSObject::cast(current_map->prototype()));
61     current_map = handle(last->map());
62   }
63   // Compile the stub that is either shared for all names or
64   // name specific if there are global objects involved.
65   Handle<Code> handler = PropertyHandlerCompiler::Find(
66       cache_name, stub_holder_map, Code::LOAD_IC, flag);
67   if (!handler.is_null()) return handler;
68 
69   TRACE_HANDLER_STATS(isolate, LoadIC_LoadNonexistent);
70   NamedLoadHandlerCompiler compiler(isolate, receiver_map, last, flag);
71   handler = compiler.CompileLoadNonexistent(cache_name);
72   Map::UpdateCodeCache(stub_holder_map, cache_name, handler);
73   return handler;
74 }
75 
76 
GetCode(Code::Kind kind,Handle<Name> name)77 Handle<Code> PropertyHandlerCompiler::GetCode(Code::Kind kind,
78                                               Handle<Name> name) {
79   Code::Flags flags = Code::ComputeHandlerFlags(kind, cache_holder());
80   Handle<Code> code = GetCodeWithFlags(flags, name);
81   PROFILE(isolate(), CodeCreateEvent(CodeEventListener::HANDLER_TAG,
82                                      AbstractCode::cast(*code), *name));
83 #ifdef DEBUG
84   code->VerifyEmbeddedObjects();
85 #endif
86   return code;
87 }
88 
89 
90 #define __ ACCESS_MASM(masm())
91 
92 
FrontendHeader(Register object_reg,Handle<Name> name,Label * miss,ReturnHolder return_what)93 Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg,
94                                                   Handle<Name> name,
95                                                   Label* miss,
96                                                   ReturnHolder return_what) {
97   PrototypeCheckType check_type = SKIP_RECEIVER;
98   int function_index = map()->IsPrimitiveMap()
99                            ? map()->GetConstructorFunctionIndex()
100                            : Map::kNoConstructorFunctionIndex;
101   if (function_index != Map::kNoConstructorFunctionIndex) {
102     GenerateDirectLoadGlobalFunctionPrototype(masm(), function_index,
103                                               scratch1(), miss);
104     Object* function = isolate()->native_context()->get(function_index);
105     Object* prototype = JSFunction::cast(function)->instance_prototype();
106     Handle<Map> map(JSObject::cast(prototype)->map());
107     set_map(map);
108     object_reg = scratch1();
109     check_type = CHECK_ALL_MAPS;
110   }
111 
112   // Check that the maps starting from the prototype haven't changed.
113   return CheckPrototypes(object_reg, scratch1(), scratch2(), scratch3(), name,
114                          miss, check_type, return_what);
115 }
116 
117 
118 // Frontend for store uses the name register. It has to be restored before a
119 // miss.
FrontendHeader(Register object_reg,Handle<Name> name,Label * miss,ReturnHolder return_what)120 Register NamedStoreHandlerCompiler::FrontendHeader(Register object_reg,
121                                                    Handle<Name> name,
122                                                    Label* miss,
123                                                    ReturnHolder return_what) {
124   return CheckPrototypes(object_reg, this->name(), scratch1(), scratch2(), name,
125                          miss, SKIP_RECEIVER, return_what);
126 }
127 
128 
Frontend(Handle<Name> name)129 Register PropertyHandlerCompiler::Frontend(Handle<Name> name) {
130   Label miss;
131   if (IC::ICUseVector(kind())) {
132     PushVectorAndSlot();
133   }
134   Register reg = FrontendHeader(receiver(), name, &miss, RETURN_HOLDER);
135   FrontendFooter(name, &miss);
136   // The footer consumes the vector and slot from the stack if miss occurs.
137   if (IC::ICUseVector(kind())) {
138     DiscardVectorAndSlot();
139   }
140   return reg;
141 }
142 
143 
NonexistentFrontendHeader(Handle<Name> name,Label * miss,Register scratch1,Register scratch2)144 void PropertyHandlerCompiler::NonexistentFrontendHeader(Handle<Name> name,
145                                                         Label* miss,
146                                                         Register scratch1,
147                                                         Register scratch2) {
148   Register holder_reg;
149   Handle<Map> last_map;
150   if (holder().is_null()) {
151     holder_reg = receiver();
152     last_map = map();
153     // If |type| has null as its prototype, |holder()| is
154     // Handle<JSObject>::null().
155     DCHECK(last_map->prototype() == isolate()->heap()->null_value());
156   } else {
157     last_map = handle(holder()->map());
158     // This condition matches the branches below.
159     bool need_holder =
160         last_map->is_dictionary_map() && !last_map->IsJSGlobalObjectMap();
161     holder_reg =
162         FrontendHeader(receiver(), name, miss,
163                        need_holder ? RETURN_HOLDER : DONT_RETURN_ANYTHING);
164   }
165 
166   if (last_map->is_dictionary_map()) {
167     if (last_map->IsJSGlobalObjectMap()) {
168       Handle<JSGlobalObject> global =
169           holder().is_null()
170               ? Handle<JSGlobalObject>::cast(isolate()->global_object())
171               : Handle<JSGlobalObject>::cast(holder());
172       GenerateCheckPropertyCell(masm(), global, name, scratch1, miss);
173     } else {
174       if (!name->IsUniqueName()) {
175         DCHECK(name->IsString());
176         name = factory()->InternalizeString(Handle<String>::cast(name));
177       }
178       DCHECK(holder().is_null() ||
179              holder()->property_dictionary()->FindEntry(name) ==
180                  NameDictionary::kNotFound);
181       GenerateDictionaryNegativeLookup(masm(), miss, holder_reg, name, scratch1,
182                                        scratch2);
183     }
184   }
185 }
186 
187 
CompileLoadField(Handle<Name> name,FieldIndex field)188 Handle<Code> NamedLoadHandlerCompiler::CompileLoadField(Handle<Name> name,
189                                                         FieldIndex field) {
190   Register reg = Frontend(name);
191   __ Move(receiver(), reg);
192   LoadFieldStub stub(isolate(), field);
193   GenerateTailCall(masm(), stub.GetCode());
194   return GetCode(kind(), name);
195 }
196 
197 
CompileLoadConstant(Handle<Name> name,int constant_index)198 Handle<Code> NamedLoadHandlerCompiler::CompileLoadConstant(Handle<Name> name,
199                                                            int constant_index) {
200   Register reg = Frontend(name);
201   __ Move(receiver(), reg);
202   LoadConstantStub stub(isolate(), constant_index);
203   GenerateTailCall(masm(), stub.GetCode());
204   return GetCode(kind(), name);
205 }
206 
207 
CompileLoadNonexistent(Handle<Name> name)208 Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent(
209     Handle<Name> name) {
210   Label miss;
211   if (IC::ICUseVector(kind())) {
212     DCHECK(kind() == Code::LOAD_IC);
213     PushVectorAndSlot();
214   }
215   NonexistentFrontendHeader(name, &miss, scratch2(), scratch3());
216   if (IC::ICUseVector(kind())) {
217     DiscardVectorAndSlot();
218   }
219   GenerateLoadConstant(isolate()->factory()->undefined_value());
220   FrontendFooter(name, &miss);
221   return GetCode(kind(), name);
222 }
223 
224 
CompileLoadCallback(Handle<Name> name,Handle<AccessorInfo> callback)225 Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
226     Handle<Name> name, Handle<AccessorInfo> callback) {
227   Register reg = Frontend(name);
228   if (FLAG_runtime_call_stats) {
229     TailCallBuiltin(masm(), Builtins::kLoadIC_Slow);
230   } else {
231     GenerateLoadCallback(reg, callback);
232   }
233   return GetCode(kind(), name);
234 }
235 
236 
CompileLoadCallback(Handle<Name> name,const CallOptimization & call_optimization,int accessor_index)237 Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
238     Handle<Name> name, const CallOptimization& call_optimization,
239     int accessor_index) {
240   DCHECK(call_optimization.is_simple_api_call());
241   Register holder = Frontend(name);
242   if (FLAG_runtime_call_stats) {
243     TailCallBuiltin(masm(), Builtins::kLoadIC_Slow);
244   } else {
245     GenerateApiAccessorCall(masm(), call_optimization, map(), receiver(),
246                             scratch2(), false, no_reg, holder, accessor_index);
247   }
248   return GetCode(kind(), name);
249 }
250 
251 
InterceptorVectorSlotPush(Register holder_reg)252 void NamedLoadHandlerCompiler::InterceptorVectorSlotPush(Register holder_reg) {
253   if (IC::ICUseVector(kind())) {
254     if (holder_reg.is(receiver())) {
255       PushVectorAndSlot();
256     } else {
257       DCHECK(holder_reg.is(scratch1()));
258       PushVectorAndSlot(scratch2(), scratch3());
259     }
260   }
261 }
262 
263 
InterceptorVectorSlotPop(Register holder_reg,PopMode mode)264 void NamedLoadHandlerCompiler::InterceptorVectorSlotPop(Register holder_reg,
265                                                         PopMode mode) {
266   if (IC::ICUseVector(kind())) {
267     if (mode == DISCARD) {
268       DiscardVectorAndSlot();
269     } else {
270       if (holder_reg.is(receiver())) {
271         PopVectorAndSlot();
272       } else {
273         DCHECK(holder_reg.is(scratch1()));
274         PopVectorAndSlot(scratch2(), scratch3());
275       }
276     }
277   }
278 }
279 
280 
CompileLoadInterceptor(LookupIterator * it)281 Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor(
282     LookupIterator* it) {
283   // So far the most popular follow ups for interceptor loads are DATA and
284   // AccessorInfo, so inline only them. Other cases may be added
285   // later.
286   bool inline_followup = false;
287   switch (it->state()) {
288     case LookupIterator::TRANSITION:
289       UNREACHABLE();
290     case LookupIterator::ACCESS_CHECK:
291     case LookupIterator::INTERCEPTOR:
292     case LookupIterator::JSPROXY:
293     case LookupIterator::NOT_FOUND:
294     case LookupIterator::INTEGER_INDEXED_EXOTIC:
295       break;
296     case LookupIterator::DATA:
297       inline_followup =
298           it->property_details().type() == DATA && !it->is_dictionary_holder();
299       break;
300     case LookupIterator::ACCESSOR: {
301       Handle<Object> accessors = it->GetAccessors();
302       if (accessors->IsAccessorInfo()) {
303         Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
304         inline_followup =
305             info->getter() != NULL &&
306             AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map());
307       } else if (accessors->IsAccessorPair()) {
308         Handle<JSObject> property_holder(it->GetHolder<JSObject>());
309         Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
310                               isolate());
311         if (!(getter->IsJSFunction() || getter->IsFunctionTemplateInfo())) {
312           break;
313         }
314         if (!property_holder->HasFastProperties()) break;
315         CallOptimization call_optimization(getter);
316         Handle<Map> receiver_map = map();
317         inline_followup = call_optimization.is_simple_api_call() &&
318                           call_optimization.IsCompatibleReceiverMap(
319                               receiver_map, property_holder);
320       }
321     }
322   }
323 
324   Label miss;
325   InterceptorVectorSlotPush(receiver());
326   bool lost_holder_register = false;
327   auto holder_orig = holder();
328   // non masking interceptors must check the entire chain, so temporarily reset
329   // the holder to be that last element for the FrontendHeader call.
330   if (holder()->GetNamedInterceptor()->non_masking()) {
331     DCHECK(!inline_followup);
332     JSObject* last = *holder();
333     PrototypeIterator iter(isolate(), last);
334     while (!iter.IsAtEnd()) {
335       lost_holder_register = true;
336       // Casting to JSObject is fine here. The LookupIterator makes sure to
337       // look behind non-masking interceptors during the original lookup, and
338       // we wouldn't try to compile a handler if there was a Proxy anywhere.
339       last = iter.GetCurrent<JSObject>();
340       iter.Advance();
341     }
342     auto last_handle = handle(last);
343     set_holder(last_handle);
344   }
345   Register reg = FrontendHeader(receiver(), it->name(), &miss, RETURN_HOLDER);
346   // Reset the holder so further calculations are correct.
347   set_holder(holder_orig);
348   if (lost_holder_register) {
349     if (*it->GetReceiver() == *holder()) {
350       reg = receiver();
351     } else {
352       // Reload lost holder register.
353       auto cell = isolate()->factory()->NewWeakCell(holder());
354       __ LoadWeakValue(reg, cell, &miss);
355     }
356   }
357   FrontendFooter(it->name(), &miss);
358   InterceptorVectorSlotPop(reg);
359   if (inline_followup) {
360     // TODO(368): Compile in the whole chain: all the interceptors in
361     // prototypes and ultimate answer.
362     GenerateLoadInterceptorWithFollowup(it, reg);
363   } else {
364     GenerateLoadInterceptor(reg);
365   }
366   return GetCode(kind(), it->name());
367 }
368 
GenerateLoadCallback(Register reg,Handle<AccessorInfo> callback)369 void NamedLoadHandlerCompiler::GenerateLoadCallback(
370     Register reg, Handle<AccessorInfo> callback) {
371   DCHECK(receiver().is(ApiGetterDescriptor::ReceiverRegister()));
372   __ Move(ApiGetterDescriptor::HolderRegister(), reg);
373   // The callback is alive if this instruction is executed,
374   // so the weak cell is not cleared and points to data.
375   Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
376   __ GetWeakValue(ApiGetterDescriptor::CallbackRegister(), cell);
377 
378   CallApiGetterStub stub(isolate());
379   __ TailCallStub(&stub);
380 }
381 
GenerateLoadPostInterceptor(LookupIterator * it,Register interceptor_reg)382 void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor(
383     LookupIterator* it, Register interceptor_reg) {
384   Handle<JSObject> real_named_property_holder(it->GetHolder<JSObject>());
385 
386   Handle<Map> holder_map(holder()->map());
387   set_map(holder_map);
388   set_holder(real_named_property_holder);
389 
390   Label miss;
391   InterceptorVectorSlotPush(interceptor_reg);
392   Register reg =
393       FrontendHeader(interceptor_reg, it->name(), &miss, RETURN_HOLDER);
394   FrontendFooter(it->name(), &miss);
395   // We discard the vector and slot now because we don't miss below this point.
396   InterceptorVectorSlotPop(reg, DISCARD);
397 
398   switch (it->state()) {
399     case LookupIterator::ACCESS_CHECK:
400     case LookupIterator::INTERCEPTOR:
401     case LookupIterator::JSPROXY:
402     case LookupIterator::NOT_FOUND:
403     case LookupIterator::INTEGER_INDEXED_EXOTIC:
404     case LookupIterator::TRANSITION:
405       UNREACHABLE();
406     case LookupIterator::DATA: {
407       DCHECK_EQ(DATA, it->property_details().type());
408       __ Move(receiver(), reg);
409       LoadFieldStub stub(isolate(), it->GetFieldIndex());
410       GenerateTailCall(masm(), stub.GetCode());
411       break;
412     }
413     case LookupIterator::ACCESSOR:
414       if (it->GetAccessors()->IsAccessorInfo()) {
415         Handle<AccessorInfo> info =
416             Handle<AccessorInfo>::cast(it->GetAccessors());
417         DCHECK_NOT_NULL(info->getter());
418         GenerateLoadCallback(reg, info);
419       } else {
420         Handle<Object> function = handle(
421             AccessorPair::cast(*it->GetAccessors())->getter(), isolate());
422         CallOptimization call_optimization(function);
423         GenerateApiAccessorCall(masm(), call_optimization, holder_map,
424                                 receiver(), scratch2(), false, no_reg, reg,
425                                 it->GetAccessorIndex());
426       }
427   }
428 }
429 
CompileLoadViaGetter(Handle<Name> name,int accessor_index,int expected_arguments)430 Handle<Code> NamedLoadHandlerCompiler::CompileLoadViaGetter(
431     Handle<Name> name, int accessor_index, int expected_arguments) {
432   Register holder = Frontend(name);
433   GenerateLoadViaGetter(masm(), map(), receiver(), holder, accessor_index,
434                         expected_arguments, scratch2());
435   return GetCode(kind(), name);
436 }
437 
438 
439 // TODO(verwaest): Cleanup. holder() is actually the receiver.
CompileStoreTransition(Handle<Map> transition,Handle<Name> name)440 Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition(
441     Handle<Map> transition, Handle<Name> name) {
442   Label miss;
443 
444   PushVectorAndSlot();
445 
446   // Check that we are allowed to write this.
447   bool is_nonexistent = holder()->map() == transition->GetBackPointer();
448   if (is_nonexistent) {
449     // Find the top object.
450     Handle<JSObject> last;
451     PrototypeIterator::WhereToEnd end =
452         name->IsPrivate() ? PrototypeIterator::END_AT_NON_HIDDEN
453                           : PrototypeIterator::END_AT_NULL;
454     PrototypeIterator iter(isolate(), holder(), kStartAtPrototype, end);
455     while (!iter.IsAtEnd()) {
456       last = PrototypeIterator::GetCurrent<JSObject>(iter);
457       iter.Advance();
458     }
459     if (!last.is_null()) set_holder(last);
460     NonexistentFrontendHeader(name, &miss, scratch1(), scratch2());
461   } else {
462     FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
463     DCHECK(holder()->HasFastProperties());
464   }
465 
466   int descriptor = transition->LastAdded();
467   Handle<DescriptorArray> descriptors(transition->instance_descriptors());
468   PropertyDetails details = descriptors->GetDetails(descriptor);
469   Representation representation = details.representation();
470   DCHECK(!representation.IsNone());
471 
472   // Stub is never generated for objects that require access checks.
473   DCHECK(!transition->is_access_check_needed());
474 
475   // Call to respective StoreTransitionStub.
476   bool virtual_args = StoreTransitionHelper::HasVirtualSlotArg();
477   Register map_reg = StoreTransitionHelper::MapRegister();
478 
479   if (details.type() == DATA_CONSTANT) {
480     DCHECK(descriptors->GetValue(descriptor)->IsJSFunction());
481     Register tmp =
482         virtual_args ? VectorStoreICDescriptor::VectorRegister() : map_reg;
483     GenerateRestoreMap(transition, tmp, scratch2(), &miss);
484     GenerateConstantCheck(tmp, descriptor, value(), scratch2(), &miss);
485     if (virtual_args) {
486       // This will move the map from tmp into map_reg.
487       RearrangeVectorAndSlot(tmp, map_reg);
488     } else {
489       PopVectorAndSlot();
490     }
491     GenerateRestoreName(name);
492     StoreTransitionStub stub(isolate());
493     GenerateTailCall(masm(), stub.GetCode());
494 
495   } else {
496     if (representation.IsHeapObject()) {
497       GenerateFieldTypeChecks(descriptors->GetFieldType(descriptor), value(),
498                               &miss);
499     }
500     StoreTransitionStub::StoreMode store_mode =
501         Map::cast(transition->GetBackPointer())->unused_property_fields() == 0
502             ? StoreTransitionStub::ExtendStorageAndStoreMapAndValue
503             : StoreTransitionStub::StoreMapAndValue;
504 
505     Register tmp =
506         virtual_args ? VectorStoreICDescriptor::VectorRegister() : map_reg;
507     GenerateRestoreMap(transition, tmp, scratch2(), &miss);
508     if (virtual_args) {
509       RearrangeVectorAndSlot(tmp, map_reg);
510     } else {
511       PopVectorAndSlot();
512     }
513     GenerateRestoreName(name);
514     StoreTransitionStub stub(isolate(),
515                              FieldIndex::ForDescriptor(*transition, descriptor),
516                              representation, store_mode);
517     GenerateTailCall(masm(), stub.GetCode());
518   }
519 
520   GenerateRestoreName(&miss, name);
521   PopVectorAndSlot();
522   TailCallBuiltin(masm(), MissBuiltin(kind()));
523 
524   return GetCode(kind(), name);
525 }
526 
RequiresFieldTypeChecks(FieldType * field_type) const527 bool NamedStoreHandlerCompiler::RequiresFieldTypeChecks(
528     FieldType* field_type) const {
529   return field_type->IsClass();
530 }
531 
532 
CompileStoreField(LookupIterator * it)533 Handle<Code> NamedStoreHandlerCompiler::CompileStoreField(LookupIterator* it) {
534   Label miss;
535   DCHECK(it->representation().IsHeapObject());
536 
537   FieldType* field_type = *it->GetFieldType();
538   bool need_save_restore = false;
539   if (RequiresFieldTypeChecks(field_type)) {
540     need_save_restore = IC::ICUseVector(kind());
541     if (need_save_restore) PushVectorAndSlot();
542     GenerateFieldTypeChecks(field_type, value(), &miss);
543     if (need_save_restore) PopVectorAndSlot();
544   }
545 
546   StoreFieldStub stub(isolate(), it->GetFieldIndex(), it->representation());
547   GenerateTailCall(masm(), stub.GetCode());
548 
549   __ bind(&miss);
550   if (need_save_restore) PopVectorAndSlot();
551   TailCallBuiltin(masm(), MissBuiltin(kind()));
552   return GetCode(kind(), it->name());
553 }
554 
555 
CompileStoreViaSetter(Handle<JSObject> object,Handle<Name> name,int accessor_index,int expected_arguments)556 Handle<Code> NamedStoreHandlerCompiler::CompileStoreViaSetter(
557     Handle<JSObject> object, Handle<Name> name, int accessor_index,
558     int expected_arguments) {
559   Register holder = Frontend(name);
560   GenerateStoreViaSetter(masm(), map(), receiver(), holder, accessor_index,
561                          expected_arguments, scratch2());
562 
563   return GetCode(kind(), name);
564 }
565 
566 
CompileStoreCallback(Handle<JSObject> object,Handle<Name> name,const CallOptimization & call_optimization,int accessor_index)567 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
568     Handle<JSObject> object, Handle<Name> name,
569     const CallOptimization& call_optimization, int accessor_index) {
570   Register holder = Frontend(name);
571   if (FLAG_runtime_call_stats) {
572     GenerateRestoreName(name);
573     TailCallBuiltin(masm(), Builtins::kStoreIC_Slow);
574   } else {
575     GenerateApiAccessorCall(masm(), call_optimization, handle(object->map()),
576                             receiver(), scratch2(), true, value(), holder,
577                             accessor_index);
578   }
579   return GetCode(kind(), name);
580 }
581 
582 
583 #undef __
584 
CompileElementHandlers(MapHandleList * receiver_maps,CodeHandleList * handlers)585 void ElementHandlerCompiler::CompileElementHandlers(
586     MapHandleList* receiver_maps, CodeHandleList* handlers) {
587   for (int i = 0; i < receiver_maps->length(); ++i) {
588     Handle<Map> receiver_map = receiver_maps->at(i);
589     Handle<Code> cached_stub;
590 
591     if (receiver_map->IsStringMap()) {
592       cached_stub = LoadIndexedStringStub(isolate()).GetCode();
593     } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
594       cached_stub = isolate()->builtins()->KeyedLoadIC_Slow();
595     } else {
596       bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
597       ElementsKind elements_kind = receiver_map->elements_kind();
598 
599       // No need to check for an elements-free prototype chain here, the
600       // generated stub code needs to check that dynamically anyway.
601       bool convert_hole_to_undefined =
602           (is_js_array && elements_kind == FAST_HOLEY_ELEMENTS &&
603            *receiver_map == isolate()->get_initial_js_array_map(elements_kind));
604 
605       if (receiver_map->has_indexed_interceptor() &&
606           !receiver_map->GetIndexedInterceptor()->getter()->IsUndefined(
607               isolate()) &&
608           !receiver_map->GetIndexedInterceptor()->non_masking()) {
609         cached_stub = LoadIndexedInterceptorStub(isolate()).GetCode();
610       } else if (IsSloppyArgumentsElements(elements_kind)) {
611         cached_stub = KeyedLoadSloppyArgumentsStub(isolate()).GetCode();
612       } else if (IsFastElementsKind(elements_kind) ||
613                  IsFixedTypedArrayElementsKind(elements_kind)) {
614         cached_stub = LoadFastElementStub(isolate(), is_js_array, elements_kind,
615                                           convert_hole_to_undefined).GetCode();
616       } else {
617         DCHECK(elements_kind == DICTIONARY_ELEMENTS);
618         cached_stub = LoadDictionaryElementStub(isolate()).GetCode();
619       }
620     }
621 
622     handlers->Add(cached_stub);
623   }
624 }
625 }  // namespace internal
626 }  // namespace v8
627