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/handler-configuration-inl.h"
10#include "src/ic/ic-inl.h"
11#include "src/ic/ic.h"
12#include "src/isolate-inl.h"
13
14namespace v8 {
15namespace internal {
16
17Handle<Code> PropertyHandlerCompiler::Find(Handle<Name> name,
18                                           Handle<Map> stub_holder,
19                                           Code::Kind kind,
20                                           CacheHolderFlag cache_holder) {
21  Code::Flags flags = Code::ComputeHandlerFlags(kind, cache_holder);
22  Code* code = stub_holder->LookupInCodeCache(*name, flags);
23  if (code == nullptr) return Handle<Code>();
24  return handle(code);
25}
26
27
28Handle<Code> NamedLoadHandlerCompiler::ComputeLoadNonexistent(
29    Handle<Name> name, Handle<Map> receiver_map) {
30  Isolate* isolate = name->GetIsolate();
31  if (receiver_map->prototype()->IsNull(isolate)) {
32    // TODO(jkummerow/verwaest): If there is no prototype and the property
33    // is nonexistent, introduce a builtin to handle this (fast properties
34    // -> return undefined, dictionary properties -> do negative lookup).
35    return Handle<Code>();
36  }
37  CacheHolderFlag flag;
38  Handle<Map> stub_holder_map =
39      IC::GetHandlerCacheHolder(receiver_map, false, isolate, &flag);
40
41  // If no dictionary mode objects are present in the prototype chain, the load
42  // nonexistent IC stub can be shared for all names for a given map and we use
43  // the empty string for the map cache in that case. If there are dictionary
44  // mode objects involved, we need to do negative lookups in the stub and
45  // therefore the stub will be specific to the name.
46  Handle<Name> cache_name =
47      receiver_map->is_dictionary_map()
48          ? name
49          : Handle<Name>::cast(isolate->factory()->nonexistent_symbol());
50  Handle<Map> current_map = stub_holder_map;
51  Handle<JSObject> last(JSObject::cast(receiver_map->prototype()));
52  while (true) {
53    if (current_map->is_dictionary_map()) cache_name = name;
54    if (current_map->prototype()->IsNull(isolate)) break;
55    if (name->IsPrivate()) {
56      // TODO(verwaest): Use nonexistent_private_symbol.
57      cache_name = name;
58      if (!current_map->has_hidden_prototype()) break;
59    }
60
61    last = handle(JSObject::cast(current_map->prototype()));
62    current_map = handle(last->map());
63  }
64  // Compile the stub that is either shared for all names or
65  // name specific if there are global objects involved.
66  Handle<Code> handler = PropertyHandlerCompiler::Find(
67      cache_name, stub_holder_map, Code::LOAD_IC, flag);
68  if (!handler.is_null()) {
69    TRACE_HANDLER_STATS(isolate, LoadIC_HandlerCacheHit_NonExistent);
70    return handler;
71  }
72
73  TRACE_HANDLER_STATS(isolate, LoadIC_LoadNonexistent);
74  NamedLoadHandlerCompiler compiler(isolate, receiver_map, last, flag);
75  handler = compiler.CompileLoadNonexistent(cache_name);
76  Map::UpdateCodeCache(stub_holder_map, cache_name, handler);
77  return handler;
78}
79
80
81Handle<Code> PropertyHandlerCompiler::GetCode(Code::Kind kind,
82                                              Handle<Name> name) {
83  Code::Flags flags = Code::ComputeHandlerFlags(kind, cache_holder());
84  Handle<Code> code = GetCodeWithFlags(flags, name);
85  PROFILE(isolate(), CodeCreateEvent(CodeEventListener::HANDLER_TAG,
86                                     AbstractCode::cast(*code), *name));
87#ifdef DEBUG
88  code->VerifyEmbeddedObjects();
89#endif
90  return code;
91}
92
93
94#define __ ACCESS_MASM(masm())
95
96
97Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg,
98                                                  Handle<Name> name,
99                                                  Label* miss,
100                                                  ReturnHolder return_what) {
101  if (map()->IsPrimitiveMap() || map()->IsJSGlobalProxyMap()) {
102    // If the receiver is a global proxy and if we get to this point then
103    // the compile-time (current) native context has access to global proxy's
104    // native context. Since access rights revocation is not supported at all,
105    // we can generate a check that an execution-time native context is either
106    // the same as compile-time native context or has the same access token.
107    Handle<Context> native_context = isolate()->native_context();
108    Handle<WeakCell> weak_cell(native_context->self_weak_cell(), isolate());
109
110    bool compare_native_contexts_only = map()->IsPrimitiveMap();
111    GenerateAccessCheck(weak_cell, scratch1(), scratch2(), miss,
112                        compare_native_contexts_only);
113  }
114
115  // Check that the maps starting from the prototype haven't changed.
116  return CheckPrototypes(object_reg, scratch1(), scratch2(), scratch3(), name,
117                         miss, return_what);
118}
119
120
121// Frontend for store uses the name register. It has to be restored before a
122// miss.
123Register NamedStoreHandlerCompiler::FrontendHeader(Register object_reg,
124                                                   Handle<Name> name,
125                                                   Label* miss,
126                                                   ReturnHolder return_what) {
127  if (map()->IsJSGlobalProxyMap()) {
128    Handle<Context> native_context = isolate()->native_context();
129    Handle<WeakCell> weak_cell(native_context->self_weak_cell(), isolate());
130    GenerateAccessCheck(weak_cell, scratch1(), scratch2(), miss, false);
131  }
132
133  return CheckPrototypes(object_reg, this->name(), scratch1(), scratch2(), name,
134                         miss, return_what);
135}
136
137
138Register PropertyHandlerCompiler::Frontend(Handle<Name> name) {
139  Label miss;
140  if (IC::ShouldPushPopSlotAndVector(kind())) {
141    PushVectorAndSlot();
142  }
143  Register reg = FrontendHeader(receiver(), name, &miss, RETURN_HOLDER);
144  FrontendFooter(name, &miss);
145  // The footer consumes the vector and slot from the stack if miss occurs.
146  if (IC::ShouldPushPopSlotAndVector(kind())) {
147    DiscardVectorAndSlot();
148  }
149  return reg;
150}
151
152
153void PropertyHandlerCompiler::NonexistentFrontendHeader(Handle<Name> name,
154                                                        Label* miss,
155                                                        Register scratch1,
156                                                        Register scratch2) {
157  Register holder_reg;
158  Handle<Map> last_map;
159  if (holder().is_null()) {
160    holder_reg = receiver();
161    last_map = map();
162    // If |type| has null as its prototype, |holder()| is
163    // Handle<JSObject>::null().
164    DCHECK(last_map->prototype() == isolate()->heap()->null_value());
165  } else {
166    last_map = handle(holder()->map());
167    // This condition matches the branches below.
168    bool need_holder =
169        last_map->is_dictionary_map() && !last_map->IsJSGlobalObjectMap();
170    holder_reg =
171        FrontendHeader(receiver(), name, miss,
172                       need_holder ? RETURN_HOLDER : DONT_RETURN_ANYTHING);
173  }
174
175  if (last_map->is_dictionary_map()) {
176    if (last_map->IsJSGlobalObjectMap()) {
177      Handle<JSGlobalObject> global =
178          holder().is_null()
179              ? Handle<JSGlobalObject>::cast(isolate()->global_object())
180              : Handle<JSGlobalObject>::cast(holder());
181      GenerateCheckPropertyCell(masm(), global, name, scratch1, miss);
182    } else {
183      if (!name->IsUniqueName()) {
184        DCHECK(name->IsString());
185        name = factory()->InternalizeString(Handle<String>::cast(name));
186      }
187      DCHECK(holder().is_null() ||
188             holder()->property_dictionary()->FindEntry(name) ==
189                 NameDictionary::kNotFound);
190      GenerateDictionaryNegativeLookup(masm(), miss, holder_reg, name, scratch1,
191                                       scratch2);
192    }
193  }
194}
195
196
197Handle<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
207Handle<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
217Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent(
218    Handle<Name> name) {
219  Label miss;
220  if (IC::ShouldPushPopSlotAndVector(kind())) {
221    DCHECK(kind() == Code::LOAD_IC);
222    PushVectorAndSlot();
223  }
224  NonexistentFrontendHeader(name, &miss, scratch2(), scratch3());
225  if (IC::ShouldPushPopSlotAndVector(kind())) {
226    DiscardVectorAndSlot();
227  }
228  GenerateLoadConstant(isolate()->factory()->undefined_value());
229  FrontendFooter(name, &miss);
230  return GetCode(kind(), name);
231}
232
233Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
234    Handle<Name> name, Handle<AccessorInfo> callback, Handle<Code> slow_stub) {
235  if (V8_UNLIKELY(FLAG_runtime_stats)) {
236    GenerateTailCall(masm(), slow_stub);
237  }
238  Register reg = Frontend(name);
239  GenerateLoadCallback(reg, callback);
240  return GetCode(kind(), name);
241}
242
243Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
244    Handle<Name> name, const CallOptimization& call_optimization,
245    int accessor_index, Handle<Code> slow_stub) {
246  DCHECK(call_optimization.is_simple_api_call());
247  if (V8_UNLIKELY(FLAG_runtime_stats)) {
248    GenerateTailCall(masm(), slow_stub);
249  }
250  Register holder = Frontend(name);
251  GenerateApiAccessorCall(masm(), call_optimization, map(), receiver(),
252                          scratch2(), false, no_reg, holder, accessor_index);
253  return GetCode(kind(), name);
254}
255
256
257void NamedLoadHandlerCompiler::InterceptorVectorSlotPush(Register holder_reg) {
258  if (IC::ShouldPushPopSlotAndVector(kind())) {
259    if (holder_reg.is(receiver())) {
260      PushVectorAndSlot();
261    } else {
262      DCHECK(holder_reg.is(scratch1()));
263      PushVectorAndSlot(scratch2(), scratch3());
264    }
265  }
266}
267
268
269void NamedLoadHandlerCompiler::InterceptorVectorSlotPop(Register holder_reg,
270                                                        PopMode mode) {
271  if (IC::ShouldPushPopSlotAndVector(kind())) {
272    if (mode == DISCARD) {
273      DiscardVectorAndSlot();
274    } else {
275      if (holder_reg.is(receiver())) {
276        PopVectorAndSlot();
277      } else {
278        DCHECK(holder_reg.is(scratch1()));
279        PopVectorAndSlot(scratch2(), scratch3());
280      }
281    }
282  }
283}
284
285
286Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor(
287    LookupIterator* it) {
288  // So far the most popular follow ups for interceptor loads are DATA and
289  // AccessorInfo, so inline only them. Other cases may be added
290  // later.
291  bool inline_followup = false;
292  switch (it->state()) {
293    case LookupIterator::TRANSITION:
294      UNREACHABLE();
295    case LookupIterator::ACCESS_CHECK:
296    case LookupIterator::INTERCEPTOR:
297    case LookupIterator::JSPROXY:
298    case LookupIterator::NOT_FOUND:
299    case LookupIterator::INTEGER_INDEXED_EXOTIC:
300      break;
301    case LookupIterator::DATA:
302      inline_followup =
303          it->property_details().type() == DATA && !it->is_dictionary_holder();
304      break;
305    case LookupIterator::ACCESSOR: {
306      Handle<Object> accessors = it->GetAccessors();
307      if (accessors->IsAccessorInfo()) {
308        Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
309        inline_followup =
310            info->getter() != NULL &&
311            AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map());
312      } else if (accessors->IsAccessorPair()) {
313        Handle<JSObject> property_holder(it->GetHolder<JSObject>());
314        Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
315                              isolate());
316        if (!(getter->IsJSFunction() || getter->IsFunctionTemplateInfo())) {
317          break;
318        }
319        if (!property_holder->HasFastProperties()) break;
320        CallOptimization call_optimization(getter);
321        Handle<Map> receiver_map = map();
322        inline_followup = call_optimization.is_simple_api_call() &&
323                          call_optimization.IsCompatibleReceiverMap(
324                              receiver_map, property_holder);
325      }
326    }
327  }
328
329  Label miss;
330  InterceptorVectorSlotPush(receiver());
331  bool lost_holder_register = false;
332  auto holder_orig = holder();
333  // non masking interceptors must check the entire chain, so temporarily reset
334  // the holder to be that last element for the FrontendHeader call.
335  if (holder()->GetNamedInterceptor()->non_masking()) {
336    DCHECK(!inline_followup);
337    JSObject* last = *holder();
338    PrototypeIterator iter(isolate(), last);
339    while (!iter.IsAtEnd()) {
340      lost_holder_register = true;
341      // Casting to JSObject is fine here. The LookupIterator makes sure to
342      // look behind non-masking interceptors during the original lookup, and
343      // we wouldn't try to compile a handler if there was a Proxy anywhere.
344      last = iter.GetCurrent<JSObject>();
345      iter.Advance();
346    }
347    auto last_handle = handle(last);
348    set_holder(last_handle);
349  }
350  Register reg = FrontendHeader(receiver(), it->name(), &miss, RETURN_HOLDER);
351  // Reset the holder so further calculations are correct.
352  set_holder(holder_orig);
353  if (lost_holder_register) {
354    if (*it->GetReceiver() == *holder()) {
355      reg = receiver();
356    } else {
357      // Reload lost holder register.
358      auto cell = isolate()->factory()->NewWeakCell(holder());
359      __ LoadWeakValue(reg, cell, &miss);
360    }
361  }
362  FrontendFooter(it->name(), &miss);
363  InterceptorVectorSlotPop(reg);
364  if (inline_followup) {
365    // TODO(368): Compile in the whole chain: all the interceptors in
366    // prototypes and ultimate answer.
367    GenerateLoadInterceptorWithFollowup(it, reg);
368  } else {
369    GenerateLoadInterceptor(reg);
370  }
371  return GetCode(kind(), it->name());
372}
373
374void NamedLoadHandlerCompiler::GenerateLoadCallback(
375    Register reg, Handle<AccessorInfo> callback) {
376  DCHECK(receiver().is(ApiGetterDescriptor::ReceiverRegister()));
377  __ Move(ApiGetterDescriptor::HolderRegister(), reg);
378  // The callback is alive if this instruction is executed,
379  // so the weak cell is not cleared and points to data.
380  Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
381  __ GetWeakValue(ApiGetterDescriptor::CallbackRegister(), cell);
382
383  CallApiGetterStub stub(isolate());
384  __ TailCallStub(&stub);
385}
386
387void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor(
388    LookupIterator* it, Register interceptor_reg) {
389  Handle<JSObject> real_named_property_holder(it->GetHolder<JSObject>());
390
391  Handle<Map> holder_map(holder()->map());
392  set_map(holder_map);
393  set_holder(real_named_property_holder);
394
395  Label miss;
396  InterceptorVectorSlotPush(interceptor_reg);
397  Register reg =
398      FrontendHeader(interceptor_reg, it->name(), &miss, RETURN_HOLDER);
399  FrontendFooter(it->name(), &miss);
400  // We discard the vector and slot now because we don't miss below this point.
401  InterceptorVectorSlotPop(reg, DISCARD);
402
403  switch (it->state()) {
404    case LookupIterator::ACCESS_CHECK:
405    case LookupIterator::INTERCEPTOR:
406    case LookupIterator::JSPROXY:
407    case LookupIterator::NOT_FOUND:
408    case LookupIterator::INTEGER_INDEXED_EXOTIC:
409    case LookupIterator::TRANSITION:
410      UNREACHABLE();
411    case LookupIterator::DATA: {
412      DCHECK_EQ(DATA, it->property_details().type());
413      __ Move(receiver(), reg);
414      LoadFieldStub stub(isolate(), it->GetFieldIndex());
415      GenerateTailCall(masm(), stub.GetCode());
416      break;
417    }
418    case LookupIterator::ACCESSOR:
419      if (it->GetAccessors()->IsAccessorInfo()) {
420        Handle<AccessorInfo> info =
421            Handle<AccessorInfo>::cast(it->GetAccessors());
422        DCHECK_NOT_NULL(info->getter());
423        GenerateLoadCallback(reg, info);
424      } else {
425        Handle<Object> function = handle(
426            AccessorPair::cast(*it->GetAccessors())->getter(), isolate());
427        CallOptimization call_optimization(function);
428        GenerateApiAccessorCall(masm(), call_optimization, holder_map,
429                                receiver(), scratch2(), false, no_reg, reg,
430                                it->GetAccessorIndex());
431      }
432  }
433}
434
435Handle<Code> NamedLoadHandlerCompiler::CompileLoadViaGetter(
436    Handle<Name> name, int accessor_index, int expected_arguments) {
437  Register holder = Frontend(name);
438  GenerateLoadViaGetter(masm(), map(), receiver(), holder, accessor_index,
439                        expected_arguments, scratch2());
440  return GetCode(kind(), name);
441}
442
443
444// TODO(verwaest): Cleanup. holder() is actually the receiver.
445Handle<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
555bool NamedStoreHandlerCompiler::RequiresFieldTypeChecks(
556    FieldType* field_type) const {
557  return field_type->IsClass();
558}
559
560
561Handle<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
587Handle<Code> NamedStoreHandlerCompiler::CompileStoreViaSetter(
588    Handle<JSObject> object, Handle<Name> name, int accessor_index,
589    int expected_arguments) {
590  Register holder = Frontend(name);
591  GenerateStoreViaSetter(masm(), map(), receiver(), holder, accessor_index,
592                         expected_arguments, scratch2());
593
594  return GetCode(kind(), name);
595}
596
597Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
598    Handle<JSObject> object, Handle<Name> name,
599    const CallOptimization& call_optimization, int accessor_index,
600    Handle<Code> slow_stub) {
601  if (V8_UNLIKELY(FLAG_runtime_stats)) {
602    GenerateTailCall(masm(), slow_stub);
603  }
604  Register holder = Frontend(name);
605  if (Descriptor::kPassLastArgsOnStack) {
606    __ LoadParameterFromStack<Descriptor>(value(), Descriptor::kValue);
607  }
608  GenerateApiAccessorCall(masm(), call_optimization, handle(object->map()),
609                          receiver(), scratch2(), true, value(), holder,
610                          accessor_index);
611  return GetCode(kind(), name);
612}
613
614
615#undef __
616
617// static
618Handle<Object> ElementHandlerCompiler::GetKeyedLoadHandler(
619    Handle<Map> receiver_map, Isolate* isolate) {
620  if (receiver_map->has_indexed_interceptor() &&
621      !receiver_map->GetIndexedInterceptor()->getter()->IsUndefined(isolate) &&
622      !receiver_map->GetIndexedInterceptor()->non_masking()) {
623    TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadIndexedInterceptorStub);
624    return LoadIndexedInterceptorStub(isolate).GetCode();
625  }
626  if (receiver_map->IsStringMap()) {
627    TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadIndexedStringStub);
628    return LoadIndexedStringStub(isolate).GetCode();
629  }
630  InstanceType instance_type = receiver_map->instance_type();
631  if (instance_type < FIRST_JS_RECEIVER_TYPE) {
632    TRACE_HANDLER_STATS(isolate, KeyedLoadIC_SlowStub);
633    return isolate->builtins()->KeyedLoadIC_Slow();
634  }
635
636  ElementsKind elements_kind = receiver_map->elements_kind();
637  if (IsSloppyArgumentsElements(elements_kind)) {
638    TRACE_HANDLER_STATS(isolate, KeyedLoadIC_KeyedLoadSloppyArgumentsStub);
639    return KeyedLoadSloppyArgumentsStub(isolate).GetCode();
640  }
641  bool is_js_array = instance_type == JS_ARRAY_TYPE;
642  if (elements_kind == DICTIONARY_ELEMENTS) {
643    if (FLAG_tf_load_ic_stub) {
644      TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadElementDH);
645      return LoadHandler::LoadElement(isolate, elements_kind, false,
646                                      is_js_array);
647    }
648    TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadDictionaryElementStub);
649    return LoadDictionaryElementStub(isolate).GetCode();
650  }
651  DCHECK(IsFastElementsKind(elements_kind) ||
652         IsFixedTypedArrayElementsKind(elements_kind));
653  // TODO(jkummerow): Use IsHoleyElementsKind(elements_kind).
654  bool convert_hole_to_undefined =
655      is_js_array && elements_kind == FAST_HOLEY_ELEMENTS &&
656      *receiver_map == isolate->get_initial_js_array_map(elements_kind);
657  if (FLAG_tf_load_ic_stub) {
658    TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadElementDH);
659    return LoadHandler::LoadElement(isolate, elements_kind,
660                                    convert_hole_to_undefined, is_js_array);
661  } else {
662    TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadFastElementStub);
663    return LoadFastElementStub(isolate, is_js_array, elements_kind,
664                               convert_hole_to_undefined)
665        .GetCode();
666  }
667}
668
669void ElementHandlerCompiler::CompileElementHandlers(
670    MapHandleList* receiver_maps, List<Handle<Object>>* handlers) {
671  for (int i = 0; i < receiver_maps->length(); ++i) {
672    handlers->Add(GetKeyedLoadHandler(receiver_maps->at(i), isolate()));
673  }
674}
675}  // namespace internal
676}  // namespace v8
677