blob: c3a2654466e6aca519e922c1be9d1c53f0157d5b [file] [log] [blame]
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001// Copyright 2012 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
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000032#include "ic-inl.h"
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000033#include "codegen.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000034#include "stub-cache.h"
35
kasperl@chromium.org71affb52009-05-26 05:44:31 +000036namespace v8 {
37namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038
ager@chromium.org65dad4b2009-04-23 08:48:43 +000039#define __ ACCESS_MASM(masm)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040
41
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000042static void ProbeTable(Isolate* isolate,
43 MacroAssembler* masm,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044 Code::Flags flags,
45 StubCache::Table table,
46 Register name,
ulan@chromium.org812308e2012-02-29 15:58:45 +000047 Register receiver,
48 // Number of the cache entry pointer-size scaled.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000049 Register offset,
50 Register extra) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000051 ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
52 ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
ulan@chromium.org812308e2012-02-29 15:58:45 +000053 ExternalReference map_offset(isolate->stub_cache()->map_reference(table));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000054
55 Label miss;
56
ulan@chromium.org812308e2012-02-29 15:58:45 +000057 // Multiply by 3 because there are 3 fields per entry (name, code, map).
58 __ lea(offset, Operand(offset, offset, times_2, 0));
59
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000060 if (extra.is_valid()) {
61 // Get the code entry from the cache.
ulan@chromium.org812308e2012-02-29 15:58:45 +000062 __ mov(extra, Operand::StaticArray(offset, times_1, value_offset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000063
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000064 // Check that the key in the entry matches the name.
ulan@chromium.org812308e2012-02-29 15:58:45 +000065 __ cmp(name, Operand::StaticArray(offset, times_1, key_offset));
66 __ j(not_equal, &miss);
67
68 // Check the map matches.
69 __ mov(offset, Operand::StaticArray(offset, times_1, map_offset));
70 __ cmp(offset, FieldOperand(receiver, HeapObject::kMapOffset));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000071 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000072
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000073 // Check that the flags match what we're looking for.
74 __ mov(offset, FieldOperand(extra, Code::kFlagsOffset));
75 __ and_(offset, ~Code::kFlagsNotUsedInLookup);
76 __ cmp(offset, flags);
77 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000078
ulan@chromium.org812308e2012-02-29 15:58:45 +000079#ifdef DEBUG
80 if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
81 __ jmp(&miss);
82 } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
83 __ jmp(&miss);
84 }
85#endif
86
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000087 // Jump to the first instruction in the code stub.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000088 __ add(extra, Immediate(Code::kHeaderSize - kHeapObjectTag));
89 __ jmp(extra);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000090
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000091 __ bind(&miss);
92 } else {
93 // Save the offset on the stack.
94 __ push(offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000095
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000096 // Check that the key in the entry matches the name.
ulan@chromium.org812308e2012-02-29 15:58:45 +000097 __ cmp(name, Operand::StaticArray(offset, times_1, key_offset));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000098 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000099
ulan@chromium.org812308e2012-02-29 15:58:45 +0000100 // Check the map matches.
101 __ mov(offset, Operand::StaticArray(offset, times_1, map_offset));
102 __ cmp(offset, FieldOperand(receiver, HeapObject::kMapOffset));
103 __ j(not_equal, &miss);
104
105 // Restore offset register.
106 __ mov(offset, Operand(esp, 0));
107
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000108 // Get the code entry from the cache.
ulan@chromium.org812308e2012-02-29 15:58:45 +0000109 __ mov(offset, Operand::StaticArray(offset, times_1, value_offset));
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000110
111 // Check that the flags match what we're looking for.
112 __ mov(offset, FieldOperand(offset, Code::kFlagsOffset));
113 __ and_(offset, ~Code::kFlagsNotUsedInLookup);
114 __ cmp(offset, flags);
115 __ j(not_equal, &miss);
116
ulan@chromium.org812308e2012-02-29 15:58:45 +0000117#ifdef DEBUG
118 if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
119 __ jmp(&miss);
120 } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
121 __ jmp(&miss);
122 }
123#endif
124
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000125 // Restore offset and re-load code entry from cache.
126 __ pop(offset);
ulan@chromium.org812308e2012-02-29 15:58:45 +0000127 __ mov(offset, Operand::StaticArray(offset, times_1, value_offset));
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000128
129 // Jump to the first instruction in the code stub.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000130 __ add(offset, Immediate(Code::kHeaderSize - kHeapObjectTag));
131 __ jmp(offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000132
133 // Pop at miss.
134 __ bind(&miss);
135 __ pop(offset);
136 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000137}
138
139
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000140// Helper function used to check that the dictionary doesn't contain
141// the property. This function may return false negatives, so miss_label
142// must always call a backup property check that is complete.
143// This function is safe to call if the receiver has fast properties.
144// Name must be a symbol and receiver must be a heap object.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000145static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
146 Label* miss_label,
147 Register receiver,
148 Handle<String> name,
149 Register r0,
150 Register r1) {
151 ASSERT(name->IsSymbol());
152 Counters* counters = masm->isolate()->counters();
153 __ IncrementCounter(counters->negative_lookups(), 1);
154 __ IncrementCounter(counters->negative_lookups_miss(), 1);
155
156 __ mov(r0, FieldOperand(receiver, HeapObject::kMapOffset));
157
158 const int kInterceptorOrAccessCheckNeededMask =
159 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
160
161 // Bail out if the receiver has a named interceptor or requires access checks.
162 __ test_b(FieldOperand(r0, Map::kBitFieldOffset),
163 kInterceptorOrAccessCheckNeededMask);
164 __ j(not_zero, miss_label);
165
166 // Check that receiver is a JSObject.
167 __ CmpInstanceType(r0, FIRST_SPEC_OBJECT_TYPE);
168 __ j(below, miss_label);
169
170 // Load properties array.
171 Register properties = r0;
172 __ mov(properties, FieldOperand(receiver, JSObject::kPropertiesOffset));
173
174 // Check that the properties array is a dictionary.
175 __ cmp(FieldOperand(properties, HeapObject::kMapOffset),
176 Immediate(masm->isolate()->factory()->hash_table_map()));
177 __ j(not_equal, miss_label);
178
179 Label done;
180 StringDictionaryLookupStub::GenerateNegativeLookup(masm,
181 miss_label,
182 &done,
183 properties,
184 name,
185 r1);
186 __ bind(&done);
187 __ DecrementCounter(counters->negative_lookups_miss(), 1);
188}
189
190
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000191void StubCache::GenerateProbe(MacroAssembler* masm,
192 Code::Flags flags,
193 Register receiver,
194 Register name,
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000195 Register scratch,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000196 Register extra,
ulan@chromium.org812308e2012-02-29 15:58:45 +0000197 Register extra2,
198 Register extra3) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000199 Label miss;
200
ulan@chromium.org812308e2012-02-29 15:58:45 +0000201 // Assert that code is valid. The multiplying code relies on the entry size
202 // being 12.
203 ASSERT(sizeof(Entry) == 12);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000204
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000205 // Assert the flags do not name a specific type.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000206 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
207
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000208 // Assert that there are no register conflicts.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000209 ASSERT(!scratch.is(receiver));
210 ASSERT(!scratch.is(name));
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000211 ASSERT(!extra.is(receiver));
212 ASSERT(!extra.is(name));
213 ASSERT(!extra.is(scratch));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000214
ulan@chromium.org812308e2012-02-29 15:58:45 +0000215 // Assert scratch and extra registers are valid, and extra2/3 are unused.
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000216 ASSERT(!scratch.is(no_reg));
217 ASSERT(extra2.is(no_reg));
ulan@chromium.org812308e2012-02-29 15:58:45 +0000218 ASSERT(extra3.is(no_reg));
219
220 Register offset = scratch;
221 scratch = no_reg;
222
223 Counters* counters = masm->isolate()->counters();
224 __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000225
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000226 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000227 __ JumpIfSmi(receiver, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000228
229 // Get the map of the receiver and compute the hash.
ulan@chromium.org812308e2012-02-29 15:58:45 +0000230 __ mov(offset, FieldOperand(name, String::kHashFieldOffset));
231 __ add(offset, FieldOperand(receiver, HeapObject::kMapOffset));
232 __ xor_(offset, flags);
233 // We mask out the last two bits because they are not part of the hash and
234 // they are always 01 for maps. Also in the two 'and' instructions below.
235 __ and_(offset, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
236 // ProbeTable expects the offset to be pointer scaled, which it is, because
237 // the heap object tag size is 2 and the pointer size log 2 is also 2.
238 ASSERT(kHeapObjectTagSize == kPointerSizeLog2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000239
240 // Probe the primary table.
ulan@chromium.org812308e2012-02-29 15:58:45 +0000241 ProbeTable(isolate(), masm, flags, kPrimary, name, receiver, offset, extra);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000242
243 // Primary miss: Compute hash for secondary probe.
ulan@chromium.org812308e2012-02-29 15:58:45 +0000244 __ mov(offset, FieldOperand(name, String::kHashFieldOffset));
245 __ add(offset, FieldOperand(receiver, HeapObject::kMapOffset));
246 __ xor_(offset, flags);
247 __ and_(offset, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
248 __ sub(offset, name);
249 __ add(offset, Immediate(flags));
250 __ and_(offset, (kSecondaryTableSize - 1) << kHeapObjectTagSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000251
252 // Probe the secondary table.
ulan@chromium.org812308e2012-02-29 15:58:45 +0000253 ProbeTable(
254 isolate(), masm, flags, kSecondary, name, receiver, offset, extra);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000255
256 // Cache miss: Fall-through and let caller handle the miss by
257 // entering the runtime system.
258 __ bind(&miss);
ulan@chromium.org812308e2012-02-29 15:58:45 +0000259 __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000260}
261
262
263void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
264 int index,
265 Register prototype) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000266 __ LoadGlobalFunction(index, prototype);
267 __ LoadGlobalFunctionInitialMap(prototype, prototype);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000268 // Load the prototype from the initial map.
269 __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
270}
271
272
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000273void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000274 MacroAssembler* masm,
275 int index,
276 Register prototype,
277 Label* miss) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000278 // Check we're still in the same context.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000279 __ cmp(Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)),
280 masm->isolate()->global_object());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000281 __ j(not_equal, miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000282 // Get the global function with the given index.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000283 Handle<JSFunction> function(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000284 JSFunction::cast(masm->isolate()->native_context()->get(index)));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000285 // Load its initial map. The global functions all have initial maps.
286 __ Set(prototype, Immediate(Handle<Map>(function->initial_map())));
287 // Load the prototype from the initial map.
288 __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
289}
290
291
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000292void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
293 Register receiver,
294 Register scratch,
295 Label* miss_label) {
296 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000297 __ JumpIfSmi(receiver, miss_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000298
299 // Check that the object is a JS array.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000300 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000301 __ j(not_equal, miss_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000302
303 // Load length directly from the JS array.
304 __ mov(eax, FieldOperand(receiver, JSArray::kLengthOffset));
305 __ ret(0);
306}
307
308
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000309// Generate code to check if an object is a string. If the object is
310// a string, the map's instance type is left in the scratch register.
311static void GenerateStringCheck(MacroAssembler* masm,
312 Register receiver,
313 Register scratch,
314 Label* smi,
315 Label* non_string_object) {
316 // Check that the object isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000317 __ JumpIfSmi(receiver, smi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000318
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000319 // Check that the object is a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000320 __ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
321 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000322 STATIC_ASSERT(kNotStringTag != 0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000323 __ test(scratch, Immediate(kNotStringTag));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000324 __ j(not_zero, non_string_object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000325}
326
327
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000328void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
329 Register receiver,
ager@chromium.org5c838252010-02-19 08:53:10 +0000330 Register scratch1,
331 Register scratch2,
ager@chromium.org378b34e2011-01-28 08:04:38 +0000332 Label* miss,
333 bool support_wrappers) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000334 Label check_wrapper;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000335
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000336 // Check if the object is a string leaving the instance type in the
337 // scratch register.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000338 GenerateStringCheck(masm, receiver, scratch1, miss,
339 support_wrappers ? &check_wrapper : miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000340
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000341 // Load length from the string and convert to a smi.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000342 __ mov(eax, FieldOperand(receiver, String::kLengthOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000343 __ ret(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000344
ager@chromium.org378b34e2011-01-28 08:04:38 +0000345 if (support_wrappers) {
346 // Check if the object is a JSValue wrapper.
347 __ bind(&check_wrapper);
348 __ cmp(scratch1, JS_VALUE_TYPE);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000349 __ j(not_equal, miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000350
ager@chromium.org378b34e2011-01-28 08:04:38 +0000351 // Check if the wrapped value is a string and load the length
352 // directly if it is.
353 __ mov(scratch2, FieldOperand(receiver, JSValue::kValueOffset));
354 GenerateStringCheck(masm, scratch2, scratch1, miss, miss);
355 __ mov(eax, FieldOperand(scratch2, String::kLengthOffset));
356 __ ret(0);
357 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000358}
359
360
361void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
362 Register receiver,
363 Register scratch1,
364 Register scratch2,
365 Label* miss_label) {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000366 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000367 __ mov(eax, scratch1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000368 __ ret(0);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000369}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000370
ager@chromium.org7c537e22008-10-16 08:43:32 +0000371
372// Load a fast property out of a holder object (src). In-object properties
373// are loaded directly otherwise the property is loaded from the properties
374// fixed array.
375void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000376 Register dst,
377 Register src,
378 Handle<JSObject> holder,
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +0000379 PropertyIndex index) {
380 if (index.is_header_index()) {
381 int offset = index.header_index() * kPointerSize;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000382 __ mov(dst, FieldOperand(src, offset));
383 } else {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +0000384 // Adjust for the number of properties stored in the holder.
385 int slot = index.field_index() - holder->map()->inobject_properties();
386 if (slot < 0) {
387 // Get the property straight out of the holder.
388 int offset = holder->map()->instance_size() + (slot * kPointerSize);
389 __ mov(dst, FieldOperand(src, offset));
390 } else {
391 // Calculate the offset into the properties array.
392 int offset = slot * kPointerSize + FixedArray::kHeaderSize;
393 __ mov(dst, FieldOperand(src, JSObject::kPropertiesOffset));
394 __ mov(dst, FieldOperand(dst, offset));
395 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000396 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000397}
398
399
ager@chromium.org5c838252010-02-19 08:53:10 +0000400static void PushInterceptorArguments(MacroAssembler* masm,
401 Register receiver,
402 Register holder,
403 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000404 Handle<JSObject> holder_obj) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000405 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000406 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
407 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000408 Register scratch = name;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000409 __ mov(scratch, Immediate(interceptor));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000410 __ push(scratch);
ager@chromium.org5c838252010-02-19 08:53:10 +0000411 __ push(receiver);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000412 __ push(holder);
413 __ push(FieldOperand(scratch, InterceptorInfo::kDataOffset));
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000414 __ push(Immediate(reinterpret_cast<int>(masm->isolate())));
ager@chromium.org5c838252010-02-19 08:53:10 +0000415}
416
417
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000418static void CompileCallLoadPropertyWithInterceptor(
419 MacroAssembler* masm,
420 Register receiver,
421 Register holder,
422 Register name,
423 Handle<JSObject> holder_obj) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000424 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
ager@chromium.org5c838252010-02-19 08:53:10 +0000425 __ CallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000426 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
427 masm->isolate()),
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000428 6);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000429}
430
431
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000432// Number of pointers to be reserved on stack for fast API call.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000433static const int kFastApiCallArguments = 4;
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000434
435
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000436// Reserves space for the extra arguments to API function in the
ager@chromium.org5c838252010-02-19 08:53:10 +0000437// caller's frame.
438//
439// These arguments are set by CheckPrototypes and GenerateFastApiCall.
440static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
441 // ----------- S t a t e -------------
442 // -- esp[0] : return address
443 // -- esp[4] : last argument in the internal frame of the caller
444 // -----------------------------------
445 __ pop(scratch);
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000446 for (int i = 0; i < kFastApiCallArguments; i++) {
447 __ push(Immediate(Smi::FromInt(0)));
448 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000449 __ push(scratch);
450}
451
452
453// Undoes the effects of ReserveSpaceForFastApiCall.
454static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
455 // ----------- S t a t e -------------
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000456 // -- esp[0] : return address.
457 // -- esp[4] : last fast api call extra argument.
ager@chromium.org5c838252010-02-19 08:53:10 +0000458 // -- ...
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000459 // -- esp[kFastApiCallArguments * 4] : first fast api call extra argument.
460 // -- esp[kFastApiCallArguments * 4 + 4] : last argument in the internal
461 // frame.
ager@chromium.org5c838252010-02-19 08:53:10 +0000462 // -----------------------------------
463 __ pop(scratch);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000464 __ add(esp, Immediate(kPointerSize * kFastApiCallArguments));
ager@chromium.org5c838252010-02-19 08:53:10 +0000465 __ push(scratch);
466}
467
468
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000469// Generates call to API function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000470static void GenerateFastApiCall(MacroAssembler* masm,
471 const CallOptimization& optimization,
472 int argc) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000473 // ----------- S t a t e -------------
474 // -- esp[0] : return address
475 // -- esp[4] : object passing the type check
476 // (last fast api call extra argument,
477 // set by CheckPrototypes)
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000478 // -- esp[8] : api function
ager@chromium.org5c838252010-02-19 08:53:10 +0000479 // (first fast api call extra argument)
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000480 // -- esp[12] : api call data
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000481 // -- esp[16] : isolate
482 // -- esp[20] : last argument
ager@chromium.org5c838252010-02-19 08:53:10 +0000483 // -- ...
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000484 // -- esp[(argc + 4) * 4] : first argument
485 // -- esp[(argc + 5) * 4] : receiver
ager@chromium.org5c838252010-02-19 08:53:10 +0000486 // -----------------------------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000487 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000488 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000489 __ LoadHeapObject(edi, function);
ager@chromium.org5c838252010-02-19 08:53:10 +0000490 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
491
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000492 // Pass the additional arguments.
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000493 __ mov(Operand(esp, 2 * kPointerSize), edi);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000494 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
495 Handle<Object> call_data(api_call_info->data());
496 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
497 __ mov(ecx, api_call_info);
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000498 __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kDataOffset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000499 __ mov(Operand(esp, 3 * kPointerSize), ebx);
500 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000501 __ mov(Operand(esp, 3 * kPointerSize), Immediate(call_data));
ager@chromium.org5c838252010-02-19 08:53:10 +0000502 }
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000503 __ mov(Operand(esp, 4 * kPointerSize),
504 Immediate(reinterpret_cast<int>(masm->isolate())));
ager@chromium.org5c838252010-02-19 08:53:10 +0000505
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000506 // Prepare arguments.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000507 __ lea(eax, Operand(esp, 4 * kPointerSize));
ager@chromium.org5c838252010-02-19 08:53:10 +0000508
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000509 const int kApiArgc = 1; // API function gets reference to the v8::Arguments.
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000510
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000511 // Allocate the v8::Arguments structure in the arguments' space since
512 // it's not controlled by GC.
513 const int kApiStackSpace = 4;
514
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000515 __ PrepareCallApiFunction(kApiArgc + kApiStackSpace);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000516
517 __ mov(ApiParameterOperand(1), eax); // v8::Arguments::implicit_args_.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000518 __ add(eax, Immediate(argc * kPointerSize));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000519 __ mov(ApiParameterOperand(2), eax); // v8::Arguments::values_.
520 __ Set(ApiParameterOperand(3), Immediate(argc)); // v8::Arguments::length_.
521 // v8::Arguments::is_construct_call_.
522 __ Set(ApiParameterOperand(4), Immediate(0));
523
524 // v8::InvocationCallback's argument.
525 __ lea(eax, ApiParameterOperand(1));
526 __ mov(ApiParameterOperand(0), eax);
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000527
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000528 // Function address is a foreign pointer outside V8's heap.
529 Address function_address = v8::ToCData<Address>(api_call_info->callback());
530 __ CallApiFunctionAndReturn(function_address,
531 argc + kFastApiCallArguments + 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000532}
533
534
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000535class CallInterceptorCompiler BASE_EMBEDDED {
536 public:
ager@chromium.org5c838252010-02-19 08:53:10 +0000537 CallInterceptorCompiler(StubCompiler* stub_compiler,
538 const ParameterCount& arguments,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000539 Register name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000540 Code::ExtraICState extra_state)
ager@chromium.org5c838252010-02-19 08:53:10 +0000541 : stub_compiler_(stub_compiler),
542 arguments_(arguments),
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000543 name_(name),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000544 extra_state_(extra_state) {}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000545
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000546 void Compile(MacroAssembler* masm,
547 Handle<JSObject> object,
548 Handle<JSObject> holder,
549 Handle<String> name,
550 LookupResult* lookup,
551 Register receiver,
552 Register scratch1,
553 Register scratch2,
554 Register scratch3,
555 Label* miss) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000556 ASSERT(holder->HasNamedInterceptor());
557 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
558
559 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000560 __ JumpIfSmi(receiver, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000561
562 CallOptimization optimization(lookup);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000563 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000564 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
565 holder, lookup, name, optimization, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000566 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000567 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
568 name, holder, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000569 }
570 }
571
572 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000573 void CompileCacheable(MacroAssembler* masm,
574 Handle<JSObject> object,
575 Register receiver,
576 Register scratch1,
577 Register scratch2,
578 Register scratch3,
579 Handle<JSObject> interceptor_holder,
580 LookupResult* lookup,
581 Handle<String> name,
582 const CallOptimization& optimization,
583 Label* miss_label) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000584 ASSERT(optimization.is_constant_call());
585 ASSERT(!lookup->holder()->IsGlobalObject());
586
587 int depth1 = kInvalidProtoDepth;
588 int depth2 = kInvalidProtoDepth;
589 bool can_do_fast_api_call = false;
590 if (optimization.is_simple_api_call() &&
591 !lookup->holder()->IsGlobalObject()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000592 depth1 = optimization.GetPrototypeDepthOfExpectedType(
593 object, interceptor_holder);
ager@chromium.org5c838252010-02-19 08:53:10 +0000594 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000595 depth2 = optimization.GetPrototypeDepthOfExpectedType(
596 interceptor_holder, Handle<JSObject>(lookup->holder()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000597 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000598 can_do_fast_api_call =
599 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000600 }
601
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000602 Counters* counters = masm->isolate()->counters();
603 __ IncrementCounter(counters->call_const_interceptor(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000604
605 if (can_do_fast_api_call) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000606 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000607 ReserveSpaceForFastApiCall(masm, scratch1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000608 }
609
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000610 // Check that the maps from receiver to interceptor's holder
611 // haven't changed and thus we can invoke interceptor.
ager@chromium.org5c838252010-02-19 08:53:10 +0000612 Label miss_cleanup;
613 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
614 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000615 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
616 scratch1, scratch2, scratch3,
617 name, depth1, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000618
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000619 // Invoke an interceptor and if it provides a value,
620 // branch to |regular_invoke|.
ager@chromium.org5c838252010-02-19 08:53:10 +0000621 Label regular_invoke;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000622 LoadWithInterceptor(masm, receiver, holder, interceptor_holder,
623 &regular_invoke);
ager@chromium.org5c838252010-02-19 08:53:10 +0000624
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000625 // Interceptor returned nothing for this property. Try to use cached
626 // constant function.
ager@chromium.org5c838252010-02-19 08:53:10 +0000627
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000628 // Check that the maps from interceptor's holder to constant function's
629 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000630 if (*interceptor_holder != lookup->holder()) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000631 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000632 Handle<JSObject>(lookup->holder()),
633 scratch1, scratch2, scratch3,
634 name, depth2, miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000635 } else {
636 // CheckPrototypes has a side effect of fetching a 'holder'
637 // for API (object which is instanceof for the signature). It's
638 // safe to omit it here, as if present, it should be fetched
639 // by the previous CheckPrototypes.
640 ASSERT(depth2 == kInvalidProtoDepth);
641 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000642
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000643 // Invoke function.
ager@chromium.org5c838252010-02-19 08:53:10 +0000644 if (can_do_fast_api_call) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000645 GenerateFastApiCall(masm, optimization, arguments_.immediate());
ager@chromium.org5c838252010-02-19 08:53:10 +0000646 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000647 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000648 ? CALL_AS_FUNCTION
649 : CALL_AS_METHOD;
ager@chromium.org5c838252010-02-19 08:53:10 +0000650 __ InvokeFunction(optimization.constant_function(), arguments_,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000651 JUMP_FUNCTION, NullCallWrapper(), call_kind);
ager@chromium.org5c838252010-02-19 08:53:10 +0000652 }
653
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000654 // Deferred code for fast API call case---clean preallocated space.
ager@chromium.org5c838252010-02-19 08:53:10 +0000655 if (can_do_fast_api_call) {
656 __ bind(&miss_cleanup);
657 FreeSpaceForFastApiCall(masm, scratch1);
658 __ jmp(miss_label);
659 }
660
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000661 // Invoke a regular function.
ager@chromium.org5c838252010-02-19 08:53:10 +0000662 __ bind(&regular_invoke);
663 if (can_do_fast_api_call) {
664 FreeSpaceForFastApiCall(masm, scratch1);
665 }
666 }
667
668 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000669 Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +0000670 Register receiver,
671 Register scratch1,
672 Register scratch2,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000673 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000674 Handle<String> name,
675 Handle<JSObject> interceptor_holder,
ager@chromium.org5c838252010-02-19 08:53:10 +0000676 Label* miss_label) {
677 Register holder =
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000678 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000679 scratch1, scratch2, scratch3,
680 name, miss_label);
ager@chromium.org5c838252010-02-19 08:53:10 +0000681
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000682 FrameScope scope(masm, StackFrame::INTERNAL);
ager@chromium.org5c838252010-02-19 08:53:10 +0000683 // Save the name_ register across the call.
684 __ push(name_);
685
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000686 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
ager@chromium.org5c838252010-02-19 08:53:10 +0000687
688 __ CallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000689 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
690 masm->isolate()),
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000691 6);
ager@chromium.org5c838252010-02-19 08:53:10 +0000692
693 // Restore the name_ register.
694 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000695
696 // Leave the internal frame.
ager@chromium.org5c838252010-02-19 08:53:10 +0000697 }
698
699 void LoadWithInterceptor(MacroAssembler* masm,
700 Register receiver,
701 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000702 Handle<JSObject> holder_obj,
ager@chromium.org5c838252010-02-19 08:53:10 +0000703 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000704 {
705 FrameScope scope(masm, StackFrame::INTERNAL);
706 __ push(holder); // Save the holder.
707 __ push(name_); // Save the name.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000708
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000709 CompileCallLoadPropertyWithInterceptor(masm,
710 receiver,
711 holder,
712 name_,
713 holder_obj);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000714
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000715 __ pop(name_); // Restore the name.
716 __ pop(receiver); // Restore the holder.
717 // Leave the internal frame.
718 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000719
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000720 __ cmp(eax, masm->isolate()->factory()->no_interceptor_result_sentinel());
ager@chromium.org5c838252010-02-19 08:53:10 +0000721 __ j(not_equal, interceptor_succeeded);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000722 }
723
ager@chromium.org5c838252010-02-19 08:53:10 +0000724 StubCompiler* stub_compiler_;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000725 const ParameterCount& arguments_;
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000726 Register name_;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000727 Code::ExtraICState extra_state_;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000728};
729
730
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000731void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
732 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000733 Handle<Code> code = (kind == Code::LOAD_IC)
734 ? masm->isolate()->builtins()->LoadIC_Miss()
735 : masm->isolate()->builtins()->KeyedLoadIC_Miss();
736 __ jmp(code, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000737}
738
739
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000740void StubCompiler::GenerateKeyedLoadMissForceGeneric(MacroAssembler* masm) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000741 Handle<Code> code =
742 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
743 __ jmp(code, RelocInfo::CODE_TARGET);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000744}
745
746
ager@chromium.org5c838252010-02-19 08:53:10 +0000747// Both name_reg and receiver_reg are preserved on jumps to miss_label,
748// but may be destroyed if store is successful.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000749void StubCompiler::GenerateStoreField(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000750 Handle<JSObject> object,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000751 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000752 Handle<Map> transition,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000753 Handle<String> name,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000754 Register receiver_reg,
755 Register name_reg,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000756 Register scratch1,
757 Register scratch2,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000758 Label* miss_label) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000759 LookupResult lookup(masm->isolate());
760 object->Lookup(*name, &lookup);
761 if (lookup.IsFound() && (lookup.IsReadOnly() || !lookup.IsCacheable())) {
762 // In sloppy mode, we could just return the value and be done. However, we
763 // might be in strict mode, where we have to throw. Since we cannot tell,
764 // go into slow case unconditionally.
765 __ jmp(miss_label);
766 return;
767 }
768
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000769 // Check that the map of the object hasn't changed.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000770 CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
771 : REQUIRE_EXACT_MAP;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000772 __ CheckMap(receiver_reg, Handle<Map>(object->map()),
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000773 miss_label, DO_SMI_CHECK, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000774
775 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000776 if (object->IsJSGlobalProxy()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000777 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
778 }
779
780 // Check that we are allowed to write this.
781 if (!transition.is_null() && object->GetPrototype()->IsJSObject()) {
782 JSObject* holder;
783 if (lookup.IsFound()) {
784 holder = lookup.holder();
785 } else {
786 // Find the top object.
787 holder = *object;
788 do {
789 holder = JSObject::cast(holder->GetPrototype());
790 } while (holder->GetPrototype()->IsJSObject());
791 }
792 // We need an extra register, push
793 __ push(name_reg);
794 Label miss_pop, done_check;
795 CheckPrototypes(object, receiver_reg, Handle<JSObject>(holder), name_reg,
796 scratch1, scratch2, name, &miss_pop);
797 __ jmp(&done_check);
798 __ bind(&miss_pop);
799 __ pop(name_reg);
800 __ jmp(miss_label);
801 __ bind(&done_check);
802 __ pop(name_reg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000803 }
804
805 // Stub never generated for non-global objects that require access
806 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000807 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000808
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000809 // Perform map transition for the receiver if necessary.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000810 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) {
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000811 // The properties must be extended before we can store the value.
ager@chromium.org32912102009-01-16 10:38:43 +0000812 // We jump to a runtime call that extends the properties array.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000813 __ pop(scratch1); // Return address.
ager@chromium.org5c838252010-02-19 08:53:10 +0000814 __ push(receiver_reg);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000815 __ push(Immediate(transition));
ager@chromium.org5c838252010-02-19 08:53:10 +0000816 __ push(eax);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000817 __ push(scratch1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000818 __ TailCallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000819 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
820 masm->isolate()),
821 3,
822 1);
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000823 return;
824 }
825
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000826 if (!transition.is_null()) {
verwaest@chromium.org37141392012-05-31 13:27:02 +0000827 // Update the map of the object.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000828 __ mov(scratch1, Immediate(transition));
829 __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1);
verwaest@chromium.org37141392012-05-31 13:27:02 +0000830
831 // Update the write barrier for the map field and pass the now unused
832 // name_reg as scratch register.
833 __ RecordWriteField(receiver_reg,
834 HeapObject::kMapOffset,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000835 scratch1,
verwaest@chromium.org37141392012-05-31 13:27:02 +0000836 name_reg,
837 kDontSaveFPRegs,
838 OMIT_REMEMBERED_SET,
839 OMIT_SMI_CHECK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000840 }
841
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000842 // Adjust for the number of properties stored in the object. Even in the
843 // face of a transition we can use the old map here because the size of the
844 // object and the number of in-object properties is not going to change.
845 index -= object->map()->inobject_properties();
846
ager@chromium.org7c537e22008-10-16 08:43:32 +0000847 if (index < 0) {
848 // Set the property straight into the object.
849 int offset = object->map()->instance_size() + (index * kPointerSize);
850 __ mov(FieldOperand(receiver_reg, offset), eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000851
ager@chromium.org7c537e22008-10-16 08:43:32 +0000852 // Update the write barrier for the array address.
853 // Pass the value being stored in the now unused name_reg.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000854 __ mov(name_reg, eax);
855 __ RecordWriteField(receiver_reg,
856 offset,
857 name_reg,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000858 scratch1,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000859 kDontSaveFPRegs);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000860 } else {
861 // Write to the properties array.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000862 int offset = index * kPointerSize + FixedArray::kHeaderSize;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000863 // Get the properties array (optimistically).
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000864 __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
865 __ mov(FieldOperand(scratch1, offset), eax);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000866
867 // Update the write barrier for the array address.
868 // Pass the value being stored in the now unused name_reg.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000869 __ mov(name_reg, eax);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000870 __ RecordWriteField(scratch1,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000871 offset,
872 name_reg,
873 receiver_reg,
874 kDontSaveFPRegs);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000875 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000876
877 // Return the value (register eax).
878 __ ret(0);
879}
880
881
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000882// Generate code to check that a global property cell is empty. Create
883// the property cell at compilation time if no cell exists for the
884// property.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000885static void GenerateCheckPropertyCell(MacroAssembler* masm,
886 Handle<GlobalObject> global,
887 Handle<String> name,
888 Register scratch,
889 Label* miss) {
890 Handle<JSGlobalPropertyCell> cell =
891 GlobalObject::EnsurePropertyCell(global, name);
892 ASSERT(cell->value()->IsTheHole());
893 Handle<Oddball> the_hole = masm->isolate()->factory()->the_hole_value();
894 if (Serializer::enabled()) {
895 __ mov(scratch, Immediate(cell));
896 __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
897 Immediate(the_hole));
898 } else {
899 __ cmp(Operand::Cell(cell), Immediate(the_hole));
900 }
901 __ j(not_equal, miss);
902}
903
904
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000905// Calls GenerateCheckPropertyCell for each global object in the prototype chain
906// from object to (but not including) holder.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000907static void GenerateCheckPropertyCells(MacroAssembler* masm,
908 Handle<JSObject> object,
909 Handle<JSObject> holder,
910 Handle<String> name,
911 Register scratch,
912 Label* miss) {
913 Handle<JSObject> current = object;
914 while (!current.is_identical_to(holder)) {
915 if (current->IsGlobalObject()) {
916 GenerateCheckPropertyCell(masm,
917 Handle<GlobalObject>::cast(current),
918 name,
919 scratch,
920 miss);
921 }
922 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
923 }
924}
925
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000926#undef __
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000927#define __ ACCESS_MASM(masm())
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000928
929
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000930Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
931 Register object_reg,
932 Handle<JSObject> holder,
933 Register holder_reg,
934 Register scratch1,
935 Register scratch2,
936 Handle<String> name,
937 int save_at_depth,
938 Label* miss) {
939 // Make sure there's no overlap between holder and object registers.
940 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
941 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
942 && !scratch2.is(scratch1));
943
944 // Keep track of the current object in register reg.
945 Register reg = object_reg;
946 Handle<JSObject> current = object;
947 int depth = 0;
948
949 if (save_at_depth == depth) {
950 __ mov(Operand(esp, kPointerSize), reg);
951 }
952
953 // Traverse the prototype chain and check the maps in the prototype chain for
954 // fast and global objects or do negative lookup for normal objects.
955 while (!current.is_identical_to(holder)) {
956 ++depth;
957
958 // Only global objects and objects that do not require access
959 // checks are allowed in stubs.
960 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
961
962 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
963 if (!current->HasFastProperties() &&
964 !current->IsJSGlobalObject() &&
965 !current->IsJSGlobalProxy()) {
966 if (!name->IsSymbol()) {
967 name = factory()->LookupSymbol(name);
968 }
969 ASSERT(current->property_dictionary()->FindEntry(*name) ==
970 StringDictionary::kNotFound);
971
972 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
973 scratch1, scratch2);
974
975 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
976 reg = holder_reg; // From now on the object will be in holder_reg.
977 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
978 } else {
979 bool in_new_space = heap()->InNewSpace(*prototype);
980 Handle<Map> current_map(current->map());
981 if (in_new_space) {
982 // Save the map in scratch1 for later.
983 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000984 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000985 __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK,
986 ALLOW_ELEMENT_TRANSITION_MAPS);
987
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000988 // Check access rights to the global object. This has to happen after
989 // the map check so that we know that the object is actually a global
990 // object.
991 if (current->IsJSGlobalProxy()) {
992 __ CheckAccessGlobalProxy(reg, scratch2, miss);
993 }
994 reg = holder_reg; // From now on the object will be in holder_reg.
995
996 if (in_new_space) {
997 // The prototype is in new space; we cannot store a reference to it
998 // in the code. Load it from the map.
999 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
1000 } else {
1001 // The prototype is in old space; load it directly.
1002 __ mov(reg, prototype);
1003 }
1004 }
1005
1006 if (save_at_depth == depth) {
1007 __ mov(Operand(esp, kPointerSize), reg);
1008 }
1009
1010 // Go to the next object in the prototype chain.
1011 current = prototype;
1012 }
1013 ASSERT(current.is_identical_to(holder));
1014
1015 // Log the check depth.
1016 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
1017
1018 // Check the holder map.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001019 __ CheckMap(reg, Handle<Map>(holder->map()),
1020 miss, DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001021
1022 // Perform security check for access to the global object.
1023 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1024 if (holder->IsJSGlobalProxy()) {
1025 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1026 }
1027
1028 // If we've skipped any global objects, it's not enough to verify that
1029 // their maps haven't changed. We also need to check that the property
1030 // cell for the property is still empty.
1031 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1032
1033 // Return the register containing the holder.
1034 return reg;
1035}
1036
1037
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001038void StubCompiler::GenerateLoadField(Handle<JSObject> object,
1039 Handle<JSObject> holder,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001040 Register receiver,
1041 Register scratch1,
1042 Register scratch2,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001043 Register scratch3,
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00001044 PropertyIndex index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001045 Handle<String> name,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001046 Label* miss) {
1047 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001048 __ JumpIfSmi(receiver, miss);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001049
1050 // Check the prototype chain.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001051 Register reg = CheckPrototypes(
1052 object, receiver, holder, scratch1, scratch2, scratch3, name, miss);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001053
1054 // Get the value from the properties.
1055 GenerateFastPropertyLoad(masm(), eax, reg, holder, index);
1056 __ ret(0);
1057}
1058
1059
erik.corry@gmail.com88767242012-08-08 14:43:45 +00001060void StubCompiler::GenerateDictionaryLoadCallback(Register receiver,
1061 Register name_reg,
1062 Register scratch1,
1063 Register scratch2,
1064 Register scratch3,
1065 Handle<AccessorInfo> callback,
1066 Handle<String> name,
1067 Label* miss) {
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001068 ASSERT(!receiver.is(scratch2));
1069 ASSERT(!receiver.is(scratch3));
erik.corry@gmail.com88767242012-08-08 14:43:45 +00001070 Register dictionary = scratch1;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001071 bool must_preserve_dictionary_reg = receiver.is(dictionary);
1072
1073 // Load the properties dictionary.
1074 if (must_preserve_dictionary_reg) {
1075 __ push(dictionary);
1076 }
erik.corry@gmail.com88767242012-08-08 14:43:45 +00001077 __ mov(dictionary, FieldOperand(receiver, JSObject::kPropertiesOffset));
1078
1079 // Probe the dictionary.
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001080 Label probe_done, pop_and_miss;
erik.corry@gmail.com88767242012-08-08 14:43:45 +00001081 StringDictionaryLookupStub::GeneratePositiveLookup(masm(),
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001082 &pop_and_miss,
erik.corry@gmail.com88767242012-08-08 14:43:45 +00001083 &probe_done,
1084 dictionary,
1085 name_reg,
1086 scratch2,
1087 scratch3);
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001088 __ bind(&pop_and_miss);
1089 if (must_preserve_dictionary_reg) {
1090 __ pop(dictionary);
1091 }
1092 __ jmp(miss);
erik.corry@gmail.com88767242012-08-08 14:43:45 +00001093 __ bind(&probe_done);
1094
1095 // If probing finds an entry in the dictionary, scratch2 contains the
1096 // index into the dictionary. Check that the value is the callback.
1097 Register index = scratch2;
1098 const int kElementsStartOffset =
1099 StringDictionary::kHeaderSize +
1100 StringDictionary::kElementsStartIndex * kPointerSize;
1101 const int kValueOffset = kElementsStartOffset + kPointerSize;
1102 __ mov(scratch3,
1103 Operand(dictionary, index, times_4, kValueOffset - kHeapObjectTag));
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001104 if (must_preserve_dictionary_reg) {
1105 __ pop(dictionary);
1106 }
erik.corry@gmail.com88767242012-08-08 14:43:45 +00001107 __ cmp(scratch3, callback);
1108 __ j(not_equal, miss);
1109}
1110
1111
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001112void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
1113 Handle<JSObject> holder,
1114 Register receiver,
1115 Register name_reg,
1116 Register scratch1,
1117 Register scratch2,
1118 Register scratch3,
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001119 Register scratch4,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001120 Handle<AccessorInfo> callback,
1121 Handle<String> name,
1122 Label* miss) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001123 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001124 __ JumpIfSmi(receiver, miss);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001125
1126 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001127 Register reg = CheckPrototypes(object, receiver, holder, scratch1,
1128 scratch2, scratch3, name, miss);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001129
erik.corry@gmail.com88767242012-08-08 14:43:45 +00001130 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
1131 GenerateDictionaryLoadCallback(
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001132 reg, name_reg, scratch1, scratch2, scratch3, callback, name, miss);
erik.corry@gmail.com88767242012-08-08 14:43:45 +00001133 }
1134
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001135 // Insert additional parameters into the stack frame above return address.
1136 ASSERT(!scratch3.is(reg));
1137 __ pop(scratch3); // Get return address to place it below.
1138
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001139 __ push(receiver); // receiver
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001140 __ mov(scratch2, esp);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001141 ASSERT(!scratch2.is(reg));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001142 __ push(reg); // holder
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001143 // Push data from AccessorInfo.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001144 if (isolate()->heap()->InNewSpace(callback->data())) {
1145 __ mov(scratch1, Immediate(callback));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001146 __ push(FieldOperand(scratch1, AccessorInfo::kDataOffset));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001147 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001148 __ push(Immediate(Handle<Object>(callback->data())));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001149 }
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001150 __ push(Immediate(reinterpret_cast<int>(isolate())));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001151
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001152 // Save a pointer to where we pushed the arguments pointer.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001153 // This will be passed as the const AccessorInfo& to the C++ callback.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001154 __ push(scratch2);
1155
1156 __ push(name_reg); // name
1157 __ mov(ebx, esp); // esp points to reference to name (handler).
1158
1159 __ push(scratch3); // Restore return address.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001160
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001161 // 4 elements array for v8::Arguments::values_, handler for name and pointer
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001162 // to the values (it considered as smi in GC).
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001163 const int kStackSpace = 6;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001164 const int kApiArgc = 2;
1165
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001166 __ PrepareCallApiFunction(kApiArgc);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001167 __ mov(ApiParameterOperand(0), ebx); // name.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001168 __ add(ebx, Immediate(kPointerSize));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001169 __ mov(ApiParameterOperand(1), ebx); // arguments pointer.
1170
kmillikin@chromium.org2d5475f2009-12-20 18:15:52 +00001171 // Emitting a stub call may try to allocate (if the code is not
1172 // already generated). Do not allow the assembler to perform a
1173 // garbage collection but instead return the allocation failure
1174 // object.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001175 Address getter_address = v8::ToCData<Address>(callback->getter());
1176 __ CallApiFunctionAndReturn(getter_address, kStackSpace);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001177}
1178
1179
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001180void StubCompiler::GenerateLoadConstant(Handle<JSObject> object,
1181 Handle<JSObject> holder,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001182 Register receiver,
1183 Register scratch1,
1184 Register scratch2,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001185 Register scratch3,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001186 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001187 Handle<String> name,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001188 Label* miss) {
1189 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001190 __ JumpIfSmi(receiver, miss);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001191
1192 // Check that the maps haven't changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001193 CheckPrototypes(
1194 object, receiver, holder, scratch1, scratch2, scratch3, name, miss);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001195
1196 // Return the constant value.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001197 __ LoadHeapObject(eax, value);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001198 __ ret(0);
1199}
1200
1201
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001202void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
1203 Handle<JSObject> interceptor_holder,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001204 LookupResult* lookup,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001205 Register receiver,
1206 Register name_reg,
1207 Register scratch1,
1208 Register scratch2,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001209 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001210 Handle<String> name,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001211 Label* miss) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001212 ASSERT(interceptor_holder->HasNamedInterceptor());
1213 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1214
1215 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001216 __ JumpIfSmi(receiver, miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001217
1218 // So far the most popular follow ups for interceptor loads are FIELD
1219 // and CALLBACKS, so inline only them, other cases may be added
1220 // later.
1221 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001222 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001223 if (lookup->IsField()) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001224 compile_followup_inline = true;
1225 } else if (lookup->type() == CALLBACKS &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001226 lookup->GetCallbackObject()->IsAccessorInfo()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001227 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
1228 compile_followup_inline = callback->getter() != NULL &&
1229 callback->IsCompatibleReceiver(*object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001230 }
1231 }
1232
1233 if (compile_followup_inline) {
1234 // Compile the interceptor call, followed by inline code to load the
1235 // property from further up the prototype chain if the call fails.
1236 // Check that the maps haven't changed.
1237 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001238 scratch1, scratch2, scratch3,
1239 name, miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001240 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
1241
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001242 // Preserve the receiver register explicitly whenever it is different from
1243 // the holder and it is needed should the interceptor return without any
1244 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1245 // the FIELD case might cause a miss during the prototype check.
1246 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
1247 bool must_preserve_receiver_reg = !receiver.is(holder_reg) &&
1248 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1249
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001250 // Save necessary data before invoking an interceptor.
1251 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001252 {
1253 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001254
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001255 if (must_preserve_receiver_reg) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001256 __ push(receiver);
1257 }
1258 __ push(holder_reg);
1259 __ push(name_reg);
1260
1261 // Invoke an interceptor. Note: map checks from receiver to
1262 // interceptor's holder has been compiled before (see a caller
1263 // of this method.)
1264 CompileCallLoadPropertyWithInterceptor(masm(),
1265 receiver,
1266 holder_reg,
1267 name_reg,
1268 interceptor_holder);
1269
1270 // Check if interceptor provided a value for property. If it's
1271 // the case, return immediately.
1272 Label interceptor_failed;
1273 __ cmp(eax, factory()->no_interceptor_result_sentinel());
1274 __ j(equal, &interceptor_failed);
1275 frame_scope.GenerateLeaveFrame();
1276 __ ret(0);
1277
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001278 // Clobber registers when generating debug-code to provoke errors.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001279 __ bind(&interceptor_failed);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001280 if (FLAG_debug_code) {
1281 __ mov(receiver, Immediate(BitCast<int32_t>(kZapValue)));
1282 __ mov(holder_reg, Immediate(BitCast<int32_t>(kZapValue)));
1283 __ mov(name_reg, Immediate(BitCast<int32_t>(kZapValue)));
1284 }
1285
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001286 __ pop(name_reg);
1287 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001288 if (must_preserve_receiver_reg) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001289 __ pop(receiver);
1290 }
1291
1292 // Leave the internal frame.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001293 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001294
1295 // Check that the maps from interceptor's holder to lookup's holder
1296 // haven't changed. And load lookup's holder into holder_reg.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001297 if (must_perfrom_prototype_check) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001298 holder_reg = CheckPrototypes(interceptor_holder,
1299 holder_reg,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001300 Handle<JSObject>(lookup->holder()),
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001301 scratch1,
1302 scratch2,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001303 scratch3,
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001304 name,
1305 miss);
1306 }
1307
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001308 if (lookup->IsField()) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001309 // We found FIELD property in prototype chain of interceptor's holder.
1310 // Retrieve a field from field's holder.
1311 GenerateFastPropertyLoad(masm(), eax, holder_reg,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001312 Handle<JSObject>(lookup->holder()),
1313 lookup->GetFieldIndex());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001314 __ ret(0);
1315 } else {
1316 // We found CALLBACKS property in prototype chain of interceptor's
1317 // holder.
1318 ASSERT(lookup->type() == CALLBACKS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001319 Handle<AccessorInfo> callback(
1320 AccessorInfo::cast(lookup->GetCallbackObject()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001321 ASSERT(callback->getter() != NULL);
1322
1323 // Tail call to runtime.
1324 // Important invariant in CALLBACKS case: the code above must be
1325 // structured to never clobber |receiver| register.
1326 __ pop(scratch2); // return address
1327 __ push(receiver);
1328 __ push(holder_reg);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001329 __ mov(holder_reg, Immediate(callback));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001330 __ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset));
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001331 __ push(Immediate(reinterpret_cast<int>(isolate())));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001332 __ push(holder_reg);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001333 __ push(name_reg);
1334 __ push(scratch2); // restore return address
1335
1336 ExternalReference ref =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001337 ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
1338 masm()->isolate());
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001339 __ TailCallExternalReference(ref, 6, 1);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001340 }
1341 } else { // !compile_followup_inline
1342 // Call the runtime system to load the interceptor.
1343 // Check that the maps haven't changed.
1344 Register holder_reg =
1345 CheckPrototypes(object, receiver, interceptor_holder,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001346 scratch1, scratch2, scratch3, name, miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001347 __ pop(scratch2); // save old return address
1348 PushInterceptorArguments(masm(), receiver, holder_reg,
1349 name_reg, interceptor_holder);
1350 __ push(scratch2); // restore old return address
1351
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001352 ExternalReference ref =
1353 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001354 isolate());
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001355 __ TailCallExternalReference(ref, 6, 1);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001356 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001357}
1358
1359
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001360void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001361 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001362 __ cmp(ecx, Immediate(name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001363 __ j(not_equal, miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001364 }
1365}
1366
1367
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001368void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1369 Handle<JSObject> holder,
1370 Handle<String> name,
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001371 Label* miss) {
1372 ASSERT(holder->IsGlobalObject());
1373
1374 // Get the number of arguments.
1375 const int argc = arguments().immediate();
1376
1377 // Get the receiver from the stack.
1378 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1379
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001380
1381 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001382 __ JumpIfSmi(edx, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001383 CheckPrototypes(object, edx, holder, ebx, eax, edi, name, miss);
1384}
1385
1386
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001387void CallStubCompiler::GenerateLoadFunctionFromCell(
1388 Handle<JSGlobalPropertyCell> cell,
1389 Handle<JSFunction> function,
1390 Label* miss) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001391 // Get the value from the cell.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001392 if (Serializer::enabled()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001393 __ mov(edi, Immediate(cell));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001394 __ mov(edi, FieldOperand(edi, JSGlobalPropertyCell::kValueOffset));
1395 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001396 __ mov(edi, Operand::Cell(cell));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001397 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001398
1399 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001400 if (isolate()->heap()->InNewSpace(*function)) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001401 // We can't embed a pointer to a function in new space so we have
1402 // to verify that the shared function info is unchanged. This has
1403 // the nice side effect that multiple closures based on the same
1404 // function can all use this call IC. Before we load through the
1405 // function, we have to verify that it still is a function.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001406 __ JumpIfSmi(edi, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001407 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001408 __ j(not_equal, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001409
1410 // Check the shared function info. Make sure it hasn't changed.
1411 __ cmp(FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset),
1412 Immediate(Handle<SharedFunctionInfo>(function->shared())));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001413 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001414 __ cmp(edi, Immediate(function));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001415 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001416 __ j(not_equal, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001417}
1418
1419
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001420void CallStubCompiler::GenerateMissBranch() {
1421 Handle<Code> code =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001422 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
danno@chromium.org40cb8782011-05-25 07:58:50 +00001423 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001424 extra_state_);
1425 __ jmp(code, RelocInfo::CODE_TARGET);
1426}
1427
1428
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001429Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1430 Handle<JSObject> holder,
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00001431 PropertyIndex index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001432 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001433 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001434 // -- ecx : name
1435 // -- esp[0] : return address
1436 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1437 // -- ...
1438 // -- esp[(argc + 1) * 4] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001439 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001440 Label miss;
1441
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001442 GenerateNameCheck(name, &miss);
1443
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001444 // Get the receiver from the stack.
1445 const int argc = arguments().immediate();
1446 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1447
1448 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001449 __ JumpIfSmi(edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001450
1451 // Do the right check and compute the holder register.
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001452 Register reg = CheckPrototypes(object, edx, holder, ebx, eax, edi,
1453 name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001454
ager@chromium.org7c537e22008-10-16 08:43:32 +00001455 GenerateFastPropertyLoad(masm(), edi, reg, holder, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001456
1457 // Check that the function really is a function.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001458 __ JumpIfSmi(edi, &miss);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001459 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001460 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001461
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001462 // Patch the receiver on the stack with the global proxy if
1463 // necessary.
1464 if (object->IsGlobalObject()) {
1465 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
1466 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
1467 }
1468
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001469 // Invoke the function.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001470 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001471 ? CALL_AS_FUNCTION
1472 : CALL_AS_METHOD;
1473 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION,
1474 NullCallWrapper(), call_kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001475
1476 // Handle call cache miss.
1477 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001478 GenerateMissBranch();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001479
1480 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001481 return GetCode(Code::FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001482}
1483
1484
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001485Handle<Code> CallStubCompiler::CompileArrayPushCall(
1486 Handle<Object> object,
1487 Handle<JSObject> holder,
1488 Handle<JSGlobalPropertyCell> cell,
1489 Handle<JSFunction> function,
1490 Handle<String> name) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001491 // ----------- S t a t e -------------
1492 // -- ecx : name
1493 // -- esp[0] : return address
1494 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1495 // -- ...
1496 // -- esp[(argc + 1) * 4] : receiver
1497 // -----------------------------------
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001498
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001499 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001500 if (!object->IsJSArray() || !cell.is_null()) {
1501 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001502 }
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001503
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001504 Label miss;
1505
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001506 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001507
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001508 // Get the receiver from the stack.
1509 const int argc = arguments().immediate();
1510 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1511
1512 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001513 __ JumpIfSmi(edx, &miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001514
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001515 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
1516 name, &miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001517
1518 if (argc == 0) {
1519 // Noop, return the length.
1520 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
1521 __ ret((argc + 1) * kPointerSize);
1522 } else {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001523 Label call_builtin;
1524
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001525 if (argc == 1) { // Otherwise fall through to call builtin.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001526 Label attempt_to_grow_elements, with_write_barrier, check_double;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001527
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001528 // Get the elements array of the object.
1529 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset));
1530
1531 // Check that the elements are in fast mode and writable.
1532 __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
1533 Immediate(factory()->fixed_array_map()));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001534 __ j(not_equal, &check_double);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001535
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001536 // Get the array's length into eax and calculate new length.
1537 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
1538 STATIC_ASSERT(kSmiTagSize == 1);
1539 STATIC_ASSERT(kSmiTag == 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001540 __ add(eax, Immediate(Smi::FromInt(argc)));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001541
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001542 // Get the elements' length into ecx.
1543 __ mov(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001544
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001545 // Check if we could survive without allocation.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001546 __ cmp(eax, ecx);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001547 __ j(greater, &attempt_to_grow_elements);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001548
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001549 // Check if value is a smi.
1550 __ mov(ecx, Operand(esp, argc * kPointerSize));
1551 __ JumpIfNotSmi(ecx, &with_write_barrier);
1552
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001553 // Save new length.
1554 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1555
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001556 // Store the value.
1557 __ mov(FieldOperand(edi,
1558 eax,
1559 times_half_pointer_size,
1560 FixedArray::kHeaderSize - argc * kPointerSize),
1561 ecx);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001562
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001563 __ ret((argc + 1) * kPointerSize);
1564
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001565 __ bind(&check_double);
1566
1567
1568 // Check that the elements are in double mode.
1569 __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
1570 Immediate(factory()->fixed_double_array_map()));
1571 __ j(not_equal, &call_builtin);
1572
1573 // Get the array's length into eax and calculate new length.
1574 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
1575 STATIC_ASSERT(kSmiTagSize == 1);
1576 STATIC_ASSERT(kSmiTag == 0);
1577 __ add(eax, Immediate(Smi::FromInt(argc)));
1578
1579 // Get the elements' length into ecx.
1580 __ mov(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
1581
1582 // Check if we could survive without allocation.
1583 __ cmp(eax, ecx);
1584 __ j(greater, &call_builtin);
1585
1586 __ mov(ecx, Operand(esp, argc * kPointerSize));
1587 __ StoreNumberToDoubleElements(
1588 ecx, edi, eax, ecx, xmm0, &call_builtin, true, argc * kDoubleSize);
1589
1590 // Save new length.
1591 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1592 __ ret((argc + 1) * kPointerSize);
1593
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001594 __ bind(&with_write_barrier);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001595
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001596 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
1597
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001598 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001599 Label fast_object, not_fast_object;
1600 __ CheckFastObjectElements(ebx, &not_fast_object, Label::kNear);
1601 __ jmp(&fast_object);
1602 // In case of fast smi-only, convert to fast object, otherwise bail out.
1603 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001604 __ CheckFastSmiElements(ebx, &call_builtin);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001605 __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
1606 Immediate(factory()->heap_number_map()));
1607 __ j(equal, &call_builtin);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001608 // edi: elements array
1609 // edx: receiver
1610 // ebx: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001611 Label try_holey_map;
1612 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001613 FAST_ELEMENTS,
1614 ebx,
1615 edi,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001616 &try_holey_map);
1617
1618 ElementsTransitionGenerator::
1619 GenerateMapChangeElementsTransition(masm());
1620 // Restore edi.
1621 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset));
1622 __ jmp(&fast_object);
1623
1624 __ bind(&try_holey_map);
1625 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1626 FAST_HOLEY_ELEMENTS,
1627 ebx,
1628 edi,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001629 &call_builtin);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001630 ElementsTransitionGenerator::
1631 GenerateMapChangeElementsTransition(masm());
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001632 // Restore edi.
1633 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset));
1634 __ bind(&fast_object);
1635 } else {
1636 __ CheckFastObjectElements(ebx, &call_builtin);
1637 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001638
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001639 // Save new length.
1640 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1641
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001642 // Store the value.
1643 __ lea(edx, FieldOperand(edi,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001644 eax, times_half_pointer_size,
1645 FixedArray::kHeaderSize - argc * kPointerSize));
1646 __ mov(Operand(edx, 0), ecx);
1647
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001648 __ RecordWrite(edi, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001649 OMIT_SMI_CHECK);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001650
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001651 __ ret((argc + 1) * kPointerSize);
1652
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001653 __ bind(&attempt_to_grow_elements);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001654 if (!FLAG_inline_new) {
1655 __ jmp(&call_builtin);
1656 }
1657
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001658 __ mov(ebx, Operand(esp, argc * kPointerSize));
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001659 // Growing elements that are SMI-only requires special handling in case
1660 // the new element is non-Smi. For now, delegate to the builtin.
1661 Label no_fast_elements_check;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001662 __ JumpIfSmi(ebx, &no_fast_elements_check);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001663 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
1664 __ CheckFastObjectElements(ecx, &call_builtin, Label::kFar);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001665 __ bind(&no_fast_elements_check);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001666
1667 // We could be lucky and the elements array could be at the top of
1668 // new-space. In this case we can just grow it in place by moving the
1669 // allocation pointer up.
1670
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001671 ExternalReference new_space_allocation_top =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001672 ExternalReference::new_space_allocation_top_address(isolate());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001673 ExternalReference new_space_allocation_limit =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001674 ExternalReference::new_space_allocation_limit_address(isolate());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001675
1676 const int kAllocationDelta = 4;
1677 // Load top.
1678 __ mov(ecx, Operand::StaticVariable(new_space_allocation_top));
1679
1680 // Check if it's the end of elements.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001681 __ lea(edx, FieldOperand(edi,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001682 eax, times_half_pointer_size,
1683 FixedArray::kHeaderSize - argc * kPointerSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001684 __ cmp(edx, ecx);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001685 __ j(not_equal, &call_builtin);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001686 __ add(ecx, Immediate(kAllocationDelta * kPointerSize));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001687 __ cmp(ecx, Operand::StaticVariable(new_space_allocation_limit));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001688 __ j(above, &call_builtin);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001689
1690 // We fit and could grow elements.
1691 __ mov(Operand::StaticVariable(new_space_allocation_top), ecx);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001692
1693 // Push the argument...
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001694 __ mov(Operand(edx, 0), ebx);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001695 // ... and fill the rest with holes.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001696 for (int i = 1; i < kAllocationDelta; i++) {
1697 __ mov(Operand(edx, i * kPointerSize),
lrn@chromium.org7516f052011-03-30 08:52:27 +00001698 Immediate(factory()->the_hole_value()));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001699 }
1700
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001701 // We know the elements array is in new space so we don't need the
1702 // remembered set, but we just pushed a value onto it so we may have to
1703 // tell the incremental marker to rescan the object that we just grew. We
1704 // don't need to worry about the holes because they are in old space and
1705 // already marked black.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001706 __ RecordWrite(edi, edx, ebx, kDontSaveFPRegs, OMIT_REMEMBERED_SET);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001707
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001708 // Restore receiver to edx as finish sequence assumes it's here.
1709 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1710
1711 // Increment element's and array's sizes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001712 __ add(FieldOperand(edi, FixedArray::kLengthOffset),
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001713 Immediate(Smi::FromInt(kAllocationDelta)));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001714
1715 // NOTE: This only happen in new-space, where we don't
1716 // care about the black-byte-count on pages. Otherwise we should
1717 // update that too if the object is black.
1718
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001719 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1720
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001721 __ ret((argc + 1) * kPointerSize);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001722 }
1723
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001724 __ bind(&call_builtin);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001725 __ TailCallExternalReference(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001726 ExternalReference(Builtins::c_ArrayPush, isolate()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001727 argc + 1,
1728 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001729 }
1730
1731 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001732 GenerateMissBranch();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001733
1734 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001735 return GetCode(function);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001736}
1737
1738
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001739Handle<Code> CallStubCompiler::CompileArrayPopCall(
1740 Handle<Object> object,
1741 Handle<JSObject> holder,
1742 Handle<JSGlobalPropertyCell> cell,
1743 Handle<JSFunction> function,
1744 Handle<String> name) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001745 // ----------- S t a t e -------------
1746 // -- ecx : name
1747 // -- esp[0] : return address
1748 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1749 // -- ...
1750 // -- esp[(argc + 1) * 4] : receiver
1751 // -----------------------------------
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001752
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001753 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001754 if (!object->IsJSArray() || !cell.is_null()) {
1755 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001756 }
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001757
ager@chromium.orgac091b72010-05-05 07:34:42 +00001758 Label miss, return_undefined, call_builtin;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001759
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001760 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001761
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001762 // Get the receiver from the stack.
1763 const int argc = arguments().immediate();
1764 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1765
1766 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001767 __ JumpIfSmi(edx, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001768 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
1769 name, &miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001770
1771 // Get the elements array of the object.
1772 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset));
1773
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001774 // Check that the elements are in fast mode and writable.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001775 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
lrn@chromium.org7516f052011-03-30 08:52:27 +00001776 Immediate(factory()->fixed_array_map()));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001777 __ j(not_equal, &call_builtin);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001778
1779 // Get the array's length into ecx and calculate new length.
1780 __ mov(ecx, FieldOperand(edx, JSArray::kLengthOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001781 __ sub(ecx, Immediate(Smi::FromInt(1)));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001782 __ j(negative, &return_undefined);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001783
1784 // Get the last element.
1785 STATIC_ASSERT(kSmiTagSize == 1);
1786 STATIC_ASSERT(kSmiTag == 0);
1787 __ mov(eax, FieldOperand(ebx,
1788 ecx, times_half_pointer_size,
1789 FixedArray::kHeaderSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001790 __ cmp(eax, Immediate(factory()->the_hole_value()));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001791 __ j(equal, &call_builtin);
1792
1793 // Set the array's length.
1794 __ mov(FieldOperand(edx, JSArray::kLengthOffset), ecx);
1795
1796 // Fill with the hole.
1797 __ mov(FieldOperand(ebx,
1798 ecx, times_half_pointer_size,
1799 FixedArray::kHeaderSize),
lrn@chromium.org7516f052011-03-30 08:52:27 +00001800 Immediate(factory()->the_hole_value()));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001801 __ ret((argc + 1) * kPointerSize);
1802
ager@chromium.orgac091b72010-05-05 07:34:42 +00001803 __ bind(&return_undefined);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001804 __ mov(eax, Immediate(factory()->undefined_value()));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001805 __ ret((argc + 1) * kPointerSize);
1806
1807 __ bind(&call_builtin);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001808 __ TailCallExternalReference(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001809 ExternalReference(Builtins::c_ArrayPop, isolate()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001810 argc + 1,
1811 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001812
1813 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001814 GenerateMissBranch();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001815
1816 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001817 return GetCode(function);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001818}
1819
1820
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001821Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1822 Handle<Object> object,
1823 Handle<JSObject> holder,
1824 Handle<JSGlobalPropertyCell> cell,
1825 Handle<JSFunction> function,
1826 Handle<String> name) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001827 // ----------- S t a t e -------------
1828 // -- ecx : function name
1829 // -- esp[0] : return address
1830 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1831 // -- ...
1832 // -- esp[(argc + 1) * 4] : receiver
1833 // -----------------------------------
1834
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001835 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001836 if (!object->IsString() || !cell.is_null()) {
1837 return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001838 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001839
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001840 const int argc = arguments().immediate();
1841
1842 Label miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001843 Label name_miss;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001844 Label index_out_of_range;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001845 Label* index_out_of_range_label = &index_out_of_range;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001846
danno@chromium.org40cb8782011-05-25 07:58:50 +00001847 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001848 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001849 DEFAULT_STRING_STUB)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001850 index_out_of_range_label = &miss;
1851 }
1852
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001853 GenerateNameCheck(name, &name_miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001854
1855 // Check that the maps starting from the prototype haven't changed.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001856 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1857 Context::STRING_FUNCTION_INDEX,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001858 eax,
1859 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001860 ASSERT(!object.is_identical_to(holder));
1861 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1862 eax, holder, ebx, edx, edi, name, &miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001863
1864 Register receiver = ebx;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001865 Register index = edi;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001866 Register result = eax;
1867 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize));
1868 if (argc > 0) {
1869 __ mov(index, Operand(esp, (argc - 0) * kPointerSize));
1870 } else {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001871 __ Set(index, Immediate(factory()->undefined_value()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001872 }
1873
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001874 StringCharCodeAtGenerator generator(receiver,
1875 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001876 result,
1877 &miss, // When not a string.
1878 &miss, // When not a number.
1879 index_out_of_range_label,
1880 STRING_INDEX_IS_NUMBER);
1881 generator.GenerateFast(masm());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001882 __ ret((argc + 1) * kPointerSize);
1883
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001884 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001885 generator.GenerateSlow(masm(), call_helper);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001886
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001887 if (index_out_of_range.is_linked()) {
1888 __ bind(&index_out_of_range);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001889 __ Set(eax, Immediate(factory()->nan_value()));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001890 __ ret((argc + 1) * kPointerSize);
1891 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001892
1893 __ bind(&miss);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001894 // Restore function name in ecx.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001895 __ Set(ecx, Immediate(name));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001896 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001897 GenerateMissBranch();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001898
1899 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001900 return GetCode(function);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001901}
1902
1903
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001904Handle<Code> CallStubCompiler::CompileStringCharAtCall(
1905 Handle<Object> object,
1906 Handle<JSObject> holder,
1907 Handle<JSGlobalPropertyCell> cell,
1908 Handle<JSFunction> function,
1909 Handle<String> name) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001910 // ----------- S t a t e -------------
1911 // -- ecx : function name
1912 // -- esp[0] : return address
1913 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1914 // -- ...
1915 // -- esp[(argc + 1) * 4] : receiver
1916 // -----------------------------------
1917
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001918 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001919 if (!object->IsString() || !cell.is_null()) {
1920 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001921 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001922
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001923 const int argc = arguments().immediate();
1924
1925 Label miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001926 Label name_miss;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001927 Label index_out_of_range;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001928 Label* index_out_of_range_label = &index_out_of_range;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001929
danno@chromium.org40cb8782011-05-25 07:58:50 +00001930 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001931 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001932 DEFAULT_STRING_STUB)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001933 index_out_of_range_label = &miss;
1934 }
1935
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001936 GenerateNameCheck(name, &name_miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001937
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001938 // Check that the maps starting from the prototype haven't changed.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001939 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1940 Context::STRING_FUNCTION_INDEX,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001941 eax,
1942 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001943 ASSERT(!object.is_identical_to(holder));
1944 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1945 eax, holder, ebx, edx, edi, name, &miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001946
1947 Register receiver = eax;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001948 Register index = edi;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001949 Register scratch = edx;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001950 Register result = eax;
1951 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize));
1952 if (argc > 0) {
1953 __ mov(index, Operand(esp, (argc - 0) * kPointerSize));
1954 } else {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001955 __ Set(index, Immediate(factory()->undefined_value()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001956 }
1957
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001958 StringCharAtGenerator generator(receiver,
1959 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00001960 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001961 result,
1962 &miss, // When not a string.
1963 &miss, // When not a number.
1964 index_out_of_range_label,
1965 STRING_INDEX_IS_NUMBER);
1966 generator.GenerateFast(masm());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001967 __ ret((argc + 1) * kPointerSize);
1968
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001969 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001970 generator.GenerateSlow(masm(), call_helper);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001971
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001972 if (index_out_of_range.is_linked()) {
1973 __ bind(&index_out_of_range);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001974 __ Set(eax, Immediate(factory()->empty_string()));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001975 __ ret((argc + 1) * kPointerSize);
1976 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001977
1978 __ bind(&miss);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001979 // Restore function name in ecx.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001980 __ Set(ecx, Immediate(name));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001981 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001982 GenerateMissBranch();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001983
1984 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001985 return GetCode(function);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001986}
1987
1988
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001989Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
1990 Handle<Object> object,
1991 Handle<JSObject> holder,
1992 Handle<JSGlobalPropertyCell> cell,
1993 Handle<JSFunction> function,
1994 Handle<String> name) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001995 // ----------- S t a t e -------------
1996 // -- ecx : function name
1997 // -- esp[0] : return address
1998 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1999 // -- ...
2000 // -- esp[(argc + 1) * 4] : receiver
2001 // -----------------------------------
2002
2003 const int argc = arguments().immediate();
2004
2005 // If the object is not a JSObject or we got an unexpected number of
2006 // arguments, bail out to the regular call.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002007 if (!object->IsJSObject() || argc != 1) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002008 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002009 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002010
2011 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002012 GenerateNameCheck(name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002013
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002014 if (cell.is_null()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002015 __ mov(edx, Operand(esp, 2 * kPointerSize));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002016 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002017 __ JumpIfSmi(edx, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002018 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2019 name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002020 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002021 ASSERT(cell->value() == *function);
2022 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2023 &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002024 GenerateLoadFunctionFromCell(cell, function, &miss);
2025 }
2026
2027 // Load the char code argument.
2028 Register code = ebx;
2029 __ mov(code, Operand(esp, 1 * kPointerSize));
2030
2031 // Check the code is a smi.
2032 Label slow;
2033 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002034 __ JumpIfNotSmi(code, &slow);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002035
2036 // Convert the smi code to uint16.
2037 __ and_(code, Immediate(Smi::FromInt(0xffff)));
2038
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002039 StringCharFromCodeGenerator generator(code, eax);
2040 generator.GenerateFast(masm());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002041 __ ret(2 * kPointerSize);
2042
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002043 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002044 generator.GenerateSlow(masm(), call_helper);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002045
2046 // Tail call the full function. We do not have to patch the receiver
2047 // because the function makes no use of it.
2048 __ bind(&slow);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002049 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002050 ? CALL_AS_FUNCTION
2051 : CALL_AS_METHOD;
2052 __ InvokeFunction(function, arguments(), JUMP_FUNCTION,
2053 NullCallWrapper(), call_kind);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002054
2055 __ bind(&miss);
2056 // ecx: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002057 GenerateMissBranch();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002058
2059 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002060 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002061}
2062
2063
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002064Handle<Code> CallStubCompiler::CompileMathFloorCall(
2065 Handle<Object> object,
2066 Handle<JSObject> holder,
2067 Handle<JSGlobalPropertyCell> cell,
2068 Handle<JSFunction> function,
2069 Handle<String> name) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002070 // ----------- S t a t e -------------
2071 // -- ecx : name
2072 // -- esp[0] : return address
2073 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2074 // -- ...
2075 // -- esp[(argc + 1) * 4] : receiver
2076 // -----------------------------------
2077
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002078 if (!CpuFeatures::IsSupported(SSE2)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002079 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002080 }
2081
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002082 CpuFeatures::Scope use_sse2(SSE2);
2083
2084 const int argc = arguments().immediate();
2085
2086 // If the object is not a JSObject or we got an unexpected number of
2087 // arguments, bail out to the regular call.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002088 if (!object->IsJSObject() || argc != 1) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002089 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002090 }
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002091
2092 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002093 GenerateNameCheck(name, &miss);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002094
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002095 if (cell.is_null()) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002096 __ mov(edx, Operand(esp, 2 * kPointerSize));
2097
2098 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002099 __ JumpIfSmi(edx, &miss);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002100
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002101 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2102 name, &miss);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002103 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002104 ASSERT(cell->value() == *function);
2105 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2106 &miss);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002107 GenerateLoadFunctionFromCell(cell, function, &miss);
2108 }
2109
2110 // Load the (only) argument into eax.
2111 __ mov(eax, Operand(esp, 1 * kPointerSize));
2112
2113 // Check if the argument is a smi.
2114 Label smi;
2115 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002116 __ JumpIfSmi(eax, &smi);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002117
2118 // Check if the argument is a heap number and load its value into xmm0.
2119 Label slow;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002120 __ CheckMap(eax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002121 __ movdbl(xmm0, FieldOperand(eax, HeapNumber::kValueOffset));
2122
2123 // Check if the argument is strictly positive. Note this also
2124 // discards NaN.
2125 __ xorpd(xmm1, xmm1);
2126 __ ucomisd(xmm0, xmm1);
2127 __ j(below_equal, &slow);
2128
2129 // Do a truncating conversion.
2130 __ cvttsd2si(eax, Operand(xmm0));
2131
2132 // Check if the result fits into a smi. Note this also checks for
2133 // 0x80000000 which signals a failed conversion.
2134 Label wont_fit_into_smi;
2135 __ test(eax, Immediate(0xc0000000));
2136 __ j(not_zero, &wont_fit_into_smi);
2137
2138 // Smi tag and return.
2139 __ SmiTag(eax);
2140 __ bind(&smi);
2141 __ ret(2 * kPointerSize);
2142
2143 // Check if the argument is < 2^kMantissaBits.
2144 Label already_round;
2145 __ bind(&wont_fit_into_smi);
2146 __ LoadPowerOf2(xmm1, ebx, HeapNumber::kMantissaBits);
2147 __ ucomisd(xmm0, xmm1);
2148 __ j(above_equal, &already_round);
2149
2150 // Save a copy of the argument.
2151 __ movaps(xmm2, xmm0);
2152
2153 // Compute (argument + 2^kMantissaBits) - 2^kMantissaBits.
2154 __ addsd(xmm0, xmm1);
2155 __ subsd(xmm0, xmm1);
2156
2157 // Compare the argument and the tentative result to get the right mask:
2158 // if xmm2 < xmm0:
2159 // xmm2 = 1...1
2160 // else:
2161 // xmm2 = 0...0
2162 __ cmpltsd(xmm2, xmm0);
2163
2164 // Subtract 1 if the argument was less than the tentative result.
2165 __ LoadPowerOf2(xmm1, ebx, 0);
2166 __ andpd(xmm1, xmm2);
2167 __ subsd(xmm0, xmm1);
2168
2169 // Return a new heap number.
2170 __ AllocateHeapNumber(eax, ebx, edx, &slow);
2171 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
2172 __ ret(2 * kPointerSize);
2173
2174 // Return the argument (when it's an already round heap number).
2175 __ bind(&already_round);
2176 __ mov(eax, Operand(esp, 1 * kPointerSize));
2177 __ ret(2 * kPointerSize);
2178
2179 // Tail call the full function. We do not have to patch the receiver
2180 // because the function makes no use of it.
2181 __ bind(&slow);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002182 __ InvokeFunction(function, arguments(), JUMP_FUNCTION,
2183 NullCallWrapper(), CALL_AS_METHOD);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002184
2185 __ bind(&miss);
2186 // ecx: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002187 GenerateMissBranch();
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002188
2189 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002190 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002191}
2192
2193
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002194Handle<Code> CallStubCompiler::CompileMathAbsCall(
2195 Handle<Object> object,
2196 Handle<JSObject> holder,
2197 Handle<JSGlobalPropertyCell> cell,
2198 Handle<JSFunction> function,
2199 Handle<String> name) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002200 // ----------- S t a t e -------------
2201 // -- ecx : name
2202 // -- esp[0] : return address
2203 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2204 // -- ...
2205 // -- esp[(argc + 1) * 4] : receiver
2206 // -----------------------------------
2207
2208 const int argc = arguments().immediate();
2209
2210 // If the object is not a JSObject or we got an unexpected number of
2211 // arguments, bail out to the regular call.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002212 if (!object->IsJSObject() || argc != 1) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002213 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002214 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002215
2216 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002217 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002218
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002219 if (cell.is_null()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002220 __ mov(edx, Operand(esp, 2 * kPointerSize));
2221
2222 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002223 __ JumpIfSmi(edx, &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002224
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002225 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2226 name, &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002227 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002228 ASSERT(cell->value() == *function);
2229 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2230 &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002231 GenerateLoadFunctionFromCell(cell, function, &miss);
2232 }
2233
2234 // Load the (only) argument into eax.
2235 __ mov(eax, Operand(esp, 1 * kPointerSize));
2236
2237 // Check if the argument is a smi.
2238 Label not_smi;
2239 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002240 __ JumpIfNotSmi(eax, &not_smi);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002241
2242 // Set ebx to 1...1 (== -1) if the argument is negative, or to 0...0
2243 // otherwise.
2244 __ mov(ebx, eax);
2245 __ sar(ebx, kBitsPerInt - 1);
2246
2247 // Do bitwise not or do nothing depending on ebx.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002248 __ xor_(eax, ebx);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002249
2250 // Add 1 or do nothing depending on ebx.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002251 __ sub(eax, ebx);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002252
2253 // If the result is still negative, go to the slow case.
2254 // This only happens for the most negative smi.
2255 Label slow;
2256 __ j(negative, &slow);
2257
2258 // Smi case done.
2259 __ ret(2 * kPointerSize);
2260
2261 // Check if the argument is a heap number and load its exponent and
2262 // sign into ebx.
2263 __ bind(&not_smi);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002264 __ CheckMap(eax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002265 __ mov(ebx, FieldOperand(eax, HeapNumber::kExponentOffset));
2266
2267 // Check the sign of the argument. If the argument is positive,
2268 // just return it.
2269 Label negative_sign;
2270 __ test(ebx, Immediate(HeapNumber::kSignMask));
2271 __ j(not_zero, &negative_sign);
2272 __ ret(2 * kPointerSize);
2273
2274 // If the argument is negative, clear the sign, and return a new
2275 // number.
2276 __ bind(&negative_sign);
2277 __ and_(ebx, ~HeapNumber::kSignMask);
2278 __ mov(ecx, FieldOperand(eax, HeapNumber::kMantissaOffset));
2279 __ AllocateHeapNumber(eax, edi, edx, &slow);
2280 __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), ebx);
2281 __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx);
2282 __ ret(2 * kPointerSize);
2283
2284 // Tail call the full function. We do not have to patch the receiver
2285 // because the function makes no use of it.
2286 __ bind(&slow);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002287 __ InvokeFunction(function, arguments(), JUMP_FUNCTION,
2288 NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002289
2290 __ bind(&miss);
2291 // ecx: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002292 GenerateMissBranch();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002293
2294 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002295 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002296}
2297
2298
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002299Handle<Code> CallStubCompiler::CompileFastApiCall(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002300 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002301 Handle<Object> object,
2302 Handle<JSObject> holder,
2303 Handle<JSGlobalPropertyCell> cell,
2304 Handle<JSFunction> function,
2305 Handle<String> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002306 ASSERT(optimization.is_simple_api_call());
2307 // Bail out if object is a global object as we don't want to
2308 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002309 if (object->IsGlobalObject()) return Handle<Code>::null();
2310 if (!cell.is_null()) return Handle<Code>::null();
2311 if (!object->IsJSObject()) return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002312 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002313 Handle<JSObject>::cast(object), holder);
2314 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002315
2316 Label miss, miss_before_stack_reserved;
2317
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002318 GenerateNameCheck(name, &miss_before_stack_reserved);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002319
2320 // Get the receiver from the stack.
2321 const int argc = arguments().immediate();
2322 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
2323
2324 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002325 __ JumpIfSmi(edx, &miss_before_stack_reserved);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002326
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002327 Counters* counters = isolate()->counters();
2328 __ IncrementCounter(counters->call_const(), 1);
2329 __ IncrementCounter(counters->call_const_fast_api(), 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002330
2331 // Allocate space for v8::Arguments implicit values. Must be initialized
2332 // before calling any runtime function.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002333 __ sub(esp, Immediate(kFastApiCallArguments * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002334
2335 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002336 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2337 name, depth, &miss);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002338
2339 // Move the return address on top of the stack.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00002340 __ mov(eax, Operand(esp, 4 * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002341 __ mov(Operand(esp, 0 * kPointerSize), eax);
2342
2343 // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains
2344 // duplicate of return address and will be overwritten.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002345 GenerateFastApiCall(masm(), optimization, argc);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002346
2347 __ bind(&miss);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002348 __ add(esp, Immediate(kFastApiCallArguments * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002349
2350 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002351 GenerateMissBranch();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002352
2353 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002354 return GetCode(function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002355}
2356
2357
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002358Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object,
2359 Handle<JSObject> holder,
2360 Handle<JSFunction> function,
2361 Handle<String> name,
2362 CheckType check) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002363 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00002364 // -- ecx : name
2365 // -- esp[0] : return address
2366 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2367 // -- ...
2368 // -- esp[(argc + 1) * 4] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002369 // -----------------------------------
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002370
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002371 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002372 Handle<Code> code = CompileCustomCall(object, holder,
2373 Handle<JSGlobalPropertyCell>::null(),
2374 function, name);
2375 // A null handle means bail out to the regular compiler code below.
2376 if (!code.is_null()) return code;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002377 }
2378
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002379 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002380 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002381
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002382 // Get the receiver from the stack.
2383 const int argc = arguments().immediate();
2384 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
2385
2386 // Check that the receiver isn't a smi.
2387 if (check != NUMBER_CHECK) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00002388 __ JumpIfSmi(edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002389 }
2390
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002391 // Make sure that it's okay not to patch the on stack receiver
2392 // unless we're doing a receiver map check.
2393 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002394 switch (check) {
2395 case RECEIVER_MAP_CHECK:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002396 __ IncrementCounter(isolate()->counters()->call_const(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00002397
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002398 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002399 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax,
2400 edi, name, &miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002401
2402 // Patch the receiver on the stack with the global proxy if
2403 // necessary.
2404 if (object->IsGlobalObject()) {
2405 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
2406 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
2407 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002408 break;
2409
2410 case STRING_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002411 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002412 // Check that the object is a string or a symbol.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002413 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, eax);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002414 __ j(above_equal, &miss);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002415 // Check that the maps starting from the prototype haven't changed.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002416 GenerateDirectLoadGlobalFunctionPrototype(
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002417 masm(), Context::STRING_FUNCTION_INDEX, eax, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002418 CheckPrototypes(
2419 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2420 eax, holder, ebx, edx, edi, name, &miss);
2421 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002422 // Calling non-strict non-builtins with a value as the receiver
2423 // requires boxing.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002424 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002425 }
2426 break;
2427
2428 case NUMBER_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002429 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002430 Label fast;
2431 // Check that the object is a smi or a heap number.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002432 __ JumpIfSmi(edx, &fast);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002433 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, eax);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002434 __ j(not_equal, &miss);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002435 __ bind(&fast);
2436 // Check that the maps starting from the prototype haven't changed.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002437 GenerateDirectLoadGlobalFunctionPrototype(
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002438 masm(), Context::NUMBER_FUNCTION_INDEX, eax, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002439 CheckPrototypes(
2440 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2441 eax, holder, ebx, edx, edi, name, &miss);
2442 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002443 // Calling non-strict non-builtins with a value as the receiver
2444 // requires boxing.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002445 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002446 }
2447 break;
2448
2449 case BOOLEAN_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002450 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002451 Label fast;
2452 // Check that the object is a boolean.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002453 __ cmp(edx, factory()->true_value());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002454 __ j(equal, &fast);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002455 __ cmp(edx, factory()->false_value());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002456 __ j(not_equal, &miss);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002457 __ bind(&fast);
2458 // Check that the maps starting from the prototype haven't changed.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002459 GenerateDirectLoadGlobalFunctionPrototype(
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002460 masm(), Context::BOOLEAN_FUNCTION_INDEX, eax, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002461 CheckPrototypes(
2462 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2463 eax, holder, ebx, edx, edi, name, &miss);
2464 } else {
2465 // Calling non-strict non-builtins with a value as the receiver
2466 // requires boxing.
2467 __ jmp(&miss);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002468 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002469 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002470 }
2471
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002472 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002473 ? CALL_AS_FUNCTION
2474 : CALL_AS_METHOD;
2475 __ InvokeFunction(function, arguments(), JUMP_FUNCTION,
2476 NullCallWrapper(), call_kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002477
2478 // Handle call cache miss.
2479 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002480 GenerateMissBranch();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002481
2482 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002483 return GetCode(function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002484}
2485
2486
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002487Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2488 Handle<JSObject> holder,
2489 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002490 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00002491 // -- ecx : name
2492 // -- esp[0] : return address
2493 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2494 // -- ...
2495 // -- esp[(argc + 1) * 4] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002496 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002497 Label miss;
2498
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002499 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002500
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002501 // Get the number of arguments.
2502 const int argc = arguments().immediate();
2503
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002504 LookupResult lookup(isolate());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002505 LookupPostInterceptor(holder, name, &lookup);
2506
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002507 // Get the receiver from the stack.
2508 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002509
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002510 CallInterceptorCompiler compiler(this, arguments(), ecx, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002511 compiler.Compile(masm(), object, holder, name, &lookup, edx, ebx, edi, eax,
2512 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002513
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002514 // Restore receiver.
2515 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002516
2517 // Check that the function really is a function.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002518 __ JumpIfSmi(eax, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002519 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002520 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002521
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002522 // Patch the receiver on the stack with the global proxy if
2523 // necessary.
2524 if (object->IsGlobalObject()) {
2525 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
2526 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
2527 }
2528
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002529 // Invoke the function.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002530 __ mov(edi, eax);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002531 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002532 ? CALL_AS_FUNCTION
2533 : CALL_AS_METHOD;
2534 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION,
2535 NullCallWrapper(), call_kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002536
2537 // Handle load cache miss.
2538 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002539 GenerateMissBranch();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002540
2541 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002542 return GetCode(Code::INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002543}
2544
2545
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002546Handle<Code> CallStubCompiler::CompileCallGlobal(
2547 Handle<JSObject> object,
2548 Handle<GlobalObject> holder,
2549 Handle<JSGlobalPropertyCell> cell,
2550 Handle<JSFunction> function,
2551 Handle<String> name) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002552 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00002553 // -- ecx : name
2554 // -- esp[0] : return address
2555 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2556 // -- ...
2557 // -- esp[(argc + 1) * 4] : receiver
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002558 // -----------------------------------
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002559
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002560 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002561 Handle<Code> code = CompileCustomCall(object, holder, cell, function, name);
2562 // A null handle means bail out to the regular compiler code below.
2563 if (!code.is_null()) return code;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002564 }
2565
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002566 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002567 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002568
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002569 // Get the number of arguments.
2570 const int argc = arguments().immediate();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002571 GenerateGlobalReceiverCheck(object, holder, name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002572 GenerateLoadFunctionFromCell(cell, function, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002573
2574 // Patch the receiver on the stack with the global proxy.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002575 if (object->IsGlobalObject()) {
2576 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
2577 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
2578 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002579
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002580 // Set up the context (function already in edi).
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002581 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
2582
2583 // Jump to the cached code (tail call).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002584 Counters* counters = isolate()->counters();
2585 __ IncrementCounter(counters->call_global_inline(), 1);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002586 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002587 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002588 ? CALL_AS_FUNCTION
2589 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002590 // We call indirectly through the code field in the function to
2591 // allow recompilation to take effect without changing any of the
2592 // call sites.
2593 __ InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset),
2594 expected, arguments(), JUMP_FUNCTION,
2595 NullCallWrapper(), call_kind);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002596
2597 // Handle call cache miss.
2598 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002599 __ IncrementCounter(counters->call_global_inline_miss(), 1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002600 GenerateMissBranch();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002601
2602 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002603 return GetCode(Code::NORMAL, name);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002604}
2605
2606
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002607Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002608 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002609 Handle<Map> transition,
2610 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002611 // ----------- S t a t e -------------
2612 // -- eax : value
2613 // -- ecx : name
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002614 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002615 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002616 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002617 Label miss;
2618
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002619 // Generate store field code. Trashes the name register.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002620 GenerateStoreField(masm(),
2621 object,
2622 index,
2623 transition,
2624 name,
2625 edx, ecx, ebx, edi,
2626 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002627 // Handle store cache miss.
2628 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002629 __ mov(ecx, Immediate(name)); // restore name
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002630 Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
ager@chromium.org236ad962008-09-25 09:45:57 +00002631 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002632
2633 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002634 return GetCode(transition.is_null()
2635 ? Code::FIELD
2636 : Code::MAP_TRANSITION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002637}
2638
2639
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002640Handle<Code> StoreStubCompiler::CompileStoreCallback(
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002641 Handle<String> name,
2642 Handle<JSObject> receiver,
2643 Handle<JSObject> holder,
2644 Handle<AccessorInfo> callback) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002645 // ----------- S t a t e -------------
2646 // -- eax : value
2647 // -- ecx : name
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002648 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002649 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002650 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002651 Label miss;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002652 // Check that the maps haven't changed, preserving the value register.
2653 __ push(eax);
2654 __ JumpIfSmi(edx, &miss);
2655 CheckPrototypes(receiver, edx, holder, ebx, eax, edi, name, &miss);
2656 __ pop(eax); // restore value
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002657
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002658 // Stub never generated for non-global objects that require access checks.
2659 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002660
2661 __ pop(ebx); // remove the return address
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002662 __ push(edx); // receiver
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002663 __ push(Immediate(callback)); // callback info
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002664 __ push(ecx); // name
2665 __ push(eax); // value
2666 __ push(ebx); // restore return address
2667
mads.s.ager31e71382008-08-13 09:32:07 +00002668 // Do tail-call to the runtime system.
2669 ExternalReference store_callback_property =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002670 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002671 __ TailCallExternalReference(store_callback_property, 4, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002672
2673 // Handle store cache miss.
2674 __ bind(&miss);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002675 __ pop(eax);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002676 Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
ager@chromium.org236ad962008-09-25 09:45:57 +00002677 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002678
2679 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002680 return GetCode(Code::CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002681}
2682
2683
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002684#undef __
2685#define __ ACCESS_MASM(masm)
2686
2687
2688void StoreStubCompiler::GenerateStoreViaSetter(
2689 MacroAssembler* masm,
2690 Handle<JSFunction> setter) {
2691 // ----------- S t a t e -------------
2692 // -- eax : value
2693 // -- ecx : name
2694 // -- edx : receiver
2695 // -- esp[0] : return address
2696 // -----------------------------------
2697 {
2698 FrameScope scope(masm, StackFrame::INTERNAL);
2699
2700 // Save value register, so we can restore it later.
2701 __ push(eax);
2702
2703 if (!setter.is_null()) {
2704 // Call the JavaScript setter with receiver and value on the stack.
2705 __ push(edx);
2706 __ push(eax);
2707 ParameterCount actual(1);
2708 __ InvokeFunction(setter, actual, CALL_FUNCTION, NullCallWrapper(),
2709 CALL_AS_METHOD);
2710 } else {
2711 // If we generate a global code snippet for deoptimization only, remember
2712 // the place to continue after deoptimization.
2713 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2714 }
2715
2716 // We have to return the passed value, not the return value of the setter.
2717 __ pop(eax);
2718
2719 // Restore context register.
2720 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
2721 }
2722 __ ret(0);
2723}
2724
2725
2726#undef __
2727#define __ ACCESS_MASM(masm())
2728
2729
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002730Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002731 Handle<String> name,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002732 Handle<JSObject> receiver,
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002733 Handle<JSObject> holder,
2734 Handle<JSFunction> setter) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002735 // ----------- S t a t e -------------
2736 // -- eax : value
2737 // -- ecx : name
2738 // -- edx : receiver
2739 // -- esp[0] : return address
2740 // -----------------------------------
2741 Label miss;
2742
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002743 // Check that the maps haven't changed, preserving the name register.
2744 __ push(ecx);
2745 __ JumpIfSmi(edx, &miss);
2746 CheckPrototypes(receiver, edx, holder, ebx, ecx, edi, name, &miss);
2747 __ pop(ecx);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002748
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002749 GenerateStoreViaSetter(masm(), setter);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002750
2751 __ bind(&miss);
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002752 __ pop(ecx);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002753 Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
2754 __ jmp(ic, RelocInfo::CODE_TARGET);
2755
2756 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002757 return GetCode(Code::CALLBACKS, name);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002758}
2759
2760
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002761Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
2762 Handle<JSObject> receiver,
2763 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002764 // ----------- S t a t e -------------
2765 // -- eax : value
2766 // -- ecx : name
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002767 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002768 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002769 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002770 Label miss;
2771
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002772 // Check that the map of the object hasn't changed.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002773 __ CheckMap(edx, Handle<Map>(receiver->map()),
2774 &miss, DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002775
2776 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002777 if (receiver->IsJSGlobalProxy()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002778 __ CheckAccessGlobalProxy(edx, ebx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002779 }
2780
2781 // Stub never generated for non-global objects that require access
2782 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002783 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002784
2785 __ pop(ebx); // remove the return address
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002786 __ push(edx); // receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002787 __ push(ecx); // name
2788 __ push(eax); // value
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002789 __ push(Immediate(Smi::FromInt(strict_mode_)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002790 __ push(ebx); // restore return address
2791
mads.s.ager31e71382008-08-13 09:32:07 +00002792 // Do tail-call to the runtime system.
2793 ExternalReference store_ic_property =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002794 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002795 __ TailCallExternalReference(store_ic_property, 4, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002796
2797 // Handle store cache miss.
2798 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002799 Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
ager@chromium.org236ad962008-09-25 09:45:57 +00002800 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002801
2802 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002803 return GetCode(Code::INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002804}
2805
2806
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002807Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2808 Handle<GlobalObject> object,
2809 Handle<JSGlobalPropertyCell> cell,
2810 Handle<String> name) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002811 // ----------- S t a t e -------------
2812 // -- eax : value
2813 // -- ecx : name
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002814 // -- edx : receiver
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002815 // -- esp[0] : return address
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002816 // -----------------------------------
2817 Label miss;
2818
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002819 // Check that the map of the global has not changed.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002820 __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002821 Immediate(Handle<Map>(object->map())));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002822 __ j(not_equal, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002823
ager@chromium.org378b34e2011-01-28 08:04:38 +00002824 // Compute the cell operand to use.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002825 __ mov(ebx, Immediate(cell));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002826 Operand cell_operand = FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002827
ager@chromium.org378b34e2011-01-28 08:04:38 +00002828 // Check that the value in the cell is not the hole. If it is, this
2829 // cell could have been deleted and reintroducing the global needs
2830 // to update the property details in the property dictionary of the
2831 // global object. We bail out to the runtime system to do that.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002832 __ cmp(cell_operand, factory()->the_hole_value());
ager@chromium.org378b34e2011-01-28 08:04:38 +00002833 __ j(equal, &miss);
2834
2835 // Store the value in the cell.
2836 __ mov(cell_operand, eax);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002837 // No write barrier here, because cells are always rescanned.
ager@chromium.org378b34e2011-01-28 08:04:38 +00002838
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002839 // Return the value (register eax).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002840 Counters* counters = isolate()->counters();
2841 __ IncrementCounter(counters->named_store_global_inline(), 1);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002842 __ ret(0);
2843
2844 // Handle store cache miss.
2845 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002846 __ IncrementCounter(counters->named_store_global_inline_miss(), 1);
2847 Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002848 __ jmp(ic, RelocInfo::CODE_TARGET);
2849
2850 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002851 return GetCode(Code::NORMAL, name);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002852}
2853
2854
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002855Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002856 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002857 Handle<Map> transition,
2858 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002859 // ----------- S t a t e -------------
2860 // -- eax : value
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002861 // -- ecx : key
2862 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002863 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002864 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002865 Label miss;
2866
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002867 Counters* counters = isolate()->counters();
2868 __ IncrementCounter(counters->keyed_store_field(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002869
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002870 // Check that the name has not changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002871 __ cmp(ecx, Immediate(name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002872 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002873
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002874 // Generate store field code. Trashes the name register.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002875 GenerateStoreField(masm(),
2876 object,
2877 index,
2878 transition,
2879 name,
2880 edx, ecx, ebx, edi,
2881 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002882
2883 // Handle store cache miss.
2884 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002885 __ DecrementCounter(counters->keyed_store_field(), 1);
2886 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
ager@chromium.org236ad962008-09-25 09:45:57 +00002887 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002888
2889 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002890 return GetCode(transition.is_null()
2891 ? Code::FIELD
2892 : Code::MAP_TRANSITION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002893}
2894
2895
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002896Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
2897 Handle<Map> receiver_map) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002898 // ----------- S t a t e -------------
2899 // -- eax : value
2900 // -- ecx : key
2901 // -- edx : receiver
2902 // -- esp[0] : return address
2903 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002904 ElementsKind elements_kind = receiver_map->elements_kind();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002905 bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002906 Handle<Code> stub =
ulan@chromium.org65a89c22012-02-14 11:46:07 +00002907 KeyedStoreElementStub(is_jsarray, elements_kind, grow_mode_).GetCode();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002908
2909 __ DispatchMap(edx, receiver_map, stub, DO_SMI_CHECK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002910
2911 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
2912 __ jmp(ic, RelocInfo::CODE_TARGET);
2913
2914 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002915 return GetCode(Code::NORMAL, factory()->empty_string());
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002916}
2917
2918
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002919Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
2920 MapHandleList* receiver_maps,
2921 CodeHandleList* handler_stubs,
2922 MapHandleList* transitioned_maps) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002923 // ----------- S t a t e -------------
2924 // -- eax : value
2925 // -- ecx : key
2926 // -- edx : receiver
2927 // -- esp[0] : return address
2928 // -----------------------------------
2929 Label miss;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002930 __ JumpIfSmi(edx, &miss, Label::kNear);
2931 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
2932 // ebx: receiver->map().
2933 for (int i = 0; i < receiver_maps->length(); ++i) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002934 __ cmp(edi, receiver_maps->at(i));
2935 if (transitioned_maps->at(i).is_null()) {
2936 __ j(equal, handler_stubs->at(i));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002937 } else {
2938 Label next_map;
2939 __ j(not_equal, &next_map, Label::kNear);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002940 __ mov(ebx, Immediate(transitioned_maps->at(i)));
2941 __ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002942 __ bind(&next_map);
2943 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002944 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002945 __ bind(&miss);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002946 Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
2947 __ jmp(miss_ic, RelocInfo::CODE_TARGET);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002948
2949 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002950 return GetCode(Code::NORMAL, factory()->empty_string(), MEGAMORPHIC);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002951}
2952
2953
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002954Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
2955 Handle<JSObject> object,
2956 Handle<JSObject> last) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002957 // ----------- S t a t e -------------
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002958 // -- ecx : name
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002959 // -- edx : receiver
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002960 // -- esp[0] : return address
2961 // -----------------------------------
2962 Label miss;
2963
2964 // Check that the receiver isn't a smi.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002965 __ JumpIfSmi(edx, &miss);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002966
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00002967 ASSERT(last->IsGlobalObject() || last->HasFastProperties());
2968
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002969 // Check the maps of the full prototype chain. Also check that
2970 // global property cells up to (but not including) the last object
2971 // in the prototype chain are empty.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002972 CheckPrototypes(object, edx, last, ebx, eax, edi, name, &miss);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002973
2974 // If the last object in the prototype chain is a global object,
2975 // check that the global property cell is empty.
2976 if (last->IsGlobalObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002977 GenerateCheckPropertyCell(
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002978 masm(), Handle<GlobalObject>::cast(last), name, eax, &miss);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002979 }
2980
2981 // Return undefined if maps of the full prototype chain are still the
2982 // same and no global property with this name contains a value.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002983 __ mov(eax, isolate()->factory()->undefined_value());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002984 __ ret(0);
2985
2986 __ bind(&miss);
2987 GenerateLoadMiss(masm(), Code::LOAD_IC);
2988
2989 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002990 return GetCode(Code::NONEXISTENT, factory()->empty_string());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002991}
2992
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002993
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002994Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object,
2995 Handle<JSObject> holder,
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002996 PropertyIndex index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002997 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002998 // ----------- S t a t e -------------
2999 // -- ecx : name
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003000 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003001 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003002 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003003 Label miss;
3004
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003005 GenerateLoadField(object, holder, edx, ebx, eax, edi, index, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003006 __ bind(&miss);
3007 GenerateLoadMiss(masm(), Code::LOAD_IC);
3008
3009 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003010 return GetCode(Code::FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003011}
3012
3013
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003014Handle<Code> LoadStubCompiler::CompileLoadCallback(
3015 Handle<String> name,
3016 Handle<JSObject> object,
3017 Handle<JSObject> holder,
3018 Handle<AccessorInfo> callback) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003019 // ----------- S t a t e -------------
3020 // -- ecx : name
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003021 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003022 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003023 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003024 Label miss;
3025
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00003026 GenerateLoadCallback(object, holder, edx, ecx, ebx, eax, edi, no_reg,
3027 callback, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003028 __ bind(&miss);
3029 GenerateLoadMiss(masm(), Code::LOAD_IC);
3030
3031 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003032 return GetCode(Code::CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003033}
3034
3035
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003036#undef __
3037#define __ ACCESS_MASM(masm)
3038
3039
3040void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
3041 Handle<JSFunction> getter) {
3042 // ----------- S t a t e -------------
3043 // -- ecx : name
3044 // -- edx : receiver
3045 // -- esp[0] : return address
3046 // -----------------------------------
3047 {
3048 FrameScope scope(masm, StackFrame::INTERNAL);
3049
3050 if (!getter.is_null()) {
3051 // Call the JavaScript getter with the receiver on the stack.
3052 __ push(edx);
3053 ParameterCount actual(0);
3054 __ InvokeFunction(getter, actual, CALL_FUNCTION, NullCallWrapper(),
3055 CALL_AS_METHOD);
3056 } else {
3057 // If we generate a global code snippet for deoptimization only, remember
3058 // the place to continue after deoptimization.
3059 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
3060 }
3061
3062 // Restore context register.
3063 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
3064 }
3065 __ ret(0);
3066}
3067
3068
3069#undef __
3070#define __ ACCESS_MASM(masm())
3071
3072
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003073Handle<Code> LoadStubCompiler::CompileLoadViaGetter(
3074 Handle<String> name,
3075 Handle<JSObject> receiver,
3076 Handle<JSObject> holder,
3077 Handle<JSFunction> getter) {
3078 // ----------- S t a t e -------------
3079 // -- ecx : name
3080 // -- edx : receiver
3081 // -- esp[0] : return address
3082 // -----------------------------------
3083 Label miss;
3084
3085 // Check that the maps haven't changed.
3086 __ JumpIfSmi(edx, &miss);
3087 CheckPrototypes(receiver, edx, holder, ebx, eax, edi, name, &miss);
3088
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003089 GenerateLoadViaGetter(masm(), getter);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003090
3091 __ bind(&miss);
3092 GenerateLoadMiss(masm(), Code::LOAD_IC);
3093
3094 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003095 return GetCode(Code::CALLBACKS, name);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003096}
3097
3098
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003099Handle<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object,
3100 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003101 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003102 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003103 // ----------- S t a t e -------------
3104 // -- ecx : name
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003105 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003106 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003107 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003108 Label miss;
3109
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003110 GenerateLoadConstant(object, holder, edx, ebx, eax, edi, value, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003111 __ bind(&miss);
3112 GenerateLoadMiss(masm(), Code::LOAD_IC);
3113
3114 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003115 return GetCode(Code::CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003116}
3117
3118
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003119Handle<Code> LoadStubCompiler::CompileLoadInterceptor(Handle<JSObject> receiver,
3120 Handle<JSObject> holder,
3121 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003122 // ----------- S t a t e -------------
3123 // -- ecx : name
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003124 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003125 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003126 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003127 Label miss;
3128
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003129 LookupResult lookup(isolate());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003130 LookupPostInterceptor(holder, name, &lookup);
3131
ager@chromium.orge2902be2009-06-08 12:21:35 +00003132 // TODO(368): Compile in the whole chain: all the interceptors in
3133 // prototypes and ultimate answer.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003134 GenerateLoadInterceptor(receiver, holder, &lookup, edx, ecx, eax, ebx, edi,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003135 name, &miss);
ager@chromium.orge2902be2009-06-08 12:21:35 +00003136
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003137 __ bind(&miss);
3138 GenerateLoadMiss(masm(), Code::LOAD_IC);
3139
3140 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003141 return GetCode(Code::INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003142}
3143
3144
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003145Handle<Code> LoadStubCompiler::CompileLoadGlobal(
3146 Handle<JSObject> object,
3147 Handle<GlobalObject> holder,
3148 Handle<JSGlobalPropertyCell> cell,
3149 Handle<String> name,
3150 bool is_dont_delete) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003151 // ----------- S t a t e -------------
3152 // -- ecx : name
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003153 // -- edx : receiver
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003154 // -- esp[0] : return address
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003155 // -----------------------------------
3156 Label miss;
3157
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003158 // Check that the maps haven't changed.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003159 __ JumpIfSmi(edx, &miss);
3160 CheckPrototypes(object, edx, holder, ebx, eax, edi, name, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003161
3162 // Get the value from the cell.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003163 if (Serializer::enabled()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003164 __ mov(ebx, Immediate(cell));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003165 __ mov(ebx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset));
3166 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003167 __ mov(ebx, Operand::Cell(cell));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003168 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003169
3170 // Check for deleted property if property can actually be deleted.
3171 if (!is_dont_delete) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00003172 __ cmp(ebx, factory()->the_hole_value());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003173 __ j(equal, &miss);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003174 } else if (FLAG_debug_code) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00003175 __ cmp(ebx, factory()->the_hole_value());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003176 __ Check(not_equal, "DontDelete cells can't contain the hole");
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003177 }
3178
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003179 Counters* counters = isolate()->counters();
3180 __ IncrementCounter(counters->named_load_global_stub(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00003181 __ mov(eax, ebx);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003182 __ ret(0);
3183
3184 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003185 __ IncrementCounter(counters->named_load_global_stub_miss(), 1);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003186 GenerateLoadMiss(masm(), Code::LOAD_IC);
3187
3188 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003189 return GetCode(Code::NORMAL, name);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003190}
3191
3192
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003193Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
3194 Handle<JSObject> receiver,
3195 Handle<JSObject> holder,
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00003196 PropertyIndex index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003197 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003198 // -- ecx : key
ager@chromium.org5c838252010-02-19 08:53:10 +00003199 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003200 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003201 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003202 Label miss;
3203
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003204 Counters* counters = isolate()->counters();
3205 __ IncrementCounter(counters->keyed_load_field(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003206
3207 // Check that the name has not changed.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003208 __ cmp(ecx, Immediate(name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003209 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003210
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003211 GenerateLoadField(receiver, holder, edx, ebx, eax, edi, index, name, &miss);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003212
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003213 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003214 __ DecrementCounter(counters->keyed_load_field(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003215 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3216
3217 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003218 return GetCode(Code::FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003219}
3220
3221
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003222Handle<Code> KeyedLoadStubCompiler::CompileLoadCallback(
3223 Handle<String> name,
3224 Handle<JSObject> receiver,
3225 Handle<JSObject> holder,
3226 Handle<AccessorInfo> callback) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003227 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003228 // -- ecx : key
ager@chromium.org5c838252010-02-19 08:53:10 +00003229 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003230 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003231 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003232 Label miss;
3233
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003234 Counters* counters = isolate()->counters();
3235 __ IncrementCounter(counters->keyed_load_callback(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003236
3237 // Check that the name has not changed.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003238 __ cmp(ecx, Immediate(name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003239 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003240
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00003241 GenerateLoadCallback(receiver, holder, edx, ecx, ebx, eax, edi, no_reg,
3242 callback, name, &miss);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00003243
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003244 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003245 __ DecrementCounter(counters->keyed_load_callback(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003246 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3247
3248 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003249 return GetCode(Code::CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003250}
3251
3252
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003253Handle<Code> KeyedLoadStubCompiler::CompileLoadConstant(
3254 Handle<String> name,
3255 Handle<JSObject> receiver,
3256 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003257 Handle<JSFunction> value) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003258 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003259 // -- ecx : key
ager@chromium.org5c838252010-02-19 08:53:10 +00003260 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003261 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003262 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003263 Label miss;
3264
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003265 Counters* counters = isolate()->counters();
3266 __ IncrementCounter(counters->keyed_load_constant_function(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003267
3268 // Check that the name has not changed.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003269 __ cmp(ecx, Immediate(name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003270 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003271
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003272 GenerateLoadConstant(
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003273 receiver, holder, edx, ebx, eax, edi, value, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003274 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003275 __ DecrementCounter(counters->keyed_load_constant_function(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003276 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3277
3278 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003279 return GetCode(Code::CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003280}
3281
3282
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003283Handle<Code> KeyedLoadStubCompiler::CompileLoadInterceptor(
3284 Handle<JSObject> receiver,
3285 Handle<JSObject> holder,
3286 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003287 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003288 // -- ecx : key
ager@chromium.org5c838252010-02-19 08:53:10 +00003289 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003290 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003291 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003292 Label miss;
3293
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003294 Counters* counters = isolate()->counters();
3295 __ IncrementCounter(counters->keyed_load_interceptor(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003296
3297 // Check that the name has not changed.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003298 __ cmp(ecx, Immediate(name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003299 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003300
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003301 LookupResult lookup(isolate());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003302 LookupPostInterceptor(holder, name, &lookup);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003303 GenerateLoadInterceptor(receiver, holder, &lookup, edx, ecx, eax, ebx, edi,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003304 name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003305 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003306 __ DecrementCounter(counters->keyed_load_interceptor(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003307 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3308
3309 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003310 return GetCode(Code::INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003311}
3312
3313
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003314Handle<Code> KeyedLoadStubCompiler::CompileLoadArrayLength(
3315 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003316 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003317 // -- ecx : key
ager@chromium.org5c838252010-02-19 08:53:10 +00003318 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003319 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003320 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003321 Label miss;
3322
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003323 Counters* counters = isolate()->counters();
3324 __ IncrementCounter(counters->keyed_load_array_length(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003325
3326 // Check that the name has not changed.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003327 __ cmp(ecx, Immediate(name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003328 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003329
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003330 GenerateLoadArrayLength(masm(), edx, eax, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003331 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003332 __ DecrementCounter(counters->keyed_load_array_length(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003333 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3334
3335 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003336 return GetCode(Code::CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003337}
3338
3339
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003340Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength(
3341 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003342 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003343 // -- ecx : key
ager@chromium.org5c838252010-02-19 08:53:10 +00003344 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003345 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003346 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003347 Label miss;
3348
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003349 Counters* counters = isolate()->counters();
3350 __ IncrementCounter(counters->keyed_load_string_length(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003351
3352 // Check that the name has not changed.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003353 __ cmp(ecx, Immediate(name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003354 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003355
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003356 GenerateLoadStringLength(masm(), edx, eax, ebx, &miss, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003357 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003358 __ DecrementCounter(counters->keyed_load_string_length(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003359 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3360
3361 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003362 return GetCode(Code::CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003363}
3364
3365
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003366Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype(
3367 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003368 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003369 // -- ecx : key
ager@chromium.org5c838252010-02-19 08:53:10 +00003370 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003371 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003372 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003373 Label miss;
3374
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003375 Counters* counters = isolate()->counters();
3376 __ IncrementCounter(counters->keyed_load_function_prototype(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003377
3378 // Check that the name has not changed.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003379 __ cmp(ecx, Immediate(name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003380 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003381
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003382 GenerateLoadFunctionPrototype(masm(), edx, eax, ebx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003383 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003384 __ DecrementCounter(counters->keyed_load_function_prototype(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003385 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3386
3387 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003388 return GetCode(Code::CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003389}
3390
3391
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003392Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
3393 Handle<Map> receiver_map) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003394 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003395 // -- ecx : key
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003396 // -- edx : receiver
3397 // -- esp[0] : return address
3398 // -----------------------------------
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003399
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003400 ElementsKind elements_kind = receiver_map->elements_kind();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003401 Handle<Code> stub = KeyedLoadElementStub(elements_kind).GetCode();
3402
3403 __ DispatchMap(edx, receiver_map, stub, DO_SMI_CHECK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003404
3405 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3406
3407 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003408 return GetCode(Code::NORMAL, factory()->empty_string());
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003409}
3410
3411
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003412Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
3413 MapHandleList* receiver_maps,
3414 CodeHandleList* handler_ics) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003415 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003416 // -- ecx : key
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003417 // -- edx : receiver
3418 // -- esp[0] : return address
3419 // -----------------------------------
3420 Label miss;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003421 __ JumpIfSmi(edx, &miss);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003422
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003423 Register map_reg = ebx;
3424 __ mov(map_reg, FieldOperand(edx, HeapObject::kMapOffset));
3425 int receiver_count = receiver_maps->length();
3426 for (int current = 0; current < receiver_count; ++current) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003427 __ cmp(map_reg, receiver_maps->at(current));
3428 __ j(equal, handler_ics->at(current));
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003429 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003430
3431 __ bind(&miss);
3432 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3433
3434 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003435 return GetCode(Code::NORMAL, factory()->empty_string(), MEGAMORPHIC);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003436}
3437
3438
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003439// Specialized stub for constructing objects from functions which only have only
3440// simple assignments of the form this.x = ...; in their body.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003441Handle<Code> ConstructStubCompiler::CompileConstructStub(
3442 Handle<JSFunction> function) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003443 // ----------- S t a t e -------------
3444 // -- eax : argc
3445 // -- edi : constructor
3446 // -- esp[0] : return address
3447 // -- esp[4] : last argument
3448 // -----------------------------------
3449 Label generic_stub_call;
3450#ifdef ENABLE_DEBUGGER_SUPPORT
3451 // Check to see whether there are any break points in the function code. If
3452 // there are jump to the generic constructor stub which calls the actual
3453 // code for the function thereby hitting the break points.
3454 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
3455 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kDebugInfoOffset));
lrn@chromium.org7516f052011-03-30 08:52:27 +00003456 __ cmp(ebx, factory()->undefined_value());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003457 __ j(not_equal, &generic_stub_call);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003458#endif
3459
3460 // Load the initial map and verify that it is in fact a map.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003461 // edi: constructor
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003462 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
3463 // Will both indicate a NULL and a Smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003464 __ JumpIfSmi(ebx, &generic_stub_call);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003465 __ CmpObjectType(ebx, MAP_TYPE, ecx);
3466 __ j(not_equal, &generic_stub_call);
3467
3468#ifdef DEBUG
3469 // Cannot construct functions this way.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003470 // ebx: initial map
3471 __ CmpInstanceType(ebx, JS_FUNCTION_TYPE);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003472 __ Check(not_equal, "Function constructed by construct stub.");
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003473#endif
3474
3475 // Now allocate the JSObject on the heap by moving the new space allocation
3476 // top forward.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003477 // ebx: initial map
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003478 ASSERT(function->has_initial_map());
3479 int instance_size = function->initial_map()->instance_size();
3480#ifdef DEBUG
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003481 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset));
3482 __ shl(ecx, kPointerSizeLog2);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003483 __ cmp(ecx, Immediate(instance_size));
3484 __ Check(equal, "Instance size of initial map changed.");
3485#endif
3486 __ AllocateInNewSpace(instance_size, edx, ecx, no_reg,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003487 &generic_stub_call, NO_ALLOCATION_FLAGS);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003488
3489 // Allocated the JSObject, now initialize the fields and add the heap tag.
3490 // ebx: initial map
3491 // edx: JSObject (untagged)
3492 __ mov(Operand(edx, JSObject::kMapOffset), ebx);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003493 __ mov(ebx, factory()->empty_fixed_array());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003494 __ mov(Operand(edx, JSObject::kPropertiesOffset), ebx);
3495 __ mov(Operand(edx, JSObject::kElementsOffset), ebx);
3496
3497 // Push the allocated object to the stack. This is the object that will be
3498 // returned (after it is tagged).
3499 __ push(edx);
3500
3501 // eax: argc
3502 // edx: JSObject (untagged)
3503 // Load the address of the first in-object property into edx.
3504 __ lea(edx, Operand(edx, JSObject::kHeaderSize));
3505 // Calculate the location of the first argument. The stack contains the
3506 // allocated object and the return address on top of the argc arguments.
3507 __ lea(ecx, Operand(esp, eax, times_4, 1 * kPointerSize));
3508
3509 // Use edi for holding undefined which is used in several places below.
lrn@chromium.org7516f052011-03-30 08:52:27 +00003510 __ mov(edi, factory()->undefined_value());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003511
3512 // eax: argc
3513 // ecx: first argument
3514 // edx: first in-object property of the JSObject
3515 // edi: undefined
3516 // Fill the initialized properties with a constant value or a passed argument
3517 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003518 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003519 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3520 if (shared->IsThisPropertyAssignmentArgument(i)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003521 // Check if the argument assigned to the property is actually passed.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003522 // If argument is not passed the property is set to undefined,
3523 // otherwise find it on the stack.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003524 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003525 __ mov(ebx, edi);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003526 __ cmp(eax, arg_number);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003527 if (CpuFeatures::IsSupported(CMOV)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003528 CpuFeatures::Scope use_cmov(CMOV);
3529 __ cmov(above, ebx, Operand(ecx, arg_number * -kPointerSize));
3530 } else {
3531 Label not_passed;
3532 __ j(below_equal, &not_passed);
3533 __ mov(ebx, Operand(ecx, arg_number * -kPointerSize));
3534 __ bind(&not_passed);
3535 }
3536 // Store value in the property.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003537 __ mov(Operand(edx, i * kPointerSize), ebx);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003538 } else {
3539 // Set the property to the constant value.
3540 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
3541 __ mov(Operand(edx, i * kPointerSize), Immediate(constant));
3542 }
3543 }
3544
3545 // Fill the unused in-object property fields with undefined.
3546 for (int i = shared->this_property_assignments_count();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00003547 i < function->initial_map()->inobject_properties();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003548 i++) {
3549 __ mov(Operand(edx, i * kPointerSize), edi);
3550 }
3551
3552 // Move argc to ebx and retrieve and tag the JSObject to return.
3553 __ mov(ebx, eax);
3554 __ pop(eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003555 __ or_(eax, Immediate(kHeapObjectTag));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003556
3557 // Remove caller arguments and receiver from the stack and return.
3558 __ pop(ecx);
3559 __ lea(esp, Operand(esp, ebx, times_pointer_size, 1 * kPointerSize));
3560 __ push(ecx);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003561 Counters* counters = isolate()->counters();
3562 __ IncrementCounter(counters->constructed_objects(), 1);
3563 __ IncrementCounter(counters->constructed_objects_stub(), 1);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003564 __ ret(0);
3565
3566 // Jump to the generic stub in case the specialized code cannot handle the
3567 // construction.
3568 __ bind(&generic_stub_call);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003569 Handle<Code> code = isolate()->builtins()->JSConstructStubGeneric();
3570 __ jmp(code, RelocInfo::CODE_TARGET);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003571
3572 // Return the generated code.
3573 return GetCode();
3574}
3575
3576
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003577#undef __
3578#define __ ACCESS_MASM(masm)
3579
3580
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003581void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3582 MacroAssembler* masm) {
3583 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003584 // -- ecx : key
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003585 // -- edx : receiver
3586 // -- esp[0] : return address
3587 // -----------------------------------
3588 Label slow, miss_force_generic;
3589
3590 // This stub is meant to be tail-jumped to, the receiver must already
3591 // have been verified by the caller to not be a smi.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003592 __ JumpIfNotSmi(ecx, &miss_force_generic);
3593 __ mov(ebx, ecx);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003594 __ SmiUntag(ebx);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003595 __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset));
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003596
3597 // Push receiver on the stack to free up a register for the dictionary
3598 // probing.
3599 __ push(edx);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003600 __ LoadFromNumberDictionary(&slow, eax, ecx, ebx, edx, edi, eax);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003601 // Pop receiver before returning.
3602 __ pop(edx);
3603 __ ret(0);
3604
3605 __ bind(&slow);
3606 __ pop(edx);
3607
3608 // ----------- S t a t e -------------
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003609 // -- ecx : key
3610 // -- edx : receiver
3611 // -- esp[0] : return address
3612 // -----------------------------------
3613
3614 Handle<Code> slow_ic =
3615 masm->isolate()->builtins()->KeyedLoadIC_Slow();
3616 __ jmp(slow_ic, RelocInfo::CODE_TARGET);
3617
3618 __ bind(&miss_force_generic);
3619 // ----------- S t a t e -------------
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003620 // -- ecx : key
3621 // -- edx : receiver
3622 // -- esp[0] : return address
3623 // -----------------------------------
3624
3625 Handle<Code> miss_force_generic_ic =
3626 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3627 __ jmp(miss_force_generic_ic, RelocInfo::CODE_TARGET);
3628}
3629
3630
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003631static void GenerateSmiKeyCheck(MacroAssembler* masm,
3632 Register key,
3633 Register scratch,
3634 XMMRegister xmm_scratch0,
3635 XMMRegister xmm_scratch1,
3636 Label* fail) {
3637 // Check that key is a smi and if SSE2 is available a heap number
3638 // containing a smi and branch if the check fails.
3639 if (CpuFeatures::IsSupported(SSE2)) {
3640 CpuFeatures::Scope use_sse2(SSE2);
3641 Label key_ok;
3642 __ JumpIfSmi(key, &key_ok);
3643 __ cmp(FieldOperand(key, HeapObject::kMapOffset),
3644 Immediate(Handle<Map>(masm->isolate()->heap()->heap_number_map())));
3645 __ j(not_equal, fail);
3646 __ movdbl(xmm_scratch0, FieldOperand(key, HeapNumber::kValueOffset));
3647 __ cvttsd2si(scratch, Operand(xmm_scratch0));
3648 __ cvtsi2sd(xmm_scratch1, scratch);
3649 __ ucomisd(xmm_scratch1, xmm_scratch0);
3650 __ j(not_equal, fail);
3651 __ j(parity_even, fail); // NaN.
3652 // Check if the key fits in the smi range.
3653 __ cmp(scratch, 0xc0000000);
3654 __ j(sign, fail);
3655 __ SmiTag(scratch);
3656 __ mov(key, scratch);
3657 __ bind(&key_ok);
3658 } else {
3659 __ JumpIfNotSmi(key, fail);
3660 }
3661}
3662
3663
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003664void KeyedLoadStubCompiler::GenerateLoadExternalArray(
3665 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003666 ElementsKind elements_kind) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003667 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003668 // -- ecx : key
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003669 // -- edx : receiver
3670 // -- esp[0] : return address
3671 // -----------------------------------
3672 Label miss_force_generic, failed_allocation, slow;
3673
3674 // This stub is meant to be tail-jumped to, the receiver must already
3675 // have been verified by the caller to not be a smi.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003676
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003677 // Check that the key is a smi or a heap number convertible to a smi.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003678 GenerateSmiKeyCheck(masm, ecx, eax, xmm0, xmm1, &miss_force_generic);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003679
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003680 // Check that the index is in range.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003681 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003682 __ cmp(ecx, FieldOperand(ebx, ExternalArray::kLengthOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003683 // Unsigned comparison catches both negative and too-large values.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003684 __ j(above_equal, &miss_force_generic);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003685 __ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset));
3686 // ebx: base pointer of external storage
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003687 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003688 case EXTERNAL_BYTE_ELEMENTS:
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003689 __ SmiUntag(ecx); // Untag the index.
3690 __ movsx_b(eax, Operand(ebx, ecx, times_1, 0));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003691 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003692 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3693 case EXTERNAL_PIXEL_ELEMENTS:
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003694 __ SmiUntag(ecx); // Untag the index.
3695 __ movzx_b(eax, Operand(ebx, ecx, times_1, 0));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003696 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003697 case EXTERNAL_SHORT_ELEMENTS:
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003698 __ movsx_w(eax, Operand(ebx, ecx, times_1, 0));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003699 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003700 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003701 __ movzx_w(eax, Operand(ebx, ecx, times_1, 0));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003702 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003703 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3704 case EXTERNAL_INT_ELEMENTS:
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003705 __ mov(eax, Operand(ebx, ecx, times_2, 0));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003706 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003707 case EXTERNAL_FLOAT_ELEMENTS:
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003708 __ fld_s(Operand(ebx, ecx, times_2, 0));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003709 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003710 case EXTERNAL_DOUBLE_ELEMENTS:
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003711 __ fld_d(Operand(ebx, ecx, times_4, 0));
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003712 break;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003713 default:
3714 UNREACHABLE();
3715 break;
3716 }
3717
3718 // For integer array types:
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003719 // eax: value
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003720 // For floating-point array type:
3721 // FP(0): value
3722
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003723 if (elements_kind == EXTERNAL_INT_ELEMENTS ||
3724 elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003725 // For the Int and UnsignedInt array types, we need to see whether
3726 // the value can be represented in a Smi. If not, we need to convert
3727 // it to a HeapNumber.
3728 Label box_int;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003729 if (elements_kind == EXTERNAL_INT_ELEMENTS) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003730 __ cmp(eax, 0xc0000000);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003731 __ j(sign, &box_int);
3732 } else {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003733 ASSERT_EQ(EXTERNAL_UNSIGNED_INT_ELEMENTS, elements_kind);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003734 // The test is different for unsigned int values. Since we need
3735 // the value to be in the range of a positive smi, we can't
3736 // handle either of the top two bits being set in the value.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003737 __ test(eax, Immediate(0xc0000000));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003738 __ j(not_zero, &box_int);
3739 }
3740
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003741 __ SmiTag(eax);
3742 __ ret(0);
3743
3744 __ bind(&box_int);
3745
3746 // Allocate a HeapNumber for the int and perform int-to-double
3747 // conversion.
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003748 if (elements_kind == EXTERNAL_INT_ELEMENTS) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003749 __ push(eax);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003750 __ fild_s(Operand(esp, 0));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003751 __ pop(eax);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003752 } else {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003753 ASSERT_EQ(EXTERNAL_UNSIGNED_INT_ELEMENTS, elements_kind);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003754 // Need to zero-extend the value.
3755 // There's no fild variant for unsigned values, so zero-extend
3756 // to a 64-bit int manually.
3757 __ push(Immediate(0));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003758 __ push(eax);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003759 __ fild_d(Operand(esp, 0));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003760 __ pop(eax);
3761 __ pop(eax);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003762 }
3763 // FP(0): value
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003764 __ AllocateHeapNumber(eax, ebx, edi, &failed_allocation);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003765 // Set the value.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003766 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
3767 __ ret(0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003768 } else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
3769 elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003770 // For the floating-point array type, we need to always allocate a
3771 // HeapNumber.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003772 __ AllocateHeapNumber(eax, ebx, edi, &failed_allocation);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003773 // Set the value.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003774 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
3775 __ ret(0);
3776 } else {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003777 __ SmiTag(eax);
3778 __ ret(0);
3779 }
3780
3781 // If we fail allocation of the HeapNumber, we still have a value on
3782 // top of the FPU stack. Remove it.
3783 __ bind(&failed_allocation);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003784 __ fstp(0);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003785 // Fall through to slow case.
3786
3787 // Slow case: Jump to runtime.
3788 __ bind(&slow);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003789 Counters* counters = masm->isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003790 __ IncrementCounter(counters->keyed_load_external_array_slow(), 1);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003791
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003792 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003793 // -- ecx : key
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003794 // -- edx : receiver
3795 // -- esp[0] : return address
3796 // -----------------------------------
3797
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003798 Handle<Code> ic = masm->isolate()->builtins()->KeyedLoadIC_Slow();
3799 __ jmp(ic, RelocInfo::CODE_TARGET);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003800
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003801 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003802 // -- ecx : key
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003803 // -- edx : receiver
3804 // -- esp[0] : return address
3805 // -----------------------------------
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003806
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003807 // Miss case: Jump to runtime.
3808 __ bind(&miss_force_generic);
3809 Handle<Code> miss_ic =
3810 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3811 __ jmp(miss_ic, RelocInfo::CODE_TARGET);
3812}
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003813
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003814
3815void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3816 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003817 ElementsKind elements_kind) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003818 // ----------- S t a t e -------------
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003819 // -- eax : value
3820 // -- ecx : key
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003821 // -- edx : receiver
3822 // -- esp[0] : return address
3823 // -----------------------------------
3824 Label miss_force_generic, slow, check_heap_number;
3825
3826 // This stub is meant to be tail-jumped to, the receiver must already
3827 // have been verified by the caller to not be a smi.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003828
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003829 // Check that the key is a smi or a heap number convertible to a smi.
3830 GenerateSmiKeyCheck(masm, ecx, ebx, xmm0, xmm1, &miss_force_generic);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003831
3832 // Check that the index is in range.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003833 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003834 __ cmp(ecx, FieldOperand(edi, ExternalArray::kLengthOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003835 // Unsigned comparison catches both negative and too-large values.
3836 __ j(above_equal, &slow);
3837
3838 // Handle both smis and HeapNumbers in the fast path. Go to the
3839 // runtime for all other kinds of values.
3840 // eax: value
3841 // edx: receiver
3842 // ecx: key
3843 // edi: elements array
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003844 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00003845 __ JumpIfNotSmi(eax, &slow);
3846 } else {
3847 __ JumpIfNotSmi(eax, &check_heap_number);
3848 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003849
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003850 // smi case
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003851 __ mov(ebx, eax); // Preserve the value in eax as the return value.
3852 __ SmiUntag(ebx);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003853 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003854 // edi: base pointer of external storage
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003855 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003856 case EXTERNAL_PIXEL_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003857 __ ClampUint8(ebx);
3858 __ SmiUntag(ecx);
3859 __ mov_b(Operand(edi, ecx, times_1, 0), ebx);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003860 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003861 case EXTERNAL_BYTE_ELEMENTS:
3862 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003863 __ SmiUntag(ecx);
3864 __ mov_b(Operand(edi, ecx, times_1, 0), ebx);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003865 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003866 case EXTERNAL_SHORT_ELEMENTS:
3867 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003868 __ mov_w(Operand(edi, ecx, times_1, 0), ebx);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003869 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003870 case EXTERNAL_INT_ELEMENTS:
3871 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003872 __ mov(Operand(edi, ecx, times_2, 0), ebx);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003873 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003874 case EXTERNAL_FLOAT_ELEMENTS:
3875 case EXTERNAL_DOUBLE_ELEMENTS:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003876 // Need to perform int-to-float conversion.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003877 __ push(ebx);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003878 __ fild_s(Operand(esp, 0));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003879 __ pop(ebx);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003880 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003881 __ fstp_s(Operand(edi, ecx, times_2, 0));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003882 } else { // elements_kind == EXTERNAL_DOUBLE_ELEMENTS.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003883 __ fstp_d(Operand(edi, ecx, times_4, 0));
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003884 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003885 break;
3886 default:
3887 UNREACHABLE();
3888 break;
3889 }
3890 __ ret(0); // Return the original value.
3891
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003892 // TODO(danno): handle heap number -> pixel array conversion
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003893 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003894 __ bind(&check_heap_number);
3895 // eax: value
3896 // edx: receiver
3897 // ecx: key
3898 // edi: elements array
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003899 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003900 Immediate(masm->isolate()->factory()->heap_number_map()));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003901 __ j(not_equal, &slow);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003902
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003903 // The WebGL specification leaves the behavior of storing NaN and
3904 // +/-Infinity into integer arrays basically undefined. For more
3905 // reproducible behavior, convert these to zero.
3906 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003907 // edi: base pointer of external storage
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003908 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003909 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003910 __ fstp_s(Operand(edi, ecx, times_2, 0));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003911 __ ret(0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003912 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003913 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003914 __ fstp_d(Operand(edi, ecx, times_4, 0));
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003915 __ ret(0);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003916 } else {
3917 // Perform float-to-int conversion with truncation (round-to-zero)
3918 // behavior.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003919
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003920 // For the moment we make the slow call to the runtime on
3921 // processors that don't support SSE2. The code in IntegerConvert
3922 // (code-stubs-ia32.cc) is roughly what is needed here though the
3923 // conversion failure case does not need to be handled.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003924 if (CpuFeatures::IsSupported(SSE2)) {
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003925 if ((elements_kind == EXTERNAL_INT_ELEMENTS ||
3926 elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) &&
3927 CpuFeatures::IsSupported(SSE3)) {
3928 CpuFeatures::Scope scope(SSE3);
3929 // fisttp stores values as signed integers. To represent the
3930 // entire range of int and unsigned int arrays, store as a
3931 // 64-bit int and discard the high 32 bits.
3932 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
3933 __ sub(esp, Immediate(2 * kPointerSize));
3934 __ fisttp_d(Operand(esp, 0));
3935
3936 // If conversion failed (NaN, infinity, or a number outside
3937 // signed int64 range), the result is 0x8000000000000000, and
3938 // we must handle this case in the runtime.
3939 Label ok;
3940 __ cmp(Operand(esp, kPointerSize), Immediate(0x80000000u));
3941 __ j(not_equal, &ok);
3942 __ cmp(Operand(esp, 0), Immediate(0));
3943 __ j(not_equal, &ok);
3944 __ add(esp, Immediate(2 * kPointerSize)); // Restore the stack.
3945 __ jmp(&slow);
3946
3947 __ bind(&ok);
3948 __ pop(ebx);
3949 __ add(esp, Immediate(kPointerSize));
3950 __ mov(Operand(edi, ecx, times_2, 0), ebx);
3951 } else {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003952 ASSERT(CpuFeatures::IsSupported(SSE2));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003953 CpuFeatures::Scope scope(SSE2);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003954 __ cvttsd2si(ebx, FieldOperand(eax, HeapNumber::kValueOffset));
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003955 __ cmp(ebx, 0x80000000u);
3956 __ j(equal, &slow);
3957 // ebx: untagged integer value
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003958 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003959 case EXTERNAL_PIXEL_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003960 __ ClampUint8(ebx);
3961 // Fall through.
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003962 case EXTERNAL_BYTE_ELEMENTS:
3963 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003964 __ SmiUntag(ecx);
3965 __ mov_b(Operand(edi, ecx, times_1, 0), ebx);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003966 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003967 case EXTERNAL_SHORT_ELEMENTS:
3968 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003969 __ mov_w(Operand(edi, ecx, times_1, 0), ebx);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003970 break;
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003971 case EXTERNAL_INT_ELEMENTS:
3972 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3973 __ mov(Operand(edi, ecx, times_2, 0), ebx);
3974 break;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003975 default:
3976 UNREACHABLE();
3977 break;
3978 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003979 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003980 __ ret(0); // Return original value.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003981 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003982 }
3983 }
3984
3985 // Slow case: call runtime.
3986 __ bind(&slow);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003987 Counters* counters = masm->isolate()->counters();
3988 __ IncrementCounter(counters->keyed_store_external_array_slow(), 1);
3989
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003990 // ----------- S t a t e -------------
3991 // -- eax : value
3992 // -- ecx : key
3993 // -- edx : receiver
3994 // -- esp[0] : return address
3995 // -----------------------------------
3996
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003997 Handle<Code> ic = masm->isolate()->builtins()->KeyedStoreIC_Slow();
3998 __ jmp(ic, RelocInfo::CODE_TARGET);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003999
ager@chromium.orgea91cc52011-05-23 06:06:11 +00004000 // ----------- S t a t e -------------
4001 // -- eax : value
4002 // -- ecx : key
4003 // -- edx : receiver
4004 // -- esp[0] : return address
4005 // -----------------------------------
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004006
ager@chromium.orgea91cc52011-05-23 06:06:11 +00004007 __ bind(&miss_force_generic);
4008 Handle<Code> miss_ic =
4009 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4010 __ jmp(miss_ic, RelocInfo::CODE_TARGET);
4011}
4012
4013
ager@chromium.orgea91cc52011-05-23 06:06:11 +00004014void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
4015 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00004016 // -- ecx : key
ager@chromium.orgea91cc52011-05-23 06:06:11 +00004017 // -- edx : receiver
4018 // -- esp[0] : return address
4019 // -----------------------------------
4020 Label miss_force_generic;
4021
4022 // This stub is meant to be tail-jumped to, the receiver must already
4023 // have been verified by the caller to not be a smi.
4024
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00004025 // Check that the key is a smi or a heap number convertible to a smi.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00004026 GenerateSmiKeyCheck(masm, ecx, eax, xmm0, xmm1, &miss_force_generic);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00004027
4028 // Get the elements array.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00004029 __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset));
4030 __ AssertFastElements(eax);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00004031
4032 // Check that the key is within bounds.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00004033 __ cmp(ecx, FieldOperand(eax, FixedArray::kLengthOffset));
ager@chromium.orgea91cc52011-05-23 06:06:11 +00004034 __ j(above_equal, &miss_force_generic);
4035
4036 // Load the result and make sure it's not the hole.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00004037 __ mov(ebx, Operand(eax, ecx, times_2,
ager@chromium.orgea91cc52011-05-23 06:06:11 +00004038 FixedArray::kHeaderSize - kHeapObjectTag));
4039 __ cmp(ebx, masm->isolate()->factory()->the_hole_value());
4040 __ j(equal, &miss_force_generic);
4041 __ mov(eax, ebx);
4042 __ ret(0);
4043
4044 __ bind(&miss_force_generic);
4045 Handle<Code> miss_ic =
4046 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4047 __ jmp(miss_ic, RelocInfo::CODE_TARGET);
4048}
4049
4050
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004051void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
4052 MacroAssembler* masm) {
4053 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00004054 // -- ecx : key
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004055 // -- edx : receiver
4056 // -- esp[0] : return address
4057 // -----------------------------------
4058 Label miss_force_generic, slow_allocate_heapnumber;
4059
4060 // This stub is meant to be tail-jumped to, the receiver must already
4061 // have been verified by the caller to not be a smi.
4062
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00004063 // Check that the key is a smi or a heap number convertible to a smi.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00004064 GenerateSmiKeyCheck(masm, ecx, eax, xmm0, xmm1, &miss_force_generic);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004065
4066 // Get the elements array.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00004067 __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset));
4068 __ AssertFastElements(eax);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004069
4070 // Check that the key is within bounds.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00004071 __ cmp(ecx, FieldOperand(eax, FixedDoubleArray::kLengthOffset));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004072 __ j(above_equal, &miss_force_generic);
4073
4074 // Check for the hole
4075 uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00004076 __ cmp(FieldOperand(eax, ecx, times_4, offset), Immediate(kHoleNanUpper32));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004077 __ j(equal, &miss_force_generic);
4078
4079 // Always allocate a heap number for the result.
4080 if (CpuFeatures::IsSupported(SSE2)) {
4081 CpuFeatures::Scope use_sse2(SSE2);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00004082 __ movdbl(xmm0, FieldOperand(eax, ecx, times_4,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004083 FixedDoubleArray::kHeaderSize));
4084 } else {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00004085 __ fld_d(FieldOperand(eax, ecx, times_4, FixedDoubleArray::kHeaderSize));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004086 }
danno@chromium.org1044a4d2012-04-30 12:34:39 +00004087 __ AllocateHeapNumber(eax, ebx, edi, &slow_allocate_heapnumber);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004088 // Set the value.
4089 if (CpuFeatures::IsSupported(SSE2)) {
4090 CpuFeatures::Scope use_sse2(SSE2);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00004091 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004092 } else {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00004093 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004094 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004095 __ ret(0);
4096
4097 __ bind(&slow_allocate_heapnumber);
4098 // A value was pushed on the floating point stack before the allocation, if
4099 // the allocation fails it needs to be removed.
4100 if (!CpuFeatures::IsSupported(SSE2)) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004101 __ fstp(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004102 }
4103 Handle<Code> slow_ic =
4104 masm->isolate()->builtins()->KeyedLoadIC_Slow();
4105 __ jmp(slow_ic, RelocInfo::CODE_TARGET);
4106
4107 __ bind(&miss_force_generic);
4108 Handle<Code> miss_ic =
4109 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4110 __ jmp(miss_ic, RelocInfo::CODE_TARGET);
4111}
4112
4113
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004114void KeyedStoreStubCompiler::GenerateStoreFastElement(
4115 MacroAssembler* masm,
4116 bool is_js_array,
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004117 ElementsKind elements_kind,
4118 KeyedAccessGrowMode grow_mode) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00004119 // ----------- S t a t e -------------
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00004120 // -- eax : value
4121 // -- ecx : key
ager@chromium.orgea91cc52011-05-23 06:06:11 +00004122 // -- edx : receiver
4123 // -- esp[0] : return address
4124 // -----------------------------------
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004125 Label miss_force_generic, grow, slow, transition_elements_kind;
4126 Label check_capacity, prepare_slow, finish_store, commit_backing_store;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00004127
4128 // This stub is meant to be tail-jumped to, the receiver must already
4129 // have been verified by the caller to not be a smi.
4130
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00004131 // Check that the key is a smi or a heap number convertible to a smi.
4132 GenerateSmiKeyCheck(masm, ecx, ebx, xmm0, xmm1, &miss_force_generic);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00004133
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004134 if (IsFastSmiElementsKind(elements_kind)) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004135 __ JumpIfNotSmi(eax, &transition_elements_kind);
4136 }
4137
ager@chromium.orgea91cc52011-05-23 06:06:11 +00004138 // Get the elements array and make sure it is a fast element array, not 'cow'.
4139 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
ager@chromium.orgea91cc52011-05-23 06:06:11 +00004140 if (is_js_array) {
4141 // Check that the key is within bounds.
4142 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // smis.
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004143 if (grow_mode == ALLOW_JSARRAY_GROWTH) {
4144 __ j(above_equal, &grow);
4145 } else {
4146 __ j(above_equal, &miss_force_generic);
4147 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00004148 } else {
4149 // Check that the key is within bounds.
4150 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); // smis.
4151 __ j(above_equal, &miss_force_generic);
4152 }
4153
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004154 __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
4155 Immediate(masm->isolate()->factory()->fixed_array_map()));
4156 __ j(not_equal, &miss_force_generic);
4157
4158 __ bind(&finish_store);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004159 if (IsFastSmiElementsKind(elements_kind)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004160 // ecx is a smi, use times_half_pointer_size instead of
4161 // times_pointer_size
4162 __ mov(FieldOperand(edi,
4163 ecx,
4164 times_half_pointer_size,
4165 FixedArray::kHeaderSize), eax);
4166 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004167 ASSERT(IsFastObjectElementsKind(elements_kind));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004168 // Do the store and update the write barrier.
4169 // ecx is a smi, use times_half_pointer_size instead of
4170 // times_pointer_size
4171 __ lea(ecx, FieldOperand(edi,
4172 ecx,
4173 times_half_pointer_size,
4174 FixedArray::kHeaderSize));
4175 __ mov(Operand(ecx, 0), eax);
4176 // Make sure to preserve the value in register eax.
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004177 __ mov(ebx, eax);
4178 __ RecordWrite(edi, ecx, ebx, kDontSaveFPRegs);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004179 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00004180
4181 // Done.
4182 __ ret(0);
4183
4184 // Handle store cache miss, replacing the ic with the generic stub.
4185 __ bind(&miss_force_generic);
4186 Handle<Code> ic_force_generic =
4187 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4188 __ jmp(ic_force_generic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004189
4190 // Handle transition to other elements kinds without using the generic stub.
4191 __ bind(&transition_elements_kind);
4192 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4193 __ jmp(ic_miss, RelocInfo::CODE_TARGET);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004194
4195 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4196 // Handle transition requiring the array to grow.
4197 __ bind(&grow);
4198
4199 // Make sure the array is only growing by a single element, anything else
4200 // must be handled by the runtime. Flags are already set by previous
4201 // compare.
4202 __ j(not_equal, &miss_force_generic);
4203
4204 // Check for the empty array, and preallocate a small backing store if
4205 // possible.
4206 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
4207 __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array()));
4208 __ j(not_equal, &check_capacity);
4209
4210 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
4211 __ AllocateInNewSpace(size, edi, ebx, ecx, &prepare_slow, TAG_OBJECT);
4212 // Restore the key, which is known to be the array length.
4213
4214 // eax: value
4215 // ecx: key
4216 // edx: receiver
4217 // edi: elements
4218 // Make sure that the backing store can hold additional elements.
4219 __ mov(FieldOperand(edi, JSObject::kMapOffset),
4220 Immediate(masm->isolate()->factory()->fixed_array_map()));
4221 __ mov(FieldOperand(edi, FixedArray::kLengthOffset),
4222 Immediate(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4223 __ mov(ebx, Immediate(masm->isolate()->factory()->the_hole_value()));
4224 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
4225 __ mov(FieldOperand(edi, FixedArray::SizeFor(i)), ebx);
4226 }
4227
4228 // Store the element at index zero.
4229 __ mov(FieldOperand(edi, FixedArray::SizeFor(0)), eax);
4230
4231 // Install the new backing store in the JSArray.
4232 __ mov(FieldOperand(edx, JSObject::kElementsOffset), edi);
4233 __ RecordWriteField(edx, JSObject::kElementsOffset, edi, ebx,
4234 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4235
4236 // Increment the length of the array.
4237 __ mov(FieldOperand(edx, JSArray::kLengthOffset),
4238 Immediate(Smi::FromInt(1)));
4239 __ ret(0);
4240
4241 __ bind(&check_capacity);
4242 __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
4243 Immediate(masm->isolate()->factory()->fixed_cow_array_map()));
4244 __ j(equal, &miss_force_generic);
4245
4246 // eax: value
4247 // ecx: key
4248 // edx: receiver
4249 // edi: elements
4250 // Make sure that the backing store can hold additional elements.
4251 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
4252 __ j(above_equal, &slow);
4253
4254 // Grow the array and finish the store.
4255 __ add(FieldOperand(edx, JSArray::kLengthOffset),
4256 Immediate(Smi::FromInt(1)));
4257 __ jmp(&finish_store);
4258
4259 __ bind(&prepare_slow);
4260 // Restore the key, which is known to be the array length.
4261 __ mov(ecx, Immediate(0));
4262
4263 __ bind(&slow);
4264 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4265 __ jmp(ic_slow, RelocInfo::CODE_TARGET);
4266 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004267}
4268
4269
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004270void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
4271 MacroAssembler* masm,
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004272 bool is_js_array,
4273 KeyedAccessGrowMode grow_mode) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004274 // ----------- S t a t e -------------
4275 // -- eax : value
4276 // -- ecx : key
4277 // -- edx : receiver
4278 // -- esp[0] : return address
4279 // -----------------------------------
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004280 Label miss_force_generic, transition_elements_kind, grow, slow;
4281 Label check_capacity, prepare_slow, finish_store, commit_backing_store;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004282
4283 // This stub is meant to be tail-jumped to, the receiver must already
4284 // have been verified by the caller to not be a smi.
4285
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00004286 // Check that the key is a smi or a heap number convertible to a smi.
4287 GenerateSmiKeyCheck(masm, ecx, ebx, xmm0, xmm1, &miss_force_generic);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004288
4289 // Get the elements array.
4290 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
4291 __ AssertFastElements(edi);
4292
4293 if (is_js_array) {
4294 // Check that the key is within bounds.
4295 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // smis.
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004296 if (grow_mode == ALLOW_JSARRAY_GROWTH) {
4297 __ j(above_equal, &grow);
4298 } else {
4299 __ j(above_equal, &miss_force_generic);
4300 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004301 } else {
4302 // Check that the key is within bounds.
4303 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); // smis.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004304 __ j(above_equal, &miss_force_generic);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004305 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004306
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004307 __ bind(&finish_store);
4308 __ StoreNumberToDoubleElements(eax, edi, ecx, edx, xmm0,
4309 &transition_elements_kind, true);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004310 __ ret(0);
4311
4312 // Handle store cache miss, replacing the ic with the generic stub.
4313 __ bind(&miss_force_generic);
4314 Handle<Code> ic_force_generic =
4315 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4316 __ jmp(ic_force_generic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004317
4318 // Handle transition to other elements kinds without using the generic stub.
4319 __ bind(&transition_elements_kind);
4320 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4321 __ jmp(ic_miss, RelocInfo::CODE_TARGET);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004322
4323 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4324 // Handle transition requiring the array to grow.
4325 __ bind(&grow);
4326
4327 // Make sure the array is only growing by a single element, anything else
4328 // must be handled by the runtime. Flags are already set by previous
4329 // compare.
4330 __ j(not_equal, &miss_force_generic);
4331
4332 // Transition on values that can't be stored in a FixedDoubleArray.
4333 Label value_is_smi;
4334 __ JumpIfSmi(eax, &value_is_smi);
4335 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
4336 Immediate(Handle<Map>(masm->isolate()->heap()->heap_number_map())));
4337 __ j(not_equal, &transition_elements_kind);
4338 __ bind(&value_is_smi);
4339
4340 // Check for the empty array, and preallocate a small backing store if
4341 // possible.
4342 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
4343 __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array()));
4344 __ j(not_equal, &check_capacity);
4345
4346 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
4347 __ AllocateInNewSpace(size, edi, ebx, ecx, &prepare_slow, TAG_OBJECT);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004348
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004349 // Restore the key, which is known to be the array length.
4350 __ mov(ecx, Immediate(0));
4351
4352 // eax: value
4353 // ecx: key
4354 // edx: receiver
4355 // edi: elements
danno@chromium.org1f34ad32012-11-26 14:53:56 +00004356 // Initialize the new FixedDoubleArray.
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004357 __ mov(FieldOperand(edi, JSObject::kMapOffset),
4358 Immediate(masm->isolate()->factory()->fixed_double_array_map()));
4359 __ mov(FieldOperand(edi, FixedDoubleArray::kLengthOffset),
4360 Immediate(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4361
danno@chromium.org1f34ad32012-11-26 14:53:56 +00004362 for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) {
4363 int offset = FixedDoubleArray::OffsetOfElementAt(i);
4364 __ mov(FieldOperand(edi, offset), Immediate(kHoleNanLower32));
4365 __ mov(FieldOperand(edi, offset + kPointerSize),
4366 Immediate(kHoleNanUpper32));
4367 }
4368
4369 __ StoreNumberToDoubleElements(eax, edi, ecx, ebx, xmm0,
4370 &transition_elements_kind, true);
4371
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004372 // Install the new backing store in the JSArray.
4373 __ mov(FieldOperand(edx, JSObject::kElementsOffset), edi);
4374 __ RecordWriteField(edx, JSObject::kElementsOffset, edi, ebx,
4375 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4376
4377 // Increment the length of the array.
4378 __ add(FieldOperand(edx, JSArray::kLengthOffset),
4379 Immediate(Smi::FromInt(1)));
yangguo@chromium.org56454712012-02-16 15:33:53 +00004380 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
danno@chromium.org1f34ad32012-11-26 14:53:56 +00004381 __ ret(0);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004382
4383 __ bind(&check_capacity);
4384 // eax: value
4385 // ecx: key
4386 // edx: receiver
4387 // edi: elements
4388 // Make sure that the backing store can hold additional elements.
4389 __ cmp(ecx, FieldOperand(edi, FixedDoubleArray::kLengthOffset));
4390 __ j(above_equal, &slow);
4391
4392 // Grow the array and finish the store.
4393 __ add(FieldOperand(edx, JSArray::kLengthOffset),
4394 Immediate(Smi::FromInt(1)));
4395 __ jmp(&finish_store);
4396
4397 __ bind(&prepare_slow);
4398 // Restore the key, which is known to be the array length.
4399 __ mov(ecx, Immediate(0));
4400
4401 __ bind(&slow);
4402 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4403 __ jmp(ic_slow, RelocInfo::CODE_TARGET);
4404 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004405}
4406
4407
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004408#undef __
4409
4410} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004411
4412#endif // V8_TARGET_ARCH_IA32