blob: ccbc615bdf43732f7db59ac0936dd38be1a70087 [file] [log] [blame]
ager@chromium.org5ec48922009-05-05 07:25:34 +00001// Copyright 2009 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
kasperl@chromium.org71affb52009-05-26 05:44:31 +000028#include "v8.h"
29
30#include "codegen-inl.h"
31#include "ic-inl.h"
32#include "runtime.h"
33#include "stub-cache.h"
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000034#include "utils.h"
kasperl@chromium.org71affb52009-05-26 05:44:31 +000035
36namespace v8 {
37namespace internal {
38
ager@chromium.org5aa501c2009-06-23 07:57:28 +000039// ----------------------------------------------------------------------------
40// Static IC stub generators.
41//
42
43#define __ ACCESS_MASM(masm)
44
kasperl@chromium.org71affb52009-05-26 05:44:31 +000045
kasperl@chromium.orge959c182009-07-27 08:59:04 +000046// Helper function used to load a property from a dictionary backing storage.
47// This function may return false negatives, so miss_label
48// must always call a backup property load that is complete.
49// This function is safe to call if the receiver has fast properties,
50// or if name is not a symbol, and will jump to the miss_label in that case.
51static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label,
52 Register r0, Register r1, Register r2,
53 Register name) {
54 // Register use:
55 //
56 // r0 - used to hold the property dictionary.
57 //
58 // r1 - initially the receiver
59 // - used for the index into the property dictionary
60 // - holds the result on exit.
61 //
62 // r2 - used to hold the capacity of the property dictionary.
63 //
64 // name - holds the name of the property and is unchanged.
65
66 Label done;
67
68 // Check for the absence of an interceptor.
69 // Load the map into r0.
70 __ movq(r0, FieldOperand(r1, JSObject::kMapOffset));
71 // Test the has_named_interceptor bit in the map.
72 __ testl(FieldOperand(r0, Map::kInstanceAttributesOffset),
73 Immediate(1 << (Map::kHasNamedInterceptor + (3 * 8))));
74
75 // Jump to miss if the interceptor bit is set.
76 __ j(not_zero, miss_label);
77
78 // Bail out if we have a JS global proxy object.
79 __ movzxbq(r0, FieldOperand(r0, Map::kInstanceTypeOffset));
80 __ cmpb(r0, Immediate(JS_GLOBAL_PROXY_TYPE));
81 __ j(equal, miss_label);
82
83 // Possible work-around for http://crbug.com/16276.
84 __ cmpb(r0, Immediate(JS_GLOBAL_OBJECT_TYPE));
85 __ j(equal, miss_label);
86 __ cmpb(r0, Immediate(JS_BUILTINS_OBJECT_TYPE));
87 __ j(equal, miss_label);
88
89 // Check that the properties array is a dictionary.
90 __ movq(r0, FieldOperand(r1, JSObject::kPropertiesOffset));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000091 __ Cmp(FieldOperand(r0, HeapObject::kMapOffset), Factory::hash_table_map());
kasperl@chromium.orge959c182009-07-27 08:59:04 +000092 __ j(not_equal, miss_label);
93
94 // Compute the capacity mask.
95 const int kCapacityOffset =
96 StringDictionary::kHeaderSize +
97 StringDictionary::kCapacityIndex * kPointerSize;
98 __ movq(r2, FieldOperand(r0, kCapacityOffset));
ager@chromium.org4af710e2009-09-15 12:20:11 +000099 __ SmiToInteger32(r2, r2);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000100 __ decl(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.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000111 __ movl(r1, FieldOperand(name, String::kHashFieldOffset));
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000112 __ shrl(r1, Immediate(String::kHashShift));
113 if (i > 0) {
114 __ addl(r1, Immediate(StringDictionary::GetProbeOffset(i)));
115 }
116 __ and_(r1, 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 __ cmpq(name, Operand(r0, r1, times_pointer_size,
124 kElementsStartOffset - kHeapObjectTag));
125 if (i != kProbes - 1) {
126 __ j(equal, &done);
127 } else {
128 __ j(not_equal, miss_label);
129 }
130 }
131
132 // Check that the value is a normal property.
133 __ bind(&done);
134 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000135 __ Test(Operand(r0, r1, times_pointer_size, kDetailsOffset - kHeapObjectTag),
136 Smi::FromInt(PropertyDetails::TypeField::mask()));
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000137 __ j(not_zero, miss_label);
138
139 // Get the value at the masked, scaled index.
140 const int kValueOffset = kElementsStartOffset + kPointerSize;
141 __ movq(r1,
142 Operand(r0, r1, times_pointer_size, kValueOffset - kHeapObjectTag));
143}
144
145
146// Helper function used to check that a value is either not an object
147// or is loaded if it is an object.
148static void GenerateCheckNonObjectOrLoaded(MacroAssembler* masm, Label* miss,
149 Register value) {
150 Label done;
151 // Check if the value is a Smi.
ager@chromium.org4af710e2009-09-15 12:20:11 +0000152 __ JumpIfSmi(value, &done);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000153 // Check if the object has been loaded.
154 __ movq(kScratchRegister, FieldOperand(value, JSFunction::kMapOffset));
155 __ testb(FieldOperand(kScratchRegister, Map::kBitField2Offset),
156 Immediate(1 << Map::kNeedsLoading));
157 __ j(not_zero, miss);
158 __ bind(&done);
159}
160
161
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000162// One byte opcode for test eax,0xXXXXXXXX.
163static const byte kTestEaxByte = 0xA9;
164
165
166static bool PatchInlinedMapCheck(Address address, Object* map) {
167 // Arguments are address of start of call sequence that called
168 // the IC,
169 Address test_instruction_address =
ager@chromium.org4af710e2009-09-15 12:20:11 +0000170 address + Assembler::kCallTargetAddressOffset;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000171 // The keyed load has a fast inlined case if the IC call instruction
172 // is immediately followed by a test instruction.
173 if (*test_instruction_address != kTestEaxByte) return false;
174
175 // Fetch the offset from the test instruction to the map compare
176 // instructions (starting with the 64-bit immediate mov of the map
177 // address). This offset is stored in the last 4 bytes of the 5
178 // byte test instruction.
179 Address delta_address = test_instruction_address + 1;
180 int delta = *reinterpret_cast<int*>(delta_address);
181 // Compute the map address. The map address is in the last 8 bytes
182 // of the 10-byte immediate mov instruction (incl. REX prefix), so we add 2
183 // to the offset to get the map address.
184 Address map_address = test_instruction_address + delta + 2;
185 // Patch the map check.
186 *(reinterpret_cast<Object**>(map_address)) = map;
187 return true;
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000188}
189
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000190
191bool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) {
192 return PatchInlinedMapCheck(address, map);
193}
194
195
196bool KeyedStoreIC::PatchInlinedStore(Address address, Object* map) {
197 return PatchInlinedMapCheck(address, map);
198}
199
200
201void KeyedLoadIC::ClearInlinedVersion(Address address) {
202 // Insert null as the map to check for to make sure the map check fails
203 // sending control flow to the IC instead of the inlined version.
204 PatchInlinedLoad(address, Heap::null_value());
205}
206
207
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000208void KeyedStoreIC::ClearInlinedVersion(Address address) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000209 // Insert null as the elements map to check for. This will make
210 // sure that the elements fast-case map check fails so that control
211 // flows to the IC instead of the inlined version.
212 PatchInlinedStore(address, Heap::null_value());
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000213}
214
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000215
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000216void KeyedStoreIC::RestoreInlinedVersion(Address address) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000217 // Restore the fast-case elements map check so that the inlined
218 // version can be used again.
219 PatchInlinedStore(address, Heap::fixed_array_map());
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000220}
221
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000222
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000223void KeyedLoadIC::Generate(MacroAssembler* masm,
224 ExternalReference const& f) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000225 // ----------- S t a t e -------------
226 // -- rsp[0] : return address
227 // -- rsp[8] : name
228 // -- rsp[16] : receiver
229 // -----------------------------------
230
231 __ movq(rax, Operand(rsp, kPointerSize));
232 __ movq(rcx, Operand(rsp, 2 * kPointerSize));
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000233 __ pop(rbx);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000234 __ push(rcx); // receiver
235 __ push(rax); // name
236 __ push(rbx); // return address
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000237
238 // Perform tail call to the entry.
ager@chromium.orga1645e22009-09-09 19:27:10 +0000239 __ TailCallRuntime(f, 2, 1);
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000240}
241
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000242
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000243void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000244 // ----------- S t a t e -------------
245 // -- rsp[0] : return address
246 // -- rsp[8] : name
247 // -- rsp[16] : receiver
248 // -----------------------------------
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000249 Label slow, check_string, index_int, index_string, check_pixel_array;
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000250
251 // Load name and receiver.
252 __ movq(rax, Operand(rsp, kPointerSize));
253 __ movq(rcx, Operand(rsp, 2 * kPointerSize));
254
255 // Check that the object isn't a smi.
ager@chromium.org4af710e2009-09-15 12:20:11 +0000256 __ JumpIfSmi(rcx, &slow);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000257
258 // Check that the object is some kind of JS object EXCEPT JS Value type.
259 // In the case that the object is a value-wrapper object,
260 // we enter the runtime system to make sure that indexing
261 // into string objects work as intended.
262 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
263 __ CmpObjectType(rcx, JS_OBJECT_TYPE, rdx);
264 __ j(below, &slow);
265 // Check that the receiver does not require access checks. We need
266 // to check this explicitly since this generic stub does not perform
267 // map checks. The map is already in rdx.
268 __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
269 Immediate(1 << Map::kIsAccessCheckNeeded));
270 __ j(not_zero, &slow);
271
272 // Check that the key is a smi.
ager@chromium.org4af710e2009-09-15 12:20:11 +0000273 __ JumpIfNotSmi(rax, &check_string);
274 __ SmiToInteger32(rax, rax);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000275 // Get the elements array of the object.
276 __ bind(&index_int);
277 __ movq(rcx, FieldOperand(rcx, JSObject::kElementsOffset));
278 // Check that the object is in fast mode (not dictionary).
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000279 __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset),
280 Heap::kFixedArrayMapRootIndex);
281 __ j(not_equal, &check_pixel_array);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000282 // Check that the key (index) is within bounds.
283 __ cmpl(rax, FieldOperand(rcx, FixedArray::kLengthOffset));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000284 __ j(above_equal, &slow); // Unsigned comparison rejects negative indices.
285 // Fast case: Do the load.
286 __ movq(rax, Operand(rcx, rax, times_pointer_size,
287 FixedArray::kHeaderSize - kHeapObjectTag));
288 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
289 // In case the loaded value is the_hole we have to consult GetProperty
290 // to ensure the prototype chain is searched.
291 __ j(equal, &slow);
292 __ IncrementCounter(&Counters::keyed_load_generic_smi, 1);
293 __ ret(0);
294
295 // Check whether the elements is a pixel array.
296 // rax: untagged index
297 // rcx: elements array
298 __ bind(&check_pixel_array);
299 __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset),
300 Heap::kPixelArrayMapRootIndex);
301 __ j(not_equal, &slow);
302 __ cmpl(rax, FieldOperand(rcx, PixelArray::kLengthOffset));
303 __ j(above_equal, &slow);
304 __ movq(rcx, FieldOperand(rcx, PixelArray::kExternalPointerOffset));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000305 __ movzxbq(rax, Operand(rcx, rax, times_1, 0));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000306 __ Integer32ToSmi(rax, rax);
307 __ ret(0);
308
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000309 // Slow case: Load name and receiver from stack and jump to runtime.
310 __ bind(&slow);
311 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1);
ager@chromium.org3811b432009-10-28 14:53:37 +0000312 Generate(masm, ExternalReference(Runtime::kKeyedGetProperty));
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000313 __ bind(&check_string);
314 // The key is not a smi.
315 // Is it a string?
316 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rdx);
317 __ j(above_equal, &slow);
318 // Is the string an array index, with cached numeric value?
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000319 __ movl(rbx, FieldOperand(rax, String::kHashFieldOffset));
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000320 __ testl(rbx, Immediate(String::kIsArrayIndexMask));
321
322 // If the string is a symbol, do a quick inline probe of the receiver's
323 // dictionary, if it exists.
324 __ j(not_zero, &index_string); // The value in rbx is used at jump target.
325 __ testb(FieldOperand(rdx, Map::kInstanceTypeOffset),
326 Immediate(kIsSymbolMask));
327 __ j(zero, &slow);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000328 // Probe the dictionary leaving result in rcx.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000329 GenerateDictionaryLoad(masm, &slow, rbx, rcx, rdx, rax);
330 GenerateCheckNonObjectOrLoaded(masm, &slow, rcx);
331 __ movq(rax, rcx);
332 __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
333 __ ret(0);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000334 // If the hash field contains an array index pick it out. The assert checks
335 // that the constants for the maximum number of digits for an array index
336 // cached in the hash field and the number of bits reserved for it does not
337 // conflict.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000338 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000339 (1 << String::kArrayIndexValueBits));
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000340 __ bind(&index_string);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000341 __ movl(rax, rbx);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000342 __ and_(rax, Immediate(String::kArrayIndexHashMask));
343 __ shrl(rax, Immediate(String::kHashShift));
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000344 __ jmp(&index_int);
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000345}
346
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000347
ager@chromium.org3811b432009-10-28 14:53:37 +0000348void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm,
349 ExternalArrayType array_type) {
350 // ----------- S t a t e -------------
351 // -- rsp[0] : return address
352 // -- rsp[8] : name
353 // -- rsp[16] : receiver
354 // -----------------------------------
355 Label slow, failed_allocation;
356
357 // Load name and receiver.
358 __ movq(rax, Operand(rsp, kPointerSize));
359 __ movq(rcx, Operand(rsp, 2 * kPointerSize));
360
361 // Check that the object isn't a smi.
362 __ JumpIfSmi(rcx, &slow);
363
364 // Check that the key is a smi.
365 __ JumpIfNotSmi(rax, &slow);
366
367 // Check that the object is a JS object.
368 __ CmpObjectType(rcx, JS_OBJECT_TYPE, rdx);
369 __ j(not_equal, &slow);
370 // Check that the receiver does not require access checks. We need
371 // to check this explicitly since this generic stub does not perform
372 // map checks. The map is already in rdx.
373 __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
374 Immediate(1 << Map::kIsAccessCheckNeeded));
375 __ j(not_zero, &slow);
376
377 // Check that the elements array is the appropriate type of
378 // ExternalArray.
379 // rax: index (as a smi)
380 // rcx: JSObject
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000381 __ movq(rcx, FieldOperand(rcx, JSObject::kElementsOffset));
ager@chromium.org3811b432009-10-28 14:53:37 +0000382 __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset),
383 Heap::RootIndexForExternalArrayType(array_type));
384 __ j(not_equal, &slow);
385
386 // Check that the index is in range.
387 __ SmiToInteger32(rax, rax);
388 __ cmpl(rax, FieldOperand(rcx, ExternalArray::kLengthOffset));
389 // Unsigned comparison catches both negative and too-large values.
390 __ j(above_equal, &slow);
391
392 // rax: untagged index
393 // rcx: elements array
394 __ movq(rcx, FieldOperand(rcx, ExternalArray::kExternalPointerOffset));
395 // rcx: base pointer of external storage
396 switch (array_type) {
397 case kExternalByteArray:
398 __ movsxbq(rax, Operand(rcx, rax, times_1, 0));
399 break;
400 case kExternalUnsignedByteArray:
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000401 __ movzxbq(rax, Operand(rcx, rax, times_1, 0));
ager@chromium.org3811b432009-10-28 14:53:37 +0000402 break;
403 case kExternalShortArray:
404 __ movsxwq(rax, Operand(rcx, rax, times_2, 0));
405 break;
406 case kExternalUnsignedShortArray:
407 __ movzxwq(rax, Operand(rcx, rax, times_2, 0));
408 break;
409 case kExternalIntArray:
410 __ movsxlq(rax, Operand(rcx, rax, times_4, 0));
411 break;
412 case kExternalUnsignedIntArray:
413 __ movl(rax, Operand(rcx, rax, times_4, 0));
414 break;
415 case kExternalFloatArray:
416 __ fld_s(Operand(rcx, rax, times_4, 0));
417 break;
418 default:
419 UNREACHABLE();
420 break;
421 }
422
423 // For integer array types:
424 // rax: value
425 // For floating-point array type:
426 // FP(0): value
427
428 if (array_type == kExternalIntArray ||
429 array_type == kExternalUnsignedIntArray) {
430 // For the Int and UnsignedInt array types, we need to see whether
431 // the value can be represented in a Smi. If not, we need to convert
432 // it to a HeapNumber.
433 Label box_int;
434 if (array_type == kExternalIntArray) {
435 __ JumpIfNotValidSmiValue(rax, &box_int);
436 } else {
437 ASSERT_EQ(array_type, kExternalUnsignedIntArray);
438 __ JumpIfUIntNotValidSmiValue(rax, &box_int);
439 }
440
441 __ Integer32ToSmi(rax, rax);
442 __ ret(0);
443
444 __ bind(&box_int);
445
446 // Allocate a HeapNumber for the int and perform int-to-double
447 // conversion.
448 __ push(rax);
449 if (array_type == kExternalIntArray) {
450 __ fild_s(Operand(rsp, 0));
451 } else {
452 ASSERT(array_type == kExternalUnsignedIntArray);
453 // Need to zero-extend the value.
454 __ fild_d(Operand(rsp, 0));
455 }
456 __ pop(rax);
457 // FP(0): value
458 __ AllocateHeapNumber(rax, rbx, &failed_allocation);
459 // Set the value.
460 __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset));
461 __ ret(0);
462 } else if (array_type == kExternalFloatArray) {
463 // For the floating-point array type, we need to always allocate a
464 // HeapNumber.
465 __ AllocateHeapNumber(rax, rbx, &failed_allocation);
466 // Set the value.
467 __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset));
468 __ ret(0);
469 } else {
470 __ Integer32ToSmi(rax, rax);
471 __ ret(0);
472 }
473
474 // If we fail allocation of the HeapNumber, we still have a value on
475 // top of the FPU stack. Remove it.
476 __ bind(&failed_allocation);
477 __ ffree();
478 __ fincstp();
479 // Fall through to slow case.
480
481 // Slow case: Load name and receiver from stack and jump to runtime.
482 __ bind(&slow);
483 __ IncrementCounter(&Counters::keyed_load_external_array_slow, 1);
484 Generate(masm, ExternalReference(Runtime::kKeyedGetProperty));
485}
486
487
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000488void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000489 // ----------- S t a t e -------------
490 // -- rsp[0] : return address
491 // -- rsp[8] : name
492 // -- rsp[16] : receiver
493 // -----------------------------------
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000494 Generate(masm, ExternalReference(IC_Utility(kKeyedLoadIC_Miss)));
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000495}
496
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000497
498void KeyedStoreIC::Generate(MacroAssembler* masm, ExternalReference const& f) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000499 // ----------- S t a t e -------------
500 // -- rax : value
501 // -- rsp[0] : return address
502 // -- rsp[8] : key
503 // -- rsp[16] : receiver
504 // -----------------------------------
505
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000506 __ pop(rcx);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000507 __ push(Operand(rsp, 1 * kPointerSize)); // receiver
508 __ push(Operand(rsp, 1 * kPointerSize)); // key
509 __ push(rax); // value
510 __ push(rcx); // return address
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000511
512 // Do tail-call to runtime routine.
ager@chromium.orga1645e22009-09-09 19:27:10 +0000513 __ TailCallRuntime(f, 3, 1);
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000514}
515
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000516
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000517void KeyedStoreIC::GenerateExtendStorage(MacroAssembler* masm) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000518 // ----------- S t a t e -------------
519 // -- rax : value
520 // -- rcx : transition map
521 // -- rsp[0] : return address
522 // -- rsp[8] : key
523 // -- rsp[16] : receiver
524 // -----------------------------------
525
526 __ pop(rbx);
527 __ push(Operand(rsp, 1 * kPointerSize)); // receiver
528 __ push(rcx); // transition map
529 __ push(rax); // value
530 __ push(rbx); // return address
531
532 // Do tail-call to runtime routine.
533 __ TailCallRuntime(
ager@chromium.orga1645e22009-09-09 19:27:10 +0000534 ExternalReference(IC_Utility(kSharedStoreIC_ExtendStorage)), 3, 1);
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000535}
536
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000537
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000538void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000539 // ----------- S t a t e -------------
540 // -- rax : value
541 // -- rsp[0] : return address
542 // -- rsp[8] : key
543 // -- rsp[16] : receiver
544 // -----------------------------------
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000545 Label slow, fast, array, extra, check_pixel_array;
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000546
547 // Get the receiver from the stack.
548 __ movq(rdx, Operand(rsp, 2 * kPointerSize)); // 2 ~ return address, key
549 // Check that the object isn't a smi.
ager@chromium.org4af710e2009-09-15 12:20:11 +0000550 __ JumpIfSmi(rdx, &slow);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000551 // Get the map from the receiver.
552 __ movq(rcx, FieldOperand(rdx, HeapObject::kMapOffset));
553 // Check that the receiver does not require access checks. We need
554 // to do this because this generic stub does not perform map checks.
555 __ testb(FieldOperand(rcx, Map::kBitFieldOffset),
556 Immediate(1 << Map::kIsAccessCheckNeeded));
557 __ j(not_zero, &slow);
558 // Get the key from the stack.
559 __ movq(rbx, Operand(rsp, 1 * kPointerSize)); // 1 ~ return address
560 // Check that the key is a smi.
ager@chromium.org4af710e2009-09-15 12:20:11 +0000561 __ JumpIfNotSmi(rbx, &slow);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000562
563 __ CmpInstanceType(rcx, JS_ARRAY_TYPE);
564 __ j(equal, &array);
565 // Check that the object is some kind of JS object.
566 __ CmpInstanceType(rcx, FIRST_JS_OBJECT_TYPE);
567 __ j(below, &slow);
568
569 // Object case: Check key against length in the elements array.
570 // rax: value
571 // rdx: JSObject
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000572 // rbx: index (as a smi)
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000573 __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
574 // Check that the object is in fast mode (not dictionary).
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000575 __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset),
576 Heap::kFixedArrayMapRootIndex);
577 __ j(not_equal, &check_pixel_array);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000578 // Untag the key (for checking against untagged length in the fixed array).
ager@chromium.org4af710e2009-09-15 12:20:11 +0000579 __ SmiToInteger32(rdx, rbx);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000580 __ cmpl(rdx, FieldOperand(rcx, Array::kLengthOffset));
581 // rax: value
582 // rcx: FixedArray
583 // rbx: index (as a smi)
584 __ j(below, &fast);
585
ager@chromium.org3811b432009-10-28 14:53:37 +0000586 // Slow case: call runtime.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000587 __ bind(&slow);
ager@chromium.org3811b432009-10-28 14:53:37 +0000588 Generate(masm, ExternalReference(Runtime::kSetProperty));
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000589
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000590 // Check whether the elements is a pixel array.
591 // rax: value
592 // rcx: elements array
593 // rbx: index (as a smi), zero-extended.
594 __ bind(&check_pixel_array);
595 __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset),
596 Heap::kPixelArrayMapRootIndex);
597 __ j(not_equal, &slow);
598 // Check that the value is a smi. If a conversion is needed call into the
599 // runtime to convert and clamp.
600 __ JumpIfNotSmi(rax, &slow);
601 __ SmiToInteger32(rbx, rbx);
602 __ cmpl(rbx, FieldOperand(rcx, PixelArray::kLengthOffset));
603 __ j(above_equal, &slow);
604 __ movq(rdx, rax); // Save the value.
605 __ SmiToInteger32(rax, rax);
606 { // Clamp the value to [0..255].
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000607 Label done;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000608 __ testl(rax, Immediate(0xFFFFFF00));
609 __ j(zero, &done);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000610 __ setcc(negative, rax); // 1 if negative, 0 if positive.
611 __ decb(rax); // 0 if negative, 255 if positive.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000612 __ bind(&done);
613 }
614 __ movq(rcx, FieldOperand(rcx, PixelArray::kExternalPointerOffset));
615 __ movb(Operand(rcx, rbx, times_1, 0), rax);
616 __ movq(rax, rdx); // Return the original value.
617 __ ret(0);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000618
619 // Extra capacity case: Check if there is extra capacity to
620 // perform the store and update the length. Used for adding one
621 // element to the array by writing to array[array.length].
622 __ bind(&extra);
623 // rax: value
624 // rdx: JSArray
625 // rcx: FixedArray
626 // rbx: index (as a smi)
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000627 // flags: smicompare (rdx.length(), rbx)
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000628 __ j(not_equal, &slow); // do not leave holes in the array
ager@chromium.org4af710e2009-09-15 12:20:11 +0000629 __ SmiToInteger64(rbx, rbx);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000630 __ cmpl(rbx, FieldOperand(rcx, FixedArray::kLengthOffset));
631 __ j(above_equal, &slow);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000632 // Increment and restore smi-tag.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000633 __ Integer64PlusConstantToSmi(rbx, rbx, 1);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000634 __ movq(FieldOperand(rdx, JSArray::kLengthOffset), rbx);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000635 __ SmiSubConstant(rbx, rbx, Smi::FromInt(1));
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000636 __ jmp(&fast);
637
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000638 // Array case: Get the length and the elements array from the JS
639 // array. Check that the array is in fast mode; if it is the
640 // length is always a smi.
641 __ bind(&array);
642 // rax: value
643 // rdx: JSArray
644 // rbx: index (as a smi)
645 __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000646 __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset),
647 Heap::kFixedArrayMapRootIndex);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000648 __ j(not_equal, &slow);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000649
650 // Check the key against the length in the array, compute the
651 // address to store into and fall through to fast case.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000652 __ SmiCompare(FieldOperand(rdx, JSArray::kLengthOffset), rbx);
653 __ j(below_equal, &extra);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000654
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000655 // Fast case: Do the store.
656 __ bind(&fast);
657 // rax: value
658 // rcx: FixedArray
659 // rbx: index (as a smi)
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000660 Label non_smi_value;
661 __ JumpIfNotSmi(rax, &non_smi_value);
662 SmiIndex index = masm->SmiToIndex(rbx, rbx, kPointerSizeLog2);
663 __ movq(Operand(rcx, index.reg, index.scale,
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000664 FixedArray::kHeaderSize - kHeapObjectTag),
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000665 rax);
666 __ ret(0);
667 __ bind(&non_smi_value);
668 // Slow case that needs to retain rbx for use by RecordWrite.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000669 // Update write barrier for the elements array address.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000670 SmiIndex index2 = masm->SmiToIndex(kScratchRegister, rbx, kPointerSizeLog2);
671 __ movq(Operand(rcx, index2.reg, index2.scale,
672 FixedArray::kHeaderSize - kHeapObjectTag),
673 rax);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000674 __ movq(rdx, rax);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000675 __ RecordWriteNonSmi(rcx, 0, rdx, rbx);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000676 __ ret(0);
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000677}
678
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000679
ager@chromium.org3811b432009-10-28 14:53:37 +0000680void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm,
681 ExternalArrayType array_type) {
682 // ----------- S t a t e -------------
683 // -- rax : value
684 // -- rsp[0] : return address
685 // -- rsp[8] : key
686 // -- rsp[16] : receiver
687 // -----------------------------------
688 Label slow, check_heap_number;
689
690 // Get the receiver from the stack.
691 __ movq(rdx, Operand(rsp, 2 * kPointerSize));
692 // Check that the object isn't a smi.
693 __ JumpIfSmi(rdx, &slow);
694 // Get the map from the receiver.
695 __ movq(rcx, FieldOperand(rdx, HeapObject::kMapOffset));
696 // Check that the receiver does not require access checks. We need
697 // to do this because this generic stub does not perform map checks.
698 __ testb(FieldOperand(rcx, Map::kBitFieldOffset),
699 Immediate(1 << Map::kIsAccessCheckNeeded));
700 __ j(not_zero, &slow);
701 // Get the key from the stack.
702 __ movq(rbx, Operand(rsp, 1 * kPointerSize)); // 1 ~ return address
703 // Check that the key is a smi.
704 __ JumpIfNotSmi(rbx, &slow);
705
706 // Check that the object is a JS object.
707 __ CmpInstanceType(rcx, JS_OBJECT_TYPE);
708 __ j(not_equal, &slow);
709
710 // Check that the elements array is the appropriate type of
711 // ExternalArray.
712 // rax: value
713 // rdx: JSObject
714 // rbx: index (as a smi)
715 __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
716 __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset),
717 Heap::RootIndexForExternalArrayType(array_type));
718 __ j(not_equal, &slow);
719
720 // Check that the index is in range.
721 __ SmiToInteger32(rbx, rbx); // Untag the index.
722 __ cmpl(rbx, FieldOperand(rcx, ExternalArray::kLengthOffset));
723 // Unsigned comparison catches both negative and too-large values.
724 __ j(above_equal, &slow);
725
726 // Handle both smis and HeapNumbers in the fast path. Go to the
727 // runtime for all other kinds of values.
728 // rax: value
729 // rcx: elements array
730 // rbx: untagged index
731 __ JumpIfNotSmi(rax, &check_heap_number);
732 __ movq(rdx, rax); // Save the value.
733 __ SmiToInteger32(rax, rax);
734 __ movq(rcx, FieldOperand(rcx, ExternalArray::kExternalPointerOffset));
735 // rcx: base pointer of external storage
736 switch (array_type) {
737 case kExternalByteArray:
738 case kExternalUnsignedByteArray:
739 __ movb(Operand(rcx, rbx, times_1, 0), rax);
740 break;
741 case kExternalShortArray:
742 case kExternalUnsignedShortArray:
743 __ movw(Operand(rcx, rbx, times_2, 0), rax);
744 break;
745 case kExternalIntArray:
746 case kExternalUnsignedIntArray:
747 __ movl(Operand(rcx, rbx, times_4, 0), rax);
748 break;
749 case kExternalFloatArray:
750 // Need to perform int-to-float conversion.
751 __ push(rax);
752 __ fild_s(Operand(rsp, 0));
753 __ pop(rax);
754 __ fstp_s(Operand(rcx, rbx, times_4, 0));
755 break;
756 default:
757 UNREACHABLE();
758 break;
759 }
760 __ movq(rax, rdx); // Return the original value.
761 __ ret(0);
762
763 __ bind(&check_heap_number);
764 __ CmpObjectType(rax, HEAP_NUMBER_TYPE, rdx);
765 __ j(not_equal, &slow);
766
767 // The WebGL specification leaves the behavior of storing NaN and
768 // +/-Infinity into integer arrays basically undefined. For more
769 // reproducible behavior, convert these to zero.
770 __ fld_d(FieldOperand(rax, HeapNumber::kValueOffset));
771 __ movq(rdx, rax); // Save the value.
772 __ movq(rcx, FieldOperand(rcx, ExternalArray::kExternalPointerOffset));
773 // rbx: untagged index
774 // rcx: base pointer of external storage
775 // top of FPU stack: value
776 if (array_type == kExternalFloatArray) {
777 __ fstp_s(Operand(rcx, rbx, times_4, 0));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000778 __ movq(rax, rdx); // Return the original value.
779 __ ret(0);
ager@chromium.org3811b432009-10-28 14:53:37 +0000780 } else {
781 // Need to perform float-to-int conversion.
782 // Test the top of the FP stack for NaN.
783 Label is_nan;
784 __ fucomi(0);
785 __ j(parity_even, &is_nan);
786
787 __ push(rax); // Make room on stack
788 __ fistp_d(Operand(rsp, 0));
789 __ pop(rax);
790 // rax: untagged integer value
791 switch (array_type) {
792 case kExternalByteArray:
793 case kExternalUnsignedByteArray:
794 __ movb(Operand(rcx, rbx, times_1, 0), rax);
795 break;
796 case kExternalShortArray:
797 case kExternalUnsignedShortArray:
798 __ movw(Operand(rcx, rbx, times_2, 0), rax);
799 break;
800 case kExternalIntArray:
801 case kExternalUnsignedIntArray: {
802 // We also need to explicitly check for +/-Infinity. These are
803 // converted to MIN_INT, but we need to be careful not to
804 // confuse with legal uses of MIN_INT.
805 Label not_infinity;
806 // This test would apparently detect both NaN and Infinity,
807 // but we've already checked for NaN using the FPU hardware
808 // above.
809 __ movzxwq(rdi, FieldOperand(rdx, HeapNumber::kValueOffset + 6));
810 __ and_(rdi, Immediate(0x7FF0));
811 __ cmpw(rdi, Immediate(0x7FF0));
812 __ j(not_equal, &not_infinity);
813 __ movq(rax, Immediate(0));
814 __ bind(&not_infinity);
815 __ movl(Operand(rcx, rbx, times_4, 0), rax);
816 break;
817 }
818 default:
819 UNREACHABLE();
820 break;
821 }
822 __ movq(rax, rdx); // Return the original value.
823 __ ret(0);
824
825 __ bind(&is_nan);
826 __ ffree();
827 __ fincstp();
828 __ movq(rax, Immediate(0));
829 switch (array_type) {
830 case kExternalByteArray:
831 case kExternalUnsignedByteArray:
832 __ movb(Operand(rcx, rbx, times_1, 0), rax);
833 break;
834 case kExternalShortArray:
835 case kExternalUnsignedShortArray:
836 __ movw(Operand(rcx, rbx, times_2, 0), rax);
837 break;
838 case kExternalIntArray:
839 case kExternalUnsignedIntArray:
840 __ movl(Operand(rcx, rbx, times_4, 0), rax);
841 break;
842 default:
843 UNREACHABLE();
844 break;
845 }
846 __ movq(rax, rdx); // Return the original value.
847 __ ret(0);
848 }
849
850 // Slow case: call runtime.
851 __ bind(&slow);
852 Generate(masm, ExternalReference(Runtime::kSetProperty));
853}
854
855
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000856void CallIC::Generate(MacroAssembler* masm,
857 int argc,
858 ExternalReference const& f) {
859 // Get the receiver of the function from the stack; 1 ~ return address.
860 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
861 // Get the name of the function to call from the stack.
862 // 2 ~ receiver, return address.
863 __ movq(rbx, Operand(rsp, (argc + 2) * kPointerSize));
864
865 // Enter an internal frame.
866 __ EnterInternalFrame();
867
868 // Push the receiver and the name of the function.
869 __ push(rdx);
870 __ push(rbx);
871
872 // Call the entry.
ager@chromium.orga1645e22009-09-09 19:27:10 +0000873 CEntryStub stub(1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000874 __ movq(rax, Immediate(2));
875 __ movq(rbx, f);
876 __ CallStub(&stub);
877
878 // Move result to rdi and exit the internal frame.
879 __ movq(rdi, rax);
880 __ LeaveInternalFrame();
881
882 // Check if the receiver is a global object of some sort.
883 Label invoke, global;
884 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); // receiver
ager@chromium.org4af710e2009-09-15 12:20:11 +0000885 __ JumpIfSmi(rdx, &invoke);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000886 __ CmpObjectType(rdx, JS_GLOBAL_OBJECT_TYPE, rcx);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000887 __ j(equal, &global);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000888 __ CmpInstanceType(rcx, JS_BUILTINS_OBJECT_TYPE);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000889 __ j(not_equal, &invoke);
890
891 // Patch the receiver on the stack.
892 __ bind(&global);
893 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
894 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
895
896 // Invoke the function.
897 ParameterCount actual(argc);
898 __ bind(&invoke);
899 __ InvokeFunction(rdi, actual, JUMP_FUNCTION);
900}
901
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000902
903// Defined in ic.cc.
904Object* CallIC_Miss(Arguments args);
905
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000906void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000907 // ----------- S t a t e -------------
908 // rsp[0] return address
909 // rsp[8] argument argc
910 // rsp[16] argument argc - 1
911 // ...
912 // rsp[argc * 8] argument 1
913 // rsp[(argc + 1) * 8] argument 0 = reciever
914 // rsp[(argc + 2) * 8] function name
915 // -----------------------------------
916 Label number, non_number, non_string, boolean, probe, miss;
917
918 // Get the receiver of the function from the stack; 1 ~ return address.
919 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
920 // Get the name of the function from the stack; 2 ~ return address, receiver
921 __ movq(rcx, Operand(rsp, (argc + 2) * kPointerSize));
922
923 // Probe the stub cache.
924 Code::Flags flags =
925 Code::ComputeFlags(Code::CALL_IC, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc);
926 StubCache::GenerateProbe(masm, flags, rdx, rcx, rbx, rax);
927
928 // If the stub cache probing failed, the receiver might be a value.
929 // For value objects, we use the map of the prototype objects for
930 // the corresponding JSValue for the cache and that is what we need
931 // to probe.
932 //
933 // Check for number.
ager@chromium.org4af710e2009-09-15 12:20:11 +0000934 __ JumpIfSmi(rdx, &number);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000935 __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rbx);
936 __ j(not_equal, &non_number);
937 __ bind(&number);
938 StubCompiler::GenerateLoadGlobalFunctionPrototype(
939 masm, Context::NUMBER_FUNCTION_INDEX, rdx);
940 __ jmp(&probe);
941
942 // Check for string.
943 __ bind(&non_number);
944 __ CmpInstanceType(rbx, FIRST_NONSTRING_TYPE);
945 __ j(above_equal, &non_string);
946 StubCompiler::GenerateLoadGlobalFunctionPrototype(
947 masm, Context::STRING_FUNCTION_INDEX, rdx);
948 __ jmp(&probe);
949
950 // Check for boolean.
951 __ bind(&non_string);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000952 __ CompareRoot(rdx, Heap::kTrueValueRootIndex);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000953 __ j(equal, &boolean);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000954 __ CompareRoot(rdx, Heap::kFalseValueRootIndex);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000955 __ j(not_equal, &miss);
956 __ bind(&boolean);
957 StubCompiler::GenerateLoadGlobalFunctionPrototype(
958 masm, Context::BOOLEAN_FUNCTION_INDEX, rdx);
959
960 // Probe the stub cache for the value object.
961 __ bind(&probe);
962 StubCache::GenerateProbe(masm, flags, rdx, rcx, rbx, no_reg);
963
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000964 // Cache miss: Jump to runtime.
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000965 __ bind(&miss);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000966 Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss)));
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000967}
968
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000969
970static void GenerateNormalHelper(MacroAssembler* masm,
971 int argc,
972 bool is_global_object,
973 Label* miss) {
974 // Search dictionary - put result in register edx.
975 GenerateDictionaryLoad(masm, miss, rax, rdx, rbx, rcx);
976
977 // Move the result to register rdi and check that it isn't a smi.
978 __ movq(rdi, rdx);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000979 __ JumpIfSmi(rdx, miss);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000980
981 // Check that the value is a JavaScript function.
982 __ CmpObjectType(rdx, JS_FUNCTION_TYPE, rdx);
983 __ j(not_equal, miss);
984 // Check that the function has been loaded.
985 __ testb(FieldOperand(rdx, Map::kBitField2Offset),
986 Immediate(1 << Map::kNeedsLoading));
987 __ j(not_zero, miss);
988
989 // Patch the receiver with the global proxy if necessary.
990 if (is_global_object) {
991 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
992 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
993 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
994 }
995
996 // Invoke the function.
997 ParameterCount actual(argc);
998 __ InvokeFunction(rdi, actual, JUMP_FUNCTION);
999}
1000
1001
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001002void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +00001003 // ----------- S t a t e -------------
1004 // rsp[0] return address
1005 // rsp[8] argument argc
1006 // rsp[16] argument argc - 1
1007 // ...
1008 // rsp[argc * 8] argument 1
1009 // rsp[(argc + 1) * 8] argument 0 = reciever
1010 // rsp[(argc + 2) * 8] function name
1011 // -----------------------------------
1012
1013 Label miss, global_object, non_global_object;
1014
1015 // Get the receiver of the function from the stack.
1016 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
1017 // Get the name of the function from the stack.
1018 __ movq(rcx, Operand(rsp, (argc + 2) * kPointerSize));
1019
1020 // Check that the receiver isn't a smi.
ager@chromium.org4af710e2009-09-15 12:20:11 +00001021 __ JumpIfSmi(rdx, &miss);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +00001022
1023 // Check that the receiver is a valid JS object.
1024 // Because there are so many map checks and type checks, do not
1025 // use CmpObjectType, but load map and type into registers.
1026 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
1027 __ movb(rax, FieldOperand(rbx, Map::kInstanceTypeOffset));
1028 __ cmpb(rax, Immediate(FIRST_JS_OBJECT_TYPE));
1029 __ j(below, &miss);
1030
1031 // If this assert fails, we have to check upper bound too.
1032 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
1033
1034 // Check for access to global object.
1035 __ cmpb(rax, Immediate(JS_GLOBAL_OBJECT_TYPE));
1036 __ j(equal, &global_object);
1037 __ cmpb(rax, Immediate(JS_BUILTINS_OBJECT_TYPE));
1038 __ j(not_equal, &non_global_object);
1039
1040 // Accessing global object: Load and invoke.
1041 __ bind(&global_object);
1042 // Check that the global object does not require access checks.
1043 __ movb(rbx, FieldOperand(rbx, Map::kBitFieldOffset));
1044 __ testb(rbx, Immediate(1 << Map::kIsAccessCheckNeeded));
1045 __ j(not_equal, &miss);
1046 GenerateNormalHelper(masm, argc, true, &miss);
1047
1048 // Accessing non-global object: Check for access to global proxy.
1049 Label global_proxy, invoke;
1050 __ bind(&non_global_object);
1051 __ cmpb(rax, Immediate(JS_GLOBAL_PROXY_TYPE));
1052 __ j(equal, &global_proxy);
1053 // Check that the non-global, non-global-proxy object does not
1054 // require access checks.
1055 __ movb(rbx, FieldOperand(rbx, Map::kBitFieldOffset));
1056 __ testb(rbx, Immediate(1 << Map::kIsAccessCheckNeeded));
1057 __ j(not_equal, &miss);
1058 __ bind(&invoke);
1059 GenerateNormalHelper(masm, argc, false, &miss);
1060
1061 // Global object proxy access: Check access rights.
1062 __ bind(&global_proxy);
1063 __ CheckAccessGlobalProxy(rdx, rax, &miss);
1064 __ jmp(&invoke);
1065
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001066 // Cache miss: Jump to runtime.
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +00001067 __ bind(&miss);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001068 Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss)));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001069}
1070
1071
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001072// The offset from the inlined patch site to the start of the
1073// inlined load instruction.
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001074const int LoadIC::kOffsetToLoadInstruction = 20;
1075
1076
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001077void LoadIC::ClearInlinedVersion(Address address) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001078 // Reset the map check of the inlined inobject property load (if
1079 // present) to guarantee failure by holding an invalid map (the null
1080 // value). The offset can be patched to anything.
1081 PatchInlinedLoad(address, Heap::null_value(), kMaxInt);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001082}
1083
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001084
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001085void LoadIC::Generate(MacroAssembler* masm, ExternalReference const& f) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001086 // ----------- S t a t e -------------
1087 // -- rcx : name
1088 // -- rsp[0] : return address
1089 // -- rsp[8] : receiver
1090 // -----------------------------------
1091
1092 __ movq(rax, Operand(rsp, kPointerSize));
1093
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001094 __ pop(rbx);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001095 __ push(rax); // receiver
1096 __ push(rcx); // name
1097 __ push(rbx); // return address
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001098
1099 // Perform tail call to the entry.
ager@chromium.orga1645e22009-09-09 19:27:10 +00001100 __ TailCallRuntime(f, 2, 1);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001101}
1102
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001103
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001104void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00001105 // ----------- S t a t e -------------
1106 // -- rcx : name
1107 // -- rsp[0] : return address
1108 // -- rsp[8] : receiver
1109 // -----------------------------------
1110
1111 Label miss;
1112
1113 __ movq(rax, Operand(rsp, kPointerSize));
1114
1115 StubCompiler::GenerateLoadArrayLength(masm, rax, rdx, &miss);
1116 __ bind(&miss);
1117 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001118}
1119
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00001120
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001121void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001122 // ----------- S t a t e -------------
1123 // -- rcx : name
1124 // -- rsp[0] : return address
1125 // -- rsp[8] : receiver
1126 // -----------------------------------
1127
1128 Label miss;
1129
1130 __ movq(rax, Operand(rsp, kPointerSize));
1131
1132 StubCompiler::GenerateLoadFunctionPrototype(masm, rax, rdx, rbx, &miss);
1133 __ bind(&miss);
1134 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001135}
1136
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001137
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001138void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001139 // ----------- S t a t e -------------
1140 // -- rcx : name
1141 // -- rsp[0] : return address
1142 // -- rsp[8] : receiver
1143 // -----------------------------------
1144
1145 __ movq(rax, Operand(rsp, kPointerSize));
1146
1147 // Probe the stub cache.
1148 Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
1149 NOT_IN_LOOP,
1150 MONOMORPHIC);
1151 StubCache::GenerateProbe(masm, flags, rax, rcx, rbx, rdx);
1152
1153 // Cache miss: Jump to runtime.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001154 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001155}
1156
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001157
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001158void LoadIC::GenerateMiss(MacroAssembler* masm) {
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001159 // ----------- S t a t e -------------
1160 // -- rcx : name
1161 // -- rsp[0] : return address
1162 // -- rsp[8] : receiver
1163 // -----------------------------------
1164
1165 Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001166}
1167
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001168
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001169void LoadIC::GenerateNormal(MacroAssembler* masm) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001170 // ----------- S t a t e -------------
1171 // -- rcx : name
1172 // -- rsp[0] : return address
1173 // -- rsp[8] : receiver
1174 // -----------------------------------
1175
1176 Label miss, probe, global;
1177
1178 __ movq(rax, Operand(rsp, kPointerSize));
1179
1180 // Check that the receiver isn't a smi.
ager@chromium.org4af710e2009-09-15 12:20:11 +00001181 __ JumpIfSmi(rax, &miss);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001182
1183 // Check that the receiver is a valid JS object.
1184 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx);
1185 __ j(below, &miss);
1186
1187 // If this assert fails, we have to check upper bound too.
1188 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
1189
1190 // Check for access to global object (unlikely).
1191 __ CmpInstanceType(rbx, JS_GLOBAL_PROXY_TYPE);
1192 __ j(equal, &global);
1193
1194 // Check for non-global object that requires access check.
1195 __ testl(FieldOperand(rbx, Map::kBitFieldOffset),
1196 Immediate(1 << Map::kIsAccessCheckNeeded));
1197 __ j(not_zero, &miss);
1198
1199 // Search the dictionary placing the result in eax.
1200 __ bind(&probe);
1201 GenerateDictionaryLoad(masm, &miss, rdx, rax, rbx, rcx);
1202 GenerateCheckNonObjectOrLoaded(masm, &miss, rax);
1203 __ ret(0);
1204
1205 // Global object access: Check access rights.
1206 __ bind(&global);
1207 __ CheckAccessGlobalProxy(rax, rdx, &miss);
1208 __ jmp(&probe);
1209
1210 // Cache miss: Restore receiver from stack and jump to runtime.
1211 __ bind(&miss);
1212 __ movq(rax, Operand(rsp, 1 * kPointerSize));
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001213 Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001214}
1215
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001216
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001217void LoadIC::GenerateStringLength(MacroAssembler* masm) {
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00001218 // ----------- S t a t e -------------
1219 // -- rcx : name
1220 // -- rsp[0] : return address
1221 // -- rsp[8] : receiver
1222 // -----------------------------------
1223
1224 Label miss;
1225
1226 __ movq(rax, Operand(rsp, kPointerSize));
1227
1228 StubCompiler::GenerateLoadStringLength(masm, rax, rdx, &miss);
1229 __ bind(&miss);
1230 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001231}
1232
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001233
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00001234
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001235bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
1236 // The address of the instruction following the call.
1237 Address test_instruction_address =
ager@chromium.org4af710e2009-09-15 12:20:11 +00001238 address + Assembler::kCallTargetAddressOffset;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001239 // If the instruction following the call is not a test eax, nothing
1240 // was inlined.
1241 if (*test_instruction_address != kTestEaxByte) return false;
1242
1243 Address delta_address = test_instruction_address + 1;
1244 // The delta to the start of the map check instruction.
1245 int delta = *reinterpret_cast<int*>(delta_address);
1246
1247 // The map address is the last 8 bytes of the 10-byte
1248 // immediate move instruction, so we add 2 to get the
1249 // offset to the last 8 bytes.
1250 Address map_address = test_instruction_address + delta + 2;
1251 *(reinterpret_cast<Object**>(map_address)) = map;
1252
1253 // The offset is in the 32-bit displacement of a seven byte
1254 // memory-to-register move instruction (REX.W 0x88 ModR/M disp32),
1255 // so we add 3 to get the offset of the displacement.
1256 Address offset_address =
1257 test_instruction_address + delta + kOffsetToLoadInstruction + 3;
1258 *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag;
1259 return true;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001260}
1261
1262void StoreIC::Generate(MacroAssembler* masm, ExternalReference const& f) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001263 // ----------- S t a t e -------------
1264 // -- rax : value
1265 // -- rcx : name
1266 // -- rsp[0] : return address
1267 // -- rsp[8] : receiver
1268 // -----------------------------------
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001269 __ pop(rbx);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001270 __ push(Operand(rsp, 0)); // receiver
1271 __ push(rcx); // name
1272 __ push(rax); // value
1273 __ push(rbx); // return address
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001274
1275 // Perform tail call to the entry.
ager@chromium.orga1645e22009-09-09 19:27:10 +00001276 __ TailCallRuntime(f, 3, 1);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001277}
1278
1279void StoreIC::GenerateExtendStorage(MacroAssembler* masm) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001280 // ----------- S t a t e -------------
1281 // -- rax : value
1282 // -- rcx : Map (target of map transition)
1283 // -- rsp[0] : return address
1284 // -- rsp[8] : receiver
1285 // -----------------------------------
1286
1287 __ pop(rbx);
1288 __ push(Operand(rsp, 0)); // receiver
1289 __ push(rcx); // transition map
1290 __ push(rax); // value
1291 __ push(rbx); // return address
1292
1293 // Perform tail call to the entry.
1294 __ TailCallRuntime(
ager@chromium.orga1645e22009-09-09 19:27:10 +00001295 ExternalReference(IC_Utility(kSharedStoreIC_ExtendStorage)), 3, 1);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001296}
1297
1298void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001299 // ----------- S t a t e -------------
1300 // -- rax : value
1301 // -- rcx : name
1302 // -- rsp[0] : return address
1303 // -- rsp[8] : receiver
1304 // -----------------------------------
1305
1306 // Get the receiver from the stack and probe the stub cache.
1307 __ movq(rdx, Operand(rsp, kPointerSize));
1308 Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
1309 NOT_IN_LOOP,
1310 MONOMORPHIC);
1311 StubCache::GenerateProbe(masm, flags, rdx, rcx, rbx, no_reg);
1312
1313 // Cache miss: Jump to runtime.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001314 Generate(masm, ExternalReference(IC_Utility(kStoreIC_Miss)));
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001315}
1316
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001317
1318#undef __
1319
1320
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001321} } // namespace v8::internal