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 
14 namespace v8 {
15 namespace internal {
16 
Find(Handle<Name> name,Handle<Map> stub_holder,Code::Kind kind,CacheHolderFlag cache_holder)17 Handle<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 
ComputeLoadNonexistent(Handle<Name> name,Handle<Map> receiver_map)28 Handle<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 
GetCode(Code::Kind kind,Handle<Name> name)81 Handle<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 
FrontendHeader(Register object_reg,Handle<Name> name,Label * miss,ReturnHolder return_what)97 Register 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.
FrontendHeader(Register object_reg,Handle<Name> name,Label * miss,ReturnHolder return_what)123 Register 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 
Frontend(Handle<Name> name)138 Register 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 
NonexistentFrontendHeader(Handle<Name> name,Label * miss,Register scratch1,Register scratch2)153 void 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 
CompileLoadField(Handle<Name> name,FieldIndex field)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 
CompileLoadConstant(Handle<Name> name,int constant_index)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 
CompileLoadNonexistent(Handle<Name> name)217 Handle<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 
CompileLoadCallback(Handle<Name> name,Handle<AccessorInfo> callback,Handle<Code> slow_stub)233 Handle<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 
CompileLoadCallback(Handle<Name> name,const CallOptimization & call_optimization,int accessor_index,Handle<Code> slow_stub)243 Handle<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 
InterceptorVectorSlotPush(Register holder_reg)257 void 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 
InterceptorVectorSlotPop(Register holder_reg,PopMode mode)269 void 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 
CompileLoadInterceptor(LookupIterator * it)286 Handle<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 
GenerateLoadCallback(Register reg,Handle<AccessorInfo> callback)374 void 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 
GenerateLoadPostInterceptor(LookupIterator * it,Register interceptor_reg)387 void 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 
CompileLoadViaGetter(Handle<Name> name,int accessor_index,int expected_arguments)435 Handle<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.
CompileStoreTransition(Handle<Map> transition,Handle<Name> name)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 
RequiresFieldTypeChecks(FieldType * field_type) const555 bool NamedStoreHandlerCompiler::RequiresFieldTypeChecks(
556     FieldType* field_type) const {
557   return field_type->IsClass();
558 }
559 
560 
CompileStoreField(LookupIterator * it)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 
CompileStoreViaSetter(Handle<JSObject> object,Handle<Name> name,int accessor_index,int expected_arguments)587 Handle<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 
CompileStoreCallback(Handle<JSObject> object,Handle<Name> name,const CallOptimization & call_optimization,int accessor_index,Handle<Code> slow_stub)597 Handle<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
GetKeyedLoadHandler(Handle<Map> receiver_map,Isolate * isolate)618 Handle<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 
CompileElementHandlers(MapHandleList * receiver_maps,List<Handle<Object>> * handlers)669 void 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