1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #include "v8.h"
29
30 #if defined(V8_TARGET_ARCH_X64)
31
32 #include "codegen.h"
33 #include "ic-inl.h"
34 #include "runtime.h"
35 #include "stub-cache.h"
36
37 namespace v8 {
38 namespace internal {
39
40 // ----------------------------------------------------------------------------
41 // Static IC stub generators.
42 //
43
44 #define __ ACCESS_MASM(masm)
45
46
GenerateGlobalInstanceTypeCheck(MacroAssembler * masm,Register type,Label * global_object)47 static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
48 Register type,
49 Label* global_object) {
50 // Register usage:
51 // type: holds the receiver instance type on entry.
52 __ cmpb(type, Immediate(JS_GLOBAL_OBJECT_TYPE));
53 __ j(equal, global_object);
54 __ cmpb(type, Immediate(JS_BUILTINS_OBJECT_TYPE));
55 __ j(equal, global_object);
56 __ cmpb(type, Immediate(JS_GLOBAL_PROXY_TYPE));
57 __ j(equal, global_object);
58 }
59
60
61 // Generated code falls through if the receiver is a regular non-global
62 // JS object with slow properties and no interceptors.
GenerateStringDictionaryReceiverCheck(MacroAssembler * masm,Register receiver,Register r0,Register r1,Label * miss)63 static void GenerateStringDictionaryReceiverCheck(MacroAssembler* masm,
64 Register receiver,
65 Register r0,
66 Register r1,
67 Label* miss) {
68 // Register usage:
69 // receiver: holds the receiver on entry and is unchanged.
70 // r0: used to hold receiver instance type.
71 // Holds the property dictionary on fall through.
72 // r1: used to hold receivers map.
73
74 __ JumpIfSmi(receiver, miss);
75
76 // Check that the receiver is a valid JS object.
77 __ movq(r1, FieldOperand(receiver, HeapObject::kMapOffset));
78 __ movb(r0, FieldOperand(r1, Map::kInstanceTypeOffset));
79 __ cmpb(r0, Immediate(FIRST_SPEC_OBJECT_TYPE));
80 __ j(below, miss);
81
82 // If this assert fails, we have to check upper bound too.
83 STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
84
85 GenerateGlobalInstanceTypeCheck(masm, r0, miss);
86
87 // Check for non-global object that requires access check.
88 __ testb(FieldOperand(r1, Map::kBitFieldOffset),
89 Immediate((1 << Map::kIsAccessCheckNeeded) |
90 (1 << Map::kHasNamedInterceptor)));
91 __ j(not_zero, miss);
92
93 __ movq(r0, FieldOperand(receiver, JSObject::kPropertiesOffset));
94 __ CompareRoot(FieldOperand(r0, HeapObject::kMapOffset),
95 Heap::kHashTableMapRootIndex);
96 __ j(not_equal, miss);
97 }
98
99
100
101 // Helper function used to load a property from a dictionary backing storage.
102 // This function may return false negatives, so miss_label
103 // must always call a backup property load that is complete.
104 // This function is safe to call if name is not a symbol, and will jump to
105 // the miss_label in that case.
106 // The generated code assumes that the receiver has slow properties,
107 // is not a global object and does not have interceptors.
GenerateDictionaryLoad(MacroAssembler * masm,Label * miss_label,Register elements,Register name,Register r0,Register r1,Register result)108 static void GenerateDictionaryLoad(MacroAssembler* masm,
109 Label* miss_label,
110 Register elements,
111 Register name,
112 Register r0,
113 Register r1,
114 Register result) {
115 // Register use:
116 //
117 // elements - holds the property dictionary on entry and is unchanged.
118 //
119 // name - holds the name of the property on entry and is unchanged.
120 //
121 // r0 - used to hold the capacity of the property dictionary.
122 //
123 // r1 - used to hold the index into the property dictionary.
124 //
125 // result - holds the result on exit if the load succeeded.
126
127 Label done;
128
129 // Probe the dictionary.
130 StringDictionaryLookupStub::GeneratePositiveLookup(masm,
131 miss_label,
132 &done,
133 elements,
134 name,
135 r0,
136 r1);
137
138 // If probing finds an entry in the dictionary, r0 contains the
139 // index into the dictionary. Check that the value is a normal
140 // property.
141 __ bind(&done);
142 const int kElementsStartOffset =
143 StringDictionary::kHeaderSize +
144 StringDictionary::kElementsStartIndex * kPointerSize;
145 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
146 __ Test(Operand(elements, r1, times_pointer_size,
147 kDetailsOffset - kHeapObjectTag),
148 Smi::FromInt(PropertyDetails::TypeField::kMask));
149 __ j(not_zero, miss_label);
150
151 // Get the value at the masked, scaled index.
152 const int kValueOffset = kElementsStartOffset + kPointerSize;
153 __ movq(result,
154 Operand(elements, r1, times_pointer_size,
155 kValueOffset - kHeapObjectTag));
156 }
157
158
159 // Helper function used to store a property to a dictionary backing
160 // storage. This function may fail to store a property even though it
161 // is in the dictionary, so code at miss_label must always call a
162 // backup property store that is complete. This function is safe to
163 // call if name is not a symbol, and will jump to the miss_label in
164 // that case. The generated code assumes that the receiver has slow
165 // properties, is not a global object and does not have interceptors.
GenerateDictionaryStore(MacroAssembler * masm,Label * miss_label,Register elements,Register name,Register value,Register scratch0,Register scratch1)166 static void GenerateDictionaryStore(MacroAssembler* masm,
167 Label* miss_label,
168 Register elements,
169 Register name,
170 Register value,
171 Register scratch0,
172 Register scratch1) {
173 // Register use:
174 //
175 // elements - holds the property dictionary on entry and is clobbered.
176 //
177 // name - holds the name of the property on entry and is unchanged.
178 //
179 // value - holds the value to store and is unchanged.
180 //
181 // scratch0 - used for index into the property dictionary and is clobbered.
182 //
183 // scratch1 - used to hold the capacity of the property dictionary and is
184 // clobbered.
185 Label done;
186
187 // Probe the dictionary.
188 StringDictionaryLookupStub::GeneratePositiveLookup(masm,
189 miss_label,
190 &done,
191 elements,
192 name,
193 scratch0,
194 scratch1);
195
196 // If probing finds an entry in the dictionary, scratch0 contains the
197 // index into the dictionary. Check that the value is a normal
198 // property that is not read only.
199 __ bind(&done);
200 const int kElementsStartOffset =
201 StringDictionary::kHeaderSize +
202 StringDictionary::kElementsStartIndex * kPointerSize;
203 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
204 const int kTypeAndReadOnlyMask =
205 (PropertyDetails::TypeField::kMask |
206 PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
207 __ Test(Operand(elements,
208 scratch1,
209 times_pointer_size,
210 kDetailsOffset - kHeapObjectTag),
211 Smi::FromInt(kTypeAndReadOnlyMask));
212 __ j(not_zero, miss_label);
213
214 // Store the value at the masked, scaled index.
215 const int kValueOffset = kElementsStartOffset + kPointerSize;
216 __ lea(scratch1, Operand(elements,
217 scratch1,
218 times_pointer_size,
219 kValueOffset - kHeapObjectTag));
220 __ movq(Operand(scratch1, 0), value);
221
222 // Update write barrier. Make sure not to clobber the value.
223 __ movq(scratch0, value);
224 __ RecordWrite(elements, scratch1, scratch0, kDontSaveFPRegs);
225 }
226
227
GenerateArrayLength(MacroAssembler * masm)228 void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
229 // ----------- S t a t e -------------
230 // -- rax : receiver
231 // -- rcx : name
232 // -- rsp[0] : return address
233 // -----------------------------------
234 Label miss;
235
236 StubCompiler::GenerateLoadArrayLength(masm, rax, rdx, &miss);
237 __ bind(&miss);
238 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
239 }
240
241
GenerateStringLength(MacroAssembler * masm,bool support_wrappers)242 void LoadIC::GenerateStringLength(MacroAssembler* masm, bool support_wrappers) {
243 // ----------- S t a t e -------------
244 // -- rax : receiver
245 // -- rcx : name
246 // -- rsp[0] : return address
247 // -----------------------------------
248 Label miss;
249
250 StubCompiler::GenerateLoadStringLength(masm, rax, rdx, rbx, &miss,
251 support_wrappers);
252 __ bind(&miss);
253 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
254 }
255
256
GenerateFunctionPrototype(MacroAssembler * masm)257 void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
258 // ----------- S t a t e -------------
259 // -- rax : receiver
260 // -- rcx : name
261 // -- rsp[0] : return address
262 // -----------------------------------
263 Label miss;
264
265 StubCompiler::GenerateLoadFunctionPrototype(masm, rax, rdx, rbx, &miss);
266 __ bind(&miss);
267 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
268 }
269
270
271 // Checks the receiver for special cases (value type, slow case bits).
272 // Falls through for regular JS object.
GenerateKeyedLoadReceiverCheck(MacroAssembler * masm,Register receiver,Register map,int interceptor_bit,Label * slow)273 static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
274 Register receiver,
275 Register map,
276 int interceptor_bit,
277 Label* slow) {
278 // Register use:
279 // receiver - holds the receiver and is unchanged.
280 // Scratch registers:
281 // map - used to hold the map of the receiver.
282
283 // Check that the object isn't a smi.
284 __ JumpIfSmi(receiver, slow);
285
286 // Check that the object is some kind of JS object EXCEPT JS Value type.
287 // In the case that the object is a value-wrapper object,
288 // we enter the runtime system to make sure that indexing
289 // into string objects work as intended.
290 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
291 __ CmpObjectType(receiver, JS_OBJECT_TYPE, map);
292 __ j(below, slow);
293
294 // Check bit field.
295 __ testb(FieldOperand(map, Map::kBitFieldOffset),
296 Immediate((1 << Map::kIsAccessCheckNeeded) |
297 (1 << interceptor_bit)));
298 __ j(not_zero, slow);
299 }
300
301
302 // Loads an indexed element from a fast case array.
303 // If not_fast_array is NULL, doesn't perform the elements map check.
GenerateFastArrayLoad(MacroAssembler * masm,Register receiver,Register key,Register elements,Register scratch,Register result,Label * not_fast_array,Label * out_of_range)304 static void GenerateFastArrayLoad(MacroAssembler* masm,
305 Register receiver,
306 Register key,
307 Register elements,
308 Register scratch,
309 Register result,
310 Label* not_fast_array,
311 Label* out_of_range) {
312 // Register use:
313 //
314 // receiver - holds the receiver on entry.
315 // Unchanged unless 'result' is the same register.
316 //
317 // key - holds the smi key on entry.
318 // Unchanged unless 'result' is the same register.
319 //
320 // elements - holds the elements of the receiver on exit.
321 //
322 // result - holds the result on exit if the load succeeded.
323 // Allowed to be the the same as 'receiver' or 'key'.
324 // Unchanged on bailout so 'receiver' and 'key' can be safely
325 // used by further computation.
326 //
327 // Scratch registers:
328 //
329 // scratch - used to hold elements of the receiver and the loaded value.
330
331 __ movq(elements, FieldOperand(receiver, JSObject::kElementsOffset));
332 if (not_fast_array != NULL) {
333 // Check that the object is in fast mode and writable.
334 __ CompareRoot(FieldOperand(elements, HeapObject::kMapOffset),
335 Heap::kFixedArrayMapRootIndex);
336 __ j(not_equal, not_fast_array);
337 } else {
338 __ AssertFastElements(elements);
339 }
340 // Check that the key (index) is within bounds.
341 __ SmiCompare(key, FieldOperand(elements, FixedArray::kLengthOffset));
342 // Unsigned comparison rejects negative indices.
343 __ j(above_equal, out_of_range);
344 // Fast case: Do the load.
345 SmiIndex index = masm->SmiToIndex(scratch, key, kPointerSizeLog2);
346 __ movq(scratch, FieldOperand(elements,
347 index.reg,
348 index.scale,
349 FixedArray::kHeaderSize));
350 __ CompareRoot(scratch, Heap::kTheHoleValueRootIndex);
351 // In case the loaded value is the_hole we have to consult GetProperty
352 // to ensure the prototype chain is searched.
353 __ j(equal, out_of_range);
354 if (!result.is(scratch)) {
355 __ movq(result, scratch);
356 }
357 }
358
359
360 // Checks whether a key is an array index string or a symbol string.
361 // Falls through if the key is a symbol.
GenerateKeyStringCheck(MacroAssembler * masm,Register key,Register map,Register hash,Label * index_string,Label * not_symbol)362 static void GenerateKeyStringCheck(MacroAssembler* masm,
363 Register key,
364 Register map,
365 Register hash,
366 Label* index_string,
367 Label* not_symbol) {
368 // Register use:
369 // key - holds the key and is unchanged. Assumed to be non-smi.
370 // Scratch registers:
371 // map - used to hold the map of the key.
372 // hash - used to hold the hash of the key.
373 __ CmpObjectType(key, FIRST_NONSTRING_TYPE, map);
374 __ j(above_equal, not_symbol);
375 // Is the string an array index, with cached numeric value?
376 __ movl(hash, FieldOperand(key, String::kHashFieldOffset));
377 __ testl(hash, Immediate(String::kContainsCachedArrayIndexMask));
378 __ j(zero, index_string); // The value in hash is used at jump target.
379
380 // Is the string a symbol?
381 STATIC_ASSERT(kSymbolTag != 0);
382 __ testb(FieldOperand(map, Map::kInstanceTypeOffset),
383 Immediate(kIsSymbolMask));
384 __ j(zero, not_symbol);
385 }
386
387
388
GenerateGeneric(MacroAssembler * masm)389 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
390 // ----------- S t a t e -------------
391 // -- rax : key
392 // -- rdx : receiver
393 // -- rsp[0] : return address
394 // -----------------------------------
395 Label slow, check_string, index_smi, index_string, property_array_property;
396 Label probe_dictionary, check_number_dictionary;
397
398 // Check that the key is a smi.
399 __ JumpIfNotSmi(rax, &check_string);
400 __ bind(&index_smi);
401 // Now the key is known to be a smi. This place is also jumped to from below
402 // where a numeric string is converted to a smi.
403
404 GenerateKeyedLoadReceiverCheck(
405 masm, rdx, rcx, Map::kHasIndexedInterceptor, &slow);
406
407 // Check the receiver's map to see if it has fast elements.
408 __ CheckFastElements(rcx, &check_number_dictionary);
409
410 GenerateFastArrayLoad(masm,
411 rdx,
412 rax,
413 rcx,
414 rbx,
415 rax,
416 NULL,
417 &slow);
418 Counters* counters = masm->isolate()->counters();
419 __ IncrementCounter(counters->keyed_load_generic_smi(), 1);
420 __ ret(0);
421
422 __ bind(&check_number_dictionary);
423 __ SmiToInteger32(rbx, rax);
424 __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
425
426 // Check whether the elements is a number dictionary.
427 // rdx: receiver
428 // rax: key
429 // rbx: key as untagged int32
430 // rcx: elements
431 __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset),
432 Heap::kHashTableMapRootIndex);
433 __ j(not_equal, &slow);
434 __ LoadFromNumberDictionary(&slow, rcx, rax, rbx, r9, rdi, rax);
435 __ ret(0);
436
437 __ bind(&slow);
438 // Slow case: Jump to runtime.
439 // rdx: receiver
440 // rax: key
441 __ IncrementCounter(counters->keyed_load_generic_slow(), 1);
442 GenerateRuntimeGetProperty(masm);
443
444 __ bind(&check_string);
445 GenerateKeyStringCheck(masm, rax, rcx, rbx, &index_string, &slow);
446
447 GenerateKeyedLoadReceiverCheck(
448 masm, rdx, rcx, Map::kHasNamedInterceptor, &slow);
449
450 // If the receiver is a fast-case object, check the keyed lookup
451 // cache. Otherwise probe the dictionary leaving result in rcx.
452 __ movq(rbx, FieldOperand(rdx, JSObject::kPropertiesOffset));
453 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
454 Heap::kHashTableMapRootIndex);
455 __ j(equal, &probe_dictionary);
456
457 // Load the map of the receiver, compute the keyed lookup cache hash
458 // based on 32 bits of the map pointer and the string hash.
459 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
460 __ movl(rcx, rbx);
461 __ shr(rcx, Immediate(KeyedLookupCache::kMapHashShift));
462 __ movl(rdi, FieldOperand(rax, String::kHashFieldOffset));
463 __ shr(rdi, Immediate(String::kHashShift));
464 __ xor_(rcx, rdi);
465 int mask = (KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask);
466 __ and_(rcx, Immediate(mask));
467
468 // Load the key (consisting of map and symbol) from the cache and
469 // check for match.
470 Label load_in_object_property;
471 static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket;
472 Label hit_on_nth_entry[kEntriesPerBucket];
473 ExternalReference cache_keys
474 = ExternalReference::keyed_lookup_cache_keys(masm->isolate());
475
476 for (int i = 0; i < kEntriesPerBucket - 1; i++) {
477 Label try_next_entry;
478 __ movq(rdi, rcx);
479 __ shl(rdi, Immediate(kPointerSizeLog2 + 1));
480 __ LoadAddress(kScratchRegister, cache_keys);
481 int off = kPointerSize * i * 2;
482 __ cmpq(rbx, Operand(kScratchRegister, rdi, times_1, off));
483 __ j(not_equal, &try_next_entry);
484 __ cmpq(rax, Operand(kScratchRegister, rdi, times_1, off + kPointerSize));
485 __ j(equal, &hit_on_nth_entry[i]);
486 __ bind(&try_next_entry);
487 }
488
489 int off = kPointerSize * (kEntriesPerBucket - 1) * 2;
490 __ cmpq(rbx, Operand(kScratchRegister, rdi, times_1, off));
491 __ j(not_equal, &slow);
492 __ cmpq(rax, Operand(kScratchRegister, rdi, times_1, off + kPointerSize));
493 __ j(not_equal, &slow);
494
495 // Get field offset, which is a 32-bit integer.
496 ExternalReference cache_field_offsets
497 = ExternalReference::keyed_lookup_cache_field_offsets(masm->isolate());
498
499 // Hit on nth entry.
500 for (int i = kEntriesPerBucket - 1; i >= 0; i--) {
501 __ bind(&hit_on_nth_entry[i]);
502 if (i != 0) {
503 __ addl(rcx, Immediate(i));
504 }
505 __ LoadAddress(kScratchRegister, cache_field_offsets);
506 __ movl(rdi, Operand(kScratchRegister, rcx, times_4, 0));
507 __ movzxbq(rcx, FieldOperand(rbx, Map::kInObjectPropertiesOffset));
508 __ subq(rdi, rcx);
509 __ j(above_equal, &property_array_property);
510 if (i != 0) {
511 __ jmp(&load_in_object_property);
512 }
513 }
514
515 // Load in-object property.
516 __ bind(&load_in_object_property);
517 __ movzxbq(rcx, FieldOperand(rbx, Map::kInstanceSizeOffset));
518 __ addq(rcx, rdi);
519 __ movq(rax, FieldOperand(rdx, rcx, times_pointer_size, 0));
520 __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1);
521 __ ret(0);
522
523 // Load property array property.
524 __ bind(&property_array_property);
525 __ movq(rax, FieldOperand(rdx, JSObject::kPropertiesOffset));
526 __ movq(rax, FieldOperand(rax, rdi, times_pointer_size,
527 FixedArray::kHeaderSize));
528 __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1);
529 __ ret(0);
530
531 // Do a quick inline probe of the receiver's dictionary, if it
532 // exists.
533 __ bind(&probe_dictionary);
534 // rdx: receiver
535 // rax: key
536 // rbx: elements
537
538 __ movq(rcx, FieldOperand(rdx, JSObject::kMapOffset));
539 __ movb(rcx, FieldOperand(rcx, Map::kInstanceTypeOffset));
540 GenerateGlobalInstanceTypeCheck(masm, rcx, &slow);
541
542 GenerateDictionaryLoad(masm, &slow, rbx, rax, rcx, rdi, rax);
543 __ IncrementCounter(counters->keyed_load_generic_symbol(), 1);
544 __ ret(0);
545
546 __ bind(&index_string);
547 __ IndexFromHash(rbx, rax);
548 __ jmp(&index_smi);
549 }
550
551
GenerateString(MacroAssembler * masm)552 void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
553 // ----------- S t a t e -------------
554 // -- rax : key
555 // -- rdx : receiver
556 // -- rsp[0] : return address
557 // -----------------------------------
558 Label miss;
559
560 Register receiver = rdx;
561 Register index = rax;
562 Register scratch = rcx;
563 Register result = rax;
564
565 StringCharAtGenerator char_at_generator(receiver,
566 index,
567 scratch,
568 result,
569 &miss, // When not a string.
570 &miss, // When not a number.
571 &miss, // When index out of range.
572 STRING_INDEX_IS_ARRAY_INDEX);
573 char_at_generator.GenerateFast(masm);
574 __ ret(0);
575
576 StubRuntimeCallHelper call_helper;
577 char_at_generator.GenerateSlow(masm, call_helper);
578
579 __ bind(&miss);
580 GenerateMiss(masm, false);
581 }
582
583
GenerateIndexedInterceptor(MacroAssembler * masm)584 void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
585 // ----------- S t a t e -------------
586 // -- rax : key
587 // -- rdx : receiver
588 // -- rsp[0] : return address
589 // -----------------------------------
590 Label slow;
591
592 // Check that the receiver isn't a smi.
593 __ JumpIfSmi(rdx, &slow);
594
595 // Check that the key is an array index, that is Uint32.
596 STATIC_ASSERT(kSmiValueSize <= 32);
597 __ JumpUnlessNonNegativeSmi(rax, &slow);
598
599 // Get the map of the receiver.
600 __ movq(rcx, FieldOperand(rdx, HeapObject::kMapOffset));
601
602 // Check that it has indexed interceptor and access checks
603 // are not enabled for this object.
604 __ movb(rcx, FieldOperand(rcx, Map::kBitFieldOffset));
605 __ andb(rcx, Immediate(kSlowCaseBitFieldMask));
606 __ cmpb(rcx, Immediate(1 << Map::kHasIndexedInterceptor));
607 __ j(not_zero, &slow);
608
609 // Everything is fine, call runtime.
610 __ pop(rcx);
611 __ push(rdx); // receiver
612 __ push(rax); // key
613 __ push(rcx); // return address
614
615 // Perform tail call to the entry.
616 __ TailCallExternalReference(
617 ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor),
618 masm->isolate()),
619 2,
620 1);
621
622 __ bind(&slow);
623 GenerateMiss(masm, false);
624 }
625
626
GenerateGeneric(MacroAssembler * masm,StrictModeFlag strict_mode)627 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
628 StrictModeFlag strict_mode) {
629 // ----------- S t a t e -------------
630 // -- rax : value
631 // -- rcx : key
632 // -- rdx : receiver
633 // -- rsp[0] : return address
634 // -----------------------------------
635 Label slow, slow_with_tagged_index, fast, array, extra, check_extra_double;
636 Label fast_object_with_map_check, fast_object_without_map_check;
637 Label fast_double_with_map_check, fast_double_without_map_check;
638 Label transition_smi_elements, finish_object_store, non_double_value;
639 Label transition_double_elements;
640
641 // Check that the object isn't a smi.
642 __ JumpIfSmi(rdx, &slow_with_tagged_index);
643 // Get the map from the receiver.
644 __ movq(r9, FieldOperand(rdx, HeapObject::kMapOffset));
645 // Check that the receiver does not require access checks. We need
646 // to do this because this generic stub does not perform map checks.
647 __ testb(FieldOperand(r9, Map::kBitFieldOffset),
648 Immediate(1 << Map::kIsAccessCheckNeeded));
649 __ j(not_zero, &slow_with_tagged_index);
650 // Check that the key is a smi.
651 __ JumpIfNotSmi(rcx, &slow_with_tagged_index);
652 __ SmiToInteger32(rcx, rcx);
653
654 __ CmpInstanceType(r9, JS_ARRAY_TYPE);
655 __ j(equal, &array);
656 // Check that the object is some kind of JSObject.
657 __ CmpInstanceType(r9, FIRST_JS_OBJECT_TYPE);
658 __ j(below, &slow);
659
660 // Object case: Check key against length in the elements array.
661 // rax: value
662 // rdx: JSObject
663 // rcx: index
664 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
665 // Check array bounds.
666 __ SmiCompareInteger32(FieldOperand(rbx, FixedArray::kLengthOffset), rcx);
667 // rax: value
668 // rbx: FixedArray
669 // rcx: index
670 __ j(above, &fast_object_with_map_check);
671
672 // Slow case: call runtime.
673 __ bind(&slow);
674 __ Integer32ToSmi(rcx, rcx);
675 __ bind(&slow_with_tagged_index);
676 GenerateRuntimeSetProperty(masm, strict_mode);
677 // Never returns to here.
678
679 // Extra capacity case: Check if there is extra capacity to
680 // perform the store and update the length. Used for adding one
681 // element to the array by writing to array[array.length].
682 __ bind(&extra);
683 // rax: value
684 // rdx: receiver (a JSArray)
685 // rbx: receiver's elements array (a FixedArray)
686 // rcx: index
687 // flags: smicompare (rdx.length(), rbx)
688 __ j(not_equal, &slow); // do not leave holes in the array
689 __ SmiCompareInteger32(FieldOperand(rbx, FixedArray::kLengthOffset), rcx);
690 __ j(below_equal, &slow);
691 // Increment index to get new length.
692 __ movq(rdi, FieldOperand(rbx, HeapObject::kMapOffset));
693 __ CompareRoot(rdi, Heap::kFixedArrayMapRootIndex);
694 __ j(not_equal, &check_extra_double);
695 __ leal(rdi, Operand(rcx, 1));
696 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi);
697 __ jmp(&fast_object_without_map_check);
698
699 __ bind(&check_extra_double);
700 // rdi: elements array's map
701 __ CompareRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex);
702 __ j(not_equal, &slow);
703 __ leal(rdi, Operand(rcx, 1));
704 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi);
705 __ jmp(&fast_double_without_map_check);
706
707 // Array case: Get the length and the elements array from the JS
708 // array. Check that the array is in fast mode (and writable); if it
709 // is the length is always a smi.
710 __ bind(&array);
711 // rax: value
712 // rdx: receiver (a JSArray)
713 // rcx: index
714 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
715
716 // Check the key against the length in the array, compute the
717 // address to store into and fall through to fast case.
718 __ SmiCompareInteger32(FieldOperand(rdx, JSArray::kLengthOffset), rcx);
719 __ j(below_equal, &extra);
720
721 // Fast case: Do the store.
722 __ bind(&fast_object_with_map_check);
723 // rax: value
724 // rbx: receiver's elements array (a FixedArray)
725 // rcx: index
726 // rdx: receiver (a JSArray)
727 __ movq(rdi, FieldOperand(rbx, HeapObject::kMapOffset));
728 __ CompareRoot(rdi, Heap::kFixedArrayMapRootIndex);
729 __ j(not_equal, &fast_double_with_map_check);
730 __ bind(&fast_object_without_map_check);
731 // Smi stores don't require further checks.
732 Label non_smi_value;
733 __ JumpIfNotSmi(rax, &non_smi_value);
734 // It's irrelevant whether array is smi-only or not when writing a smi.
735 __ movq(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize),
736 rax);
737 __ ret(0);
738
739 __ bind(&non_smi_value);
740 // Writing a non-smi, check whether array allows non-smi elements.
741 // r9: receiver's map
742 __ CheckFastObjectElements(r9, &transition_smi_elements);
743 __ bind(&finish_object_store);
744 __ movq(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize),
745 rax);
746 __ movq(rdx, rax); // Preserve the value which is returned.
747 __ RecordWriteArray(
748 rbx, rdx, rcx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
749 __ ret(0);
750
751 __ bind(&fast_double_with_map_check);
752 // Check for fast double array case. If this fails, call through to the
753 // runtime.
754 // rdi: elements array's map
755 __ CompareRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex);
756 __ j(not_equal, &slow);
757 __ bind(&fast_double_without_map_check);
758 // If the value is a number, store it as a double in the FastDoubleElements
759 // array.
760 __ StoreNumberToDoubleElements(rax, rbx, rcx, xmm0,
761 &transition_double_elements);
762 __ ret(0);
763
764 __ bind(&transition_smi_elements);
765 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
766
767 // Transition the array appropriately depending on the value type.
768 __ movq(r9, FieldOperand(rax, HeapObject::kMapOffset));
769 __ CompareRoot(r9, Heap::kHeapNumberMapRootIndex);
770 __ j(not_equal, &non_double_value);
771
772 // Value is a double. Transition FAST_SMI_ONLY_ELEMENTS ->
773 // FAST_DOUBLE_ELEMENTS and complete the store.
774 __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
775 FAST_DOUBLE_ELEMENTS,
776 rbx,
777 rdi,
778 &slow);
779 ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &slow);
780 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
781 __ jmp(&fast_double_without_map_check);
782
783 __ bind(&non_double_value);
784 // Value is not a double, FAST_SMI_ONLY_ELEMENTS -> FAST_ELEMENTS
785 __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
786 FAST_ELEMENTS,
787 rbx,
788 rdi,
789 &slow);
790 ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm);
791 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
792 __ jmp(&finish_object_store);
793
794 __ bind(&transition_double_elements);
795 // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
796 // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
797 // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
798 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
799 __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
800 FAST_ELEMENTS,
801 rbx,
802 rdi,
803 &slow);
804 ElementsTransitionGenerator::GenerateDoubleToObject(masm, &slow);
805 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
806 __ jmp(&finish_object_store);
807 }
808
809
810 // The generated code does not accept smi keys.
811 // The generated code falls through if both probes miss.
GenerateMonomorphicCacheProbe(MacroAssembler * masm,int argc,Code::Kind kind,Code::ExtraICState extra_state)812 void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm,
813 int argc,
814 Code::Kind kind,
815 Code::ExtraICState extra_state) {
816 // ----------- S t a t e -------------
817 // rcx : function name
818 // rdx : receiver
819 // -----------------------------------
820 Label number, non_number, non_string, boolean, probe, miss;
821
822 // Probe the stub cache.
823 Code::Flags flags = Code::ComputeFlags(kind,
824 MONOMORPHIC,
825 extra_state,
826 NORMAL,
827 argc);
828 Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, rdx, rcx, rbx,
829 rax);
830
831 // If the stub cache probing failed, the receiver might be a value.
832 // For value objects, we use the map of the prototype objects for
833 // the corresponding JSValue for the cache and that is what we need
834 // to probe.
835 //
836 // Check for number.
837 __ JumpIfSmi(rdx, &number);
838 __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rbx);
839 __ j(not_equal, &non_number);
840 __ bind(&number);
841 StubCompiler::GenerateLoadGlobalFunctionPrototype(
842 masm, Context::NUMBER_FUNCTION_INDEX, rdx);
843 __ jmp(&probe);
844
845 // Check for string.
846 __ bind(&non_number);
847 __ CmpInstanceType(rbx, FIRST_NONSTRING_TYPE);
848 __ j(above_equal, &non_string);
849 StubCompiler::GenerateLoadGlobalFunctionPrototype(
850 masm, Context::STRING_FUNCTION_INDEX, rdx);
851 __ jmp(&probe);
852
853 // Check for boolean.
854 __ bind(&non_string);
855 __ CompareRoot(rdx, Heap::kTrueValueRootIndex);
856 __ j(equal, &boolean);
857 __ CompareRoot(rdx, Heap::kFalseValueRootIndex);
858 __ j(not_equal, &miss);
859 __ bind(&boolean);
860 StubCompiler::GenerateLoadGlobalFunctionPrototype(
861 masm, Context::BOOLEAN_FUNCTION_INDEX, rdx);
862
863 // Probe the stub cache for the value object.
864 __ bind(&probe);
865 Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, rdx, rcx, rbx,
866 no_reg);
867
868 __ bind(&miss);
869 }
870
871
GenerateFunctionTailCall(MacroAssembler * masm,int argc,Label * miss)872 static void GenerateFunctionTailCall(MacroAssembler* masm,
873 int argc,
874 Label* miss) {
875 // ----------- S t a t e -------------
876 // rcx : function name
877 // rdi : function
878 // rsp[0] : return address
879 // rsp[8] : argument argc
880 // rsp[16] : argument argc - 1
881 // ...
882 // rsp[argc * 8] : argument 1
883 // rsp[(argc + 1) * 8] : argument 0 = receiver
884 // -----------------------------------
885 __ JumpIfSmi(rdi, miss);
886 // Check that the value is a JavaScript function.
887 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rdx);
888 __ j(not_equal, miss);
889
890 // Invoke the function.
891 ParameterCount actual(argc);
892 __ InvokeFunction(rdi, actual, JUMP_FUNCTION,
893 NullCallWrapper(), CALL_AS_METHOD);
894 }
895
896
897 // The generated code falls through if the call should be handled by runtime.
GenerateNormal(MacroAssembler * masm,int argc)898 void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) {
899 // ----------- S t a t e -------------
900 // rcx : function name
901 // rsp[0] : return address
902 // rsp[8] : argument argc
903 // rsp[16] : argument argc - 1
904 // ...
905 // rsp[argc * 8] : argument 1
906 // rsp[(argc + 1) * 8] : argument 0 = receiver
907 // -----------------------------------
908 Label miss;
909
910 // Get the receiver of the function from the stack.
911 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
912
913 GenerateStringDictionaryReceiverCheck(masm, rdx, rax, rbx, &miss);
914
915 // rax: elements
916 // Search the dictionary placing the result in rdi.
917 GenerateDictionaryLoad(masm, &miss, rax, rcx, rbx, rdi, rdi);
918
919 GenerateFunctionTailCall(masm, argc, &miss);
920
921 __ bind(&miss);
922 }
923
924
GenerateMiss(MacroAssembler * masm,int argc,IC::UtilityId id,Code::ExtraICState extra_state)925 void CallICBase::GenerateMiss(MacroAssembler* masm,
926 int argc,
927 IC::UtilityId id,
928 Code::ExtraICState extra_state) {
929 // ----------- S t a t e -------------
930 // rcx : function name
931 // rsp[0] : return address
932 // rsp[8] : argument argc
933 // rsp[16] : argument argc - 1
934 // ...
935 // rsp[argc * 8] : argument 1
936 // rsp[(argc + 1) * 8] : argument 0 = receiver
937 // -----------------------------------
938
939 Counters* counters = masm->isolate()->counters();
940 if (id == IC::kCallIC_Miss) {
941 __ IncrementCounter(counters->call_miss(), 1);
942 } else {
943 __ IncrementCounter(counters->keyed_call_miss(), 1);
944 }
945
946 // Get the receiver of the function from the stack; 1 ~ return address.
947 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
948
949 // Enter an internal frame.
950 {
951 FrameScope scope(masm, StackFrame::INTERNAL);
952
953 // Push the receiver and the name of the function.
954 __ push(rdx);
955 __ push(rcx);
956
957 // Call the entry.
958 CEntryStub stub(1);
959 __ Set(rax, 2);
960 __ LoadAddress(rbx, ExternalReference(IC_Utility(id), masm->isolate()));
961 __ CallStub(&stub);
962
963 // Move result to rdi and exit the internal frame.
964 __ movq(rdi, rax);
965 }
966
967 // Check if the receiver is a global object of some sort.
968 // This can happen only for regular CallIC but not KeyedCallIC.
969 if (id == IC::kCallIC_Miss) {
970 Label invoke, global;
971 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); // receiver
972 __ JumpIfSmi(rdx, &invoke);
973 __ CmpObjectType(rdx, JS_GLOBAL_OBJECT_TYPE, rcx);
974 __ j(equal, &global);
975 __ CmpInstanceType(rcx, JS_BUILTINS_OBJECT_TYPE);
976 __ j(not_equal, &invoke);
977
978 // Patch the receiver on the stack.
979 __ bind(&global);
980 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
981 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
982 __ bind(&invoke);
983 }
984
985 // Invoke the function.
986 CallKind call_kind = CallICBase::Contextual::decode(extra_state)
987 ? CALL_AS_FUNCTION
988 : CALL_AS_METHOD;
989 ParameterCount actual(argc);
990 __ InvokeFunction(rdi,
991 actual,
992 JUMP_FUNCTION,
993 NullCallWrapper(),
994 call_kind);
995 }
996
997
GenerateMegamorphic(MacroAssembler * masm,int argc,Code::ExtraICState extra_ic_state)998 void CallIC::GenerateMegamorphic(MacroAssembler* masm,
999 int argc,
1000 Code::ExtraICState extra_ic_state) {
1001 // ----------- S t a t e -------------
1002 // rcx : function name
1003 // rsp[0] : return address
1004 // rsp[8] : argument argc
1005 // rsp[16] : argument argc - 1
1006 // ...
1007 // rsp[argc * 8] : argument 1
1008 // rsp[(argc + 1) * 8] : argument 0 = receiver
1009 // -----------------------------------
1010
1011 // Get the receiver of the function from the stack; 1 ~ return address.
1012 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
1013 GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC, extra_ic_state);
1014 GenerateMiss(masm, argc, extra_ic_state);
1015 }
1016
1017
GenerateMegamorphic(MacroAssembler * masm,int argc)1018 void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
1019 // ----------- S t a t e -------------
1020 // rcx : function name
1021 // rsp[0] : return address
1022 // rsp[8] : argument argc
1023 // rsp[16] : argument argc - 1
1024 // ...
1025 // rsp[argc * 8] : argument 1
1026 // rsp[(argc + 1) * 8] : argument 0 = receiver
1027 // -----------------------------------
1028
1029 // Get the receiver of the function from the stack; 1 ~ return address.
1030 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
1031
1032 Label do_call, slow_call, slow_load;
1033 Label check_number_dictionary, check_string, lookup_monomorphic_cache;
1034 Label index_smi, index_string;
1035
1036 // Check that the key is a smi.
1037 __ JumpIfNotSmi(rcx, &check_string);
1038
1039 __ bind(&index_smi);
1040 // Now the key is known to be a smi. This place is also jumped to from below
1041 // where a numeric string is converted to a smi.
1042
1043 GenerateKeyedLoadReceiverCheck(
1044 masm, rdx, rax, Map::kHasIndexedInterceptor, &slow_call);
1045
1046 GenerateFastArrayLoad(
1047 masm, rdx, rcx, rax, rbx, rdi, &check_number_dictionary, &slow_load);
1048 Counters* counters = masm->isolate()->counters();
1049 __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1);
1050
1051 __ bind(&do_call);
1052 // receiver in rdx is not used after this point.
1053 // rcx: key
1054 // rdi: function
1055 GenerateFunctionTailCall(masm, argc, &slow_call);
1056
1057 __ bind(&check_number_dictionary);
1058 // rax: elements
1059 // rcx: smi key
1060 // Check whether the elements is a number dictionary.
1061 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
1062 Heap::kHashTableMapRootIndex);
1063 __ j(not_equal, &slow_load);
1064 __ SmiToInteger32(rbx, rcx);
1065 // ebx: untagged index
1066 __ LoadFromNumberDictionary(&slow_load, rax, rcx, rbx, r9, rdi, rdi);
1067 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1);
1068 __ jmp(&do_call);
1069
1070 __ bind(&slow_load);
1071 // This branch is taken when calling KeyedCallIC_Miss is neither required
1072 // nor beneficial.
1073 __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1);
1074 {
1075 FrameScope scope(masm, StackFrame::INTERNAL);
1076 __ push(rcx); // save the key
1077 __ push(rdx); // pass the receiver
1078 __ push(rcx); // pass the key
1079 __ CallRuntime(Runtime::kKeyedGetProperty, 2);
1080 __ pop(rcx); // restore the key
1081 }
1082 __ movq(rdi, rax);
1083 __ jmp(&do_call);
1084
1085 __ bind(&check_string);
1086 GenerateKeyStringCheck(masm, rcx, rax, rbx, &index_string, &slow_call);
1087
1088 // The key is known to be a symbol.
1089 // If the receiver is a regular JS object with slow properties then do
1090 // a quick inline probe of the receiver's dictionary.
1091 // Otherwise do the monomorphic cache probe.
1092 GenerateKeyedLoadReceiverCheck(
1093 masm, rdx, rax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
1094
1095 __ movq(rbx, FieldOperand(rdx, JSObject::kPropertiesOffset));
1096 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
1097 Heap::kHashTableMapRootIndex);
1098 __ j(not_equal, &lookup_monomorphic_cache);
1099
1100 GenerateDictionaryLoad(masm, &slow_load, rbx, rcx, rax, rdi, rdi);
1101 __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1);
1102 __ jmp(&do_call);
1103
1104 __ bind(&lookup_monomorphic_cache);
1105 __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1);
1106 GenerateMonomorphicCacheProbe(masm,
1107 argc,
1108 Code::KEYED_CALL_IC,
1109 Code::kNoExtraICState);
1110 // Fall through on miss.
1111
1112 __ bind(&slow_call);
1113 // This branch is taken if:
1114 // - the receiver requires boxing or access check,
1115 // - the key is neither smi nor symbol,
1116 // - the value loaded is not a function,
1117 // - there is hope that the runtime will create a monomorphic call stub
1118 // that will get fetched next time.
1119 __ IncrementCounter(counters->keyed_call_generic_slow(), 1);
1120 GenerateMiss(masm, argc);
1121
1122 __ bind(&index_string);
1123 __ IndexFromHash(rbx, rcx);
1124 // Now jump to the place where smi keys are handled.
1125 __ jmp(&index_smi);
1126 }
1127
1128
GenerateNormal(MacroAssembler * masm,int argc)1129 void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
1130 // ----------- S t a t e -------------
1131 // rcx : function name
1132 // rsp[0] : return address
1133 // rsp[8] : argument argc
1134 // rsp[16] : argument argc - 1
1135 // ...
1136 // rsp[argc * 8] : argument 1
1137 // rsp[(argc + 1) * 8] : argument 0 = receiver
1138 // -----------------------------------
1139
1140 // Check if the name is a string.
1141 Label miss;
1142 __ JumpIfSmi(rcx, &miss);
1143 Condition cond = masm->IsObjectStringType(rcx, rax, rax);
1144 __ j(NegateCondition(cond), &miss);
1145 CallICBase::GenerateNormal(masm, argc);
1146 __ bind(&miss);
1147 GenerateMiss(masm, argc);
1148 }
1149
1150
GenerateMappedArgumentsLookup(MacroAssembler * masm,Register object,Register key,Register scratch1,Register scratch2,Register scratch3,Label * unmapped_case,Label * slow_case)1151 static Operand GenerateMappedArgumentsLookup(MacroAssembler* masm,
1152 Register object,
1153 Register key,
1154 Register scratch1,
1155 Register scratch2,
1156 Register scratch3,
1157 Label* unmapped_case,
1158 Label* slow_case) {
1159 Heap* heap = masm->isolate()->heap();
1160
1161 // Check that the receiver is a JSObject. Because of the elements
1162 // map check later, we do not need to check for interceptors or
1163 // whether it requires access checks.
1164 __ JumpIfSmi(object, slow_case);
1165 // Check that the object is some kind of JSObject.
1166 __ CmpObjectType(object, FIRST_JS_RECEIVER_TYPE, scratch1);
1167 __ j(below, slow_case);
1168
1169 // Check that the key is a positive smi.
1170 Condition check = masm->CheckNonNegativeSmi(key);
1171 __ j(NegateCondition(check), slow_case);
1172
1173 // Load the elements into scratch1 and check its map. If not, jump
1174 // to the unmapped lookup with the parameter map in scratch1.
1175 Handle<Map> arguments_map(heap->non_strict_arguments_elements_map());
1176 __ movq(scratch1, FieldOperand(object, JSObject::kElementsOffset));
1177 __ CheckMap(scratch1, arguments_map, slow_case, DONT_DO_SMI_CHECK);
1178
1179 // Check if element is in the range of mapped arguments.
1180 __ movq(scratch2, FieldOperand(scratch1, FixedArray::kLengthOffset));
1181 __ SmiSubConstant(scratch2, scratch2, Smi::FromInt(2));
1182 __ cmpq(key, scratch2);
1183 __ j(greater_equal, unmapped_case);
1184
1185 // Load element index and check whether it is the hole.
1186 const int kHeaderSize = FixedArray::kHeaderSize + 2 * kPointerSize;
1187 __ SmiToInteger64(scratch3, key);
1188 __ movq(scratch2, FieldOperand(scratch1,
1189 scratch3,
1190 times_pointer_size,
1191 kHeaderSize));
1192 __ CompareRoot(scratch2, Heap::kTheHoleValueRootIndex);
1193 __ j(equal, unmapped_case);
1194
1195 // Load value from context and return it. We can reuse scratch1 because
1196 // we do not jump to the unmapped lookup (which requires the parameter
1197 // map in scratch1).
1198 __ movq(scratch1, FieldOperand(scratch1, FixedArray::kHeaderSize));
1199 __ SmiToInteger64(scratch3, scratch2);
1200 return FieldOperand(scratch1,
1201 scratch3,
1202 times_pointer_size,
1203 Context::kHeaderSize);
1204 }
1205
1206
GenerateUnmappedArgumentsLookup(MacroAssembler * masm,Register key,Register parameter_map,Register scratch,Label * slow_case)1207 static Operand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
1208 Register key,
1209 Register parameter_map,
1210 Register scratch,
1211 Label* slow_case) {
1212 // Element is in arguments backing store, which is referenced by the
1213 // second element of the parameter_map. The parameter_map register
1214 // must be loaded with the parameter map of the arguments object and is
1215 // overwritten.
1216 const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize;
1217 Register backing_store = parameter_map;
1218 __ movq(backing_store, FieldOperand(parameter_map, kBackingStoreOffset));
1219 Handle<Map> fixed_array_map(masm->isolate()->heap()->fixed_array_map());
1220 __ CheckMap(backing_store, fixed_array_map, slow_case, DONT_DO_SMI_CHECK);
1221 __ movq(scratch, FieldOperand(backing_store, FixedArray::kLengthOffset));
1222 __ cmpq(key, scratch);
1223 __ j(greater_equal, slow_case);
1224 __ SmiToInteger64(scratch, key);
1225 return FieldOperand(backing_store,
1226 scratch,
1227 times_pointer_size,
1228 FixedArray::kHeaderSize);
1229 }
1230
1231
GenerateNonStrictArguments(MacroAssembler * masm)1232 void KeyedLoadIC::GenerateNonStrictArguments(MacroAssembler* masm) {
1233 // ----------- S t a t e -------------
1234 // -- rax : key
1235 // -- rdx : receiver
1236 // -- rsp[0] : return address
1237 // -----------------------------------
1238 Label slow, notin;
1239 Operand mapped_location =
1240 GenerateMappedArgumentsLookup(
1241 masm, rdx, rax, rbx, rcx, rdi, ¬in, &slow);
1242 __ movq(rax, mapped_location);
1243 __ Ret();
1244 __ bind(¬in);
1245 // The unmapped lookup expects that the parameter map is in rbx.
1246 Operand unmapped_location =
1247 GenerateUnmappedArgumentsLookup(masm, rax, rbx, rcx, &slow);
1248 __ CompareRoot(unmapped_location, Heap::kTheHoleValueRootIndex);
1249 __ j(equal, &slow);
1250 __ movq(rax, unmapped_location);
1251 __ Ret();
1252 __ bind(&slow);
1253 GenerateMiss(masm, false);
1254 }
1255
1256
GenerateNonStrictArguments(MacroAssembler * masm)1257 void KeyedStoreIC::GenerateNonStrictArguments(MacroAssembler* masm) {
1258 // ----------- S t a t e -------------
1259 // -- rax : value
1260 // -- rcx : key
1261 // -- rdx : receiver
1262 // -- rsp[0] : return address
1263 // -----------------------------------
1264 Label slow, notin;
1265 Operand mapped_location = GenerateMappedArgumentsLookup(
1266 masm, rdx, rcx, rbx, rdi, r8, ¬in, &slow);
1267 __ movq(mapped_location, rax);
1268 __ lea(r9, mapped_location);
1269 __ movq(r8, rax);
1270 __ RecordWrite(rbx,
1271 r9,
1272 r8,
1273 kDontSaveFPRegs,
1274 EMIT_REMEMBERED_SET,
1275 INLINE_SMI_CHECK);
1276 __ Ret();
1277 __ bind(¬in);
1278 // The unmapped lookup expects that the parameter map is in rbx.
1279 Operand unmapped_location =
1280 GenerateUnmappedArgumentsLookup(masm, rcx, rbx, rdi, &slow);
1281 __ movq(unmapped_location, rax);
1282 __ lea(r9, unmapped_location);
1283 __ movq(r8, rax);
1284 __ RecordWrite(rbx,
1285 r9,
1286 r8,
1287 kDontSaveFPRegs,
1288 EMIT_REMEMBERED_SET,
1289 INLINE_SMI_CHECK);
1290 __ Ret();
1291 __ bind(&slow);
1292 GenerateMiss(masm, false);
1293 }
1294
1295
GenerateNonStrictArguments(MacroAssembler * masm,int argc)1296 void KeyedCallIC::GenerateNonStrictArguments(MacroAssembler* masm,
1297 int argc) {
1298 // ----------- S t a t e -------------
1299 // rcx : function name
1300 // rsp[0] : return address
1301 // rsp[8] : argument argc
1302 // rsp[16] : argument argc - 1
1303 // ...
1304 // rsp[argc * 8] : argument 1
1305 // rsp[(argc + 1) * 8] : argument 0 = receiver
1306 // -----------------------------------
1307 Label slow, notin;
1308 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
1309 Operand mapped_location = GenerateMappedArgumentsLookup(
1310 masm, rdx, rcx, rbx, rax, r8, ¬in, &slow);
1311 __ movq(rdi, mapped_location);
1312 GenerateFunctionTailCall(masm, argc, &slow);
1313 __ bind(¬in);
1314 // The unmapped lookup expects that the parameter map is in rbx.
1315 Operand unmapped_location =
1316 GenerateUnmappedArgumentsLookup(masm, rcx, rbx, rax, &slow);
1317 __ CompareRoot(unmapped_location, Heap::kTheHoleValueRootIndex);
1318 __ j(equal, &slow);
1319 __ movq(rdi, unmapped_location);
1320 GenerateFunctionTailCall(masm, argc, &slow);
1321 __ bind(&slow);
1322 GenerateMiss(masm, argc);
1323 }
1324
1325
GenerateMegamorphic(MacroAssembler * masm)1326 void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
1327 // ----------- S t a t e -------------
1328 // -- rax : receiver
1329 // -- rcx : name
1330 // -- rsp[0] : return address
1331 // -----------------------------------
1332
1333 // Probe the stub cache.
1334 Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, MONOMORPHIC);
1335 Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, rax, rcx, rbx,
1336 rdx);
1337
1338 // Cache miss: Jump to runtime.
1339 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
1340 }
1341
1342
GenerateNormal(MacroAssembler * masm)1343 void LoadIC::GenerateNormal(MacroAssembler* masm) {
1344 // ----------- S t a t e -------------
1345 // -- rax : receiver
1346 // -- rcx : name
1347 // -- rsp[0] : return address
1348 // -----------------------------------
1349 Label miss;
1350
1351 GenerateStringDictionaryReceiverCheck(masm, rax, rdx, rbx, &miss);
1352
1353 // rdx: elements
1354 // Search the dictionary placing the result in rax.
1355 GenerateDictionaryLoad(masm, &miss, rdx, rcx, rbx, rdi, rax);
1356 __ ret(0);
1357
1358 // Cache miss: Jump to runtime.
1359 __ bind(&miss);
1360 GenerateMiss(masm);
1361 }
1362
1363
GenerateMiss(MacroAssembler * masm)1364 void LoadIC::GenerateMiss(MacroAssembler* masm) {
1365 // ----------- S t a t e -------------
1366 // -- rax : receiver
1367 // -- rcx : name
1368 // -- rsp[0] : return address
1369 // -----------------------------------
1370
1371 Counters* counters = masm->isolate()->counters();
1372 __ IncrementCounter(counters->load_miss(), 1);
1373
1374 __ pop(rbx);
1375 __ push(rax); // receiver
1376 __ push(rcx); // name
1377 __ push(rbx); // return address
1378
1379 // Perform tail call to the entry.
1380 ExternalReference ref =
1381 ExternalReference(IC_Utility(kLoadIC_Miss), masm->isolate());
1382 __ TailCallExternalReference(ref, 2, 1);
1383 }
1384
1385
GenerateMiss(MacroAssembler * masm,bool force_generic)1386 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
1387 // ----------- S t a t e -------------
1388 // -- rax : key
1389 // -- rdx : receiver
1390 // -- rsp[0] : return address
1391 // -----------------------------------
1392
1393 Counters* counters = masm->isolate()->counters();
1394 __ IncrementCounter(counters->keyed_load_miss(), 1);
1395
1396 __ pop(rbx);
1397 __ push(rdx); // receiver
1398 __ push(rax); // name
1399 __ push(rbx); // return address
1400
1401 // Perform tail call to the entry.
1402 ExternalReference ref = force_generic
1403 ? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric),
1404 masm->isolate())
1405 : ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate());
1406 __ TailCallExternalReference(ref, 2, 1);
1407 }
1408
1409
GenerateRuntimeGetProperty(MacroAssembler * masm)1410 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
1411 // ----------- S t a t e -------------
1412 // -- rax : key
1413 // -- rdx : receiver
1414 // -- rsp[0] : return address
1415 // -----------------------------------
1416
1417 __ pop(rbx);
1418 __ push(rdx); // receiver
1419 __ push(rax); // name
1420 __ push(rbx); // return address
1421
1422 // Perform tail call to the entry.
1423 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
1424 }
1425
1426
GenerateMegamorphic(MacroAssembler * masm,StrictModeFlag strict_mode)1427 void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
1428 StrictModeFlag strict_mode) {
1429 // ----------- S t a t e -------------
1430 // -- rax : value
1431 // -- rcx : name
1432 // -- rdx : receiver
1433 // -- rsp[0] : return address
1434 // -----------------------------------
1435
1436 // Get the receiver from the stack and probe the stub cache.
1437 Code::Flags flags =
1438 Code::ComputeFlags(Code::STORE_IC, MONOMORPHIC, strict_mode);
1439 Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, rdx, rcx, rbx,
1440 no_reg);
1441
1442 // Cache miss: Jump to runtime.
1443 GenerateMiss(masm);
1444 }
1445
1446
GenerateMiss(MacroAssembler * masm)1447 void StoreIC::GenerateMiss(MacroAssembler* masm) {
1448 // ----------- S t a t e -------------
1449 // -- rax : value
1450 // -- rcx : name
1451 // -- rdx : receiver
1452 // -- rsp[0] : return address
1453 // -----------------------------------
1454
1455 __ pop(rbx);
1456 __ push(rdx); // receiver
1457 __ push(rcx); // name
1458 __ push(rax); // value
1459 __ push(rbx); // return address
1460
1461 // Perform tail call to the entry.
1462 ExternalReference ref =
1463 ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate());
1464 __ TailCallExternalReference(ref, 3, 1);
1465 }
1466
1467
GenerateArrayLength(MacroAssembler * masm)1468 void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
1469 // ----------- S t a t e -------------
1470 // -- rax : value
1471 // -- rcx : name
1472 // -- rdx : receiver
1473 // -- rsp[0] : return address
1474 // -----------------------------------
1475 //
1476 // This accepts as a receiver anything JSArray::SetElementsLength accepts
1477 // (currently anything except for external arrays which means anything with
1478 // elements of FixedArray type). Value must be a number, but only smis are
1479 // accepted as the most common case.
1480
1481 Label miss;
1482
1483 Register receiver = rdx;
1484 Register value = rax;
1485 Register scratch = rbx;
1486
1487 // Check that the receiver isn't a smi.
1488 __ JumpIfSmi(receiver, &miss);
1489
1490 // Check that the object is a JS array.
1491 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
1492 __ j(not_equal, &miss);
1493
1494 // Check that elements are FixedArray.
1495 // We rely on StoreIC_ArrayLength below to deal with all types of
1496 // fast elements (including COW).
1497 __ movq(scratch, FieldOperand(receiver, JSArray::kElementsOffset));
1498 __ CmpObjectType(scratch, FIXED_ARRAY_TYPE, scratch);
1499 __ j(not_equal, &miss);
1500
1501 // Check that the array has fast properties, otherwise the length
1502 // property might have been redefined.
1503 __ movq(scratch, FieldOperand(receiver, JSArray::kPropertiesOffset));
1504 __ CompareRoot(FieldOperand(scratch, FixedArray::kMapOffset),
1505 Heap::kHashTableMapRootIndex);
1506 __ j(equal, &miss);
1507
1508 // Check that value is a smi.
1509 __ JumpIfNotSmi(value, &miss);
1510
1511 // Prepare tail call to StoreIC_ArrayLength.
1512 __ pop(scratch);
1513 __ push(receiver);
1514 __ push(value);
1515 __ push(scratch); // return address
1516
1517 ExternalReference ref =
1518 ExternalReference(IC_Utility(kStoreIC_ArrayLength), masm->isolate());
1519 __ TailCallExternalReference(ref, 2, 1);
1520
1521 __ bind(&miss);
1522
1523 GenerateMiss(masm);
1524 }
1525
1526
GenerateNormal(MacroAssembler * masm)1527 void StoreIC::GenerateNormal(MacroAssembler* masm) {
1528 // ----------- S t a t e -------------
1529 // -- rax : value
1530 // -- rcx : name
1531 // -- rdx : receiver
1532 // -- rsp[0] : return address
1533 // -----------------------------------
1534
1535 Label miss;
1536
1537 GenerateStringDictionaryReceiverCheck(masm, rdx, rbx, rdi, &miss);
1538
1539 GenerateDictionaryStore(masm, &miss, rbx, rcx, rax, r8, r9);
1540 Counters* counters = masm->isolate()->counters();
1541 __ IncrementCounter(counters->store_normal_hit(), 1);
1542 __ ret(0);
1543
1544 __ bind(&miss);
1545 __ IncrementCounter(counters->store_normal_miss(), 1);
1546 GenerateMiss(masm);
1547 }
1548
1549
GenerateGlobalProxy(MacroAssembler * masm,StrictModeFlag strict_mode)1550 void StoreIC::GenerateGlobalProxy(MacroAssembler* masm,
1551 StrictModeFlag strict_mode) {
1552 // ----------- S t a t e -------------
1553 // -- rax : value
1554 // -- rcx : name
1555 // -- rdx : receiver
1556 // -- rsp[0] : return address
1557 // -----------------------------------
1558 __ pop(rbx);
1559 __ push(rdx);
1560 __ push(rcx);
1561 __ push(rax);
1562 __ Push(Smi::FromInt(NONE)); // PropertyAttributes
1563 __ Push(Smi::FromInt(strict_mode));
1564 __ push(rbx); // return address
1565
1566 // Do tail-call to runtime routine.
1567 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
1568 }
1569
1570
GenerateRuntimeSetProperty(MacroAssembler * masm,StrictModeFlag strict_mode)1571 void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
1572 StrictModeFlag strict_mode) {
1573 // ----------- S t a t e -------------
1574 // -- rax : value
1575 // -- rcx : key
1576 // -- rdx : receiver
1577 // -- rsp[0] : return address
1578 // -----------------------------------
1579
1580 __ pop(rbx);
1581 __ push(rdx); // receiver
1582 __ push(rcx); // key
1583 __ push(rax); // value
1584 __ Push(Smi::FromInt(NONE)); // PropertyAttributes
1585 __ Push(Smi::FromInt(strict_mode)); // Strict mode.
1586 __ push(rbx); // return address
1587
1588 // Do tail-call to runtime routine.
1589 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
1590 }
1591
1592
GenerateSlow(MacroAssembler * masm)1593 void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
1594 // ----------- S t a t e -------------
1595 // -- rax : value
1596 // -- rcx : key
1597 // -- rdx : receiver
1598 // -- rsp[0] : return address
1599 // -----------------------------------
1600
1601 __ pop(rbx);
1602 __ push(rdx); // receiver
1603 __ push(rcx); // key
1604 __ push(rax); // value
1605 __ push(rbx); // return address
1606
1607 // Do tail-call to runtime routine.
1608 ExternalReference ref(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
1609 __ TailCallExternalReference(ref, 3, 1);
1610 }
1611
1612
GenerateMiss(MacroAssembler * masm,bool force_generic)1613 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
1614 // ----------- S t a t e -------------
1615 // -- rax : value
1616 // -- rcx : key
1617 // -- rdx : receiver
1618 // -- rsp[0] : return address
1619 // -----------------------------------
1620
1621 __ pop(rbx);
1622 __ push(rdx); // receiver
1623 __ push(rcx); // key
1624 __ push(rax); // value
1625 __ push(rbx); // return address
1626
1627 // Do tail-call to runtime routine.
1628 ExternalReference ref = force_generic
1629 ? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric),
1630 masm->isolate())
1631 : ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
1632 __ TailCallExternalReference(ref, 3, 1);
1633 }
1634
1635
GenerateTransitionElementsSmiToDouble(MacroAssembler * masm)1636 void KeyedStoreIC::GenerateTransitionElementsSmiToDouble(MacroAssembler* masm) {
1637 // ----------- S t a t e -------------
1638 // -- rbx : target map
1639 // -- rdx : receiver
1640 // -- rsp[0] : return address
1641 // -----------------------------------
1642 // Must return the modified receiver in eax.
1643 if (!FLAG_trace_elements_transitions) {
1644 Label fail;
1645 ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &fail);
1646 __ movq(rax, rdx);
1647 __ Ret();
1648 __ bind(&fail);
1649 }
1650
1651 __ pop(rbx);
1652 __ push(rdx);
1653 __ push(rbx); // return address
1654 __ TailCallRuntime(Runtime::kTransitionElementsSmiToDouble, 1, 1);
1655 }
1656
1657
GenerateTransitionElementsDoubleToObject(MacroAssembler * masm)1658 void KeyedStoreIC::GenerateTransitionElementsDoubleToObject(
1659 MacroAssembler* masm) {
1660 // ----------- S t a t e -------------
1661 // -- rbx : target map
1662 // -- rdx : receiver
1663 // -- rsp[0] : return address
1664 // -----------------------------------
1665 // Must return the modified receiver in eax.
1666 if (!FLAG_trace_elements_transitions) {
1667 Label fail;
1668 ElementsTransitionGenerator::GenerateDoubleToObject(masm, &fail);
1669 __ movq(rax, rdx);
1670 __ Ret();
1671 __ bind(&fail);
1672 }
1673
1674 __ pop(rbx);
1675 __ push(rdx);
1676 __ push(rbx); // return address
1677 __ TailCallRuntime(Runtime::kTransitionElementsDoubleToObject, 1, 1);
1678 }
1679
1680
1681 #undef __
1682
1683
ComputeCondition(Token::Value op)1684 Condition CompareIC::ComputeCondition(Token::Value op) {
1685 switch (op) {
1686 case Token::EQ_STRICT:
1687 case Token::EQ:
1688 return equal;
1689 case Token::LT:
1690 return less;
1691 case Token::GT:
1692 return greater;
1693 case Token::LTE:
1694 return less_equal;
1695 case Token::GTE:
1696 return greater_equal;
1697 default:
1698 UNREACHABLE();
1699 return no_condition;
1700 }
1701 }
1702
1703
HasInlinedSmiCode(Address address)1704 static bool HasInlinedSmiCode(Address address) {
1705 // The address of the instruction following the call.
1706 Address test_instruction_address =
1707 address + Assembler::kCallTargetAddressOffset;
1708
1709 // If the instruction following the call is not a test al, nothing
1710 // was inlined.
1711 return *test_instruction_address == Assembler::kTestAlByte;
1712 }
1713
1714
UpdateCaches(Handle<Object> x,Handle<Object> y)1715 void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
1716 HandleScope scope;
1717 Handle<Code> rewritten;
1718 State previous_state = GetState();
1719
1720 State state = TargetState(previous_state, HasInlinedSmiCode(address()), x, y);
1721 if (state == GENERIC) {
1722 CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS);
1723 rewritten = stub.GetCode();
1724 } else {
1725 ICCompareStub stub(op_, state);
1726 if (state == KNOWN_OBJECTS) {
1727 stub.set_known_map(Handle<Map>(Handle<JSObject>::cast(x)->map()));
1728 }
1729 rewritten = stub.GetCode();
1730 }
1731 set_target(*rewritten);
1732
1733 #ifdef DEBUG
1734 if (FLAG_trace_ic) {
1735 PrintF("[CompareIC (%s->%s)#%s]\n",
1736 GetStateName(previous_state),
1737 GetStateName(state),
1738 Token::Name(op_));
1739 }
1740 #endif
1741
1742 // Activate inlined smi code.
1743 if (previous_state == UNINITIALIZED) {
1744 PatchInlinedSmiCode(address());
1745 }
1746 }
1747
PatchInlinedSmiCode(Address address)1748 void PatchInlinedSmiCode(Address address) {
1749 // The address of the instruction following the call.
1750 Address test_instruction_address =
1751 address + Assembler::kCallTargetAddressOffset;
1752
1753 // If the instruction following the call is not a test al, nothing
1754 // was inlined.
1755 if (*test_instruction_address != Assembler::kTestAlByte) {
1756 ASSERT(*test_instruction_address == Assembler::kNopByte);
1757 return;
1758 }
1759
1760 Address delta_address = test_instruction_address + 1;
1761 // The delta to the start of the map check instruction and the
1762 // condition code uses at the patched jump.
1763 int8_t delta = *reinterpret_cast<int8_t*>(delta_address);
1764 if (FLAG_trace_ic) {
1765 PrintF("[ patching ic at %p, test=%p, delta=%d\n",
1766 address, test_instruction_address, delta);
1767 }
1768
1769 // Patch with a short conditional jump. There must be a
1770 // short jump-if-carry/not-carry at this position.
1771 Address jmp_address = test_instruction_address - delta;
1772 ASSERT(*jmp_address == Assembler::kJncShortOpcode ||
1773 *jmp_address == Assembler::kJcShortOpcode);
1774 Condition cc = *jmp_address == Assembler::kJncShortOpcode
1775 ? not_zero
1776 : zero;
1777 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc);
1778 }
1779
1780
1781 } } // namespace v8::internal
1782
1783 #endif // V8_TARGET_ARCH_X64
1784