Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: src/ic/keyed-store-generic.cc

Issue 2444353002: [stubs] Port KeyedStoreIC_Megamorphic stub to Turbofan (Closed)
Patch Set: polishing Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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/keyed-store-generic.h"
6
7 #include "src/compiler/code-assembler.h"
8 #include "src/contexts.h"
9 #include "src/isolate.h"
10
11 namespace v8 {
12 namespace internal {
13
14 using compiler::Node;
15
16 class KeyedStoreGenericAssembler : public CodeStubAssembler {
17 public:
18 void KeyedStoreGeneric(const StoreICParameters* p,
19 LanguageMode language_mode);
20
21 private:
22 enum UpdateLength {
23 kDontChangeLength,
24 kIncrementLengthByOne,
25 kBumpLengthWithGap
26 };
27
28 void EmitGenericElementStore(Node* receiver, Node* receiver_map,
29 Node* instance_type, Node* intptr_index,
30 Node* value, Node* context, Label* slow);
31
32 void EmitGenericPropertyStore(Node* receiver, Node* receiver_map,
33 const StoreICParameters* p, Label* slow);
34
35 void BranchIfPrototypesHaveNonFastElements(Node* receiver_map,
36 Label* non_fast_elements,
37 Label* only_fast_elements);
38
39 void TryRewriteElements(Node* receiver, Node* receiver_map, Node* elements,
40 Node* native_context, ElementsKind from_kind,
41 ElementsKind to_kind, Label* bailout);
42
43 void StoreElementWithCapacity(Node* receiver, Node* receiver_map,
44 Node* elements, Node* elements_kind,
45 Node* intptr_index, Node* value, Node* context,
46 Label* slow, UpdateLength update_length);
47
48 void MaybeUpdateLengthAndReturn(Node* receiver, Node* index, Node* value,
49 UpdateLength update_length);
50
51 void TryChangeToHoleyMapHelper(Node* receiver, Node* receiver_map,
52 Node* native_context, ElementsKind packed_kind,
53 ElementsKind holey_kind, Label* done,
54 Label* map_mismatch, Label* bailout);
55 void TryChangeToHoleyMap(Node* receiver, Node* receiver_map,
56 Node* current_elements_kind, Node* context,
57 ElementsKind packed_kind, Label* bailout);
58 void TryChangeToHoleyMapMulti(Node* receiver, Node* receiver_map,
59 Node* current_elements_kind, Node* context,
60 ElementsKind packed_kind,
61 ElementsKind packed_kind_2, Label* bailout);
62 };
63
64 // Do not add fields, so that this is safe to reinterpret_cast to CSA.
65 STATIC_ASSERT(sizeof(CodeStubAssembler) == sizeof(KeyedStoreGenericAssembler));
Igor Sheludko 2016/11/07 14:43:39 Maybe put it near the reinterpret cast.
Jakob Kummerow 2016/11/07 16:55:25 Done.
66
67 void KeyedStoreGenericGenerator::Generate(
68 CodeStubAssembler* assembler, const CodeStubAssembler::StoreICParameters* p,
69 LanguageMode language_mode) {
70 auto assm = reinterpret_cast<KeyedStoreGenericAssembler*>(assembler);
71 assm->KeyedStoreGeneric(p, language_mode);
72 }
73
74 void KeyedStoreGenericAssembler::BranchIfPrototypesHaveNonFastElements(
75 Node* receiver_map, Label* non_fast_elements, Label* only_fast_elements) {
76 Variable var_map(this, MachineRepresentation::kTagged);
77 var_map.Bind(receiver_map);
78 Label loop_body(this, &var_map);
79 Goto(&loop_body);
80
81 Bind(&loop_body);
82 {
83 Node* map = var_map.value();
84 Node* prototype = LoadMapPrototype(map);
85 GotoIf(WordEqual(prototype, NullConstant()), only_fast_elements);
86 Node* prototype_map = LoadMap(prototype);
87 var_map.Bind(prototype_map);
88 Node* instance_type = LoadMapInstanceType(prototype_map);
89 STATIC_ASSERT(JS_PROXY_TYPE < JS_OBJECT_TYPE);
90 STATIC_ASSERT(JS_VALUE_TYPE < JS_OBJECT_TYPE);
91 GotoIf(Int32LessThanOrEqual(instance_type,
92 Int32Constant(LAST_CUSTOM_ELEMENTS_RECEIVER)),
93 non_fast_elements);
94 Node* elements_kind = LoadMapElementsKind(prototype_map);
95 STATIC_ASSERT(FIRST_ELEMENTS_KIND == FIRST_FAST_ELEMENTS_KIND);
96 GotoIf(Int32LessThanOrEqual(elements_kind,
97 Int32Constant(LAST_FAST_ELEMENTS_KIND)),
98 &loop_body);
99 GotoIf(Word32Equal(elements_kind, Int32Constant(NO_ELEMENTS)), &loop_body);
100 Goto(non_fast_elements);
101 }
102 }
103
104 void KeyedStoreGenericAssembler::TryRewriteElements(
105 Node* receiver, Node* receiver_map, Node* elements, Node* native_context,
106 ElementsKind from_kind, ElementsKind to_kind, Label* bailout) {
107 DCHECK(IsFastPackedElementsKind(from_kind));
108 ElementsKind holey_from_kind = GetHoleyElementsKind(from_kind);
109 ElementsKind holey_to_kind = GetHoleyElementsKind(to_kind);
110 if (AllocationSite::GetMode(from_kind, to_kind) == TRACK_ALLOCATION_SITE) {
111 TrapAllocationMemento(receiver, bailout);
112 }
113 Label perform_transition(this), check_holey_map(this);
114 Variable var_target_map(this, MachineType::PointerRepresentation());
115 // Check if the receiver has the default |from_kind| map.
116 {
117 Node* packed_map =
118 LoadContextElement(native_context, Context::ArrayMapIndex(from_kind));
119 GotoIf(WordNotEqual(receiver_map, packed_map), &check_holey_map);
120 var_target_map.Bind(
121 LoadContextElement(native_context, Context::ArrayMapIndex(to_kind)));
122 Goto(&perform_transition);
123 }
124
125 // Check if the receiver has the default |holey_from_kind| map.
126 Bind(&check_holey_map);
127 {
128 Node* holey_map = LoadContextElement(
129 native_context, Context::ArrayMapIndex(holey_from_kind));
130 GotoIf(WordNotEqual(receiver_map, holey_map), bailout);
131 var_target_map.Bind(LoadContextElement(
132 native_context, Context::ArrayMapIndex(holey_to_kind)));
133 Goto(&perform_transition);
134 }
135
136 // Found a supported transition target map, perform the transition!
137 Bind(&perform_transition);
138 {
139 Node* capacity = LoadFixedArrayBaseLength(elements);
140 GrowElementsCapacity(receiver, elements, from_kind, to_kind, capacity,
141 capacity, INTPTR_PARAMETERS, bailout);
142 StoreObjectField(receiver, JSObject::kMapOffset, var_target_map.value());
143 }
144 }
145
146 void KeyedStoreGenericAssembler::TryChangeToHoleyMapHelper(
147 Node* receiver, Node* receiver_map, Node* native_context,
148 ElementsKind packed_kind, ElementsKind holey_kind, Label* done,
149 Label* map_mismatch, Label* bailout) {
150 Node* packed_map =
151 LoadContextElement(native_context, Context::ArrayMapIndex(packed_kind));
152 GotoIf(WordNotEqual(receiver_map, packed_map), map_mismatch);
153 if (AllocationSite::GetMode(packed_kind, holey_kind) ==
154 TRACK_ALLOCATION_SITE) {
155 TrapAllocationMemento(receiver, bailout);
156 }
157 Node* holey_map =
158 LoadContextElement(native_context, Context::ArrayMapIndex(holey_kind));
159 StoreObjectFieldNoWriteBarrier(receiver, JSObject::kMapOffset, holey_map);
Igor Sheludko 2016/11/07 14:43:39 I don't think we can skip write barrier here.
Jakob Kummerow 2016/11/07 16:55:25 Done.
160 Goto(done);
161 }
162
163 void KeyedStoreGenericAssembler::TryChangeToHoleyMap(
164 Node* receiver, Node* receiver_map, Node* current_elements_kind,
165 Node* context, ElementsKind packed_kind, Label* bailout) {
166 ElementsKind holey_kind = GetHoleyElementsKind(packed_kind);
167 Label already_holey(this);
168
169 GotoIf(Word32Equal(current_elements_kind, Int32Constant(holey_kind)),
170 &already_holey);
171 Node* native_context = LoadNativeContext(context);
172 TryChangeToHoleyMapHelper(receiver, receiver_map, native_context, packed_kind,
173 holey_kind, &already_holey, bailout, bailout);
174 Bind(&already_holey);
175 }
176
177 void KeyedStoreGenericAssembler::TryChangeToHoleyMapMulti(
178 Node* receiver, Node* receiver_map, Node* current_elements_kind,
179 Node* context, ElementsKind packed_kind, ElementsKind packed_kind_2,
180 Label* bailout) {
181 ElementsKind holey_kind = GetHoleyElementsKind(packed_kind);
182 ElementsKind holey_kind_2 = GetHoleyElementsKind(packed_kind_2);
183 Label already_holey(this), check_other_kind(this);
184
185 GotoIf(Word32Equal(current_elements_kind, Int32Constant(holey_kind)),
186 &already_holey);
187 GotoIf(Word32Equal(current_elements_kind, Int32Constant(holey_kind_2)),
188 &already_holey);
189
190 Node* native_context = LoadNativeContext(context);
191 TryChangeToHoleyMapHelper(receiver, receiver_map, native_context, packed_kind,
192 holey_kind, &already_holey, &check_other_kind,
193 bailout);
194 Bind(&check_other_kind);
195 TryChangeToHoleyMapHelper(receiver, receiver_map, native_context,
196 packed_kind_2, holey_kind_2, &already_holey,
197 bailout, bailout);
198 Bind(&already_holey);
199 }
200
201 void KeyedStoreGenericAssembler::MaybeUpdateLengthAndReturn(
202 Node* receiver, Node* index, Node* value, UpdateLength update_length) {
203 if (update_length != kDontChangeLength) {
204 Node* new_length = SmiTag(IntPtrAdd(index, IntPtrConstant(1)));
205 StoreObjectFieldNoWriteBarrier(receiver, JSArray::kLengthOffset, new_length,
206 MachineRepresentation::kTagged);
207 }
208 Return(value);
209 }
210
211 void KeyedStoreGenericAssembler::StoreElementWithCapacity(
212 Node* receiver, Node* receiver_map, Node* elements, Node* elements_kind,
213 Node* intptr_index, Node* value, Node* context, Label* slow,
214 UpdateLength update_length) {
215 if (update_length != kDontChangeLength) {
216 CSA_ASSERT(Word32Equal(LoadMapInstanceType(receiver_map),
217 Int32Constant(JS_ARRAY_TYPE)));
218 }
219 STATIC_ASSERT(FixedArray::kHeaderSize == FixedDoubleArray::kHeaderSize);
220 const int kHeaderSize = FixedArray::kHeaderSize - kHeapObjectTag;
221
222 Label check_double_elements(this), check_cow_elements(this);
223 Node* elements_map = LoadMap(elements);
224 GotoIf(WordNotEqual(elements_map, LoadRoot(Heap::kFixedArrayMapRootIndex)),
225 &check_double_elements);
226
227 // FixedArray backing store -> Smi or object elements.
228 {
229 Node* offset = ElementOffsetFromIndex(intptr_index, FAST_ELEMENTS,
230 INTPTR_PARAMETERS, kHeaderSize);
231 // Check if we're about to overwrite the hole. We can safely do that
232 // only if there can be no setters on the prototype chain.
233 // If we know that we're storing beyond the previous array length, we
234 // can skip the hole check (and always assume the hole).
235 {
236 Label hole_check_passed(this);
237 if (update_length == kDontChangeLength) {
238 Node* element = Load(MachineType::AnyTagged(), elements, offset);
239 GotoIf(WordNotEqual(element, TheHoleConstant()), &hole_check_passed);
240 }
241 BranchIfPrototypesHaveNonFastElements(receiver_map, slow,
242 &hole_check_passed);
243 Bind(&hole_check_passed);
244 }
245
246 // Check if the value we're storing matches the elements_kind. Smis
247 // can always be stored.
248 {
249 Label non_smi_value(this);
250 GotoUnless(TaggedIsSmi(value), &non_smi_value);
251 // If we're about to introduce holes, ensure holey elements.
252 if (update_length == kBumpLengthWithGap) {
253 TryChangeToHoleyMapMulti(receiver, receiver_map, elements_kind, context,
254 FAST_SMI_ELEMENTS, FAST_ELEMENTS, slow);
255 }
256 StoreNoWriteBarrier(MachineRepresentation::kTagged, elements, offset,
257 value);
258 MaybeUpdateLengthAndReturn(receiver, intptr_index, value, update_length);
259
260 Bind(&non_smi_value);
261 }
262
263 // Check if we already have object elements; just do the store if so.
264 {
265 Label must_transition(this);
266 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
267 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
268 GotoIf(Int32LessThanOrEqual(elements_kind,
269 Int32Constant(FAST_HOLEY_SMI_ELEMENTS)),
270 &must_transition);
271 if (update_length == kBumpLengthWithGap) {
272 TryChangeToHoleyMap(receiver, receiver_map, elements_kind, context,
273 FAST_ELEMENTS, slow);
274 }
275 Store(MachineRepresentation::kTagged, elements, offset, value);
276 MaybeUpdateLengthAndReturn(receiver, intptr_index, value, update_length);
277
278 Bind(&must_transition);
279 }
280
281 // Transition to the required ElementsKind.
282 {
283 Label transition_to_double(this), transition_to_object(this);
284 Node* native_context = LoadNativeContext(context);
285 Branch(WordEqual(LoadMap(value), LoadRoot(Heap::kHeapNumberMapRootIndex)),
286 &transition_to_double, &transition_to_object);
287 Bind(&transition_to_double);
288 {
289 // If we're adding holes at the end, always transition to a holey
290 // elements kind, otherwise try to remain packed.
291 ElementsKind target_kind = update_length == kBumpLengthWithGap
292 ? FAST_HOLEY_DOUBLE_ELEMENTS
293 : FAST_DOUBLE_ELEMENTS;
294 TryRewriteElements(receiver, receiver_map, elements, native_context,
295 FAST_SMI_ELEMENTS, target_kind, slow);
296 // Reload migrated elements.
297 Node* double_elements = LoadElements(receiver);
298 Node* double_offset = ElementOffsetFromIndex(
299 intptr_index, FAST_DOUBLE_ELEMENTS, INTPTR_PARAMETERS, kHeaderSize);
300 // Make sure we do not store signalling NaNs into double arrays.
301 Node* double_value = Float64SilenceNaN(LoadHeapNumberValue(value));
302 StoreNoWriteBarrier(MachineRepresentation::kFloat64, double_elements,
303 double_offset, double_value);
304 MaybeUpdateLengthAndReturn(receiver, intptr_index, value,
305 update_length);
306 }
307
308 Bind(&transition_to_object);
309 {
310 // If we're adding holes at the end, always transition to a holey
311 // elements kind, otherwise try to remain packed.
312 ElementsKind target_kind = update_length == kBumpLengthWithGap
313 ? FAST_HOLEY_ELEMENTS
314 : FAST_ELEMENTS;
315 TryRewriteElements(receiver, receiver_map, elements, native_context,
316 FAST_SMI_ELEMENTS, target_kind, slow);
317 Store(MachineRepresentation::kTagged, elements, offset, value);
318 MaybeUpdateLengthAndReturn(receiver, intptr_index, value,
319 update_length);
320 }
321 }
322 }
323
324 Bind(&check_double_elements);
325 Node* fixed_double_array_map = LoadRoot(Heap::kFixedDoubleArrayMapRootIndex);
326 GotoIf(WordNotEqual(elements_map, fixed_double_array_map),
327 &check_cow_elements);
328 // FixedDoubleArray backing store -> double elements.
329 {
330 Node* offset = ElementOffsetFromIndex(intptr_index, FAST_DOUBLE_ELEMENTS,
331 INTPTR_PARAMETERS, kHeaderSize);
332 // Check if we're about to overwrite the hole. We can safely do that
333 // only if there can be no setters on the prototype chain.
334 {
335 Label hole_check_passed(this);
336 // If we know that we're storing beyond the previous array length, we
337 // can skip the hole check (and always assume the hole).
338 if (update_length == kDontChangeLength) {
339 Label found_hole(this);
340 LoadDoubleWithHoleCheck(elements, offset, &found_hole,
341 MachineType::None());
342 Goto(&hole_check_passed);
343 Bind(&found_hole);
344 }
345 BranchIfPrototypesHaveNonFastElements(receiver_map, slow,
346 &hole_check_passed);
347 Bind(&hole_check_passed);
348 }
349
350 // Try to store the value as a double.
351 {
352 Label non_number_value(this);
353 Node* double_value = PrepareValueForWrite(value, Representation::Double(),
354 &non_number_value);
355 // Make sure we do not store signalling NaNs into double arrays.
356 double_value = Float64SilenceNaN(double_value);
357 // If we're about to introduce holes, ensure holey elements.
358 if (update_length == kBumpLengthWithGap) {
359 TryChangeToHoleyMap(receiver, receiver_map, elements_kind, context,
360 FAST_DOUBLE_ELEMENTS, slow);
361 }
362 StoreNoWriteBarrier(MachineRepresentation::kFloat64, elements, offset,
363 double_value);
364 MaybeUpdateLengthAndReturn(receiver, intptr_index, value, update_length);
365
366 Bind(&non_number_value);
367 }
368
369 // Transition to object elements.
370 {
371 Node* native_context = LoadNativeContext(context);
372 ElementsKind target_kind = update_length == kBumpLengthWithGap
373 ? FAST_HOLEY_ELEMENTS
374 : FAST_ELEMENTS;
375 TryRewriteElements(receiver, receiver_map, elements, native_context,
376 FAST_DOUBLE_ELEMENTS, target_kind, slow);
377 // Reload migrated elements.
378 Node* fast_elements = LoadElements(receiver);
379 Node* fast_offset = ElementOffsetFromIndex(
380 intptr_index, FAST_ELEMENTS, INTPTR_PARAMETERS, kHeaderSize);
381 Store(MachineRepresentation::kTagged, fast_elements, fast_offset, value);
382 MaybeUpdateLengthAndReturn(receiver, intptr_index, value, update_length);
383 }
384 }
385
386 Bind(&check_cow_elements);
387 {
388 // TODO(jkummerow): Use GrowElementsCapacity instead of bailing out.
389 Goto(slow);
390 }
391 }
392
393 void KeyedStoreGenericAssembler::EmitGenericElementStore(
394 Node* receiver, Node* receiver_map, Node* instance_type, Node* intptr_index,
395 Node* value, Node* context, Label* slow) {
396 Label if_in_bounds(this), if_increment_length_by_one(this),
397 if_bump_length_with_gap(this), if_grow(this), if_nonfast(this),
398 if_typed_array(this), if_dictionary(this);
399 Node* elements = LoadElements(receiver);
400 Node* elements_kind = LoadMapElementsKind(receiver_map);
401 GotoIf(
402 IntPtrGreaterThan(elements_kind, IntPtrConstant(LAST_FAST_ELEMENTS_KIND)),
Igor Sheludko 2016/11/07 14:43:39 s/IntPtr/Int32/ as elements_kind is a 32-bit value
Jakob Kummerow 2016/11/07 16:55:25 Done.
403 &if_nonfast);
404
405 Label if_array(this);
406 GotoIf(Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE)), &if_array);
407 {
408 Node* capacity = SmiUntag(LoadFixedArrayBaseLength(elements));
409 Branch(UintPtrLessThan(intptr_index, capacity), &if_in_bounds, &if_grow);
410 }
411 Bind(&if_array);
412 {
413 Node* length = SmiUntag(LoadJSArrayLength(receiver));
414 GotoIf(UintPtrLessThan(intptr_index, length), &if_in_bounds);
415 Node* capacity = SmiUntag(LoadFixedArrayBaseLength(elements));
416 GotoIf(UintPtrGreaterThanOrEqual(intptr_index, capacity), &if_grow);
417 Branch(WordEqual(intptr_index, length), &if_increment_length_by_one,
418 &if_bump_length_with_gap);
419 }
420
421 Bind(&if_in_bounds);
422 {
423 StoreElementWithCapacity(receiver, receiver_map, elements, elements_kind,
424 intptr_index, value, context, slow,
425 kDontChangeLength);
426 }
427
428 Bind(&if_increment_length_by_one);
429 {
430 StoreElementWithCapacity(receiver, receiver_map, elements, elements_kind,
431 intptr_index, value, context, slow,
432 kIncrementLengthByOne);
433 }
434
435 Bind(&if_bump_length_with_gap);
436 {
437 StoreElementWithCapacity(receiver, receiver_map, elements, elements_kind,
438 intptr_index, value, context, slow,
439 kBumpLengthWithGap);
440 }
441
442 // Out-of-capacity accesses (index >= capacity) jump here. Additionally,
443 // an ElementsKind transition might be necessary.
444 Bind(&if_grow);
445 {
446 Comment("Grow backing store");
447 // TODO(jkummerow): Support inline backing store growth.
448 Goto(slow);
449 }
450
451 // Any ElementsKind > LAST_FAST_ELEMENTS_KIND jumps here for further dispatch.
452 Bind(&if_nonfast);
453 {
454 STATIC_ASSERT(LAST_ELEMENTS_KIND == LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND);
455 GotoIf(IntPtrGreaterThanOrEqual(
Igor Sheludko 2016/11/07 14:43:39 Same here and below
Jakob Kummerow 2016/11/07 16:55:25 Done.
456 elements_kind,
457 IntPtrConstant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND)),
458 &if_typed_array);
459 GotoIf(IntPtrEqual(elements_kind, IntPtrConstant(DICTIONARY_ELEMENTS)),
460 &if_dictionary);
461 Goto(slow);
462 }
463
464 Bind(&if_dictionary);
465 {
466 Comment("Dictionary");
467 // TODO(jkummerow): Support storing to dictionary elements.
468 Goto(slow);
469 }
470
471 Bind(&if_typed_array);
472 {
473 Comment("Typed array");
474 // TODO(jkummerow): Support typed arrays.
475 Goto(slow);
476 }
477 }
478
479 void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
480 Node* receiver, Node* receiver_map, const StoreICParameters* p,
481 Label* slow) {
482 Comment("stub cache probe");
483 // TODO(jkummerow): Don't rely on the stub cache as much.
484 // - existing properties can be overwritten inline (unless readonly).
485 // - for dictionary mode receivers, we can even add properties inline
486 // (unless the prototype chain prevents it).
487 Variable var_handler(this, MachineRepresentation::kTagged);
488 Label found_handler(this, &var_handler), stub_cache_miss(this);
489 TryProbeStubCache(isolate()->store_stub_cache(), receiver, p->name,
490 &found_handler, &var_handler, &stub_cache_miss);
491 Bind(&found_handler);
492 {
493 Comment("KeyedStoreGeneric found handler");
494 HandleStoreICHandlerCase(p, var_handler.value(), slow);
495 }
496 Bind(&stub_cache_miss);
497 {
498 Comment("KeyedStoreGeneric_miss");
499 TailCallRuntime(Runtime::kKeyedStoreIC_Miss, p->context, p->value, p->slot,
500 p->vector, p->receiver, p->name);
501 }
502 }
503
504 void KeyedStoreGenericAssembler::KeyedStoreGeneric(const StoreICParameters* p,
505 LanguageMode language_mode) {
506 Variable var_index(this, MachineType::PointerRepresentation());
507 Label if_index(this), if_unique_name(this), slow(this);
508
509 Node* receiver = p->receiver;
510 GotoIf(TaggedIsSmi(receiver), &slow);
511 Node* receiver_map = LoadMap(receiver);
512 Node* instance_type = LoadMapInstanceType(receiver_map);
513 // Receivers requiring non-standard element accesses (interceptors, access
514 // checks, strings and string wrappers, proxies) are handled in the runtime.
515 GotoIf(Int32LessThanOrEqual(instance_type,
516 Int32Constant(LAST_CUSTOM_ELEMENTS_RECEIVER)),
517 &slow);
518
519 TryToName(p->name, &if_index, &var_index, &if_unique_name, &slow);
520
521 Bind(&if_index);
522 {
523 Comment("integer index");
524 EmitGenericElementStore(receiver, receiver_map, instance_type,
525 var_index.value(), p->value, p->context, &slow);
526 }
527
528 Bind(&if_unique_name);
529 {
530 Comment("key is unique name");
531 EmitGenericPropertyStore(receiver, receiver_map, p, &slow);
532 }
533
534 Bind(&slow);
535 {
536 Comment("KeyedStoreGeneric_slow");
537 TailCallRuntime(Runtime::kSetProperty, p->context, p->receiver, p->name,
538 p->value, SmiConstant(language_mode));
539 }
540 }
541
542 } // namespace internal
543 } // namespace v8
OLDNEW
« src/ic/ic.cc ('K') | « src/ic/keyed-store-generic.h ('k') | src/objects.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698