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