blob: f5ff341f434b402581cd4ab4de8c5e0f519a34fc [file] [log] [blame]
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001// Copyright 2011 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// 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
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000030#if defined(V8_TARGET_ARCH_IA32)
31
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000032#include "codegen.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000033#include "ic-inl.h"
34#include "runtime.h"
35#include "stub-cache.h"
36
kasperl@chromium.org71affb52009-05-26 05:44:31 +000037namespace v8 {
38namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000039
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040// ----------------------------------------------------------------------------
41// Static IC stub generators.
42//
43
ager@chromium.org65dad4b2009-04-23 08:48:43 +000044#define __ ACCESS_MASM(masm)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000045
46
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000047static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
48 Register type,
49 Label* global_object) {
50 // Register usage:
51 // type: holds the receiver instance type on entry.
52 __ cmp(type, JS_GLOBAL_OBJECT_TYPE);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000053 __ j(equal, global_object);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000054 __ cmp(type, JS_BUILTINS_OBJECT_TYPE);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000055 __ j(equal, global_object);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000056 __ cmp(type, JS_GLOBAL_PROXY_TYPE);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000057 __ j(equal, global_object);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000058}
59
60
61// Generated code falls through if the receiver is a regular non-global
62// JS object with slow properties and no interceptors.
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +000063static void GenerateStringDictionaryReceiverCheck(MacroAssembler* masm,
64 Register receiver,
65 Register r0,
66 Register r1,
67 Label* miss) {
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000068 // Register usage:
69 // receiver: holds the receiver on entry and is unchanged.
70 // r0: used to hold receiver instance type.
71 // Holds the property dictionary on fall through.
72 // r1: used to hold receivers map.
73
74 // Check that the receiver isn't a smi.
75 __ test(receiver, Immediate(kSmiTagMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000076 __ j(zero, miss);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000077
78 // Check that the receiver is a valid JS object.
79 __ mov(r1, FieldOperand(receiver, HeapObject::kMapOffset));
80 __ movzx_b(r0, FieldOperand(r1, Map::kInstanceTypeOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000081 __ cmp(r0, FIRST_SPEC_OBJECT_TYPE);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000082 __ j(below, miss);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000083
84 // If this assert fails, we have to check upper bound too.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000085 STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000086
87 GenerateGlobalInstanceTypeCheck(masm, r0, miss);
88
89 // Check for non-global object that requires access check.
90 __ test_b(FieldOperand(r1, Map::kBitFieldOffset),
91 (1 << Map::kIsAccessCheckNeeded) |
92 (1 << Map::kHasNamedInterceptor));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000093 __ j(not_zero, miss);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000094
95 __ mov(r0, FieldOperand(receiver, JSObject::kPropertiesOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000096 __ CheckMap(r0, FACTORY->hash_table_map(), miss, DONT_DO_SMI_CHECK);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000097}
98
99
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000100// Helper function used to load a property from a dictionary backing
101// storage. This function may fail to load a property even though it is
102// in the dictionary, so code at miss_label must always call a backup
103// property load that is complete. This function is safe to call if
104// name is not a symbol, and will jump to the miss_label in that
105// case. The generated code assumes that the receiver has slow
106// properties, is not a global object and does not have interceptors.
107static void GenerateDictionaryLoad(MacroAssembler* masm,
108 Label* miss_label,
109 Register elements,
110 Register name,
111 Register r0,
112 Register r1,
113 Register result) {
114 // Register use:
115 //
116 // elements - holds the property dictionary on entry and is unchanged.
117 //
118 // name - holds the name of the property on entry and is unchanged.
119 //
120 // Scratch registers:
121 //
122 // r0 - used for the index into the property dictionary
123 //
124 // r1 - used to hold the capacity of the property dictionary.
125 //
126 // result - holds the result on exit.
127
128 Label done;
129
130 // Probe the dictionary.
lrn@chromium.org1c092762011-05-09 09:42:16 +0000131 StringDictionaryLookupStub::GeneratePositiveLookup(masm,
132 miss_label,
133 &done,
134 elements,
135 name,
136 r0,
137 r1);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000138
139 // If probing finds an entry in the dictionary, r0 contains the
140 // index into the dictionary. Check that the value is a normal
141 // property.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000142 __ bind(&done);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000143 const int kElementsStartOffset =
144 StringDictionary::kHeaderSize +
145 StringDictionary::kElementsStartIndex * kPointerSize;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000146 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000147 __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000148 Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000149 __ j(not_zero, miss_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000150
151 // Get the value at the masked, scaled index.
152 const int kValueOffset = kElementsStartOffset + kPointerSize;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000153 __ mov(result, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000154}
155
156
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000157// Helper function used to store a property to a dictionary backing
158// storage. This function may fail to store a property eventhough it
159// is in the dictionary, so code at miss_label must always call a
160// backup property store that is complete. This function is safe to
161// call if name is not a symbol, and will jump to the miss_label in
162// that case. The generated code assumes that the receiver has slow
163// properties, is not a global object and does not have interceptors.
164static void GenerateDictionaryStore(MacroAssembler* masm,
165 Label* miss_label,
166 Register elements,
167 Register name,
168 Register value,
169 Register r0,
170 Register r1) {
171 // Register use:
172 //
173 // elements - holds the property dictionary on entry and is clobbered.
174 //
175 // name - holds the name of the property on entry and is unchanged.
176 //
177 // value - holds the value to store and is unchanged.
178 //
179 // r0 - used for index into the property dictionary and is clobbered.
180 //
181 // r1 - used to hold the capacity of the property dictionary and is clobbered.
182 Label done;
183
184
185 // Probe the dictionary.
lrn@chromium.org1c092762011-05-09 09:42:16 +0000186 StringDictionaryLookupStub::GeneratePositiveLookup(masm,
187 miss_label,
188 &done,
189 elements,
190 name,
191 r0,
192 r1);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000193
194 // If probing finds an entry in the dictionary, r0 contains the
195 // index into the dictionary. Check that the value is a normal
196 // property that is not read only.
197 __ bind(&done);
198 const int kElementsStartOffset =
199 StringDictionary::kHeaderSize +
200 StringDictionary::kElementsStartIndex * kPointerSize;
201 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
202 const int kTypeAndReadOnlyMask
203 = (PropertyDetails::TypeField::mask() |
204 PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
205 __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
206 Immediate(kTypeAndReadOnlyMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000207 __ j(not_zero, miss_label);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000208
209 // Store the value at the masked, scaled index.
210 const int kValueOffset = kElementsStartOffset + kPointerSize;
211 __ lea(r0, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag));
212 __ mov(Operand(r0, 0), value);
213
214 // Update write barrier. Make sure not to clobber the value.
215 __ mov(r1, value);
216 __ RecordWrite(elements, r0, r1);
217}
218
219
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000220static void GenerateNumberDictionaryLoad(MacroAssembler* masm,
221 Label* miss,
222 Register elements,
223 Register key,
224 Register r0,
225 Register r1,
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000226 Register r2,
227 Register result) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000228 // Register use:
229 //
230 // elements - holds the slow-case elements of the receiver and is unchanged.
231 //
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000232 // key - holds the smi key on entry and is unchanged.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000233 //
234 // Scratch registers:
235 //
236 // r0 - holds the untagged key on entry and holds the hash once computed.
237 //
238 // r1 - used to hold the capacity mask of the dictionary
239 //
240 // r2 - used for the index into the dictionary.
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000241 //
242 // result - holds the result on exit if the load succeeds and we fall through.
243
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000244 Label done;
245
246 // Compute the hash code from the untagged key. This must be kept in sync
247 // with ComputeIntegerHash in utils.h.
248 //
249 // hash = ~hash + (hash << 15);
250 __ mov(r1, r0);
251 __ not_(r0);
252 __ shl(r1, 15);
253 __ add(r0, Operand(r1));
254 // hash = hash ^ (hash >> 12);
255 __ mov(r1, r0);
256 __ shr(r1, 12);
257 __ xor_(r0, Operand(r1));
258 // hash = hash + (hash << 2);
259 __ lea(r0, Operand(r0, r0, times_4, 0));
260 // hash = hash ^ (hash >> 4);
261 __ mov(r1, r0);
262 __ shr(r1, 4);
263 __ xor_(r0, Operand(r1));
264 // hash = hash * 2057;
265 __ imul(r0, r0, 2057);
266 // hash = hash ^ (hash >> 16);
267 __ mov(r1, r0);
268 __ shr(r1, 16);
269 __ xor_(r0, Operand(r1));
270
271 // Compute capacity mask.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000272 __ mov(r1, FieldOperand(elements, NumberDictionary::kCapacityOffset));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000273 __ shr(r1, kSmiTagSize); // convert smi to int
274 __ dec(r1);
275
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000276 // Generate an unrolled loop that performs a few probes before giving up.
277 const int kProbes = 4;
278 for (int i = 0; i < kProbes; i++) {
279 // Use r2 for index calculations and keep the hash intact in r0.
280 __ mov(r2, r0);
281 // Compute the masked index: (hash + i + i * i) & mask.
282 if (i > 0) {
283 __ add(Operand(r2), Immediate(NumberDictionary::GetProbeOffset(i)));
284 }
285 __ and_(r2, Operand(r1));
286
287 // Scale the index by multiplying by the entry size.
288 ASSERT(NumberDictionary::kEntrySize == 3);
289 __ lea(r2, Operand(r2, r2, times_2, 0)); // r2 = r2 * 3
290
291 // Check if the key matches.
292 __ cmp(key, FieldOperand(elements,
293 r2,
294 times_pointer_size,
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000295 NumberDictionary::kElementsStartOffset));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000296 if (i != (kProbes - 1)) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000297 __ j(equal, &done);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000298 } else {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000299 __ j(not_equal, miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000300 }
301 }
302
303 __ bind(&done);
304 // Check that the value is a normal propety.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000305 const int kDetailsOffset =
306 NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000307 ASSERT_EQ(NORMAL, 0);
308 __ test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset),
309 Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize));
310 __ j(not_zero, miss);
311
312 // Get the value at the masked, scaled index.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000313 const int kValueOffset =
314 NumberDictionary::kElementsStartOffset + kPointerSize;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000315 __ mov(result, FieldOperand(elements, r2, times_pointer_size, kValueOffset));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000316}
317
318
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000319void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
320 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000321 // -- eax : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000322 // -- ecx : name
323 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000324 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000325 Label miss;
326
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000327 StubCompiler::GenerateLoadArrayLength(masm, eax, edx, &miss);
328 __ bind(&miss);
329 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
330}
331
332
ager@chromium.org378b34e2011-01-28 08:04:38 +0000333void LoadIC::GenerateStringLength(MacroAssembler* masm,
334 bool support_wrappers) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000335 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000336 // -- eax : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000337 // -- ecx : name
338 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000339 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000340 Label miss;
341
ager@chromium.org378b34e2011-01-28 08:04:38 +0000342 StubCompiler::GenerateLoadStringLength(masm, eax, edx, ebx, &miss,
343 support_wrappers);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000344 __ bind(&miss);
345 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
346}
347
348
349void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
350 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000351 // -- eax : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000352 // -- ecx : name
353 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000354 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000355 Label miss;
356
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000357 StubCompiler::GenerateLoadFunctionPrototype(masm, eax, edx, ebx, &miss);
358 __ bind(&miss);
359 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
360}
361
362
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000363// Checks the receiver for special cases (value type, slow case bits).
364// Falls through for regular JS object.
365static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
366 Register receiver,
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000367 Register map,
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000368 int interceptor_bit,
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000369 Label* slow) {
370 // Register use:
371 // receiver - holds the receiver and is unchanged.
372 // Scratch registers:
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000373 // map - used to hold the map of the receiver.
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000374
375 // Check that the object isn't a smi.
376 __ test(receiver, Immediate(kSmiTagMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000377 __ j(zero, slow);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000378
379 // Get the map of the receiver.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000380 __ mov(map, FieldOperand(receiver, HeapObject::kMapOffset));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000381
382 // Check bit field.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000383 __ test_b(FieldOperand(map, Map::kBitFieldOffset),
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000384 (1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000385 __ j(not_zero, slow);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000386 // Check that the object is some kind of JS object EXCEPT JS Value type.
387 // In the case that the object is a value-wrapper object,
388 // we enter the runtime system to make sure that indexing
389 // into string objects works as intended.
390 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
391
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000392 __ CmpInstanceType(map, JS_OBJECT_TYPE);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000393 __ j(below, slow);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000394}
395
396
397// Loads an indexed element from a fast case array.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000398// If not_fast_array is NULL, doesn't perform the elements map check.
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000399static void GenerateFastArrayLoad(MacroAssembler* masm,
400 Register receiver,
401 Register key,
402 Register scratch,
403 Register result,
404 Label* not_fast_array,
405 Label* out_of_range) {
406 // Register use:
407 // receiver - holds the receiver and is unchanged.
408 // key - holds the key and is unchanged (must be a smi).
409 // Scratch registers:
410 // scratch - used to hold elements of the receiver and the loaded value.
411 // result - holds the result on exit if the load succeeds and
412 // we fall through.
413
414 __ mov(scratch, FieldOperand(receiver, JSObject::kElementsOffset));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000415 if (not_fast_array != NULL) {
416 // Check that the object is in fast mode and writable.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000417 __ CheckMap(scratch,
418 FACTORY->fixed_array_map(),
419 not_fast_array,
420 DONT_DO_SMI_CHECK);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000421 } else {
422 __ AssertFastElements(scratch);
423 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000424 // Check that the key (index) is within bounds.
425 __ cmp(key, FieldOperand(scratch, FixedArray::kLengthOffset));
426 __ j(above_equal, out_of_range);
427 // Fast case: Do the load.
428 ASSERT((kPointerSize == 4) && (kSmiTagSize == 1) && (kSmiTag == 0));
429 __ mov(scratch, FieldOperand(scratch, key, times_2, FixedArray::kHeaderSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000430 __ cmp(Operand(scratch), Immediate(FACTORY->the_hole_value()));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000431 // In case the loaded value is the_hole we have to consult GetProperty
432 // to ensure the prototype chain is searched.
433 __ j(equal, out_of_range);
434 if (!result.is(scratch)) {
435 __ mov(result, scratch);
436 }
437}
438
439
440// Checks whether a key is an array index string or a symbol string.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000441// Falls through if the key is a symbol.
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000442static void GenerateKeyStringCheck(MacroAssembler* masm,
443 Register key,
444 Register map,
445 Register hash,
446 Label* index_string,
447 Label* not_symbol) {
448 // Register use:
449 // key - holds the key and is unchanged. Assumed to be non-smi.
450 // Scratch registers:
451 // map - used to hold the map of the key.
452 // hash - used to hold the hash of the key.
453 __ CmpObjectType(key, FIRST_NONSTRING_TYPE, map);
454 __ j(above_equal, not_symbol);
455
456 // Is the string an array index, with cached numeric value?
457 __ mov(hash, FieldOperand(key, String::kHashFieldOffset));
458 __ test(hash, Immediate(String::kContainsCachedArrayIndexMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000459 __ j(zero, index_string);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000460
461 // Is the string a symbol?
462 ASSERT(kSymbolTag != 0);
463 __ test_b(FieldOperand(map, Map::kInstanceTypeOffset), kIsSymbolMask);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000464 __ j(zero, not_symbol);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000465}
466
467
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000468void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
469 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000470 // -- eax : key
471 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000472 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000473 // -----------------------------------
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000474 Label slow, check_string, index_smi, index_string, property_array_property;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000475 Label probe_dictionary, check_number_dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000476
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000477 // Check that the key is a smi.
478 __ test(eax, Immediate(kSmiTagMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000479 __ j(not_zero, &check_string);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000480 __ bind(&index_smi);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000481 // Now the key is known to be a smi. This place is also jumped to from
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000482 // where a numeric string is converted to a smi.
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000483
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000484 GenerateKeyedLoadReceiverCheck(
485 masm, edx, ecx, Map::kHasIndexedInterceptor, &slow);
486
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000487 // Check the receiver's map to see if it has fast elements.
488 __ CheckFastElements(ecx, &check_number_dictionary);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000489
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000490 GenerateFastArrayLoad(masm,
491 edx,
492 eax,
493 ecx,
494 eax,
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000495 NULL,
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000496 &slow);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000497 Isolate* isolate = masm->isolate();
498 Counters* counters = isolate->counters();
499 __ IncrementCounter(counters->keyed_load_generic_smi(), 1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000500 __ ret(0);
501
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000502 __ bind(&check_number_dictionary);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000503 __ mov(ebx, eax);
504 __ SmiUntag(ebx);
505 __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
506
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000507 // Check whether the elements is a number dictionary.
508 // edx: receiver
509 // ebx: untagged index
510 // eax: key
511 // ecx: elements
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000512 __ CheckMap(ecx,
513 isolate->factory()->hash_table_map(),
514 &slow,
515 DONT_DO_SMI_CHECK);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000516 Label slow_pop_receiver;
517 // Push receiver on the stack to free up a register for the dictionary
518 // probing.
519 __ push(edx);
520 GenerateNumberDictionaryLoad(masm,
521 &slow_pop_receiver,
522 ecx,
523 eax,
524 ebx,
525 edx,
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000526 edi,
527 eax);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000528 // Pop receiver before returning.
529 __ pop(edx);
530 __ ret(0);
531
532 __ bind(&slow_pop_receiver);
533 // Pop the receiver from the stack and jump to runtime.
534 __ pop(edx);
535
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000536 __ bind(&slow);
ager@chromium.org5c838252010-02-19 08:53:10 +0000537 // Slow case: jump to runtime.
538 // edx: receiver
539 // eax: key
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000540 __ IncrementCounter(counters->keyed_load_generic_slow(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000541 GenerateRuntimeGetProperty(masm);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000542
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000543 __ bind(&check_string);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000544 GenerateKeyStringCheck(masm, eax, ecx, ebx, &index_string, &slow);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000545
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000546 GenerateKeyedLoadReceiverCheck(
547 masm, edx, ecx, Map::kHasNamedInterceptor, &slow);
548
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000549 // If the receiver is a fast-case object, check the keyed lookup
ager@chromium.org5c838252010-02-19 08:53:10 +0000550 // cache. Otherwise probe the dictionary.
551 __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000552 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000553 Immediate(isolate->factory()->hash_table_map()));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000554 __ j(equal, &probe_dictionary);
555
556 // Load the map of the receiver, compute the keyed lookup cache hash
557 // based on 32 bits of the map pointer and the string hash.
ager@chromium.org5c838252010-02-19 08:53:10 +0000558 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
559 __ mov(ecx, ebx);
560 __ shr(ecx, KeyedLookupCache::kMapHashShift);
561 __ mov(edi, FieldOperand(eax, String::kHashFieldOffset));
562 __ shr(edi, String::kHashShift);
563 __ xor_(ecx, Operand(edi));
564 __ and_(ecx, KeyedLookupCache::kCapacityMask);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000565
566 // Load the key (consisting of map and symbol) from the cache and
567 // check for match.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000568 ExternalReference cache_keys =
569 ExternalReference::keyed_lookup_cache_keys(masm->isolate());
ager@chromium.org5c838252010-02-19 08:53:10 +0000570 __ mov(edi, ecx);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000571 __ shl(edi, kPointerSizeLog2 + 1);
572 __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys));
573 __ j(not_equal, &slow);
574 __ add(Operand(edi), Immediate(kPointerSize));
ager@chromium.org5c838252010-02-19 08:53:10 +0000575 __ cmp(eax, Operand::StaticArray(edi, times_1, cache_keys));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000576 __ j(not_equal, &slow);
577
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000578 // Get field offset.
ager@chromium.org5c838252010-02-19 08:53:10 +0000579 // edx : receiver
580 // ebx : receiver's map
581 // eax : key
582 // ecx : lookup cache index
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000583 ExternalReference cache_field_offsets =
584 ExternalReference::keyed_lookup_cache_field_offsets(masm->isolate());
ager@chromium.org5c838252010-02-19 08:53:10 +0000585 __ mov(edi,
586 Operand::StaticArray(ecx, times_pointer_size, cache_field_offsets));
587 __ movzx_b(ecx, FieldOperand(ebx, Map::kInObjectPropertiesOffset));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000588 __ sub(edi, Operand(ecx));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000589 __ j(above_equal, &property_array_property);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000590
591 // Load in-object property.
ager@chromium.org5c838252010-02-19 08:53:10 +0000592 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset));
593 __ add(ecx, Operand(edi));
594 __ mov(eax, FieldOperand(edx, ecx, times_pointer_size, 0));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000595 __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000596 __ ret(0);
597
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000598 // Load property array property.
599 __ bind(&property_array_property);
600 __ mov(eax, FieldOperand(edx, JSObject::kPropertiesOffset));
601 __ mov(eax, FieldOperand(eax, edi, times_pointer_size,
602 FixedArray::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000603 __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000604 __ ret(0);
605
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000606 // Do a quick inline probe of the receiver's dictionary, if it
607 // exists.
608 __ bind(&probe_dictionary);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000609
610 __ mov(ecx, FieldOperand(edx, JSObject::kMapOffset));
611 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
612 GenerateGlobalInstanceTypeCheck(masm, ecx, &slow);
613
614 GenerateDictionaryLoad(masm, &slow, ebx, eax, ecx, edi, eax);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000615 __ IncrementCounter(counters->keyed_load_generic_symbol(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000616 __ ret(0);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000617
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000618 __ bind(&index_string);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000619 __ IndexFromHash(ebx, eax);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000620 // Now jump to the place where smi keys are handled.
621 __ jmp(&index_smi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000622}
623
624
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000625void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
626 // ----------- S t a t e -------------
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000627 // -- eax : key (index)
ager@chromium.org5c838252010-02-19 08:53:10 +0000628 // -- edx : receiver
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000629 // -- esp[0] : return address
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000630 // -----------------------------------
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000631 Label miss;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000632
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000633 Register receiver = edx;
634 Register index = eax;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000635 Register scratch1 = ebx;
636 Register scratch2 = ecx;
637 Register result = eax;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000638
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000639 StringCharAtGenerator char_at_generator(receiver,
640 index,
641 scratch1,
642 scratch2,
643 result,
644 &miss, // When not a string.
645 &miss, // When not a number.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000646 &miss, // When index out of range.
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000647 STRING_INDEX_IS_ARRAY_INDEX);
648 char_at_generator.GenerateFast(masm);
649 __ ret(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000650
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000651 StubRuntimeCallHelper call_helper;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000652 char_at_generator.GenerateSlow(masm, call_helper);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000653
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000654 __ bind(&miss);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000655 GenerateMiss(masm, false);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000656}
657
658
ager@chromium.org5c838252010-02-19 08:53:10 +0000659void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
660 // ----------- S t a t e -------------
661 // -- eax : key
662 // -- edx : receiver
663 // -- esp[0] : return address
664 // -----------------------------------
665 Label slow;
666
667 // Check that the receiver isn't a smi.
668 __ test(edx, Immediate(kSmiTagMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000669 __ j(zero, &slow);
ager@chromium.org5c838252010-02-19 08:53:10 +0000670
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000671 // Check that the key is an array index, that is Uint32.
672 __ test(eax, Immediate(kSmiTagMask | kSmiSignMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000673 __ j(not_zero, &slow);
ager@chromium.org5c838252010-02-19 08:53:10 +0000674
675 // Get the map of the receiver.
676 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
677
678 // Check that it has indexed interceptor and access checks
679 // are not enabled for this object.
680 __ movzx_b(ecx, FieldOperand(ecx, Map::kBitFieldOffset));
681 __ and_(Operand(ecx), Immediate(kSlowCaseBitFieldMask));
682 __ cmp(Operand(ecx), Immediate(1 << Map::kHasIndexedInterceptor));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000683 __ j(not_zero, &slow);
ager@chromium.org5c838252010-02-19 08:53:10 +0000684
685 // Everything is fine, call runtime.
686 __ pop(ecx);
687 __ push(edx); // receiver
688 __ push(eax); // key
689 __ push(ecx); // return address
690
691 // Perform tail call to the entry.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000692 ExternalReference ref =
693 ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor),
694 masm->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000695 __ TailCallExternalReference(ref, 2, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000696
697 __ bind(&slow);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000698 GenerateMiss(masm, false);
ager@chromium.org3811b432009-10-28 14:53:37 +0000699}
700
701
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000702void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
703 StrictModeFlag strict_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000704 // ----------- S t a t e -------------
705 // -- eax : value
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000706 // -- ecx : key
707 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000708 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000709 // -----------------------------------
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000710 Label slow, fast, array, extra;
ager@chromium.org8bb60582008-12-11 12:02:20 +0000711
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000712 // Check that the object isn't a smi.
713 __ test(edx, Immediate(kSmiTagMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000714 __ j(zero, &slow);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000715 // Get the map from the receiver.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000716 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
ager@chromium.org8bb60582008-12-11 12:02:20 +0000717 // Check that the receiver does not require access checks. We need
718 // to do this because this generic stub does not perform map checks.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000719 __ test_b(FieldOperand(edi, Map::kBitFieldOffset),
720 1 << Map::kIsAccessCheckNeeded);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000721 __ j(not_zero, &slow);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000722 // Check that the key is a smi.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000723 __ test(ecx, Immediate(kSmiTagMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000724 __ j(not_zero, &slow);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000725 __ CmpInstanceType(edi, JS_ARRAY_TYPE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000726 __ j(equal, &array);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000727 // Check that the object is some kind of JSObject.
728 __ CmpInstanceType(edi, FIRST_JS_RECEIVER_TYPE);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000729 __ j(below, &slow);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000730 __ CmpInstanceType(edi, JS_PROXY_TYPE);
731 __ j(equal, &slow);
732 __ CmpInstanceType(edi, JS_FUNCTION_PROXY_TYPE);
733 __ j(equal, &slow);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000734
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000735 // Object case: Check key against length in the elements array.
736 // eax: value
737 // edx: JSObject
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000738 // ecx: key (a smi)
739 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000740 // Check that the object is in fast mode and writable.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000741 __ CheckMap(edi, FACTORY->fixed_array_map(), &slow, DONT_DO_SMI_CHECK);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000742 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000743 __ j(below, &fast);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000744
ager@chromium.org3811b432009-10-28 14:53:37 +0000745 // Slow case: call runtime.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000746 __ bind(&slow);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000747 GenerateRuntimeSetProperty(masm, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000748
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000749 // Extra capacity case: Check if there is extra capacity to
750 // perform the store and update the length. Used for adding one
751 // element to the array by writing to array[array.length].
752 __ bind(&extra);
753 // eax: value
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000754 // edx: receiver, a JSArray
755 // ecx: key, a smi.
756 // edi: receiver->elements, a FixedArray
757 // flags: compare (ecx, edx.length())
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000758 // do not leave holes in the array:
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000759 __ j(not_equal, &slow);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000760 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000761 __ j(above_equal, &slow);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000762 // Add 1 to receiver->length, and go to fast array write.
763 __ add(FieldOperand(edx, JSArray::kLengthOffset),
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000764 Immediate(Smi::FromInt(1)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000765 __ jmp(&fast);
766
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000767 // Array case: Get the length and the elements array from the JS
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000768 // array. Check that the array is in fast mode (and writable); if it
769 // is the length is always a smi.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000770 __ bind(&array);
771 // eax: value
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000772 // edx: receiver, a JSArray
773 // ecx: key, a smi.
774 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000775 __ CheckMap(edi, FACTORY->fixed_array_map(), &slow, DONT_DO_SMI_CHECK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000776
777 // Check the key against the length in the array, compute the
778 // address to store into and fall through to fast case.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000779 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // Compare smis.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000780 __ j(above_equal, &extra);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000781
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000782 // Fast case: Do the store.
783 __ bind(&fast);
784 // eax: value
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000785 // ecx: key (a smi)
786 // edx: receiver
787 // edi: FixedArray receiver->elements
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000788 __ mov(CodeGenerator::FixedArrayElementOperand(edi, ecx), eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000789 // Update write barrier for the elements array address.
790 __ mov(edx, Operand(eax));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000791 __ RecordWrite(edi, 0, edx, ecx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000792 __ ret(0);
793}
794
795
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000796// The generated code does not accept smi keys.
797// The generated code falls through if both probes miss.
798static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
799 int argc,
danno@chromium.org40cb8782011-05-25 07:58:50 +0000800 Code::Kind kind,
801 Code::ExtraICState extra_ic_state) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000802 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000803 // -- ecx : name
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000804 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000805 // -----------------------------------
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000806 Label number, non_number, non_string, boolean, probe, miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000807
808 // Probe the stub cache.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000809 Code::Flags flags = Code::ComputeFlags(kind,
810 NOT_IN_LOOP,
811 MONOMORPHIC,
danno@chromium.org40cb8782011-05-25 07:58:50 +0000812 extra_ic_state,
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000813 NORMAL,
814 argc);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000815 Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx,
816 eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000817
818 // If the stub cache probing failed, the receiver might be a value.
819 // For value objects, we use the map of the prototype objects for
820 // the corresponding JSValue for the cache and that is what we need
821 // to probe.
822 //
823 // Check for number.
824 __ test(edx, Immediate(kSmiTagMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000825 __ j(zero, &number);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000826 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ebx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000827 __ j(not_equal, &non_number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000828 __ bind(&number);
829 StubCompiler::GenerateLoadGlobalFunctionPrototype(
830 masm, Context::NUMBER_FUNCTION_INDEX, edx);
831 __ jmp(&probe);
832
833 // Check for string.
834 __ bind(&non_number);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000835 __ CmpInstanceType(ebx, FIRST_NONSTRING_TYPE);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000836 __ j(above_equal, &non_string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000837 StubCompiler::GenerateLoadGlobalFunctionPrototype(
838 masm, Context::STRING_FUNCTION_INDEX, edx);
839 __ jmp(&probe);
840
841 // Check for boolean.
842 __ bind(&non_string);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000843 __ cmp(edx, FACTORY->true_value());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000844 __ j(equal, &boolean);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000845 __ cmp(edx, FACTORY->false_value());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000846 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000847 __ bind(&boolean);
848 StubCompiler::GenerateLoadGlobalFunctionPrototype(
849 masm, Context::BOOLEAN_FUNCTION_INDEX, edx);
850
851 // Probe the stub cache for the value object.
852 __ bind(&probe);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000853 Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx,
854 no_reg);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000855 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000856}
857
858
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000859static void GenerateFunctionTailCall(MacroAssembler* masm,
860 int argc,
861 Label* miss) {
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000862 // ----------- S t a t e -------------
863 // -- ecx : name
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000864 // -- edi : function
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000865 // -- esp[0] : return address
866 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
867 // -- ...
868 // -- esp[(argc + 1) * 4] : receiver
869 // -----------------------------------
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000870
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000871 // Check that the result is not a smi.
872 __ test(edi, Immediate(kSmiTagMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000873 __ j(zero, miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000874
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000875 // Check that the value is a JavaScript function, fetching its map into eax.
876 __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000877 __ j(not_equal, miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000878
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000879 // Invoke the function.
880 ParameterCount actual(argc);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000881 __ InvokeFunction(edi, actual, JUMP_FUNCTION,
882 NullCallWrapper(), CALL_AS_METHOD);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000883}
884
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000885// The generated code falls through if the call should be handled by runtime.
886static void GenerateCallNormal(MacroAssembler* masm, int argc) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000887 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000888 // -- ecx : name
889 // -- esp[0] : return address
890 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
891 // -- ...
892 // -- esp[(argc + 1) * 4] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000893 // -----------------------------------
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000894 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000895
896 // Get the receiver of the function from the stack; 1 ~ return address.
897 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000898
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000899 GenerateStringDictionaryReceiverCheck(masm, edx, eax, ebx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000900
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000901 // eax: elements
902 // Search the dictionary placing the result in edi.
903 GenerateDictionaryLoad(masm, &miss, eax, ecx, edi, ebx, edi);
904 GenerateFunctionTailCall(masm, argc, &miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000905
906 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000907}
908
909
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000910static void GenerateCallMiss(MacroAssembler* masm,
911 int argc,
danno@chromium.org40cb8782011-05-25 07:58:50 +0000912 IC::UtilityId id,
913 Code::ExtraICState extra_ic_state) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000914 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000915 // -- ecx : name
916 // -- esp[0] : return address
917 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
918 // -- ...
919 // -- esp[(argc + 1) * 4] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000920 // -----------------------------------
921
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000922 Counters* counters = masm->isolate()->counters();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000923 if (id == IC::kCallIC_Miss) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000924 __ IncrementCounter(counters->call_miss(), 1);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000925 } else {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000926 __ IncrementCounter(counters->keyed_call_miss(), 1);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000927 }
928
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000929 // Get the receiver of the function from the stack; 1 ~ return address.
930 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000931
932 // Enter an internal frame.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000933 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000934
935 // Push the receiver and the name of the function.
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000936 __ push(edx);
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000937 __ push(ecx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000938
939 // Call the entry.
ager@chromium.orga1645e22009-09-09 19:27:10 +0000940 CEntryStub stub(1);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000941 __ mov(eax, Immediate(2));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000942 __ mov(ebx, Immediate(ExternalReference(IC_Utility(id), masm->isolate())));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000943 __ CallStub(&stub);
944
945 // Move result to edi and exit the internal frame.
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000946 __ mov(edi, eax);
ager@chromium.org236ad962008-09-25 09:45:57 +0000947 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000948
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000949 // Check if the receiver is a global object of some sort.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000950 // This can happen only for regular CallIC but not KeyedCallIC.
951 if (id == IC::kCallIC_Miss) {
952 Label invoke, global;
953 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); // receiver
954 __ test(edx, Immediate(kSmiTagMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000955 __ j(zero, &invoke, Label::kNear);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000956 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
957 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
958 __ cmp(ebx, JS_GLOBAL_OBJECT_TYPE);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000959 __ j(equal, &global, Label::kNear);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000960 __ cmp(ebx, JS_BUILTINS_OBJECT_TYPE);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000961 __ j(not_equal, &invoke, Label::kNear);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000962
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000963 // Patch the receiver on the stack.
964 __ bind(&global);
965 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
966 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
967 __ bind(&invoke);
968 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000969
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000970 // Invoke the function.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000971 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
972 ? CALL_AS_FUNCTION
973 : CALL_AS_METHOD;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000974 ParameterCount actual(argc);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000975 __ InvokeFunction(edi,
976 actual,
977 JUMP_FUNCTION,
978 NullCallWrapper(),
979 call_kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000980}
981
982
danno@chromium.org40cb8782011-05-25 07:58:50 +0000983void CallIC::GenerateMegamorphic(MacroAssembler* masm,
984 int argc,
985 Code::ExtraICState extra_ic_state) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000986 // ----------- S t a t e -------------
987 // -- ecx : name
988 // -- esp[0] : return address
989 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
990 // -- ...
991 // -- esp[(argc + 1) * 4] : receiver
992 // -----------------------------------
993
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000994 // Get the receiver of the function from the stack; 1 ~ return address.
995 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
danno@chromium.org40cb8782011-05-25 07:58:50 +0000996 GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC, extra_ic_state);
997
998 GenerateMiss(masm, argc, extra_ic_state);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000999}
1000
1001
1002void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001003 // ----------- S t a t e -------------
1004 // -- ecx : name
1005 // -- esp[0] : return address
1006 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1007 // -- ...
1008 // -- esp[(argc + 1) * 4] : receiver
1009 // -----------------------------------
1010
1011 GenerateCallNormal(masm, argc);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001012 GenerateMiss(masm, argc, Code::kNoExtraICState);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001013}
1014
1015
danno@chromium.org40cb8782011-05-25 07:58:50 +00001016void CallIC::GenerateMiss(MacroAssembler* masm,
1017 int argc,
1018 Code::ExtraICState extra_ic_state) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001019 // ----------- S t a t e -------------
1020 // -- ecx : name
1021 // -- esp[0] : return address
1022 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1023 // -- ...
1024 // -- esp[(argc + 1) * 4] : receiver
1025 // -----------------------------------
1026
danno@chromium.org40cb8782011-05-25 07:58:50 +00001027 GenerateCallMiss(masm, argc, IC::kCallIC_Miss, extra_ic_state);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001028}
1029
1030
1031void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
1032 // ----------- S t a t e -------------
1033 // -- ecx : name
1034 // -- esp[0] : return address
1035 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1036 // -- ...
1037 // -- esp[(argc + 1) * 4] : receiver
1038 // -----------------------------------
1039
1040 // Get the receiver of the function from the stack; 1 ~ return address.
1041 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1042
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001043 Label do_call, slow_call, slow_load, slow_reload_receiver;
1044 Label check_number_dictionary, check_string, lookup_monomorphic_cache;
1045 Label index_smi, index_string;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001046
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001047 // Check that the key is a smi.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001048 __ test(ecx, Immediate(kSmiTagMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001049 __ j(not_zero, &check_string);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001050
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001051 __ bind(&index_smi);
1052 // Now the key is known to be a smi. This place is also jumped to from
1053 // where a numeric string is converted to a smi.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001054
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001055 GenerateKeyedLoadReceiverCheck(
1056 masm, edx, eax, Map::kHasIndexedInterceptor, &slow_call);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001057
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001058 GenerateFastArrayLoad(
1059 masm, edx, ecx, eax, edi, &check_number_dictionary, &slow_load);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001060 Isolate* isolate = masm->isolate();
1061 Counters* counters = isolate->counters();
1062 __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001063
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001064 __ bind(&do_call);
1065 // receiver in edx is not used after this point.
1066 // ecx: key
1067 // edi: function
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001068 GenerateFunctionTailCall(masm, argc, &slow_call);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001069
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001070 __ bind(&check_number_dictionary);
1071 // eax: elements
1072 // ecx: smi key
1073 // Check whether the elements is a number dictionary.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001074 __ CheckMap(eax,
1075 isolate->factory()->hash_table_map(),
1076 &slow_load,
1077 DONT_DO_SMI_CHECK);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001078 __ mov(ebx, ecx);
1079 __ SmiUntag(ebx);
1080 // ebx: untagged index
1081 // Receiver in edx will be clobbered, need to reload it on miss.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001082 GenerateNumberDictionaryLoad(
1083 masm, &slow_reload_receiver, eax, ecx, ebx, edx, edi, edi);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001084 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001085 __ jmp(&do_call);
1086
1087 __ bind(&slow_reload_receiver);
1088 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1089
1090 __ bind(&slow_load);
1091 // This branch is taken when calling KeyedCallIC_Miss is neither required
1092 // nor beneficial.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001093 __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001094 __ EnterInternalFrame();
1095 __ push(ecx); // save the key
1096 __ push(edx); // pass the receiver
1097 __ push(ecx); // pass the key
1098 __ CallRuntime(Runtime::kKeyedGetProperty, 2);
1099 __ pop(ecx); // restore the key
1100 __ LeaveInternalFrame();
1101 __ mov(edi, eax);
1102 __ jmp(&do_call);
1103
1104 __ bind(&check_string);
1105 GenerateKeyStringCheck(masm, ecx, eax, ebx, &index_string, &slow_call);
1106
1107 // The key is known to be a symbol.
1108 // If the receiver is a regular JS object with slow properties then do
1109 // a quick inline probe of the receiver's dictionary.
1110 // Otherwise do the monomorphic cache probe.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001111 GenerateKeyedLoadReceiverCheck(
1112 masm, edx, eax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001113
1114 __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001115 __ CheckMap(ebx,
1116 isolate->factory()->hash_table_map(),
1117 &lookup_monomorphic_cache,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001118 DONT_DO_SMI_CHECK);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001119
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001120 GenerateDictionaryLoad(masm, &slow_load, ebx, ecx, eax, edi, edi);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001121 __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001122 __ jmp(&do_call);
1123
1124 __ bind(&lookup_monomorphic_cache);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001125 __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001126 GenerateMonomorphicCacheProbe(masm,
1127 argc,
1128 Code::KEYED_CALL_IC,
1129 Code::kNoExtraICState);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001130 // Fall through on miss.
1131
1132 __ bind(&slow_call);
1133 // This branch is taken if:
1134 // - the receiver requires boxing or access check,
1135 // - the key is neither smi nor symbol,
1136 // - the value loaded is not a function,
1137 // - there is hope that the runtime will create a monomorphic call stub
1138 // that will get fetched next time.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001139 __ IncrementCounter(counters->keyed_call_generic_slow(), 1);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001140 GenerateMiss(masm, argc);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001141
1142 __ bind(&index_string);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001143 __ IndexFromHash(ebx, ecx);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001144 // Now jump to the place where smi keys are handled.
1145 __ jmp(&index_smi);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001146}
1147
1148
1149void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001150 // ----------- S t a t e -------------
1151 // -- ecx : name
1152 // -- esp[0] : return address
1153 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1154 // -- ...
1155 // -- esp[(argc + 1) * 4] : receiver
1156 // -----------------------------------
1157
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001158 // Check if the name is a string.
1159 Label miss;
1160 __ test(ecx, Immediate(kSmiTagMask));
1161 __ j(zero, &miss);
1162 Condition cond = masm->IsObjectStringType(ecx, eax, eax);
1163 __ j(NegateCondition(cond), &miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001164 GenerateCallNormal(masm, argc);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001165 __ bind(&miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001166 GenerateMiss(masm, argc);
1167}
1168
1169
1170void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001171 // ----------- S t a t e -------------
1172 // -- ecx : name
1173 // -- esp[0] : return address
1174 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1175 // -- ...
1176 // -- esp[(argc + 1) * 4] : receiver
1177 // -----------------------------------
1178
danno@chromium.org40cb8782011-05-25 07:58:50 +00001179 GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss, Code::kNoExtraICState);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001180}
1181
1182
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001183void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
1184 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00001185 // -- eax : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001186 // -- ecx : name
1187 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001188 // -----------------------------------
1189
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001190 // Probe the stub cache.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001191 Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
1192 NOT_IN_LOOP,
1193 MONOMORPHIC);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001194 Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, eax, ecx, ebx,
1195 edx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001196
1197 // Cache miss: Jump to runtime.
ager@chromium.org5c838252010-02-19 08:53:10 +00001198 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001199}
1200
1201
1202void LoadIC::GenerateNormal(MacroAssembler* masm) {
1203 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00001204 // -- eax : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001205 // -- ecx : name
1206 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001207 // -----------------------------------
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001208 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001209
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001210 GenerateStringDictionaryReceiverCheck(masm, eax, edx, ebx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001211
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001212 // edx: elements
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001213 // Search the dictionary placing the result in eax.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001214 GenerateDictionaryLoad(masm, &miss, edx, ecx, edi, ebx, eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001215 __ ret(0);
1216
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001217 // Cache miss: Jump to runtime.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001218 __ bind(&miss);
ager@chromium.org5c838252010-02-19 08:53:10 +00001219 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001220}
1221
1222
1223void LoadIC::GenerateMiss(MacroAssembler* masm) {
1224 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00001225 // -- eax : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001226 // -- ecx : name
1227 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001228 // -----------------------------------
1229
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001230 __ IncrementCounter(masm->isolate()->counters()->load_miss(), 1);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001231
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001232 __ pop(ebx);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001233 __ push(eax); // receiver
1234 __ push(ecx); // name
1235 __ push(ebx); // return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001236
mads.s.ager31e71382008-08-13 09:32:07 +00001237 // Perform tail call to the entry.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001238 ExternalReference ref =
1239 ExternalReference(IC_Utility(kLoadIC_Miss), masm->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001240 __ TailCallExternalReference(ref, 2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001241}
1242
1243
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001244void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001245 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00001246 // -- eax : key
1247 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001248 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001249 // -----------------------------------
1250
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001251 __ IncrementCounter(masm->isolate()->counters()->keyed_load_miss(), 1);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001252
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001253 __ pop(ebx);
ager@chromium.org5c838252010-02-19 08:53:10 +00001254 __ push(edx); // receiver
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001255 __ push(eax); // name
1256 __ push(ebx); // return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001257
mads.s.ager31e71382008-08-13 09:32:07 +00001258 // Perform tail call to the entry.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001259 ExternalReference ref = force_generic
1260 ? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric),
1261 masm->isolate())
1262 : ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001263 __ TailCallExternalReference(ref, 2, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00001264}
1265
1266
1267void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
1268 // ----------- S t a t e -------------
1269 // -- eax : key
1270 // -- edx : receiver
1271 // -- esp[0] : return address
1272 // -----------------------------------
1273
1274 __ pop(ebx);
1275 __ push(edx); // receiver
1276 __ push(eax); // name
1277 __ push(ebx); // return address
1278
1279 // Perform tail call to the entry.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001280 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001281}
1282
1283
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001284void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001285 StrictModeFlag strict_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001286 // ----------- S t a t e -------------
1287 // -- eax : value
1288 // -- ecx : name
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001289 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001290 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001291 // -----------------------------------
1292
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001293 Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
1294 NOT_IN_LOOP,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001295 MONOMORPHIC,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001296 strict_mode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001297 Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx,
1298 no_reg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001299
1300 // Cache miss: Jump to runtime.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001301 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001302}
1303
1304
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001305void StoreIC::GenerateMiss(MacroAssembler* masm) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001306 // ----------- S t a t e -------------
1307 // -- eax : value
1308 // -- ecx : name
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001309 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001310 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001311 // -----------------------------------
1312
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001313 __ pop(ebx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001314 __ push(edx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001315 __ push(ecx);
1316 __ push(eax);
1317 __ push(ebx);
1318
mads.s.ager31e71382008-08-13 09:32:07 +00001319 // Perform tail call to the entry.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001320 ExternalReference ref =
1321 ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001322 __ TailCallExternalReference(ref, 3, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001323}
1324
1325
ager@chromium.org5c838252010-02-19 08:53:10 +00001326void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
1327 // ----------- S t a t e -------------
1328 // -- eax : value
1329 // -- ecx : name
1330 // -- edx : receiver
1331 // -- esp[0] : return address
1332 // -----------------------------------
1333 //
1334 // This accepts as a receiver anything JSObject::SetElementsLength accepts
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001335 // (currently anything except for external arrays which means anything with
1336 // elements of FixedArray type.), but currently is restricted to JSArray.
ager@chromium.org5c838252010-02-19 08:53:10 +00001337 // Value must be a number, but only smis are accepted as the most common case.
1338
1339 Label miss;
1340
1341 Register receiver = edx;
1342 Register value = eax;
1343 Register scratch = ebx;
1344
1345 // Check that the receiver isn't a smi.
1346 __ test(receiver, Immediate(kSmiTagMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001347 __ j(zero, &miss);
ager@chromium.org5c838252010-02-19 08:53:10 +00001348
1349 // Check that the object is a JS array.
1350 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001351 __ j(not_equal, &miss);
ager@chromium.org5c838252010-02-19 08:53:10 +00001352
1353 // Check that elements are FixedArray.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001354 // We rely on StoreIC_ArrayLength below to deal with all types of
1355 // fast elements (including COW).
ager@chromium.org5c838252010-02-19 08:53:10 +00001356 __ mov(scratch, FieldOperand(receiver, JSArray::kElementsOffset));
1357 __ CmpObjectType(scratch, FIXED_ARRAY_TYPE, scratch);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001358 __ j(not_equal, &miss);
ager@chromium.org5c838252010-02-19 08:53:10 +00001359
1360 // Check that value is a smi.
1361 __ test(value, Immediate(kSmiTagMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001362 __ j(not_zero, &miss);
ager@chromium.org5c838252010-02-19 08:53:10 +00001363
1364 // Prepare tail call to StoreIC_ArrayLength.
1365 __ pop(scratch);
1366 __ push(receiver);
1367 __ push(value);
1368 __ push(scratch); // return address
1369
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001370 ExternalReference ref =
1371 ExternalReference(IC_Utility(kStoreIC_ArrayLength), masm->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001372 __ TailCallExternalReference(ref, 2, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00001373
1374 __ bind(&miss);
1375
1376 GenerateMiss(masm);
1377}
1378
1379
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001380void StoreIC::GenerateNormal(MacroAssembler* masm) {
1381 // ----------- S t a t e -------------
1382 // -- eax : value
1383 // -- ecx : name
1384 // -- edx : receiver
1385 // -- esp[0] : return address
1386 // -----------------------------------
1387
1388 Label miss, restore_miss;
1389
1390 GenerateStringDictionaryReceiverCheck(masm, edx, ebx, edi, &miss);
1391
1392 // A lot of registers are needed for storing to slow case
1393 // objects. Push and restore receiver but rely on
1394 // GenerateDictionaryStore preserving the value and name.
1395 __ push(edx);
1396 GenerateDictionaryStore(masm, &restore_miss, ebx, ecx, eax, edx, edi);
1397 __ Drop(1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001398 Counters* counters = masm->isolate()->counters();
1399 __ IncrementCounter(counters->store_normal_hit(), 1);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001400 __ ret(0);
1401
1402 __ bind(&restore_miss);
1403 __ pop(edx);
1404
1405 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001406 __ IncrementCounter(counters->store_normal_miss(), 1);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001407 GenerateMiss(masm);
1408}
1409
1410
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001411void StoreIC::GenerateGlobalProxy(MacroAssembler* masm,
1412 StrictModeFlag strict_mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001413 // ----------- S t a t e -------------
1414 // -- eax : value
1415 // -- ecx : name
1416 // -- edx : receiver
1417 // -- esp[0] : return address
1418 // -----------------------------------
1419 __ pop(ebx);
1420 __ push(edx);
1421 __ push(ecx);
1422 __ push(eax);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001423 __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes
1424 __ push(Immediate(Smi::FromInt(strict_mode)));
1425 __ push(ebx); // return address
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001426
1427 // Do tail-call to runtime routine.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001428 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001429}
1430
1431
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001432void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
1433 StrictModeFlag strict_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001434 // ----------- S t a t e -------------
1435 // -- eax : value
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001436 // -- ecx : key
1437 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001438 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001439 // -----------------------------------
1440
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001441 __ pop(ebx);
1442 __ push(edx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001443 __ push(ecx);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001444 __ push(eax);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001445 __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes
1446 __ push(Immediate(Smi::FromInt(strict_mode))); // Strict mode.
1447 __ push(ebx); // return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001448
1449 // Do tail-call to runtime routine.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001450 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001451}
1452
1453
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001454void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
kasperl@chromium.org1accd572008-10-07 10:57:21 +00001455 // ----------- S t a t e -------------
1456 // -- eax : value
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001457 // -- ecx : key
1458 // -- edx : receiver
kasperl@chromium.org1accd572008-10-07 10:57:21 +00001459 // -- esp[0] : return address
kasperl@chromium.org1accd572008-10-07 10:57:21 +00001460 // -----------------------------------
1461
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001462 __ pop(ebx);
1463 __ push(edx);
ager@chromium.org5c838252010-02-19 08:53:10 +00001464 __ push(ecx);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001465 __ push(eax);
1466 __ push(ebx);
kasperl@chromium.org1accd572008-10-07 10:57:21 +00001467
1468 // Do tail-call to runtime routine.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001469 ExternalReference ref = force_generic
1470 ? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric),
1471 masm->isolate())
1472 : ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
1473 __ TailCallExternalReference(ref, 3, 1);
1474}
1475
1476
1477void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
1478 // ----------- S t a t e -------------
1479 // -- eax : value
1480 // -- ecx : key
1481 // -- edx : receiver
1482 // -- esp[0] : return address
1483 // -----------------------------------
1484
1485 __ pop(ebx);
1486 __ push(edx);
1487 __ push(ecx);
1488 __ push(eax);
1489 __ push(ebx); // return address
1490
1491 // Do tail-call to runtime routine.
1492 ExternalReference ref(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001493 __ TailCallExternalReference(ref, 3, 1);
kasperl@chromium.org1accd572008-10-07 10:57:21 +00001494}
1495
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001496
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001497#undef __
1498
1499
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001500Condition CompareIC::ComputeCondition(Token::Value op) {
1501 switch (op) {
1502 case Token::EQ_STRICT:
1503 case Token::EQ:
1504 return equal;
1505 case Token::LT:
1506 return less;
1507 case Token::GT:
1508 // Reverse left and right operands to obtain ECMA-262 conversion order.
1509 return less;
1510 case Token::LTE:
1511 // Reverse left and right operands to obtain ECMA-262 conversion order.
1512 return greater_equal;
1513 case Token::GTE:
1514 return greater_equal;
1515 default:
1516 UNREACHABLE();
1517 return no_condition;
1518 }
1519}
1520
1521
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001522static bool HasInlinedSmiCode(Address address) {
1523 // The address of the instruction following the call.
1524 Address test_instruction_address =
1525 address + Assembler::kCallTargetAddressOffset;
1526
1527 // If the instruction following the call is not a test al, nothing
1528 // was inlined.
1529 return *test_instruction_address == Assembler::kTestAlByte;
1530}
1531
1532
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001533void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
1534 HandleScope scope;
1535 Handle<Code> rewritten;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001536 State previous_state = GetState();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001537
1538 State state = TargetState(previous_state, HasInlinedSmiCode(address()), x, y);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001539 if (state == GENERIC) {
1540 CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS);
1541 rewritten = stub.GetCode();
1542 } else {
1543 ICCompareStub stub(op_, state);
1544 rewritten = stub.GetCode();
1545 }
1546 set_target(*rewritten);
1547
1548#ifdef DEBUG
1549 if (FLAG_trace_ic) {
1550 PrintF("[CompareIC (%s->%s)#%s]\n",
1551 GetStateName(previous_state),
1552 GetStateName(state),
1553 Token::Name(op_));
1554 }
1555#endif
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001556
1557 // Activate inlined smi code.
1558 if (previous_state == UNINITIALIZED) {
1559 PatchInlinedSmiCode(address());
1560 }
1561}
1562
1563
1564void PatchInlinedSmiCode(Address address) {
1565 // The address of the instruction following the call.
1566 Address test_instruction_address =
1567 address + Assembler::kCallTargetAddressOffset;
1568
1569 // If the instruction following the call is not a test al, nothing
1570 // was inlined.
1571 if (*test_instruction_address != Assembler::kTestAlByte) {
1572 ASSERT(*test_instruction_address == Assembler::kNopByte);
1573 return;
1574 }
1575
1576 Address delta_address = test_instruction_address + 1;
1577 // The delta to the start of the map check instruction and the
1578 // condition code uses at the patched jump.
1579 int8_t delta = *reinterpret_cast<int8_t*>(delta_address);
1580 if (FLAG_trace_ic) {
1581 PrintF("[ patching ic at %p, test=%p, delta=%d\n",
1582 address, test_instruction_address, delta);
1583 }
1584
1585 // Patch with a short conditional jump. There must be a
1586 // short jump-if-carry/not-carry at this position.
1587 Address jmp_address = test_instruction_address - delta;
1588 ASSERT(*jmp_address == Assembler::kJncShortOpcode ||
1589 *jmp_address == Assembler::kJcShortOpcode);
1590 Condition cc = *jmp_address == Assembler::kJncShortOpcode
1591 ? not_zero
1592 : zero;
1593 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001594}
1595
1596
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001597} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001598
1599#endif // V8_TARGET_ARCH_IA32