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