• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2006-2008 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 #include "codegen-inl.h"
31 #include "ic-inl.h"
32 #include "runtime.h"
33 #include "stub-cache.h"
34 
35 namespace v8 {
36 namespace internal {
37 
38 // ----------------------------------------------------------------------------
39 // Static IC stub generators.
40 //
41 
42 #define __ ACCESS_MASM(masm)
43 
44 
45 // Helper function used to load a property from a dictionary backing storage.
46 // This function may return false negatives, so miss_label
47 // must always call a backup property load that is complete.
48 // This function is safe to call if the receiver has fast properties,
49 // or if name is not a symbol, and will jump to the miss_label in that case.
GenerateDictionaryLoad(MacroAssembler * masm,Label * miss_label,Register r0,Register r1,Register r2,Register name)50 static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label,
51                                    Register r0, Register r1, Register r2,
52                                    Register name) {
53   // Register use:
54   //
55   // r0   - used to hold the property dictionary.
56   //
57   // r1   - initially the receiver
58   //      - used for the index into the property dictionary
59   //      - holds the result on exit.
60   //
61   // r2   - used to hold the capacity of the property dictionary.
62   //
63   // name - holds the name of the property and is unchanged.
64 
65   Label done;
66 
67   // Check for the absence of an interceptor.
68   // Load the map into r0.
69   __ mov(r0, FieldOperand(r1, JSObject::kMapOffset));
70   // Test the has_named_interceptor bit in the map.
71   __ test(FieldOperand(r0, Map::kInstanceAttributesOffset),
72           Immediate(1 << (Map::kHasNamedInterceptor + (3 * 8))));
73 
74   // Jump to miss if the interceptor bit is set.
75   __ j(not_zero, miss_label, not_taken);
76 
77   // Bail out if we have a JS global proxy object.
78   __ movzx_b(r0, FieldOperand(r0, Map::kInstanceTypeOffset));
79   __ cmp(r0, JS_GLOBAL_PROXY_TYPE);
80   __ j(equal, miss_label, not_taken);
81 
82   // Possible work-around for http://crbug.com/16276.
83   __ cmp(r0, JS_GLOBAL_OBJECT_TYPE);
84   __ j(equal, miss_label, not_taken);
85   __ cmp(r0, JS_BUILTINS_OBJECT_TYPE);
86   __ j(equal, miss_label, not_taken);
87 
88   // Check that the properties array is a dictionary.
89   __ mov(r0, FieldOperand(r1, JSObject::kPropertiesOffset));
90   __ cmp(FieldOperand(r0, HeapObject::kMapOffset),
91          Immediate(Factory::hash_table_map()));
92   __ j(not_equal, miss_label);
93 
94   // Compute the capacity mask.
95   const int kCapacityOffset =
96       StringDictionary::kHeaderSize +
97       StringDictionary::kCapacityIndex * kPointerSize;
98   __ mov(r2, FieldOperand(r0, kCapacityOffset));
99   __ shr(r2, kSmiTagSize);  // convert smi to int
100   __ dec(r2);
101 
102   // Generate an unrolled loop that performs a few probes before
103   // giving up. Measurements done on Gmail indicate that 2 probes
104   // cover ~93% of loads from dictionaries.
105   static const int kProbes = 4;
106   const int kElementsStartOffset =
107       StringDictionary::kHeaderSize +
108       StringDictionary::kElementsStartIndex * kPointerSize;
109   for (int i = 0; i < kProbes; i++) {
110     // Compute the masked index: (hash + i + i * i) & mask.
111     __ mov(r1, FieldOperand(name, String::kLengthOffset));
112     __ shr(r1, String::kHashShift);
113     if (i > 0) {
114       __ add(Operand(r1), Immediate(StringDictionary::GetProbeOffset(i)));
115     }
116     __ and_(r1, Operand(r2));
117 
118     // Scale the index by multiplying by the entry size.
119     ASSERT(StringDictionary::kEntrySize == 3);
120     __ lea(r1, Operand(r1, r1, times_2, 0));  // r1 = r1 * 3
121 
122     // Check if the key is identical to the name.
123     __ cmp(name,
124            Operand(r0, r1, times_4, kElementsStartOffset - kHeapObjectTag));
125     if (i != kProbes - 1) {
126       __ j(equal, &done, taken);
127     } else {
128       __ j(not_equal, miss_label, not_taken);
129     }
130   }
131 
132   // Check that the value is a normal property.
133   __ bind(&done);
134   const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
135   __ test(Operand(r0, r1, times_4, kDetailsOffset - kHeapObjectTag),
136           Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize));
137   __ j(not_zero, miss_label, not_taken);
138 
139   // Get the value at the masked, scaled index.
140   const int kValueOffset = kElementsStartOffset + kPointerSize;
141   __ mov(r1, Operand(r0, r1, times_4, kValueOffset - kHeapObjectTag));
142 }
143 
144 
145 // Helper function used to check that a value is either not an object
146 // or is loaded if it is an object.
GenerateCheckNonObjectOrLoaded(MacroAssembler * masm,Label * miss,Register value,Register scratch)147 static void GenerateCheckNonObjectOrLoaded(MacroAssembler* masm, Label* miss,
148                                            Register value, Register scratch) {
149   Label done;
150   // Check if the value is a Smi.
151   __ test(value, Immediate(kSmiTagMask));
152   __ j(zero, &done, not_taken);
153   // Check if the object has been loaded.
154   __ mov(scratch, FieldOperand(value, JSFunction::kMapOffset));
155   __ mov(scratch, FieldOperand(scratch, Map::kBitField2Offset));
156   __ test(scratch, Immediate(1 << Map::kNeedsLoading));
157   __ j(not_zero, miss, not_taken);
158   __ bind(&done);
159 }
160 
161 
162 // The offset from the inlined patch site to the start of the
163 // inlined load instruction.  It is 7 bytes (test eax, imm) plus
164 // 6 bytes (jne slow_label).
165 const int LoadIC::kOffsetToLoadInstruction = 13;
166 
167 
GenerateArrayLength(MacroAssembler * masm)168 void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
169   // ----------- S t a t e -------------
170   //  -- ecx    : name
171   //  -- esp[0] : return address
172   //  -- esp[4] : receiver
173   // -----------------------------------
174 
175   Label miss;
176 
177   __ mov(eax, Operand(esp, kPointerSize));
178 
179   StubCompiler::GenerateLoadArrayLength(masm, eax, edx, &miss);
180   __ bind(&miss);
181   StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
182 }
183 
184 
GenerateStringLength(MacroAssembler * masm)185 void LoadIC::GenerateStringLength(MacroAssembler* masm) {
186   // ----------- S t a t e -------------
187   //  -- ecx    : name
188   //  -- esp[0] : return address
189   //  -- esp[4] : receiver
190   // -----------------------------------
191 
192   Label miss;
193 
194   __ mov(eax, Operand(esp, kPointerSize));
195 
196   StubCompiler::GenerateLoadStringLength(masm, eax, edx, &miss);
197   __ bind(&miss);
198   StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
199 }
200 
201 
GenerateFunctionPrototype(MacroAssembler * masm)202 void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
203   // ----------- S t a t e -------------
204   //  -- ecx    : name
205   //  -- esp[0] : return address
206   //  -- esp[4] : receiver
207   // -----------------------------------
208 
209   Label miss;
210 
211   __ mov(eax, Operand(esp, kPointerSize));
212 
213   StubCompiler::GenerateLoadFunctionPrototype(masm, eax, edx, ebx, &miss);
214   __ bind(&miss);
215   StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
216 }
217 
218 
219 #ifdef DEBUG
220 // For use in assert below.
TenToThe(int exponent)221 static int TenToThe(int exponent) {
222   ASSERT(exponent <= 9);
223   ASSERT(exponent >= 1);
224   int answer = 10;
225   for (int i = 1; i < exponent; i++) answer *= 10;
226   return answer;
227 }
228 #endif
229 
230 
GenerateGeneric(MacroAssembler * masm)231 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
232   // ----------- S t a t e -------------
233   //  -- esp[0] : return address
234   //  -- esp[4] : name
235   //  -- esp[8] : receiver
236   // -----------------------------------
237   Label slow, check_string, index_int, index_string, check_pixel_array;
238 
239   // Load name and receiver.
240   __ mov(eax, Operand(esp, kPointerSize));
241   __ mov(ecx, Operand(esp, 2 * kPointerSize));
242 
243   // Check that the object isn't a smi.
244   __ test(ecx, Immediate(kSmiTagMask));
245   __ j(zero, &slow, not_taken);
246 
247   // Get the map of the receiver.
248   __ mov(edx, FieldOperand(ecx, HeapObject::kMapOffset));
249   // Check that the receiver does not require access checks.  We need
250   // to check this explicitly since this generic stub does not perform
251   // map checks.
252   __ movzx_b(ebx, FieldOperand(edx, Map::kBitFieldOffset));
253   __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
254   __ j(not_zero, &slow, not_taken);
255   // Check that the object is some kind of JS object EXCEPT JS Value type.
256   // In the case that the object is a value-wrapper object,
257   // we enter the runtime system to make sure that indexing
258   // into string objects work as intended.
259   ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
260   __ movzx_b(edx, FieldOperand(edx, Map::kInstanceTypeOffset));
261   __ cmp(edx, JS_OBJECT_TYPE);
262   __ j(less, &slow, not_taken);
263   // Check that the key is a smi.
264   __ test(eax, Immediate(kSmiTagMask));
265   __ j(not_zero, &check_string, not_taken);
266   __ sar(eax, kSmiTagSize);
267   // Get the elements array of the object.
268   __ bind(&index_int);
269   __ mov(ecx, FieldOperand(ecx, JSObject::kElementsOffset));
270   // Check that the object is in fast mode (not dictionary).
271   __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
272          Immediate(Factory::fixed_array_map()));
273   __ j(not_equal, &check_pixel_array);
274   // Check that the key (index) is within bounds.
275   __ cmp(eax, FieldOperand(ecx, FixedArray::kLengthOffset));
276   __ j(above_equal, &slow);
277   // Fast case: Do the load.
278   __ mov(eax,
279          Operand(ecx, eax, times_4, FixedArray::kHeaderSize - kHeapObjectTag));
280   __ cmp(Operand(eax), Immediate(Factory::the_hole_value()));
281   // In case the loaded value is the_hole we have to consult GetProperty
282   // to ensure the prototype chain is searched.
283   __ j(equal, &slow);
284   __ IncrementCounter(&Counters::keyed_load_generic_smi, 1);
285   __ ret(0);
286 
287   // Check whether the elements is a pixel array.
288   // eax: untagged index
289   // ecx: elements array
290   __ bind(&check_pixel_array);
291   __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
292          Immediate(Factory::pixel_array_map()));
293   __ j(not_equal, &slow);
294   __ cmp(eax, FieldOperand(ecx, PixelArray::kLengthOffset));
295   __ j(above_equal, &slow);
296   __ mov(ecx, FieldOperand(ecx, PixelArray::kExternalPointerOffset));
297   __ movzx_b(eax, Operand(ecx, eax, times_1, 0));
298   __ shl(eax, kSmiTagSize);
299   __ ret(0);
300 
301 
302   // Slow case: Load name and receiver from stack and jump to runtime.
303   __ bind(&slow);
304   __ IncrementCounter(&Counters::keyed_load_generic_slow, 1);
305   KeyedLoadIC::Generate(masm, ExternalReference(Runtime::kKeyedGetProperty));
306 
307   __ bind(&check_string);
308   // The key is not a smi.
309   // Is it a string?
310   __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
311   __ j(above_equal, &slow);
312   // Is the string an array index, with cached numeric value?
313   __ mov(ebx, FieldOperand(eax, String::kLengthOffset));
314   __ test(ebx, Immediate(String::kIsArrayIndexMask));
315   __ j(not_zero, &index_string, not_taken);
316 
317   // If the string is a symbol, do a quick inline probe of the receiver's
318   // dictionary, if it exists.
319   __ movzx_b(ebx, FieldOperand(edx, Map::kInstanceTypeOffset));
320   __ test(ebx, Immediate(kIsSymbolMask));
321   __ j(zero, &slow, not_taken);
322   // Probe the dictionary leaving result in ecx.
323   GenerateDictionaryLoad(masm, &slow, ebx, ecx, edx, eax);
324   GenerateCheckNonObjectOrLoaded(masm, &slow, ecx, edx);
325   __ mov(eax, Operand(ecx));
326   __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
327   __ ret(0);
328   // Array index string: If short enough use cache in length/hash field (ebx).
329   // We assert that there are enough bits in an int32_t after the hash shift
330   // bits have been subtracted to allow space for the length and the cached
331   // array index.
332   ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
333          (1 << (String::kShortLengthShift - String::kHashShift)));
334   __ bind(&index_string);
335   const int kLengthFieldLimit =
336       (String::kMaxCachedArrayIndexLength + 1) << String::kShortLengthShift;
337   __ cmp(ebx, kLengthFieldLimit);
338   __ j(above_equal, &slow);
339   __ mov(eax, Operand(ebx));
340   __ and_(eax, (1 << String::kShortLengthShift) - 1);
341   __ shr(eax, String::kLongLengthShift);
342   __ jmp(&index_int);
343 }
344 
345 
GenerateGeneric(MacroAssembler * masm)346 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
347   // ----------- S t a t e -------------
348   //  -- eax    : value
349   //  -- esp[0] : return address
350   //  -- esp[4] : key
351   //  -- esp[8] : receiver
352   // -----------------------------------
353   Label slow, fast, array, extra, check_pixel_array;
354 
355   // Get the receiver from the stack.
356   __ mov(edx, Operand(esp, 2 * kPointerSize));  // 2 ~ return address, key
357   // Check that the object isn't a smi.
358   __ test(edx, Immediate(kSmiTagMask));
359   __ j(zero, &slow, not_taken);
360   // Get the map from the receiver.
361   __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
362   // Check that the receiver does not require access checks.  We need
363   // to do this because this generic stub does not perform map checks.
364   __ movzx_b(ebx, FieldOperand(ecx, Map::kBitFieldOffset));
365   __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
366   __ j(not_zero, &slow, not_taken);
367   // Get the key from the stack.
368   __ mov(ebx, Operand(esp, 1 * kPointerSize));  // 1 ~ return address
369   // Check that the key is a smi.
370   __ test(ebx, Immediate(kSmiTagMask));
371   __ j(not_zero, &slow, not_taken);
372   // Get the instance type from the map of the receiver.
373   __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
374   // Check if the object is a JS array or not.
375   __ cmp(ecx, JS_ARRAY_TYPE);
376   __ j(equal, &array);
377   // Check that the object is some kind of JS object.
378   __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
379   __ j(less, &slow, not_taken);
380 
381   // Object case: Check key against length in the elements array.
382   // eax: value
383   // edx: JSObject
384   // ebx: index (as a smi)
385   __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
386   // Check that the object is in fast mode (not dictionary).
387   __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
388          Immediate(Factory::fixed_array_map()));
389   __ j(not_equal, &check_pixel_array, not_taken);
390   // Untag the key (for checking against untagged length in the fixed array).
391   __ mov(edx, Operand(ebx));
392   __ sar(edx, kSmiTagSize);  // untag the index and use it for the comparison
393   __ cmp(edx, FieldOperand(ecx, Array::kLengthOffset));
394   // eax: value
395   // ecx: FixedArray
396   // ebx: index (as a smi)
397   __ j(below, &fast, taken);
398 
399   // Slow case: Push extra copies of the arguments (3).
400   __ bind(&slow);
401   __ pop(ecx);
402   __ push(Operand(esp, 1 * kPointerSize));
403   __ push(Operand(esp, 1 * kPointerSize));
404   __ push(eax);
405   __ push(ecx);
406   // Do tail-call to runtime routine.
407   __ TailCallRuntime(ExternalReference(Runtime::kSetProperty), 3);
408 
409   // Check whether the elements is a pixel array.
410   // eax: value
411   // ecx: elements array
412   // ebx: index (as a smi)
413   __ bind(&check_pixel_array);
414   __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
415          Immediate(Factory::pixel_array_map()));
416   __ j(not_equal, &slow);
417   // Check that the value is a smi. If a conversion is needed call into the
418   // runtime to convert and clamp.
419   __ test(eax, Immediate(kSmiTagMask));
420   __ j(not_zero, &slow);
421   __ sar(ebx, kSmiTagSize);  // Untag the index.
422   __ cmp(ebx, FieldOperand(ecx, PixelArray::kLengthOffset));
423   __ j(above_equal, &slow);
424   __ sar(eax, kSmiTagSize);  // Untag the value.
425   {  // Clamp the value to [0..255].
426     Label done, check_255;
427     __ cmp(eax, 0);
428     __ j(greater_equal, &check_255);
429     __ mov(eax, Immediate(0));
430     __ jmp(&done);
431     __ bind(&check_255);
432     __ cmp(eax, 255);
433     __ j(less_equal, &done);
434     __ mov(eax, Immediate(255));
435     __ bind(&done);
436   }
437   __ mov(ecx, FieldOperand(ecx, PixelArray::kExternalPointerOffset));
438   __ mov_b(Operand(ecx, ebx, times_1, 0), eax);
439   __ ret(0);
440 
441   // Extra capacity case: Check if there is extra capacity to
442   // perform the store and update the length. Used for adding one
443   // element to the array by writing to array[array.length].
444   __ bind(&extra);
445   // eax: value
446   // edx: JSArray
447   // ecx: FixedArray
448   // ebx: index (as a smi)
449   // flags: compare (ebx, edx.length())
450   __ j(not_equal, &slow, not_taken);  // do not leave holes in the array
451   __ sar(ebx, kSmiTagSize);  // untag
452   __ cmp(ebx, FieldOperand(ecx, Array::kLengthOffset));
453   __ j(above_equal, &slow, not_taken);
454   // Restore tag and increment.
455   __ lea(ebx, Operand(ebx, times_2, 1 << kSmiTagSize));
456   __ mov(FieldOperand(edx, JSArray::kLengthOffset), ebx);
457   __ sub(Operand(ebx), Immediate(1 << kSmiTagSize));  // decrement ebx again
458   __ jmp(&fast);
459 
460 
461   // Array case: Get the length and the elements array from the JS
462   // array. Check that the array is in fast mode; if it is the
463   // length is always a smi.
464   __ bind(&array);
465   // eax: value
466   // edx: JSArray
467   // ebx: index (as a smi)
468   __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
469   __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
470          Immediate(Factory::fixed_array_map()));
471   __ j(not_equal, &check_pixel_array);
472 
473   // Check the key against the length in the array, compute the
474   // address to store into and fall through to fast case.
475   __ cmp(ebx, FieldOperand(edx, JSArray::kLengthOffset));
476   __ j(above_equal, &extra, not_taken);
477 
478   // Fast case: Do the store.
479   __ bind(&fast);
480   // eax: value
481   // ecx: FixedArray
482   // ebx: index (as a smi)
483   __ mov(Operand(ecx, ebx, times_2, FixedArray::kHeaderSize - kHeapObjectTag),
484          eax);
485   // Update write barrier for the elements array address.
486   __ mov(edx, Operand(eax));
487   __ RecordWrite(ecx, 0, edx, ebx);
488   __ ret(0);
489 }
490 
491 
492 // Defined in ic.cc.
493 Object* CallIC_Miss(Arguments args);
494 
GenerateMegamorphic(MacroAssembler * masm,int argc)495 void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
496   // ----------- S t a t e -------------
497   // -----------------------------------
498   Label number, non_number, non_string, boolean, probe, miss;
499 
500   // Get the receiver of the function from the stack; 1 ~ return address.
501   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
502   // Get the name of the function from the stack; 2 ~ return address, receiver
503   __ mov(ecx, Operand(esp, (argc + 2) * kPointerSize));
504 
505   // Probe the stub cache.
506   Code::Flags flags =
507       Code::ComputeFlags(Code::CALL_IC, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc);
508   StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, eax);
509 
510   // If the stub cache probing failed, the receiver might be a value.
511   // For value objects, we use the map of the prototype objects for
512   // the corresponding JSValue for the cache and that is what we need
513   // to probe.
514   //
515   // Check for number.
516   __ test(edx, Immediate(kSmiTagMask));
517   __ j(zero, &number, not_taken);
518   __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ebx);
519   __ j(not_equal, &non_number, taken);
520   __ bind(&number);
521   StubCompiler::GenerateLoadGlobalFunctionPrototype(
522       masm, Context::NUMBER_FUNCTION_INDEX, edx);
523   __ jmp(&probe);
524 
525   // Check for string.
526   __ bind(&non_number);
527   __ cmp(ebx, FIRST_NONSTRING_TYPE);
528   __ j(above_equal, &non_string, taken);
529   StubCompiler::GenerateLoadGlobalFunctionPrototype(
530       masm, Context::STRING_FUNCTION_INDEX, edx);
531   __ jmp(&probe);
532 
533   // Check for boolean.
534   __ bind(&non_string);
535   __ cmp(edx, Factory::true_value());
536   __ j(equal, &boolean, not_taken);
537   __ cmp(edx, Factory::false_value());
538   __ j(not_equal, &miss, taken);
539   __ bind(&boolean);
540   StubCompiler::GenerateLoadGlobalFunctionPrototype(
541       masm, Context::BOOLEAN_FUNCTION_INDEX, edx);
542 
543   // Probe the stub cache for the value object.
544   __ bind(&probe);
545   StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg);
546 
547   // Cache miss: Jump to runtime.
548   __ bind(&miss);
549   Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss)));
550 }
551 
552 
GenerateNormalHelper(MacroAssembler * masm,int argc,bool is_global_object,Label * miss)553 static void GenerateNormalHelper(MacroAssembler* masm,
554                                  int argc,
555                                  bool is_global_object,
556                                  Label* miss) {
557   // Search dictionary - put result in register edx.
558   GenerateDictionaryLoad(masm, miss, eax, edx, ebx, ecx);
559 
560   // Move the result to register edi and check that it isn't a smi.
561   __ mov(edi, Operand(edx));
562   __ test(edx, Immediate(kSmiTagMask));
563   __ j(zero, miss, not_taken);
564 
565   // Check that the value is a JavaScript function.
566   __ CmpObjectType(edx, JS_FUNCTION_TYPE, edx);
567   __ j(not_equal, miss, not_taken);
568 
569   // Check that the function has been loaded.
570   __ mov(edx, FieldOperand(edi, JSFunction::kMapOffset));
571   __ mov(edx, FieldOperand(edx, Map::kBitField2Offset));
572   __ test(edx, Immediate(1 << Map::kNeedsLoading));
573   __ j(not_zero, miss, not_taken);
574 
575   // Patch the receiver with the global proxy if necessary.
576   if (is_global_object) {
577     __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
578     __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
579     __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
580   }
581 
582   // Invoke the function.
583   ParameterCount actual(argc);
584   __ InvokeFunction(edi, actual, JUMP_FUNCTION);
585 }
586 
587 
GenerateNormal(MacroAssembler * masm,int argc)588 void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
589   // ----------- S t a t e -------------
590   // -----------------------------------
591 
592   Label miss, global_object, non_global_object;
593 
594   // Get the receiver of the function from the stack; 1 ~ return address.
595   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
596   // Get the name of the function from the stack; 2 ~ return address, receiver.
597   __ mov(ecx, Operand(esp, (argc + 2) * kPointerSize));
598 
599   // Check that the receiver isn't a smi.
600   __ test(edx, Immediate(kSmiTagMask));
601   __ j(zero, &miss, not_taken);
602 
603   // Check that the receiver is a valid JS object.
604   __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
605   __ movzx_b(eax, FieldOperand(ebx, Map::kInstanceTypeOffset));
606   __ cmp(eax, FIRST_JS_OBJECT_TYPE);
607   __ j(below, &miss, not_taken);
608 
609   // If this assert fails, we have to check upper bound too.
610   ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
611 
612   // Check for access to global object.
613   __ cmp(eax, JS_GLOBAL_OBJECT_TYPE);
614   __ j(equal, &global_object);
615   __ cmp(eax, JS_BUILTINS_OBJECT_TYPE);
616   __ j(not_equal, &non_global_object);
617 
618   // Accessing global object: Load and invoke.
619   __ bind(&global_object);
620   // Check that the global object does not require access checks.
621   __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
622   __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
623   __ j(not_equal, &miss, not_taken);
624   GenerateNormalHelper(masm, argc, true, &miss);
625 
626   // Accessing non-global object: Check for access to global proxy.
627   Label global_proxy, invoke;
628   __ bind(&non_global_object);
629   __ cmp(eax, JS_GLOBAL_PROXY_TYPE);
630   __ j(equal, &global_proxy, not_taken);
631   // Check that the non-global, non-global-proxy object does not
632   // require access checks.
633   __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
634   __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
635   __ j(not_equal, &miss, not_taken);
636   __ bind(&invoke);
637   GenerateNormalHelper(masm, argc, false, &miss);
638 
639   // Global object proxy access: Check access rights.
640   __ bind(&global_proxy);
641   __ CheckAccessGlobalProxy(edx, eax, &miss);
642   __ jmp(&invoke);
643 
644   // Cache miss: Jump to runtime.
645   __ bind(&miss);
646   Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss)));
647 }
648 
649 
Generate(MacroAssembler * masm,int argc,const ExternalReference & f)650 void CallIC::Generate(MacroAssembler* masm,
651                       int argc,
652                       const ExternalReference& f) {
653   // ----------- S t a t e -------------
654   // -----------------------------------
655 
656   // Get the receiver of the function from the stack; 1 ~ return address.
657   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
658   // Get the name of the function to call from the stack.
659   // 2 ~ receiver, return address.
660   __ mov(ebx, Operand(esp, (argc + 2) * kPointerSize));
661 
662   // Enter an internal frame.
663   __ EnterInternalFrame();
664 
665   // Push the receiver and the name of the function.
666   __ push(edx);
667   __ push(ebx);
668 
669   // Call the entry.
670   CEntryStub stub;
671   __ mov(eax, Immediate(2));
672   __ mov(ebx, Immediate(f));
673   __ CallStub(&stub);
674 
675   // Move result to edi and exit the internal frame.
676   __ mov(edi, eax);
677   __ LeaveInternalFrame();
678 
679   // Check if the receiver is a global object of some sort.
680   Label invoke, global;
681   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));  // receiver
682   __ test(edx, Immediate(kSmiTagMask));
683   __ j(zero, &invoke, not_taken);
684   __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
685   __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
686   __ cmp(ecx, JS_GLOBAL_OBJECT_TYPE);
687   __ j(equal, &global);
688   __ cmp(ecx, JS_BUILTINS_OBJECT_TYPE);
689   __ j(not_equal, &invoke);
690 
691   // Patch the receiver on the stack.
692   __ bind(&global);
693   __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
694   __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
695 
696   // Invoke the function.
697   ParameterCount actual(argc);
698   __ bind(&invoke);
699   __ InvokeFunction(edi, actual, JUMP_FUNCTION);
700 }
701 
702 
703 // Defined in ic.cc.
704 Object* LoadIC_Miss(Arguments args);
705 
GenerateMegamorphic(MacroAssembler * masm)706 void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
707   // ----------- S t a t e -------------
708   //  -- ecx    : name
709   //  -- esp[0] : return address
710   //  -- esp[4] : receiver
711   // -----------------------------------
712 
713   __ mov(eax, Operand(esp, kPointerSize));
714 
715   // Probe the stub cache.
716   Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
717                                          NOT_IN_LOOP,
718                                          MONOMORPHIC);
719   StubCache::GenerateProbe(masm, flags, eax, ecx, ebx, edx);
720 
721   // Cache miss: Jump to runtime.
722   Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
723 }
724 
725 
GenerateNormal(MacroAssembler * masm)726 void LoadIC::GenerateNormal(MacroAssembler* masm) {
727   // ----------- S t a t e -------------
728   //  -- ecx    : name
729   //  -- esp[0] : return address
730   //  -- esp[4] : receiver
731   // -----------------------------------
732 
733   Label miss, probe, global;
734 
735   __ mov(eax, Operand(esp, kPointerSize));
736 
737   // Check that the receiver isn't a smi.
738   __ test(eax, Immediate(kSmiTagMask));
739   __ j(zero, &miss, not_taken);
740 
741   // Check that the receiver is a valid JS object.
742   __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
743   __ movzx_b(edx, FieldOperand(ebx, Map::kInstanceTypeOffset));
744   __ cmp(edx, FIRST_JS_OBJECT_TYPE);
745   __ j(less, &miss, not_taken);
746 
747   // If this assert fails, we have to check upper bound too.
748   ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
749 
750   // Check for access to global object (unlikely).
751   __ cmp(edx, JS_GLOBAL_PROXY_TYPE);
752   __ j(equal, &global, not_taken);
753 
754   // Check for non-global object that requires access check.
755   __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
756   __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
757   __ j(not_zero, &miss, not_taken);
758 
759   // Search the dictionary placing the result in eax.
760   __ bind(&probe);
761   GenerateDictionaryLoad(masm, &miss, edx, eax, ebx, ecx);
762   GenerateCheckNonObjectOrLoaded(masm, &miss, eax, edx);
763   __ ret(0);
764 
765   // Global object access: Check access rights.
766   __ bind(&global);
767   __ CheckAccessGlobalProxy(eax, edx, &miss);
768   __ jmp(&probe);
769 
770   // Cache miss: Restore receiver from stack and jump to runtime.
771   __ bind(&miss);
772   __ mov(eax, Operand(esp, 1 * kPointerSize));
773   Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
774 }
775 
776 
GenerateMiss(MacroAssembler * masm)777 void LoadIC::GenerateMiss(MacroAssembler* masm) {
778   // ----------- S t a t e -------------
779   //  -- ecx    : name
780   //  -- esp[0] : return address
781   //  -- esp[4] : receiver
782   // -----------------------------------
783 
784   Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
785 }
786 
787 
Generate(MacroAssembler * masm,const ExternalReference & f)788 void LoadIC::Generate(MacroAssembler* masm, const ExternalReference& f) {
789   // ----------- S t a t e -------------
790   //  -- ecx    : name
791   //  -- esp[0] : return address
792   //  -- esp[4] : receiver
793   // -----------------------------------
794 
795   __ mov(eax, Operand(esp, kPointerSize));
796   __ pop(ebx);
797   __ push(eax);  // receiver
798   __ push(ecx);  // name
799   __ push(ebx);  // return address
800 
801   // Perform tail call to the entry.
802   __ TailCallRuntime(f, 2);
803 }
804 
805 
806 // One byte opcode for test eax,0xXXXXXXXX.
807 static const byte kTestEaxByte = 0xA9;
808 
809 
ClearInlinedVersion(Address address)810 void LoadIC::ClearInlinedVersion(Address address) {
811   // Reset the map check of the inlined inobject property load (if
812   // present) to guarantee failure by holding an invalid map (the null
813   // value).  The offset can be patched to anything.
814   PatchInlinedLoad(address, Heap::null_value(), kMaxInt);
815 }
816 
817 
ClearInlinedVersion(Address address)818 void KeyedLoadIC::ClearInlinedVersion(Address address) {
819   // Insert null as the map to check for to make sure the map check fails
820   // sending control flow to the IC instead of the inlined version.
821   PatchInlinedLoad(address, Heap::null_value());
822 }
823 
824 
ClearInlinedVersion(Address address)825 void KeyedStoreIC::ClearInlinedVersion(Address address) {
826   // Insert null as the elements map to check for.  This will make
827   // sure that the elements fast-case map check fails so that control
828   // flows to the IC instead of the inlined version.
829   PatchInlinedStore(address, Heap::null_value());
830 }
831 
832 
RestoreInlinedVersion(Address address)833 void KeyedStoreIC::RestoreInlinedVersion(Address address) {
834   // Restore the fast-case elements map check so that the inlined
835   // version can be used again.
836   PatchInlinedStore(address, Heap::fixed_array_map());
837 }
838 
839 
PatchInlinedLoad(Address address,Object * map,int offset)840 bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
841   // The address of the instruction following the call.
842   Address test_instruction_address =
843       address + Assembler::kPatchReturnSequenceLength;
844   // If the instruction following the call is not a test eax, nothing
845   // was inlined.
846   if (*test_instruction_address != kTestEaxByte) return false;
847 
848   Address delta_address = test_instruction_address + 1;
849   // The delta to the start of the map check instruction.
850   int delta = *reinterpret_cast<int*>(delta_address);
851 
852   // The map address is the last 4 bytes of the 7-byte
853   // operand-immediate compare instruction, so we add 3 to get the
854   // offset to the last 4 bytes.
855   Address map_address = test_instruction_address + delta + 3;
856   *(reinterpret_cast<Object**>(map_address)) = map;
857 
858   // The offset is in the last 4 bytes of a six byte
859   // memory-to-register move instruction, so we add 2 to get the
860   // offset to the last 4 bytes.
861   Address offset_address =
862       test_instruction_address + delta + kOffsetToLoadInstruction + 2;
863   *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag;
864   return true;
865 }
866 
867 
PatchInlinedMapCheck(Address address,Object * map)868 static bool PatchInlinedMapCheck(Address address, Object* map) {
869   Address test_instruction_address =
870       address + Assembler::kPatchReturnSequenceLength;
871   // The keyed load has a fast inlined case if the IC call instruction
872   // is immediately followed by a test instruction.
873   if (*test_instruction_address != kTestEaxByte) return false;
874 
875   // Fetch the offset from the test instruction to the map cmp
876   // instruction.  This offset is stored in the last 4 bytes of the 5
877   // byte test instruction.
878   Address delta_address = test_instruction_address + 1;
879   int delta = *reinterpret_cast<int*>(delta_address);
880   // Compute the map address.  The map address is in the last 4 bytes
881   // of the 7-byte operand-immediate compare instruction, so we add 3
882   // to the offset to get the map address.
883   Address map_address = test_instruction_address + delta + 3;
884   // Patch the map check.
885   *(reinterpret_cast<Object**>(map_address)) = map;
886   return true;
887 }
888 
889 
PatchInlinedLoad(Address address,Object * map)890 bool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) {
891   return PatchInlinedMapCheck(address, map);
892 }
893 
894 
PatchInlinedStore(Address address,Object * map)895 bool KeyedStoreIC::PatchInlinedStore(Address address, Object* map) {
896   return PatchInlinedMapCheck(address, map);
897 }
898 
899 
900 // Defined in ic.cc.
901 Object* KeyedLoadIC_Miss(Arguments args);
902 
903 
GenerateMiss(MacroAssembler * masm)904 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
905   // ----------- S t a t e -------------
906   //  -- esp[0] : return address
907   //  -- esp[4] : name
908   //  -- esp[8] : receiver
909   // -----------------------------------
910 
911   Generate(masm, ExternalReference(IC_Utility(kKeyedLoadIC_Miss)));
912 }
913 
914 
Generate(MacroAssembler * masm,const ExternalReference & f)915 void KeyedLoadIC::Generate(MacroAssembler* masm, const ExternalReference& f) {
916   // ----------- S t a t e -------------
917   //  -- esp[0] : return address
918   //  -- esp[4] : name
919   //  -- esp[8] : receiver
920   // -----------------------------------
921 
922   __ mov(eax, Operand(esp, kPointerSize));
923   __ mov(ecx, Operand(esp, 2 * kPointerSize));
924   __ pop(ebx);
925   __ push(ecx);  // receiver
926   __ push(eax);  // name
927   __ push(ebx);  // return address
928 
929   // Perform tail call to the entry.
930   __ TailCallRuntime(f, 2);
931 }
932 
933 
GenerateMegamorphic(MacroAssembler * masm)934 void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
935   // ----------- S t a t e -------------
936   //  -- eax    : value
937   //  -- ecx    : name
938   //  -- esp[0] : return address
939   //  -- esp[4] : receiver
940   // -----------------------------------
941 
942   // Get the receiver from the stack and probe the stub cache.
943   __ mov(edx, Operand(esp, 4));
944   Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
945                                          NOT_IN_LOOP,
946                                          MONOMORPHIC);
947   StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg);
948 
949   // Cache miss: Jump to runtime.
950   Generate(masm, ExternalReference(IC_Utility(kStoreIC_Miss)));
951 }
952 
953 
GenerateExtendStorage(MacroAssembler * masm)954 void StoreIC::GenerateExtendStorage(MacroAssembler* masm) {
955   // ----------- S t a t e -------------
956   //  -- eax    : value
957   //  -- ecx    : transition map
958   //  -- esp[0] : return address
959   //  -- esp[4] : receiver
960   // -----------------------------------
961 
962   __ pop(ebx);
963   __ push(Operand(esp, 0));  // receiver
964   __ push(ecx);  // transition map
965   __ push(eax);  // value
966   __ push(ebx);  // return address
967 
968   // Perform tail call to the entry.
969   __ TailCallRuntime(
970       ExternalReference(IC_Utility(kSharedStoreIC_ExtendStorage)), 3);
971 }
972 
973 
Generate(MacroAssembler * masm,const ExternalReference & f)974 void StoreIC::Generate(MacroAssembler* masm, const ExternalReference& f) {
975   // ----------- S t a t e -------------
976   //  -- eax    : value
977   //  -- ecx    : name
978   //  -- esp[0] : return address
979   //  -- esp[4] : receiver
980   // -----------------------------------
981 
982   // Move the return address below the arguments.
983   __ pop(ebx);
984   __ push(Operand(esp, 0));
985   __ push(ecx);
986   __ push(eax);
987   __ push(ebx);
988 
989   // Perform tail call to the entry.
990   __ TailCallRuntime(f, 3);
991 }
992 
993 
994 // Defined in ic.cc.
995 Object* KeyedStoreIC_Miss(Arguments args);
996 
Generate(MacroAssembler * masm,const ExternalReference & f)997 void KeyedStoreIC::Generate(MacroAssembler* masm, const ExternalReference& f) {
998   // ----------- S t a t e -------------
999   //  -- eax    : value
1000   //  -- esp[0] : return address
1001   //  -- esp[4] : key
1002   //  -- esp[8] : receiver
1003   // -----------------------------------
1004 
1005   // Move the return address below the arguments.
1006   __ pop(ecx);
1007   __ push(Operand(esp, 1 * kPointerSize));
1008   __ push(Operand(esp, 1 * kPointerSize));
1009   __ push(eax);
1010   __ push(ecx);
1011 
1012   // Do tail-call to runtime routine.
1013   __ TailCallRuntime(f, 3);
1014 }
1015 
1016 
GenerateExtendStorage(MacroAssembler * masm)1017 void KeyedStoreIC::GenerateExtendStorage(MacroAssembler* masm) {
1018   // ----------- S t a t e -------------
1019   //  -- eax    : value
1020   //  -- ecx    : transition map
1021   //  -- esp[0] : return address
1022   //  -- esp[4] : key
1023   //  -- esp[8] : receiver
1024   // -----------------------------------
1025 
1026   // Move the return address below the arguments.
1027   __ pop(ebx);
1028   __ push(Operand(esp, 1 * kPointerSize));
1029   __ push(ecx);
1030   __ push(eax);
1031   __ push(ebx);
1032 
1033   // Do tail-call to runtime routine.
1034   __ TailCallRuntime(
1035       ExternalReference(IC_Utility(kSharedStoreIC_ExtendStorage)), 3);
1036 }
1037 
1038 #undef __
1039 
1040 
1041 } }  // namespace v8::internal
1042