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