blob: c1a5c39f4df23ea594a519846c59dffd44bbdceb [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.
279 __ cmp(Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000280 masm->isolate()->global());
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(
284 JSFunction::cast(masm->isolate()->global_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,
379 int index) {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000380 // Adjust for the number of properties stored in the holder.
381 index -= holder->map()->inobject_properties();
382 if (index < 0) {
383 // Get the property straight out of the holder.
384 int offset = holder->map()->instance_size() + (index * kPointerSize);
385 __ mov(dst, FieldOperand(src, offset));
386 } else {
387 // Calculate the offset into the properties array.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000388 int offset = index * kPointerSize + FixedArray::kHeaderSize;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000389 __ mov(dst, FieldOperand(src, JSObject::kPropertiesOffset));
390 __ mov(dst, FieldOperand(dst, offset));
391 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000392}
393
394
ager@chromium.org5c838252010-02-19 08:53:10 +0000395static void PushInterceptorArguments(MacroAssembler* masm,
396 Register receiver,
397 Register holder,
398 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000399 Handle<JSObject> holder_obj) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000400 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000401 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
402 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000403 Register scratch = name;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000404 __ mov(scratch, Immediate(interceptor));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000405 __ push(scratch);
ager@chromium.org5c838252010-02-19 08:53:10 +0000406 __ push(receiver);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000407 __ push(holder);
408 __ push(FieldOperand(scratch, InterceptorInfo::kDataOffset));
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000409 __ push(Immediate(reinterpret_cast<int>(masm->isolate())));
ager@chromium.org5c838252010-02-19 08:53:10 +0000410}
411
412
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000413static void CompileCallLoadPropertyWithInterceptor(
414 MacroAssembler* masm,
415 Register receiver,
416 Register holder,
417 Register name,
418 Handle<JSObject> holder_obj) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000419 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
ager@chromium.org5c838252010-02-19 08:53:10 +0000420 __ CallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000421 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
422 masm->isolate()),
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000423 6);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000424}
425
426
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000427// Number of pointers to be reserved on stack for fast API call.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000428static const int kFastApiCallArguments = 4;
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000429
430
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000431// Reserves space for the extra arguments to API function in the
ager@chromium.org5c838252010-02-19 08:53:10 +0000432// caller's frame.
433//
434// These arguments are set by CheckPrototypes and GenerateFastApiCall.
435static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
436 // ----------- S t a t e -------------
437 // -- esp[0] : return address
438 // -- esp[4] : last argument in the internal frame of the caller
439 // -----------------------------------
440 __ pop(scratch);
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000441 for (int i = 0; i < kFastApiCallArguments; i++) {
442 __ push(Immediate(Smi::FromInt(0)));
443 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000444 __ push(scratch);
445}
446
447
448// Undoes the effects of ReserveSpaceForFastApiCall.
449static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
450 // ----------- S t a t e -------------
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000451 // -- esp[0] : return address.
452 // -- esp[4] : last fast api call extra argument.
ager@chromium.org5c838252010-02-19 08:53:10 +0000453 // -- ...
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000454 // -- esp[kFastApiCallArguments * 4] : first fast api call extra argument.
455 // -- esp[kFastApiCallArguments * 4 + 4] : last argument in the internal
456 // frame.
ager@chromium.org5c838252010-02-19 08:53:10 +0000457 // -----------------------------------
458 __ pop(scratch);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000459 __ add(esp, Immediate(kPointerSize * kFastApiCallArguments));
ager@chromium.org5c838252010-02-19 08:53:10 +0000460 __ push(scratch);
461}
462
463
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000464// Generates call to API function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000465static void GenerateFastApiCall(MacroAssembler* masm,
466 const CallOptimization& optimization,
467 int argc) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000468 // ----------- S t a t e -------------
469 // -- esp[0] : return address
470 // -- esp[4] : object passing the type check
471 // (last fast api call extra argument,
472 // set by CheckPrototypes)
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000473 // -- esp[8] : api function
ager@chromium.org5c838252010-02-19 08:53:10 +0000474 // (first fast api call extra argument)
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000475 // -- esp[12] : api call data
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000476 // -- esp[16] : isolate
477 // -- esp[20] : last argument
ager@chromium.org5c838252010-02-19 08:53:10 +0000478 // -- ...
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000479 // -- esp[(argc + 4) * 4] : first argument
480 // -- esp[(argc + 5) * 4] : receiver
ager@chromium.org5c838252010-02-19 08:53:10 +0000481 // -----------------------------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000482 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000483 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000484 __ LoadHeapObject(edi, function);
ager@chromium.org5c838252010-02-19 08:53:10 +0000485 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
486
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000487 // Pass the additional arguments.
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000488 __ mov(Operand(esp, 2 * kPointerSize), edi);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000489 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
490 Handle<Object> call_data(api_call_info->data());
491 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
492 __ mov(ecx, api_call_info);
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000493 __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kDataOffset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000494 __ mov(Operand(esp, 3 * kPointerSize), ebx);
495 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000496 __ mov(Operand(esp, 3 * kPointerSize), Immediate(call_data));
ager@chromium.org5c838252010-02-19 08:53:10 +0000497 }
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000498 __ mov(Operand(esp, 4 * kPointerSize),
499 Immediate(reinterpret_cast<int>(masm->isolate())));
ager@chromium.org5c838252010-02-19 08:53:10 +0000500
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000501 // Prepare arguments.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000502 __ lea(eax, Operand(esp, 4 * kPointerSize));
ager@chromium.org5c838252010-02-19 08:53:10 +0000503
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000504 const int kApiArgc = 1; // API function gets reference to the v8::Arguments.
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000505
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000506 // Allocate the v8::Arguments structure in the arguments' space since
507 // it's not controlled by GC.
508 const int kApiStackSpace = 4;
509
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000510 __ PrepareCallApiFunction(kApiArgc + kApiStackSpace);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000511
512 __ mov(ApiParameterOperand(1), eax); // v8::Arguments::implicit_args_.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000513 __ add(eax, Immediate(argc * kPointerSize));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000514 __ mov(ApiParameterOperand(2), eax); // v8::Arguments::values_.
515 __ Set(ApiParameterOperand(3), Immediate(argc)); // v8::Arguments::length_.
516 // v8::Arguments::is_construct_call_.
517 __ Set(ApiParameterOperand(4), Immediate(0));
518
519 // v8::InvocationCallback's argument.
520 __ lea(eax, ApiParameterOperand(1));
521 __ mov(ApiParameterOperand(0), eax);
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000522
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000523 // Function address is a foreign pointer outside V8's heap.
524 Address function_address = v8::ToCData<Address>(api_call_info->callback());
525 __ CallApiFunctionAndReturn(function_address,
526 argc + kFastApiCallArguments + 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000527}
528
529
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000530class CallInterceptorCompiler BASE_EMBEDDED {
531 public:
ager@chromium.org5c838252010-02-19 08:53:10 +0000532 CallInterceptorCompiler(StubCompiler* stub_compiler,
533 const ParameterCount& arguments,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000534 Register name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000535 Code::ExtraICState extra_state)
ager@chromium.org5c838252010-02-19 08:53:10 +0000536 : stub_compiler_(stub_compiler),
537 arguments_(arguments),
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000538 name_(name),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000539 extra_state_(extra_state) {}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000540
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000541 void Compile(MacroAssembler* masm,
542 Handle<JSObject> object,
543 Handle<JSObject> holder,
544 Handle<String> name,
545 LookupResult* lookup,
546 Register receiver,
547 Register scratch1,
548 Register scratch2,
549 Register scratch3,
550 Label* miss) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000551 ASSERT(holder->HasNamedInterceptor());
552 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
553
554 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000555 __ JumpIfSmi(receiver, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000556
557 CallOptimization optimization(lookup);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000558 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000559 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
560 holder, lookup, name, optimization, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000561 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000562 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
563 name, holder, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000564 }
565 }
566
567 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000568 void CompileCacheable(MacroAssembler* masm,
569 Handle<JSObject> object,
570 Register receiver,
571 Register scratch1,
572 Register scratch2,
573 Register scratch3,
574 Handle<JSObject> interceptor_holder,
575 LookupResult* lookup,
576 Handle<String> name,
577 const CallOptimization& optimization,
578 Label* miss_label) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000579 ASSERT(optimization.is_constant_call());
580 ASSERT(!lookup->holder()->IsGlobalObject());
581
582 int depth1 = kInvalidProtoDepth;
583 int depth2 = kInvalidProtoDepth;
584 bool can_do_fast_api_call = false;
585 if (optimization.is_simple_api_call() &&
586 !lookup->holder()->IsGlobalObject()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000587 depth1 = optimization.GetPrototypeDepthOfExpectedType(
588 object, interceptor_holder);
ager@chromium.org5c838252010-02-19 08:53:10 +0000589 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000590 depth2 = optimization.GetPrototypeDepthOfExpectedType(
591 interceptor_holder, Handle<JSObject>(lookup->holder()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000592 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000593 can_do_fast_api_call =
594 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000595 }
596
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000597 Counters* counters = masm->isolate()->counters();
598 __ IncrementCounter(counters->call_const_interceptor(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000599
600 if (can_do_fast_api_call) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000601 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000602 ReserveSpaceForFastApiCall(masm, scratch1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000603 }
604
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000605 // Check that the maps from receiver to interceptor's holder
606 // haven't changed and thus we can invoke interceptor.
ager@chromium.org5c838252010-02-19 08:53:10 +0000607 Label miss_cleanup;
608 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
609 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000610 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
611 scratch1, scratch2, scratch3,
612 name, depth1, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000613
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000614 // Invoke an interceptor and if it provides a value,
615 // branch to |regular_invoke|.
ager@chromium.org5c838252010-02-19 08:53:10 +0000616 Label regular_invoke;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000617 LoadWithInterceptor(masm, receiver, holder, interceptor_holder,
618 &regular_invoke);
ager@chromium.org5c838252010-02-19 08:53:10 +0000619
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000620 // Interceptor returned nothing for this property. Try to use cached
621 // constant function.
ager@chromium.org5c838252010-02-19 08:53:10 +0000622
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000623 // Check that the maps from interceptor's holder to constant function's
624 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000625 if (*interceptor_holder != lookup->holder()) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000626 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000627 Handle<JSObject>(lookup->holder()),
628 scratch1, scratch2, scratch3,
629 name, depth2, miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000630 } else {
631 // CheckPrototypes has a side effect of fetching a 'holder'
632 // for API (object which is instanceof for the signature). It's
633 // safe to omit it here, as if present, it should be fetched
634 // by the previous CheckPrototypes.
635 ASSERT(depth2 == kInvalidProtoDepth);
636 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000637
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000638 // Invoke function.
ager@chromium.org5c838252010-02-19 08:53:10 +0000639 if (can_do_fast_api_call) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000640 GenerateFastApiCall(masm, optimization, arguments_.immediate());
ager@chromium.org5c838252010-02-19 08:53:10 +0000641 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000642 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000643 ? CALL_AS_FUNCTION
644 : CALL_AS_METHOD;
ager@chromium.org5c838252010-02-19 08:53:10 +0000645 __ InvokeFunction(optimization.constant_function(), arguments_,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000646 JUMP_FUNCTION, NullCallWrapper(), call_kind);
ager@chromium.org5c838252010-02-19 08:53:10 +0000647 }
648
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000649 // Deferred code for fast API call case---clean preallocated space.
ager@chromium.org5c838252010-02-19 08:53:10 +0000650 if (can_do_fast_api_call) {
651 __ bind(&miss_cleanup);
652 FreeSpaceForFastApiCall(masm, scratch1);
653 __ jmp(miss_label);
654 }
655
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000656 // Invoke a regular function.
ager@chromium.org5c838252010-02-19 08:53:10 +0000657 __ bind(&regular_invoke);
658 if (can_do_fast_api_call) {
659 FreeSpaceForFastApiCall(masm, scratch1);
660 }
661 }
662
663 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000664 Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +0000665 Register receiver,
666 Register scratch1,
667 Register scratch2,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000668 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000669 Handle<String> name,
670 Handle<JSObject> interceptor_holder,
ager@chromium.org5c838252010-02-19 08:53:10 +0000671 Label* miss_label) {
672 Register holder =
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000673 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000674 scratch1, scratch2, scratch3,
675 name, miss_label);
ager@chromium.org5c838252010-02-19 08:53:10 +0000676
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000677 FrameScope scope(masm, StackFrame::INTERNAL);
ager@chromium.org5c838252010-02-19 08:53:10 +0000678 // Save the name_ register across the call.
679 __ push(name_);
680
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000681 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
ager@chromium.org5c838252010-02-19 08:53:10 +0000682
683 __ CallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000684 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
685 masm->isolate()),
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000686 6);
ager@chromium.org5c838252010-02-19 08:53:10 +0000687
688 // Restore the name_ register.
689 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000690
691 // Leave the internal frame.
ager@chromium.org5c838252010-02-19 08:53:10 +0000692 }
693
694 void LoadWithInterceptor(MacroAssembler* masm,
695 Register receiver,
696 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000697 Handle<JSObject> holder_obj,
ager@chromium.org5c838252010-02-19 08:53:10 +0000698 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000699 {
700 FrameScope scope(masm, StackFrame::INTERNAL);
701 __ push(holder); // Save the holder.
702 __ push(name_); // Save the name.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000703
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000704 CompileCallLoadPropertyWithInterceptor(masm,
705 receiver,
706 holder,
707 name_,
708 holder_obj);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000709
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000710 __ pop(name_); // Restore the name.
711 __ pop(receiver); // Restore the holder.
712 // Leave the internal frame.
713 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000714
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000715 __ cmp(eax, masm->isolate()->factory()->no_interceptor_result_sentinel());
ager@chromium.org5c838252010-02-19 08:53:10 +0000716 __ j(not_equal, interceptor_succeeded);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000717 }
718
ager@chromium.org5c838252010-02-19 08:53:10 +0000719 StubCompiler* stub_compiler_;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000720 const ParameterCount& arguments_;
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000721 Register name_;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000722 Code::ExtraICState extra_state_;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000723};
724
725
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000726void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
727 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000728 Handle<Code> code = (kind == Code::LOAD_IC)
729 ? masm->isolate()->builtins()->LoadIC_Miss()
730 : masm->isolate()->builtins()->KeyedLoadIC_Miss();
731 __ jmp(code, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000732}
733
734
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000735void StubCompiler::GenerateKeyedLoadMissForceGeneric(MacroAssembler* masm) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000736 Handle<Code> code =
737 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
738 __ jmp(code, RelocInfo::CODE_TARGET);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000739}
740
741
ager@chromium.org5c838252010-02-19 08:53:10 +0000742// Both name_reg and receiver_reg are preserved on jumps to miss_label,
743// but may be destroyed if store is successful.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000744void StubCompiler::GenerateStoreField(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000745 Handle<JSObject> object,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000746 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000747 Handle<Map> transition,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000748 Handle<String> name,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000749 Register receiver_reg,
750 Register name_reg,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000751 Register scratch1,
752 Register scratch2,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000753 Label* miss_label) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000754 LookupResult lookup(masm->isolate());
755 object->Lookup(*name, &lookup);
756 if (lookup.IsFound() && (lookup.IsReadOnly() || !lookup.IsCacheable())) {
757 // In sloppy mode, we could just return the value and be done. However, we
758 // might be in strict mode, where we have to throw. Since we cannot tell,
759 // go into slow case unconditionally.
760 __ jmp(miss_label);
761 return;
762 }
763
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000764 // Check that the map of the object hasn't changed.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000765 CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
766 : REQUIRE_EXACT_MAP;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000767 __ CheckMap(receiver_reg, Handle<Map>(object->map()),
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000768 miss_label, DO_SMI_CHECK, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000769
770 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000771 if (object->IsJSGlobalProxy()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000772 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
773 }
774
775 // Check that we are allowed to write this.
776 if (!transition.is_null() && object->GetPrototype()->IsJSObject()) {
777 JSObject* holder;
778 if (lookup.IsFound()) {
779 holder = lookup.holder();
780 } else {
781 // Find the top object.
782 holder = *object;
783 do {
784 holder = JSObject::cast(holder->GetPrototype());
785 } while (holder->GetPrototype()->IsJSObject());
786 }
787 // We need an extra register, push
788 __ push(name_reg);
789 Label miss_pop, done_check;
790 CheckPrototypes(object, receiver_reg, Handle<JSObject>(holder), name_reg,
791 scratch1, scratch2, name, &miss_pop);
792 __ jmp(&done_check);
793 __ bind(&miss_pop);
794 __ pop(name_reg);
795 __ jmp(miss_label);
796 __ bind(&done_check);
797 __ pop(name_reg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000798 }
799
800 // Stub never generated for non-global objects that require access
801 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000802 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000803
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000804 // Perform map transition for the receiver if necessary.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000805 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) {
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000806 // The properties must be extended before we can store the value.
ager@chromium.org32912102009-01-16 10:38:43 +0000807 // We jump to a runtime call that extends the properties array.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000808 __ pop(scratch1); // Return address.
ager@chromium.org5c838252010-02-19 08:53:10 +0000809 __ push(receiver_reg);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000810 __ push(Immediate(transition));
ager@chromium.org5c838252010-02-19 08:53:10 +0000811 __ push(eax);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000812 __ push(scratch1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000813 __ TailCallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000814 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
815 masm->isolate()),
816 3,
817 1);
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000818 return;
819 }
820
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000821 if (!transition.is_null()) {
verwaest@chromium.org37141392012-05-31 13:27:02 +0000822 // Update the map of the object.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000823 __ mov(scratch1, Immediate(transition));
824 __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1);
verwaest@chromium.org37141392012-05-31 13:27:02 +0000825
826 // Update the write barrier for the map field and pass the now unused
827 // name_reg as scratch register.
828 __ RecordWriteField(receiver_reg,
829 HeapObject::kMapOffset,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000830 scratch1,
verwaest@chromium.org37141392012-05-31 13:27:02 +0000831 name_reg,
832 kDontSaveFPRegs,
833 OMIT_REMEMBERED_SET,
834 OMIT_SMI_CHECK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000835 }
836
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000837 // Adjust for the number of properties stored in the object. Even in the
838 // face of a transition we can use the old map here because the size of the
839 // object and the number of in-object properties is not going to change.
840 index -= object->map()->inobject_properties();
841
ager@chromium.org7c537e22008-10-16 08:43:32 +0000842 if (index < 0) {
843 // Set the property straight into the object.
844 int offset = object->map()->instance_size() + (index * kPointerSize);
845 __ mov(FieldOperand(receiver_reg, offset), eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000846
ager@chromium.org7c537e22008-10-16 08:43:32 +0000847 // Update the write barrier for the array address.
848 // Pass the value being stored in the now unused name_reg.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000849 __ mov(name_reg, eax);
850 __ RecordWriteField(receiver_reg,
851 offset,
852 name_reg,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000853 scratch1,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000854 kDontSaveFPRegs);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000855 } else {
856 // Write to the properties array.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000857 int offset = index * kPointerSize + FixedArray::kHeaderSize;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000858 // Get the properties array (optimistically).
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000859 __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
860 __ mov(FieldOperand(scratch1, offset), eax);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000861
862 // Update the write barrier for the array address.
863 // Pass the value being stored in the now unused name_reg.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000864 __ mov(name_reg, eax);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000865 __ RecordWriteField(scratch1,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000866 offset,
867 name_reg,
868 receiver_reg,
869 kDontSaveFPRegs);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000870 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000871
872 // Return the value (register eax).
873 __ ret(0);
874}
875
876
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000877// Generate code to check that a global property cell is empty. Create
878// the property cell at compilation time if no cell exists for the
879// property.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000880static void GenerateCheckPropertyCell(MacroAssembler* masm,
881 Handle<GlobalObject> global,
882 Handle<String> name,
883 Register scratch,
884 Label* miss) {
885 Handle<JSGlobalPropertyCell> cell =
886 GlobalObject::EnsurePropertyCell(global, name);
887 ASSERT(cell->value()->IsTheHole());
888 Handle<Oddball> the_hole = masm->isolate()->factory()->the_hole_value();
889 if (Serializer::enabled()) {
890 __ mov(scratch, Immediate(cell));
891 __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
892 Immediate(the_hole));
893 } else {
894 __ cmp(Operand::Cell(cell), Immediate(the_hole));
895 }
896 __ j(not_equal, miss);
897}
898
899
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000900// Calls GenerateCheckPropertyCell for each global object in the prototype chain
901// from object to (but not including) holder.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000902static void GenerateCheckPropertyCells(MacroAssembler* masm,
903 Handle<JSObject> object,
904 Handle<JSObject> holder,
905 Handle<String> name,
906 Register scratch,
907 Label* miss) {
908 Handle<JSObject> current = object;
909 while (!current.is_identical_to(holder)) {
910 if (current->IsGlobalObject()) {
911 GenerateCheckPropertyCell(masm,
912 Handle<GlobalObject>::cast(current),
913 name,
914 scratch,
915 miss);
916 }
917 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
918 }
919}
920
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000921#undef __
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000922#define __ ACCESS_MASM(masm())
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000923
924
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000925Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
926 Register object_reg,
927 Handle<JSObject> holder,
928 Register holder_reg,
929 Register scratch1,
930 Register scratch2,
931 Handle<String> name,
932 int save_at_depth,
933 Label* miss) {
934 // Make sure there's no overlap between holder and object registers.
935 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
936 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
937 && !scratch2.is(scratch1));
938
939 // Keep track of the current object in register reg.
940 Register reg = object_reg;
941 Handle<JSObject> current = object;
942 int depth = 0;
943
944 if (save_at_depth == depth) {
945 __ mov(Operand(esp, kPointerSize), reg);
946 }
947
948 // Traverse the prototype chain and check the maps in the prototype chain for
949 // fast and global objects or do negative lookup for normal objects.
950 while (!current.is_identical_to(holder)) {
951 ++depth;
952
953 // Only global objects and objects that do not require access
954 // checks are allowed in stubs.
955 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
956
957 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
958 if (!current->HasFastProperties() &&
959 !current->IsJSGlobalObject() &&
960 !current->IsJSGlobalProxy()) {
961 if (!name->IsSymbol()) {
962 name = factory()->LookupSymbol(name);
963 }
964 ASSERT(current->property_dictionary()->FindEntry(*name) ==
965 StringDictionary::kNotFound);
966
967 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
968 scratch1, scratch2);
969
970 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
971 reg = holder_reg; // From now on the object will be in holder_reg.
972 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
973 } else {
974 bool in_new_space = heap()->InNewSpace(*prototype);
975 Handle<Map> current_map(current->map());
976 if (in_new_space) {
977 // Save the map in scratch1 for later.
978 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000979 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000980 __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK,
981 ALLOW_ELEMENT_TRANSITION_MAPS);
982
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000983 // Check access rights to the global object. This has to happen after
984 // the map check so that we know that the object is actually a global
985 // object.
986 if (current->IsJSGlobalProxy()) {
987 __ CheckAccessGlobalProxy(reg, scratch2, miss);
988 }
989 reg = holder_reg; // From now on the object will be in holder_reg.
990
991 if (in_new_space) {
992 // The prototype is in new space; we cannot store a reference to it
993 // in the code. Load it from the map.
994 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
995 } else {
996 // The prototype is in old space; load it directly.
997 __ mov(reg, prototype);
998 }
999 }
1000
1001 if (save_at_depth == depth) {
1002 __ mov(Operand(esp, kPointerSize), reg);
1003 }
1004
1005 // Go to the next object in the prototype chain.
1006 current = prototype;
1007 }
1008 ASSERT(current.is_identical_to(holder));
1009
1010 // Log the check depth.
1011 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
1012
1013 // Check the holder map.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001014 __ CheckMap(reg, Handle<Map>(holder->map()),
1015 miss, DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001016
1017 // Perform security check for access to the global object.
1018 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1019 if (holder->IsJSGlobalProxy()) {
1020 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1021 }
1022
1023 // If we've skipped any global objects, it's not enough to verify that
1024 // their maps haven't changed. We also need to check that the property
1025 // cell for the property is still empty.
1026 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1027
1028 // Return the register containing the holder.
1029 return reg;
1030}
1031
1032
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001033void StubCompiler::GenerateLoadField(Handle<JSObject> object,
1034 Handle<JSObject> holder,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001035 Register receiver,
1036 Register scratch1,
1037 Register scratch2,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001038 Register scratch3,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001039 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001040 Handle<String> name,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001041 Label* miss) {
1042 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001043 __ JumpIfSmi(receiver, miss);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001044
1045 // Check the prototype chain.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001046 Register reg = CheckPrototypes(
1047 object, receiver, holder, scratch1, scratch2, scratch3, name, miss);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001048
1049 // Get the value from the properties.
1050 GenerateFastPropertyLoad(masm(), eax, reg, holder, index);
1051 __ ret(0);
1052}
1053
1054
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001055void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
1056 Handle<JSObject> holder,
1057 Register receiver,
1058 Register name_reg,
1059 Register scratch1,
1060 Register scratch2,
1061 Register scratch3,
1062 Handle<AccessorInfo> callback,
1063 Handle<String> name,
1064 Label* miss) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001065 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001066 __ JumpIfSmi(receiver, miss);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001067
1068 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001069 Register reg = CheckPrototypes(object, receiver, holder, scratch1,
1070 scratch2, scratch3, name, miss);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001071
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001072 // Insert additional parameters into the stack frame above return address.
1073 ASSERT(!scratch3.is(reg));
1074 __ pop(scratch3); // Get return address to place it below.
1075
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001076 __ push(receiver); // receiver
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001077 __ mov(scratch2, esp);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001078 ASSERT(!scratch2.is(reg));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001079 __ push(reg); // holder
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001080 // Push data from AccessorInfo.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001081 if (isolate()->heap()->InNewSpace(callback->data())) {
1082 __ mov(scratch1, Immediate(callback));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001083 __ push(FieldOperand(scratch1, AccessorInfo::kDataOffset));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001084 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001085 __ push(Immediate(Handle<Object>(callback->data())));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001086 }
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001087 __ push(Immediate(reinterpret_cast<int>(isolate())));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001088
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001089 // Save a pointer to where we pushed the arguments pointer.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001090 // This will be passed as the const AccessorInfo& to the C++ callback.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001091 __ push(scratch2);
1092
1093 __ push(name_reg); // name
1094 __ mov(ebx, esp); // esp points to reference to name (handler).
1095
1096 __ push(scratch3); // Restore return address.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001097
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001098 // 4 elements array for v8::Arguments::values_, handler for name and pointer
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001099 // to the values (it considered as smi in GC).
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001100 const int kStackSpace = 6;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001101 const int kApiArgc = 2;
1102
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001103 __ PrepareCallApiFunction(kApiArgc);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001104 __ mov(ApiParameterOperand(0), ebx); // name.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001105 __ add(ebx, Immediate(kPointerSize));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001106 __ mov(ApiParameterOperand(1), ebx); // arguments pointer.
1107
kmillikin@chromium.org2d5475f2009-12-20 18:15:52 +00001108 // Emitting a stub call may try to allocate (if the code is not
1109 // already generated). Do not allow the assembler to perform a
1110 // garbage collection but instead return the allocation failure
1111 // object.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001112 Address getter_address = v8::ToCData<Address>(callback->getter());
1113 __ CallApiFunctionAndReturn(getter_address, kStackSpace);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001114}
1115
1116
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001117void StubCompiler::GenerateLoadConstant(Handle<JSObject> object,
1118 Handle<JSObject> holder,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001119 Register receiver,
1120 Register scratch1,
1121 Register scratch2,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001122 Register scratch3,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001123 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001124 Handle<String> name,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001125 Label* miss) {
1126 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001127 __ JumpIfSmi(receiver, miss);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001128
1129 // Check that the maps haven't changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001130 CheckPrototypes(
1131 object, receiver, holder, scratch1, scratch2, scratch3, name, miss);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001132
1133 // Return the constant value.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001134 __ LoadHeapObject(eax, value);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001135 __ ret(0);
1136}
1137
1138
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001139void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
1140 Handle<JSObject> interceptor_holder,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001141 LookupResult* lookup,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001142 Register receiver,
1143 Register name_reg,
1144 Register scratch1,
1145 Register scratch2,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001146 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001147 Handle<String> name,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001148 Label* miss) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001149 ASSERT(interceptor_holder->HasNamedInterceptor());
1150 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1151
1152 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001153 __ JumpIfSmi(receiver, miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001154
1155 // So far the most popular follow ups for interceptor loads are FIELD
1156 // and CALLBACKS, so inline only them, other cases may be added
1157 // later.
1158 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001159 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001160 if (lookup->IsField()) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001161 compile_followup_inline = true;
1162 } else if (lookup->type() == CALLBACKS &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001163 lookup->GetCallbackObject()->IsAccessorInfo()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001164 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
1165 compile_followup_inline = callback->getter() != NULL &&
1166 callback->IsCompatibleReceiver(*object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001167 }
1168 }
1169
1170 if (compile_followup_inline) {
1171 // Compile the interceptor call, followed by inline code to load the
1172 // property from further up the prototype chain if the call fails.
1173 // Check that the maps haven't changed.
1174 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001175 scratch1, scratch2, scratch3,
1176 name, miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001177 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
1178
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001179 // Preserve the receiver register explicitly whenever it is different from
1180 // the holder and it is needed should the interceptor return without any
1181 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1182 // the FIELD case might cause a miss during the prototype check.
1183 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
1184 bool must_preserve_receiver_reg = !receiver.is(holder_reg) &&
1185 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1186
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001187 // Save necessary data before invoking an interceptor.
1188 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001189 {
1190 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001191
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001192 if (must_preserve_receiver_reg) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001193 __ push(receiver);
1194 }
1195 __ push(holder_reg);
1196 __ push(name_reg);
1197
1198 // Invoke an interceptor. Note: map checks from receiver to
1199 // interceptor's holder has been compiled before (see a caller
1200 // of this method.)
1201 CompileCallLoadPropertyWithInterceptor(masm(),
1202 receiver,
1203 holder_reg,
1204 name_reg,
1205 interceptor_holder);
1206
1207 // Check if interceptor provided a value for property. If it's
1208 // the case, return immediately.
1209 Label interceptor_failed;
1210 __ cmp(eax, factory()->no_interceptor_result_sentinel());
1211 __ j(equal, &interceptor_failed);
1212 frame_scope.GenerateLeaveFrame();
1213 __ ret(0);
1214
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001215 // Clobber registers when generating debug-code to provoke errors.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001216 __ bind(&interceptor_failed);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001217 if (FLAG_debug_code) {
1218 __ mov(receiver, Immediate(BitCast<int32_t>(kZapValue)));
1219 __ mov(holder_reg, Immediate(BitCast<int32_t>(kZapValue)));
1220 __ mov(name_reg, Immediate(BitCast<int32_t>(kZapValue)));
1221 }
1222
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001223 __ pop(name_reg);
1224 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001225 if (must_preserve_receiver_reg) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001226 __ pop(receiver);
1227 }
1228
1229 // Leave the internal frame.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001230 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001231
1232 // Check that the maps from interceptor's holder to lookup's holder
1233 // haven't changed. And load lookup's holder into holder_reg.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001234 if (must_perfrom_prototype_check) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001235 holder_reg = CheckPrototypes(interceptor_holder,
1236 holder_reg,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001237 Handle<JSObject>(lookup->holder()),
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001238 scratch1,
1239 scratch2,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001240 scratch3,
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001241 name,
1242 miss);
1243 }
1244
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001245 if (lookup->IsField()) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001246 // We found FIELD property in prototype chain of interceptor's holder.
1247 // Retrieve a field from field's holder.
1248 GenerateFastPropertyLoad(masm(), eax, holder_reg,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001249 Handle<JSObject>(lookup->holder()),
1250 lookup->GetFieldIndex());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001251 __ ret(0);
1252 } else {
1253 // We found CALLBACKS property in prototype chain of interceptor's
1254 // holder.
1255 ASSERT(lookup->type() == CALLBACKS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001256 Handle<AccessorInfo> callback(
1257 AccessorInfo::cast(lookup->GetCallbackObject()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001258 ASSERT(callback->getter() != NULL);
1259
1260 // Tail call to runtime.
1261 // Important invariant in CALLBACKS case: the code above must be
1262 // structured to never clobber |receiver| register.
1263 __ pop(scratch2); // return address
1264 __ push(receiver);
1265 __ push(holder_reg);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001266 __ mov(holder_reg, Immediate(callback));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001267 __ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset));
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001268 __ push(Immediate(reinterpret_cast<int>(isolate())));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001269 __ push(holder_reg);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001270 __ push(name_reg);
1271 __ push(scratch2); // restore return address
1272
1273 ExternalReference ref =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001274 ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
1275 masm()->isolate());
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001276 __ TailCallExternalReference(ref, 6, 1);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001277 }
1278 } else { // !compile_followup_inline
1279 // Call the runtime system to load the interceptor.
1280 // Check that the maps haven't changed.
1281 Register holder_reg =
1282 CheckPrototypes(object, receiver, interceptor_holder,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001283 scratch1, scratch2, scratch3, name, miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001284 __ pop(scratch2); // save old return address
1285 PushInterceptorArguments(masm(), receiver, holder_reg,
1286 name_reg, interceptor_holder);
1287 __ push(scratch2); // restore old return address
1288
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001289 ExternalReference ref =
1290 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001291 isolate());
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001292 __ TailCallExternalReference(ref, 6, 1);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001293 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001294}
1295
1296
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001297void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001298 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001299 __ cmp(ecx, Immediate(name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001300 __ j(not_equal, miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001301 }
1302}
1303
1304
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001305void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1306 Handle<JSObject> holder,
1307 Handle<String> name,
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001308 Label* miss) {
1309 ASSERT(holder->IsGlobalObject());
1310
1311 // Get the number of arguments.
1312 const int argc = arguments().immediate();
1313
1314 // Get the receiver from the stack.
1315 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1316
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001317
1318 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001319 __ JumpIfSmi(edx, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001320 CheckPrototypes(object, edx, holder, ebx, eax, edi, name, miss);
1321}
1322
1323
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001324void CallStubCompiler::GenerateLoadFunctionFromCell(
1325 Handle<JSGlobalPropertyCell> cell,
1326 Handle<JSFunction> function,
1327 Label* miss) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001328 // Get the value from the cell.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001329 if (Serializer::enabled()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001330 __ mov(edi, Immediate(cell));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001331 __ mov(edi, FieldOperand(edi, JSGlobalPropertyCell::kValueOffset));
1332 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001333 __ mov(edi, Operand::Cell(cell));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001334 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001335
1336 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001337 if (isolate()->heap()->InNewSpace(*function)) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001338 // We can't embed a pointer to a function in new space so we have
1339 // to verify that the shared function info is unchanged. This has
1340 // the nice side effect that multiple closures based on the same
1341 // function can all use this call IC. Before we load through the
1342 // function, we have to verify that it still is a function.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001343 __ JumpIfSmi(edi, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001344 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001345 __ j(not_equal, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001346
1347 // Check the shared function info. Make sure it hasn't changed.
1348 __ cmp(FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset),
1349 Immediate(Handle<SharedFunctionInfo>(function->shared())));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001350 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001351 __ cmp(edi, Immediate(function));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001352 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001353 __ j(not_equal, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001354}
1355
1356
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001357void CallStubCompiler::GenerateMissBranch() {
1358 Handle<Code> code =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001359 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
danno@chromium.org40cb8782011-05-25 07:58:50 +00001360 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001361 extra_state_);
1362 __ jmp(code, RelocInfo::CODE_TARGET);
1363}
1364
1365
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001366Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1367 Handle<JSObject> holder,
1368 int index,
1369 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001370 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001371 // -- ecx : name
1372 // -- esp[0] : return address
1373 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1374 // -- ...
1375 // -- esp[(argc + 1) * 4] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001376 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001377 Label miss;
1378
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001379 GenerateNameCheck(name, &miss);
1380
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001381 // Get the receiver from the stack.
1382 const int argc = arguments().immediate();
1383 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1384
1385 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001386 __ JumpIfSmi(edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001387
1388 // Do the right check and compute the holder register.
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001389 Register reg = CheckPrototypes(object, edx, holder, ebx, eax, edi,
1390 name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001391
ager@chromium.org7c537e22008-10-16 08:43:32 +00001392 GenerateFastPropertyLoad(masm(), edi, reg, holder, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001393
1394 // Check that the function really is a function.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001395 __ JumpIfSmi(edi, &miss);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001396 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001397 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001398
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001399 // Patch the receiver on the stack with the global proxy if
1400 // necessary.
1401 if (object->IsGlobalObject()) {
1402 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
1403 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
1404 }
1405
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001406 // Invoke the function.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001407 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001408 ? CALL_AS_FUNCTION
1409 : CALL_AS_METHOD;
1410 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION,
1411 NullCallWrapper(), call_kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001412
1413 // Handle call cache miss.
1414 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001415 GenerateMissBranch();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001416
1417 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001418 return GetCode(Code::FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001419}
1420
1421
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001422Handle<Code> CallStubCompiler::CompileArrayPushCall(
1423 Handle<Object> object,
1424 Handle<JSObject> holder,
1425 Handle<JSGlobalPropertyCell> cell,
1426 Handle<JSFunction> function,
1427 Handle<String> name) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001428 // ----------- S t a t e -------------
1429 // -- ecx : name
1430 // -- esp[0] : return address
1431 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1432 // -- ...
1433 // -- esp[(argc + 1) * 4] : receiver
1434 // -----------------------------------
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001435
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001436 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001437 if (!object->IsJSArray() || !cell.is_null()) {
1438 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001439 }
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001440
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001441 Label miss;
1442
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001443 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001444
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001445 // Get the receiver from the stack.
1446 const int argc = arguments().immediate();
1447 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1448
1449 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001450 __ JumpIfSmi(edx, &miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001451
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001452 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
1453 name, &miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001454
1455 if (argc == 0) {
1456 // Noop, return the length.
1457 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
1458 __ ret((argc + 1) * kPointerSize);
1459 } else {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001460 Label call_builtin;
1461
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001462 if (argc == 1) { // Otherwise fall through to call builtin.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001463 Label attempt_to_grow_elements, with_write_barrier;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001464
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001465 // Get the elements array of the object.
1466 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset));
1467
1468 // Check that the elements are in fast mode and writable.
1469 __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
1470 Immediate(factory()->fixed_array_map()));
1471 __ j(not_equal, &call_builtin);
1472
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001473 // Get the array's length into eax and calculate new length.
1474 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
1475 STATIC_ASSERT(kSmiTagSize == 1);
1476 STATIC_ASSERT(kSmiTag == 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001477 __ add(eax, Immediate(Smi::FromInt(argc)));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001478
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001479 // Get the elements' length into ecx.
1480 __ mov(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001481
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001482 // Check if we could survive without allocation.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001483 __ cmp(eax, ecx);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001484 __ j(greater, &attempt_to_grow_elements);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001485
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001486 // Check if value is a smi.
1487 __ mov(ecx, Operand(esp, argc * kPointerSize));
1488 __ JumpIfNotSmi(ecx, &with_write_barrier);
1489
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001490 // Save new length.
1491 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1492
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001493 // Store the value.
1494 __ mov(FieldOperand(edi,
1495 eax,
1496 times_half_pointer_size,
1497 FixedArray::kHeaderSize - argc * kPointerSize),
1498 ecx);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001499
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001500 __ ret((argc + 1) * kPointerSize);
1501
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001502 __ bind(&with_write_barrier);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001503
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001504 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
1505
1506 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
1507 Label fast_object, not_fast_object;
1508 __ CheckFastObjectElements(ebx, &not_fast_object, Label::kNear);
1509 __ jmp(&fast_object);
1510 // In case of fast smi-only, convert to fast object, otherwise bail out.
1511 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001512 __ CheckFastSmiElements(ebx, &call_builtin);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001513 // edi: elements array
1514 // edx: receiver
1515 // ebx: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001516 Label try_holey_map;
1517 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001518 FAST_ELEMENTS,
1519 ebx,
1520 edi,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001521 &try_holey_map);
1522
1523 ElementsTransitionGenerator::
1524 GenerateMapChangeElementsTransition(masm());
1525 // Restore edi.
1526 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset));
1527 __ jmp(&fast_object);
1528
1529 __ bind(&try_holey_map);
1530 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1531 FAST_HOLEY_ELEMENTS,
1532 ebx,
1533 edi,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001534 &call_builtin);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001535 ElementsTransitionGenerator::
1536 GenerateMapChangeElementsTransition(masm());
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001537 // Restore edi.
1538 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset));
1539 __ bind(&fast_object);
1540 } else {
1541 __ CheckFastObjectElements(ebx, &call_builtin);
1542 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001543
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001544 // Save new length.
1545 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1546
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001547 // Store the value.
1548 __ lea(edx, FieldOperand(edi,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001549 eax, times_half_pointer_size,
1550 FixedArray::kHeaderSize - argc * kPointerSize));
1551 __ mov(Operand(edx, 0), ecx);
1552
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001553 __ RecordWrite(edi, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001554 OMIT_SMI_CHECK);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001555
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001556 __ ret((argc + 1) * kPointerSize);
1557
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001558 __ bind(&attempt_to_grow_elements);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001559 if (!FLAG_inline_new) {
1560 __ jmp(&call_builtin);
1561 }
1562
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001563 __ mov(ebx, Operand(esp, argc * kPointerSize));
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001564 // Growing elements that are SMI-only requires special handling in case
1565 // the new element is non-Smi. For now, delegate to the builtin.
1566 Label no_fast_elements_check;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001567 __ JumpIfSmi(ebx, &no_fast_elements_check);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001568 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
1569 __ CheckFastObjectElements(ecx, &call_builtin, Label::kFar);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001570 __ bind(&no_fast_elements_check);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001571
1572 // We could be lucky and the elements array could be at the top of
1573 // new-space. In this case we can just grow it in place by moving the
1574 // allocation pointer up.
1575
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001576 ExternalReference new_space_allocation_top =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001577 ExternalReference::new_space_allocation_top_address(isolate());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001578 ExternalReference new_space_allocation_limit =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001579 ExternalReference::new_space_allocation_limit_address(isolate());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001580
1581 const int kAllocationDelta = 4;
1582 // Load top.
1583 __ mov(ecx, Operand::StaticVariable(new_space_allocation_top));
1584
1585 // Check if it's the end of elements.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001586 __ lea(edx, FieldOperand(edi,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001587 eax, times_half_pointer_size,
1588 FixedArray::kHeaderSize - argc * kPointerSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001589 __ cmp(edx, ecx);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001590 __ j(not_equal, &call_builtin);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001591 __ add(ecx, Immediate(kAllocationDelta * kPointerSize));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001592 __ cmp(ecx, Operand::StaticVariable(new_space_allocation_limit));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001593 __ j(above, &call_builtin);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001594
1595 // We fit and could grow elements.
1596 __ mov(Operand::StaticVariable(new_space_allocation_top), ecx);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001597
1598 // Push the argument...
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001599 __ mov(Operand(edx, 0), ebx);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001600 // ... and fill the rest with holes.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001601 for (int i = 1; i < kAllocationDelta; i++) {
1602 __ mov(Operand(edx, i * kPointerSize),
lrn@chromium.org7516f052011-03-30 08:52:27 +00001603 Immediate(factory()->the_hole_value()));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001604 }
1605
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001606 // We know the elements array is in new space so we don't need the
1607 // remembered set, but we just pushed a value onto it so we may have to
1608 // tell the incremental marker to rescan the object that we just grew. We
1609 // don't need to worry about the holes because they are in old space and
1610 // already marked black.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001611 __ RecordWrite(edi, edx, ebx, kDontSaveFPRegs, OMIT_REMEMBERED_SET);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001612
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001613 // Restore receiver to edx as finish sequence assumes it's here.
1614 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1615
1616 // Increment element's and array's sizes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001617 __ add(FieldOperand(edi, FixedArray::kLengthOffset),
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001618 Immediate(Smi::FromInt(kAllocationDelta)));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001619
1620 // NOTE: This only happen in new-space, where we don't
1621 // care about the black-byte-count on pages. Otherwise we should
1622 // update that too if the object is black.
1623
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001624 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1625
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001626 __ ret((argc + 1) * kPointerSize);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001627 }
1628
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001629 __ bind(&call_builtin);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001630 __ TailCallExternalReference(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001631 ExternalReference(Builtins::c_ArrayPush, isolate()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001632 argc + 1,
1633 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001634 }
1635
1636 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001637 GenerateMissBranch();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001638
1639 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001640 return GetCode(function);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001641}
1642
1643
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001644Handle<Code> CallStubCompiler::CompileArrayPopCall(
1645 Handle<Object> object,
1646 Handle<JSObject> holder,
1647 Handle<JSGlobalPropertyCell> cell,
1648 Handle<JSFunction> function,
1649 Handle<String> name) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001650 // ----------- S t a t e -------------
1651 // -- ecx : name
1652 // -- esp[0] : return address
1653 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1654 // -- ...
1655 // -- esp[(argc + 1) * 4] : receiver
1656 // -----------------------------------
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001657
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001658 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001659 if (!object->IsJSArray() || !cell.is_null()) {
1660 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001661 }
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001662
ager@chromium.orgac091b72010-05-05 07:34:42 +00001663 Label miss, return_undefined, call_builtin;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001664
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001665 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001666
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001667 // Get the receiver from the stack.
1668 const int argc = arguments().immediate();
1669 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1670
1671 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001672 __ JumpIfSmi(edx, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001673 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
1674 name, &miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001675
1676 // Get the elements array of the object.
1677 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset));
1678
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001679 // Check that the elements are in fast mode and writable.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001680 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
lrn@chromium.org7516f052011-03-30 08:52:27 +00001681 Immediate(factory()->fixed_array_map()));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001682 __ j(not_equal, &call_builtin);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001683
1684 // Get the array's length into ecx and calculate new length.
1685 __ mov(ecx, FieldOperand(edx, JSArray::kLengthOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001686 __ sub(ecx, Immediate(Smi::FromInt(1)));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001687 __ j(negative, &return_undefined);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001688
1689 // Get the last element.
1690 STATIC_ASSERT(kSmiTagSize == 1);
1691 STATIC_ASSERT(kSmiTag == 0);
1692 __ mov(eax, FieldOperand(ebx,
1693 ecx, times_half_pointer_size,
1694 FixedArray::kHeaderSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001695 __ cmp(eax, Immediate(factory()->the_hole_value()));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001696 __ j(equal, &call_builtin);
1697
1698 // Set the array's length.
1699 __ mov(FieldOperand(edx, JSArray::kLengthOffset), ecx);
1700
1701 // Fill with the hole.
1702 __ mov(FieldOperand(ebx,
1703 ecx, times_half_pointer_size,
1704 FixedArray::kHeaderSize),
lrn@chromium.org7516f052011-03-30 08:52:27 +00001705 Immediate(factory()->the_hole_value()));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001706 __ ret((argc + 1) * kPointerSize);
1707
ager@chromium.orgac091b72010-05-05 07:34:42 +00001708 __ bind(&return_undefined);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001709 __ mov(eax, Immediate(factory()->undefined_value()));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001710 __ ret((argc + 1) * kPointerSize);
1711
1712 __ bind(&call_builtin);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001713 __ TailCallExternalReference(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001714 ExternalReference(Builtins::c_ArrayPop, isolate()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001715 argc + 1,
1716 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001717
1718 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001719 GenerateMissBranch();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001720
1721 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001722 return GetCode(function);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001723}
1724
1725
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001726Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1727 Handle<Object> object,
1728 Handle<JSObject> holder,
1729 Handle<JSGlobalPropertyCell> cell,
1730 Handle<JSFunction> function,
1731 Handle<String> name) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001732 // ----------- S t a t e -------------
1733 // -- ecx : function name
1734 // -- esp[0] : return address
1735 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1736 // -- ...
1737 // -- esp[(argc + 1) * 4] : receiver
1738 // -----------------------------------
1739
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001740 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001741 if (!object->IsString() || !cell.is_null()) {
1742 return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001743 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001744
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001745 const int argc = arguments().immediate();
1746
1747 Label miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001748 Label name_miss;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001749 Label index_out_of_range;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001750 Label* index_out_of_range_label = &index_out_of_range;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001751
danno@chromium.org40cb8782011-05-25 07:58:50 +00001752 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001753 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001754 DEFAULT_STRING_STUB)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001755 index_out_of_range_label = &miss;
1756 }
1757
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001758 GenerateNameCheck(name, &name_miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001759
1760 // Check that the maps starting from the prototype haven't changed.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001761 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1762 Context::STRING_FUNCTION_INDEX,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001763 eax,
1764 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001765 ASSERT(!object.is_identical_to(holder));
1766 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1767 eax, holder, ebx, edx, edi, name, &miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001768
1769 Register receiver = ebx;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001770 Register index = edi;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001771 Register result = eax;
1772 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize));
1773 if (argc > 0) {
1774 __ mov(index, Operand(esp, (argc - 0) * kPointerSize));
1775 } else {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001776 __ Set(index, Immediate(factory()->undefined_value()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001777 }
1778
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001779 StringCharCodeAtGenerator generator(receiver,
1780 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001781 result,
1782 &miss, // When not a string.
1783 &miss, // When not a number.
1784 index_out_of_range_label,
1785 STRING_INDEX_IS_NUMBER);
1786 generator.GenerateFast(masm());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001787 __ ret((argc + 1) * kPointerSize);
1788
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001789 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001790 generator.GenerateSlow(masm(), call_helper);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001791
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001792 if (index_out_of_range.is_linked()) {
1793 __ bind(&index_out_of_range);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001794 __ Set(eax, Immediate(factory()->nan_value()));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001795 __ ret((argc + 1) * kPointerSize);
1796 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001797
1798 __ bind(&miss);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001799 // Restore function name in ecx.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001800 __ Set(ecx, Immediate(name));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001801 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001802 GenerateMissBranch();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001803
1804 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001805 return GetCode(function);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001806}
1807
1808
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001809Handle<Code> CallStubCompiler::CompileStringCharAtCall(
1810 Handle<Object> object,
1811 Handle<JSObject> holder,
1812 Handle<JSGlobalPropertyCell> cell,
1813 Handle<JSFunction> function,
1814 Handle<String> name) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001815 // ----------- S t a t e -------------
1816 // -- ecx : function name
1817 // -- esp[0] : return address
1818 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1819 // -- ...
1820 // -- esp[(argc + 1) * 4] : receiver
1821 // -----------------------------------
1822
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001823 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001824 if (!object->IsString() || !cell.is_null()) {
1825 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001826 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001827
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001828 const int argc = arguments().immediate();
1829
1830 Label miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001831 Label name_miss;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001832 Label index_out_of_range;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001833 Label* index_out_of_range_label = &index_out_of_range;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001834
danno@chromium.org40cb8782011-05-25 07:58:50 +00001835 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001836 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001837 DEFAULT_STRING_STUB)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001838 index_out_of_range_label = &miss;
1839 }
1840
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001841 GenerateNameCheck(name, &name_miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001842
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001843 // Check that the maps starting from the prototype haven't changed.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001844 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1845 Context::STRING_FUNCTION_INDEX,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001846 eax,
1847 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001848 ASSERT(!object.is_identical_to(holder));
1849 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1850 eax, holder, ebx, edx, edi, name, &miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001851
1852 Register receiver = eax;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001853 Register index = edi;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001854 Register scratch = edx;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001855 Register result = eax;
1856 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize));
1857 if (argc > 0) {
1858 __ mov(index, Operand(esp, (argc - 0) * kPointerSize));
1859 } else {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001860 __ Set(index, Immediate(factory()->undefined_value()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001861 }
1862
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001863 StringCharAtGenerator generator(receiver,
1864 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00001865 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001866 result,
1867 &miss, // When not a string.
1868 &miss, // When not a number.
1869 index_out_of_range_label,
1870 STRING_INDEX_IS_NUMBER);
1871 generator.GenerateFast(masm());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001872 __ ret((argc + 1) * kPointerSize);
1873
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001874 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001875 generator.GenerateSlow(masm(), call_helper);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001876
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001877 if (index_out_of_range.is_linked()) {
1878 __ bind(&index_out_of_range);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001879 __ Set(eax, Immediate(factory()->empty_string()));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001880 __ ret((argc + 1) * kPointerSize);
1881 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001882
1883 __ bind(&miss);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001884 // Restore function name in ecx.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001885 __ Set(ecx, Immediate(name));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001886 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001887 GenerateMissBranch();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001888
1889 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001890 return GetCode(function);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001891}
1892
1893
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001894Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
1895 Handle<Object> object,
1896 Handle<JSObject> holder,
1897 Handle<JSGlobalPropertyCell> cell,
1898 Handle<JSFunction> function,
1899 Handle<String> name) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001900 // ----------- S t a t e -------------
1901 // -- ecx : function name
1902 // -- esp[0] : return address
1903 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1904 // -- ...
1905 // -- esp[(argc + 1) * 4] : receiver
1906 // -----------------------------------
1907
1908 const int argc = arguments().immediate();
1909
1910 // If the object is not a JSObject or we got an unexpected number of
1911 // arguments, bail out to the regular call.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001912 if (!object->IsJSObject() || argc != 1) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001913 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001914 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001915
1916 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001917 GenerateNameCheck(name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001918
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001919 if (cell.is_null()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001920 __ mov(edx, Operand(esp, 2 * kPointerSize));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001921 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001922 __ JumpIfSmi(edx, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001923 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
1924 name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001925 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001926 ASSERT(cell->value() == *function);
1927 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
1928 &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001929 GenerateLoadFunctionFromCell(cell, function, &miss);
1930 }
1931
1932 // Load the char code argument.
1933 Register code = ebx;
1934 __ mov(code, Operand(esp, 1 * kPointerSize));
1935
1936 // Check the code is a smi.
1937 Label slow;
1938 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001939 __ JumpIfNotSmi(code, &slow);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001940
1941 // Convert the smi code to uint16.
1942 __ and_(code, Immediate(Smi::FromInt(0xffff)));
1943
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001944 StringCharFromCodeGenerator generator(code, eax);
1945 generator.GenerateFast(masm());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001946 __ ret(2 * kPointerSize);
1947
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001948 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001949 generator.GenerateSlow(masm(), call_helper);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001950
1951 // Tail call the full function. We do not have to patch the receiver
1952 // because the function makes no use of it.
1953 __ bind(&slow);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001954 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001955 ? CALL_AS_FUNCTION
1956 : CALL_AS_METHOD;
1957 __ InvokeFunction(function, arguments(), JUMP_FUNCTION,
1958 NullCallWrapper(), call_kind);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001959
1960 __ bind(&miss);
1961 // ecx: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001962 GenerateMissBranch();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001963
1964 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001965 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001966}
1967
1968
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001969Handle<Code> CallStubCompiler::CompileMathFloorCall(
1970 Handle<Object> object,
1971 Handle<JSObject> holder,
1972 Handle<JSGlobalPropertyCell> cell,
1973 Handle<JSFunction> function,
1974 Handle<String> name) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001975 // ----------- S t a t e -------------
1976 // -- ecx : name
1977 // -- esp[0] : return address
1978 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1979 // -- ...
1980 // -- esp[(argc + 1) * 4] : receiver
1981 // -----------------------------------
1982
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001983 if (!CpuFeatures::IsSupported(SSE2)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001984 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001985 }
1986
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001987 CpuFeatures::Scope use_sse2(SSE2);
1988
1989 const int argc = arguments().immediate();
1990
1991 // If the object is not a JSObject or we got an unexpected number of
1992 // arguments, bail out to the regular call.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001993 if (!object->IsJSObject() || argc != 1) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001994 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001995 }
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001996
1997 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001998 GenerateNameCheck(name, &miss);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001999
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002000 if (cell.is_null()) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002001 __ mov(edx, Operand(esp, 2 * kPointerSize));
2002
2003 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002004 __ JumpIfSmi(edx, &miss);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002005
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002006 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2007 name, &miss);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002008 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002009 ASSERT(cell->value() == *function);
2010 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2011 &miss);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002012 GenerateLoadFunctionFromCell(cell, function, &miss);
2013 }
2014
2015 // Load the (only) argument into eax.
2016 __ mov(eax, Operand(esp, 1 * kPointerSize));
2017
2018 // Check if the argument is a smi.
2019 Label smi;
2020 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002021 __ JumpIfSmi(eax, &smi);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002022
2023 // Check if the argument is a heap number and load its value into xmm0.
2024 Label slow;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002025 __ CheckMap(eax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002026 __ movdbl(xmm0, FieldOperand(eax, HeapNumber::kValueOffset));
2027
2028 // Check if the argument is strictly positive. Note this also
2029 // discards NaN.
2030 __ xorpd(xmm1, xmm1);
2031 __ ucomisd(xmm0, xmm1);
2032 __ j(below_equal, &slow);
2033
2034 // Do a truncating conversion.
2035 __ cvttsd2si(eax, Operand(xmm0));
2036
2037 // Check if the result fits into a smi. Note this also checks for
2038 // 0x80000000 which signals a failed conversion.
2039 Label wont_fit_into_smi;
2040 __ test(eax, Immediate(0xc0000000));
2041 __ j(not_zero, &wont_fit_into_smi);
2042
2043 // Smi tag and return.
2044 __ SmiTag(eax);
2045 __ bind(&smi);
2046 __ ret(2 * kPointerSize);
2047
2048 // Check if the argument is < 2^kMantissaBits.
2049 Label already_round;
2050 __ bind(&wont_fit_into_smi);
2051 __ LoadPowerOf2(xmm1, ebx, HeapNumber::kMantissaBits);
2052 __ ucomisd(xmm0, xmm1);
2053 __ j(above_equal, &already_round);
2054
2055 // Save a copy of the argument.
2056 __ movaps(xmm2, xmm0);
2057
2058 // Compute (argument + 2^kMantissaBits) - 2^kMantissaBits.
2059 __ addsd(xmm0, xmm1);
2060 __ subsd(xmm0, xmm1);
2061
2062 // Compare the argument and the tentative result to get the right mask:
2063 // if xmm2 < xmm0:
2064 // xmm2 = 1...1
2065 // else:
2066 // xmm2 = 0...0
2067 __ cmpltsd(xmm2, xmm0);
2068
2069 // Subtract 1 if the argument was less than the tentative result.
2070 __ LoadPowerOf2(xmm1, ebx, 0);
2071 __ andpd(xmm1, xmm2);
2072 __ subsd(xmm0, xmm1);
2073
2074 // Return a new heap number.
2075 __ AllocateHeapNumber(eax, ebx, edx, &slow);
2076 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
2077 __ ret(2 * kPointerSize);
2078
2079 // Return the argument (when it's an already round heap number).
2080 __ bind(&already_round);
2081 __ mov(eax, Operand(esp, 1 * kPointerSize));
2082 __ ret(2 * kPointerSize);
2083
2084 // Tail call the full function. We do not have to patch the receiver
2085 // because the function makes no use of it.
2086 __ bind(&slow);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002087 __ InvokeFunction(function, arguments(), JUMP_FUNCTION,
2088 NullCallWrapper(), CALL_AS_METHOD);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002089
2090 __ bind(&miss);
2091 // ecx: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002092 GenerateMissBranch();
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002093
2094 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002095 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002096}
2097
2098
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002099Handle<Code> CallStubCompiler::CompileMathAbsCall(
2100 Handle<Object> object,
2101 Handle<JSObject> holder,
2102 Handle<JSGlobalPropertyCell> cell,
2103 Handle<JSFunction> function,
2104 Handle<String> name) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002105 // ----------- S t a t e -------------
2106 // -- ecx : name
2107 // -- esp[0] : return address
2108 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2109 // -- ...
2110 // -- esp[(argc + 1) * 4] : receiver
2111 // -----------------------------------
2112
2113 const int argc = arguments().immediate();
2114
2115 // If the object is not a JSObject or we got an unexpected number of
2116 // arguments, bail out to the regular call.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002117 if (!object->IsJSObject() || argc != 1) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002118 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002119 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002120
2121 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002122 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002123
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002124 if (cell.is_null()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002125 __ mov(edx, Operand(esp, 2 * kPointerSize));
2126
2127 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002128 __ JumpIfSmi(edx, &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002129
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002130 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2131 name, &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002132 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002133 ASSERT(cell->value() == *function);
2134 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2135 &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002136 GenerateLoadFunctionFromCell(cell, function, &miss);
2137 }
2138
2139 // Load the (only) argument into eax.
2140 __ mov(eax, Operand(esp, 1 * kPointerSize));
2141
2142 // Check if the argument is a smi.
2143 Label not_smi;
2144 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002145 __ JumpIfNotSmi(eax, &not_smi);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002146
2147 // Set ebx to 1...1 (== -1) if the argument is negative, or to 0...0
2148 // otherwise.
2149 __ mov(ebx, eax);
2150 __ sar(ebx, kBitsPerInt - 1);
2151
2152 // Do bitwise not or do nothing depending on ebx.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002153 __ xor_(eax, ebx);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002154
2155 // Add 1 or do nothing depending on ebx.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002156 __ sub(eax, ebx);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002157
2158 // If the result is still negative, go to the slow case.
2159 // This only happens for the most negative smi.
2160 Label slow;
2161 __ j(negative, &slow);
2162
2163 // Smi case done.
2164 __ ret(2 * kPointerSize);
2165
2166 // Check if the argument is a heap number and load its exponent and
2167 // sign into ebx.
2168 __ bind(&not_smi);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002169 __ CheckMap(eax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002170 __ mov(ebx, FieldOperand(eax, HeapNumber::kExponentOffset));
2171
2172 // Check the sign of the argument. If the argument is positive,
2173 // just return it.
2174 Label negative_sign;
2175 __ test(ebx, Immediate(HeapNumber::kSignMask));
2176 __ j(not_zero, &negative_sign);
2177 __ ret(2 * kPointerSize);
2178
2179 // If the argument is negative, clear the sign, and return a new
2180 // number.
2181 __ bind(&negative_sign);
2182 __ and_(ebx, ~HeapNumber::kSignMask);
2183 __ mov(ecx, FieldOperand(eax, HeapNumber::kMantissaOffset));
2184 __ AllocateHeapNumber(eax, edi, edx, &slow);
2185 __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), ebx);
2186 __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx);
2187 __ ret(2 * kPointerSize);
2188
2189 // Tail call the full function. We do not have to patch the receiver
2190 // because the function makes no use of it.
2191 __ bind(&slow);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002192 __ InvokeFunction(function, arguments(), JUMP_FUNCTION,
2193 NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002194
2195 __ bind(&miss);
2196 // ecx: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002197 GenerateMissBranch();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002198
2199 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002200 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002201}
2202
2203
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002204Handle<Code> CallStubCompiler::CompileFastApiCall(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002205 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002206 Handle<Object> object,
2207 Handle<JSObject> holder,
2208 Handle<JSGlobalPropertyCell> cell,
2209 Handle<JSFunction> function,
2210 Handle<String> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002211 ASSERT(optimization.is_simple_api_call());
2212 // Bail out if object is a global object as we don't want to
2213 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002214 if (object->IsGlobalObject()) return Handle<Code>::null();
2215 if (!cell.is_null()) return Handle<Code>::null();
2216 if (!object->IsJSObject()) return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002217 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002218 Handle<JSObject>::cast(object), holder);
2219 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002220
2221 Label miss, miss_before_stack_reserved;
2222
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002223 GenerateNameCheck(name, &miss_before_stack_reserved);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002224
2225 // Get the receiver from the stack.
2226 const int argc = arguments().immediate();
2227 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
2228
2229 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002230 __ JumpIfSmi(edx, &miss_before_stack_reserved);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002231
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002232 Counters* counters = isolate()->counters();
2233 __ IncrementCounter(counters->call_const(), 1);
2234 __ IncrementCounter(counters->call_const_fast_api(), 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002235
2236 // Allocate space for v8::Arguments implicit values. Must be initialized
2237 // before calling any runtime function.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002238 __ sub(esp, Immediate(kFastApiCallArguments * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002239
2240 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002241 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2242 name, depth, &miss);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002243
2244 // Move the return address on top of the stack.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00002245 __ mov(eax, Operand(esp, 4 * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002246 __ mov(Operand(esp, 0 * kPointerSize), eax);
2247
2248 // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains
2249 // duplicate of return address and will be overwritten.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002250 GenerateFastApiCall(masm(), optimization, argc);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002251
2252 __ bind(&miss);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002253 __ add(esp, Immediate(kFastApiCallArguments * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002254
2255 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002256 GenerateMissBranch();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002257
2258 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002259 return GetCode(function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002260}
2261
2262
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002263Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object,
2264 Handle<JSObject> holder,
2265 Handle<JSFunction> function,
2266 Handle<String> name,
2267 CheckType check) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002268 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00002269 // -- ecx : name
2270 // -- esp[0] : return address
2271 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2272 // -- ...
2273 // -- esp[(argc + 1) * 4] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002274 // -----------------------------------
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002275
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002276 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002277 Handle<Code> code = CompileCustomCall(object, holder,
2278 Handle<JSGlobalPropertyCell>::null(),
2279 function, name);
2280 // A null handle means bail out to the regular compiler code below.
2281 if (!code.is_null()) return code;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002282 }
2283
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002284 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002285 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002286
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002287 // Get the receiver from the stack.
2288 const int argc = arguments().immediate();
2289 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
2290
2291 // Check that the receiver isn't a smi.
2292 if (check != NUMBER_CHECK) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00002293 __ JumpIfSmi(edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002294 }
2295
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002296 // Make sure that it's okay not to patch the on stack receiver
2297 // unless we're doing a receiver map check.
2298 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002299 switch (check) {
2300 case RECEIVER_MAP_CHECK:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002301 __ IncrementCounter(isolate()->counters()->call_const(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00002302
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002303 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002304 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax,
2305 edi, name, &miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002306
2307 // Patch the receiver on the stack with the global proxy if
2308 // necessary.
2309 if (object->IsGlobalObject()) {
2310 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
2311 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
2312 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002313 break;
2314
2315 case STRING_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002316 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002317 // Check that the object is a string or a symbol.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002318 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, eax);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002319 __ j(above_equal, &miss);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002320 // Check that the maps starting from the prototype haven't changed.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002321 GenerateDirectLoadGlobalFunctionPrototype(
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002322 masm(), Context::STRING_FUNCTION_INDEX, eax, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002323 CheckPrototypes(
2324 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2325 eax, holder, ebx, edx, edi, name, &miss);
2326 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002327 // Calling non-strict non-builtins with a value as the receiver
2328 // requires boxing.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002329 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002330 }
2331 break;
2332
2333 case NUMBER_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002334 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002335 Label fast;
2336 // Check that the object is a smi or a heap number.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002337 __ JumpIfSmi(edx, &fast);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002338 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, eax);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002339 __ j(not_equal, &miss);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002340 __ bind(&fast);
2341 // Check that the maps starting from the prototype haven't changed.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002342 GenerateDirectLoadGlobalFunctionPrototype(
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002343 masm(), Context::NUMBER_FUNCTION_INDEX, eax, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002344 CheckPrototypes(
2345 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2346 eax, holder, ebx, edx, edi, name, &miss);
2347 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002348 // Calling non-strict non-builtins with a value as the receiver
2349 // requires boxing.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002350 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002351 }
2352 break;
2353
2354 case BOOLEAN_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002355 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002356 Label fast;
2357 // Check that the object is a boolean.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002358 __ cmp(edx, factory()->true_value());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002359 __ j(equal, &fast);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002360 __ cmp(edx, factory()->false_value());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002361 __ j(not_equal, &miss);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002362 __ bind(&fast);
2363 // Check that the maps starting from the prototype haven't changed.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002364 GenerateDirectLoadGlobalFunctionPrototype(
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002365 masm(), Context::BOOLEAN_FUNCTION_INDEX, eax, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002366 CheckPrototypes(
2367 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2368 eax, holder, ebx, edx, edi, name, &miss);
2369 } else {
2370 // Calling non-strict non-builtins with a value as the receiver
2371 // requires boxing.
2372 __ jmp(&miss);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002373 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002374 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002375 }
2376
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002377 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002378 ? CALL_AS_FUNCTION
2379 : CALL_AS_METHOD;
2380 __ InvokeFunction(function, arguments(), JUMP_FUNCTION,
2381 NullCallWrapper(), call_kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002382
2383 // Handle call cache miss.
2384 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002385 GenerateMissBranch();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002386
2387 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002388 return GetCode(function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002389}
2390
2391
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002392Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2393 Handle<JSObject> holder,
2394 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002395 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00002396 // -- ecx : name
2397 // -- esp[0] : return address
2398 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2399 // -- ...
2400 // -- esp[(argc + 1) * 4] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002401 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002402 Label miss;
2403
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002404 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002405
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002406 // Get the number of arguments.
2407 const int argc = arguments().immediate();
2408
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002409 LookupResult lookup(isolate());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002410 LookupPostInterceptor(holder, name, &lookup);
2411
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002412 // Get the receiver from the stack.
2413 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002414
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002415 CallInterceptorCompiler compiler(this, arguments(), ecx, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002416 compiler.Compile(masm(), object, holder, name, &lookup, edx, ebx, edi, eax,
2417 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002418
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002419 // Restore receiver.
2420 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002421
2422 // Check that the function really is a function.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002423 __ JumpIfSmi(eax, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002424 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002425 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002426
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002427 // Patch the receiver on the stack with the global proxy if
2428 // necessary.
2429 if (object->IsGlobalObject()) {
2430 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
2431 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
2432 }
2433
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002434 // Invoke the function.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002435 __ mov(edi, eax);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002436 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002437 ? CALL_AS_FUNCTION
2438 : CALL_AS_METHOD;
2439 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION,
2440 NullCallWrapper(), call_kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002441
2442 // Handle load cache miss.
2443 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002444 GenerateMissBranch();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002445
2446 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002447 return GetCode(Code::INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002448}
2449
2450
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002451Handle<Code> CallStubCompiler::CompileCallGlobal(
2452 Handle<JSObject> object,
2453 Handle<GlobalObject> holder,
2454 Handle<JSGlobalPropertyCell> cell,
2455 Handle<JSFunction> function,
2456 Handle<String> name) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002457 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00002458 // -- ecx : name
2459 // -- esp[0] : return address
2460 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2461 // -- ...
2462 // -- esp[(argc + 1) * 4] : receiver
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002463 // -----------------------------------
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002464
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002465 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002466 Handle<Code> code = CompileCustomCall(object, holder, cell, function, name);
2467 // A null handle means bail out to the regular compiler code below.
2468 if (!code.is_null()) return code;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002469 }
2470
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002471 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002472 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002473
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002474 // Get the number of arguments.
2475 const int argc = arguments().immediate();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002476 GenerateGlobalReceiverCheck(object, holder, name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002477 GenerateLoadFunctionFromCell(cell, function, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002478
2479 // Patch the receiver on the stack with the global proxy.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002480 if (object->IsGlobalObject()) {
2481 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
2482 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
2483 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002484
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002485 // Set up the context (function already in edi).
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002486 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
2487
2488 // Jump to the cached code (tail call).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002489 Counters* counters = isolate()->counters();
2490 __ IncrementCounter(counters->call_global_inline(), 1);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002491 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002492 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002493 ? CALL_AS_FUNCTION
2494 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002495 // We call indirectly through the code field in the function to
2496 // allow recompilation to take effect without changing any of the
2497 // call sites.
2498 __ InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset),
2499 expected, arguments(), JUMP_FUNCTION,
2500 NullCallWrapper(), call_kind);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002501
2502 // Handle call cache miss.
2503 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002504 __ IncrementCounter(counters->call_global_inline_miss(), 1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002505 GenerateMissBranch();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002506
2507 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002508 return GetCode(Code::NORMAL, name);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002509}
2510
2511
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002512Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002513 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002514 Handle<Map> transition,
2515 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002516 // ----------- S t a t e -------------
2517 // -- eax : value
2518 // -- ecx : name
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002519 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002520 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002521 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002522 Label miss;
2523
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002524 // Generate store field code. Trashes the name register.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002525 GenerateStoreField(masm(),
2526 object,
2527 index,
2528 transition,
2529 name,
2530 edx, ecx, ebx, edi,
2531 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002532 // Handle store cache miss.
2533 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002534 __ mov(ecx, Immediate(name)); // restore name
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002535 Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
ager@chromium.org236ad962008-09-25 09:45:57 +00002536 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002537
2538 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002539 return GetCode(transition.is_null()
2540 ? Code::FIELD
2541 : Code::MAP_TRANSITION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002542}
2543
2544
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002545Handle<Code> StoreStubCompiler::CompileStoreCallback(
2546 Handle<JSObject> object,
2547 Handle<AccessorInfo> callback,
2548 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002549 // ----------- S t a t e -------------
2550 // -- eax : value
2551 // -- ecx : name
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002552 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002553 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002554 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002555 Label miss;
2556
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002557 // Check that the map of the object hasn't changed.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002558 __ CheckMap(edx, Handle<Map>(object->map()),
2559 &miss, DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002560
2561 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002562 if (object->IsJSGlobalProxy()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002563 __ CheckAccessGlobalProxy(edx, ebx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002564 }
2565
2566 // Stub never generated for non-global objects that require access
2567 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002568 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002569
2570 __ pop(ebx); // remove the return address
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002571 __ push(edx); // receiver
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002572 __ push(Immediate(callback)); // callback info
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002573 __ push(ecx); // name
2574 __ push(eax); // value
2575 __ push(ebx); // restore return address
2576
mads.s.ager31e71382008-08-13 09:32:07 +00002577 // Do tail-call to the runtime system.
2578 ExternalReference store_callback_property =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002579 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002580 __ TailCallExternalReference(store_callback_property, 4, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002581
2582 // Handle store cache miss.
2583 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002584 Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
ager@chromium.org236ad962008-09-25 09:45:57 +00002585 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002586
2587 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002588 return GetCode(Code::CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002589}
2590
2591
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002592Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002593 Handle<String> name,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002594 Handle<JSObject> receiver,
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002595 Handle<JSObject> holder,
2596 Handle<JSFunction> setter) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002597 // ----------- S t a t e -------------
2598 // -- eax : value
2599 // -- ecx : name
2600 // -- edx : receiver
2601 // -- esp[0] : return address
2602 // -----------------------------------
2603 Label miss;
2604
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002605 // Check that the maps haven't changed, preserving the name register.
2606 __ push(ecx);
2607 __ JumpIfSmi(edx, &miss);
2608 CheckPrototypes(receiver, edx, holder, ebx, ecx, edi, name, &miss);
2609 __ pop(ecx);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002610
2611 {
2612 FrameScope scope(masm(), StackFrame::INTERNAL);
2613
2614 // Save value register, so we can restore it later.
2615 __ push(eax);
2616
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002617 // Call the JavaScript setter with the receiver and the value on the stack.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002618 __ push(edx);
2619 __ push(eax);
2620 ParameterCount actual(1);
2621 __ InvokeFunction(setter, actual, CALL_FUNCTION, NullCallWrapper(),
2622 CALL_AS_METHOD);
2623
2624 // We have to return the passed value, not the return value of the setter.
2625 __ pop(eax);
2626
2627 // Restore context register.
2628 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
2629 }
2630 __ ret(0);
2631
2632 __ bind(&miss);
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002633 __ pop(ecx);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002634 Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
2635 __ jmp(ic, RelocInfo::CODE_TARGET);
2636
2637 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002638 return GetCode(Code::CALLBACKS, name);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002639}
2640
2641
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002642Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
2643 Handle<JSObject> receiver,
2644 Handle<String> name) {
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;
2652
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002653 // Check that the map of the object hasn't changed.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002654 __ CheckMap(edx, Handle<Map>(receiver->map()),
2655 &miss, DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002656
2657 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002658 if (receiver->IsJSGlobalProxy()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002659 __ CheckAccessGlobalProxy(edx, ebx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002660 }
2661
2662 // Stub never generated for non-global objects that require access
2663 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002664 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002665
2666 __ pop(ebx); // remove the return address
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002667 __ push(edx); // receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002668 __ push(ecx); // name
2669 __ push(eax); // value
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002670 __ push(Immediate(Smi::FromInt(strict_mode_)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002671 __ push(ebx); // restore return address
2672
mads.s.ager31e71382008-08-13 09:32:07 +00002673 // Do tail-call to the runtime system.
2674 ExternalReference store_ic_property =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002675 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002676 __ TailCallExternalReference(store_ic_property, 4, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002677
2678 // Handle store cache miss.
2679 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002680 Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
ager@chromium.org236ad962008-09-25 09:45:57 +00002681 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002682
2683 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002684 return GetCode(Code::INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002685}
2686
2687
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002688Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2689 Handle<GlobalObject> object,
2690 Handle<JSGlobalPropertyCell> cell,
2691 Handle<String> name) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002692 // ----------- S t a t e -------------
2693 // -- eax : value
2694 // -- ecx : name
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002695 // -- edx : receiver
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002696 // -- esp[0] : return address
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002697 // -----------------------------------
2698 Label miss;
2699
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002700 // Check that the map of the global has not changed.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002701 __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002702 Immediate(Handle<Map>(object->map())));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002703 __ j(not_equal, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002704
ager@chromium.org378b34e2011-01-28 08:04:38 +00002705 // Compute the cell operand to use.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002706 __ mov(ebx, Immediate(cell));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002707 Operand cell_operand = FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002708
ager@chromium.org378b34e2011-01-28 08:04:38 +00002709 // Check that the value in the cell is not the hole. If it is, this
2710 // cell could have been deleted and reintroducing the global needs
2711 // to update the property details in the property dictionary of the
2712 // global object. We bail out to the runtime system to do that.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002713 __ cmp(cell_operand, factory()->the_hole_value());
ager@chromium.org378b34e2011-01-28 08:04:38 +00002714 __ j(equal, &miss);
2715
2716 // Store the value in the cell.
2717 __ mov(cell_operand, eax);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002718 // No write barrier here, because cells are always rescanned.
ager@chromium.org378b34e2011-01-28 08:04:38 +00002719
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002720 // Return the value (register eax).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002721 Counters* counters = isolate()->counters();
2722 __ IncrementCounter(counters->named_store_global_inline(), 1);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002723 __ ret(0);
2724
2725 // Handle store cache miss.
2726 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002727 __ IncrementCounter(counters->named_store_global_inline_miss(), 1);
2728 Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002729 __ jmp(ic, RelocInfo::CODE_TARGET);
2730
2731 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002732 return GetCode(Code::NORMAL, name);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002733}
2734
2735
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002736Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002737 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002738 Handle<Map> transition,
2739 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002740 // ----------- S t a t e -------------
2741 // -- eax : value
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002742 // -- ecx : key
2743 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002744 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002745 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002746 Label miss;
2747
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002748 Counters* counters = isolate()->counters();
2749 __ IncrementCounter(counters->keyed_store_field(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002750
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002751 // Check that the name has not changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002752 __ cmp(ecx, Immediate(name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002753 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002754
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002755 // Generate store field code. Trashes the name register.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002756 GenerateStoreField(masm(),
2757 object,
2758 index,
2759 transition,
2760 name,
2761 edx, ecx, ebx, edi,
2762 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002763
2764 // Handle store cache miss.
2765 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002766 __ DecrementCounter(counters->keyed_store_field(), 1);
2767 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
ager@chromium.org236ad962008-09-25 09:45:57 +00002768 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002769
2770 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002771 return GetCode(transition.is_null()
2772 ? Code::FIELD
2773 : Code::MAP_TRANSITION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002774}
2775
2776
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002777Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
2778 Handle<Map> receiver_map) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002779 // ----------- S t a t e -------------
2780 // -- eax : value
2781 // -- ecx : key
2782 // -- edx : receiver
2783 // -- esp[0] : return address
2784 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002785 ElementsKind elements_kind = receiver_map->elements_kind();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002786 bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002787 Handle<Code> stub =
ulan@chromium.org65a89c22012-02-14 11:46:07 +00002788 KeyedStoreElementStub(is_jsarray, elements_kind, grow_mode_).GetCode();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002789
2790 __ DispatchMap(edx, receiver_map, stub, DO_SMI_CHECK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002791
2792 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
2793 __ jmp(ic, RelocInfo::CODE_TARGET);
2794
2795 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002796 return GetCode(Code::NORMAL, factory()->empty_string());
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002797}
2798
2799
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002800Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
2801 MapHandleList* receiver_maps,
2802 CodeHandleList* handler_stubs,
2803 MapHandleList* transitioned_maps) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002804 // ----------- S t a t e -------------
2805 // -- eax : value
2806 // -- ecx : key
2807 // -- edx : receiver
2808 // -- esp[0] : return address
2809 // -----------------------------------
2810 Label miss;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002811 __ JumpIfSmi(edx, &miss, Label::kNear);
2812 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
2813 // ebx: receiver->map().
2814 for (int i = 0; i < receiver_maps->length(); ++i) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002815 __ cmp(edi, receiver_maps->at(i));
2816 if (transitioned_maps->at(i).is_null()) {
2817 __ j(equal, handler_stubs->at(i));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002818 } else {
2819 Label next_map;
2820 __ j(not_equal, &next_map, Label::kNear);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002821 __ mov(ebx, Immediate(transitioned_maps->at(i)));
2822 __ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002823 __ bind(&next_map);
2824 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002825 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002826 __ bind(&miss);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002827 Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
2828 __ jmp(miss_ic, RelocInfo::CODE_TARGET);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002829
2830 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002831 return GetCode(Code::NORMAL, factory()->empty_string(), MEGAMORPHIC);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002832}
2833
2834
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002835Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
2836 Handle<JSObject> object,
2837 Handle<JSObject> last) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002838 // ----------- S t a t e -------------
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002839 // -- ecx : name
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002840 // -- edx : receiver
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002841 // -- esp[0] : return address
2842 // -----------------------------------
2843 Label miss;
2844
2845 // Check that the receiver isn't a smi.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002846 __ JumpIfSmi(edx, &miss);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002847
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00002848 ASSERT(last->IsGlobalObject() || last->HasFastProperties());
2849
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002850 // Check the maps of the full prototype chain. Also check that
2851 // global property cells up to (but not including) the last object
2852 // in the prototype chain are empty.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002853 CheckPrototypes(object, edx, last, ebx, eax, edi, name, &miss);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002854
2855 // If the last object in the prototype chain is a global object,
2856 // check that the global property cell is empty.
2857 if (last->IsGlobalObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002858 GenerateCheckPropertyCell(
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002859 masm(), Handle<GlobalObject>::cast(last), name, eax, &miss);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002860 }
2861
2862 // Return undefined if maps of the full prototype chain are still the
2863 // same and no global property with this name contains a value.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002864 __ mov(eax, isolate()->factory()->undefined_value());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002865 __ ret(0);
2866
2867 __ bind(&miss);
2868 GenerateLoadMiss(masm(), Code::LOAD_IC);
2869
2870 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002871 return GetCode(Code::NONEXISTENT, factory()->empty_string());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002872}
2873
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002874
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002875Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object,
2876 Handle<JSObject> holder,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002877 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002878 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002879 // ----------- S t a t e -------------
2880 // -- ecx : name
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002881 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002882 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002883 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002884 Label miss;
2885
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002886 GenerateLoadField(object, holder, edx, ebx, eax, edi, index, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002887 __ bind(&miss);
2888 GenerateLoadMiss(masm(), Code::LOAD_IC);
2889
2890 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002891 return GetCode(Code::FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002892}
2893
2894
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002895Handle<Code> LoadStubCompiler::CompileLoadCallback(
2896 Handle<String> name,
2897 Handle<JSObject> object,
2898 Handle<JSObject> holder,
2899 Handle<AccessorInfo> callback) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002900 // ----------- S t a t e -------------
2901 // -- ecx : name
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002902 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002903 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002904 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002905 Label miss;
2906
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002907 GenerateLoadCallback(object, holder, edx, ecx, ebx, eax, edi, callback,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002908 name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002909 __ bind(&miss);
2910 GenerateLoadMiss(masm(), Code::LOAD_IC);
2911
2912 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002913 return GetCode(Code::CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002914}
2915
2916
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002917Handle<Code> LoadStubCompiler::CompileLoadViaGetter(
2918 Handle<String> name,
2919 Handle<JSObject> receiver,
2920 Handle<JSObject> holder,
2921 Handle<JSFunction> getter) {
2922 // ----------- S t a t e -------------
2923 // -- ecx : name
2924 // -- edx : receiver
2925 // -- esp[0] : return address
2926 // -----------------------------------
2927 Label miss;
2928
2929 // Check that the maps haven't changed.
2930 __ JumpIfSmi(edx, &miss);
2931 CheckPrototypes(receiver, edx, holder, ebx, eax, edi, name, &miss);
2932
2933 {
2934 FrameScope scope(masm(), StackFrame::INTERNAL);
2935
2936 // Call the JavaScript getter with the receiver on the stack.
2937 __ push(edx);
2938 ParameterCount actual(0);
2939 __ InvokeFunction(getter, actual, CALL_FUNCTION, NullCallWrapper(),
2940 CALL_AS_METHOD);
2941
2942 // Restore context register.
2943 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
2944 }
2945 __ ret(0);
2946
2947 __ bind(&miss);
2948 GenerateLoadMiss(masm(), Code::LOAD_IC);
2949
2950 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002951 return GetCode(Code::CALLBACKS, name);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002952}
2953
2954
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002955Handle<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object,
2956 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002957 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002958 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002959 // ----------- S t a t e -------------
2960 // -- ecx : name
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002961 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002962 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002963 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002964 Label miss;
2965
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002966 GenerateLoadConstant(object, holder, edx, ebx, eax, edi, value, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002967 __ bind(&miss);
2968 GenerateLoadMiss(masm(), Code::LOAD_IC);
2969
2970 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002971 return GetCode(Code::CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002972}
2973
2974
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002975Handle<Code> LoadStubCompiler::CompileLoadInterceptor(Handle<JSObject> receiver,
2976 Handle<JSObject> holder,
2977 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002978 // ----------- S t a t e -------------
2979 // -- ecx : name
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002980 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002981 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002982 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002983 Label miss;
2984
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002985 LookupResult lookup(isolate());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002986 LookupPostInterceptor(holder, name, &lookup);
2987
ager@chromium.orge2902be2009-06-08 12:21:35 +00002988 // TODO(368): Compile in the whole chain: all the interceptors in
2989 // prototypes and ultimate answer.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002990 GenerateLoadInterceptor(receiver, holder, &lookup, edx, ecx, eax, ebx, edi,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002991 name, &miss);
ager@chromium.orge2902be2009-06-08 12:21:35 +00002992
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002993 __ bind(&miss);
2994 GenerateLoadMiss(masm(), Code::LOAD_IC);
2995
2996 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002997 return GetCode(Code::INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002998}
2999
3000
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003001Handle<Code> LoadStubCompiler::CompileLoadGlobal(
3002 Handle<JSObject> object,
3003 Handle<GlobalObject> holder,
3004 Handle<JSGlobalPropertyCell> cell,
3005 Handle<String> name,
3006 bool is_dont_delete) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003007 // ----------- S t a t e -------------
3008 // -- ecx : name
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003009 // -- edx : receiver
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003010 // -- esp[0] : return address
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003011 // -----------------------------------
3012 Label miss;
3013
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003014 // Check that the maps haven't changed.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003015 __ JumpIfSmi(edx, &miss);
3016 CheckPrototypes(object, edx, holder, ebx, eax, edi, name, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003017
3018 // Get the value from the cell.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003019 if (Serializer::enabled()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003020 __ mov(ebx, Immediate(cell));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003021 __ mov(ebx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset));
3022 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003023 __ mov(ebx, Operand::Cell(cell));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003024 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003025
3026 // Check for deleted property if property can actually be deleted.
3027 if (!is_dont_delete) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00003028 __ cmp(ebx, factory()->the_hole_value());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003029 __ j(equal, &miss);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003030 } else if (FLAG_debug_code) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00003031 __ cmp(ebx, factory()->the_hole_value());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003032 __ Check(not_equal, "DontDelete cells can't contain the hole");
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003033 }
3034
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003035 Counters* counters = isolate()->counters();
3036 __ IncrementCounter(counters->named_load_global_stub(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00003037 __ mov(eax, ebx);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003038 __ ret(0);
3039
3040 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003041 __ IncrementCounter(counters->named_load_global_stub_miss(), 1);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003042 GenerateLoadMiss(masm(), Code::LOAD_IC);
3043
3044 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003045 return GetCode(Code::NORMAL, name);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003046}
3047
3048
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003049Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
3050 Handle<JSObject> receiver,
3051 Handle<JSObject> holder,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003052 int index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003053 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003054 // -- ecx : key
ager@chromium.org5c838252010-02-19 08:53:10 +00003055 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003056 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003057 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003058 Label miss;
3059
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003060 Counters* counters = isolate()->counters();
3061 __ IncrementCounter(counters->keyed_load_field(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003062
3063 // Check that the name has not changed.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003064 __ cmp(ecx, Immediate(name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003065 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003066
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003067 GenerateLoadField(receiver, holder, edx, ebx, eax, edi, index, name, &miss);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003068
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003069 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003070 __ DecrementCounter(counters->keyed_load_field(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003071 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3072
3073 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003074 return GetCode(Code::FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003075}
3076
3077
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003078Handle<Code> KeyedLoadStubCompiler::CompileLoadCallback(
3079 Handle<String> name,
3080 Handle<JSObject> receiver,
3081 Handle<JSObject> holder,
3082 Handle<AccessorInfo> callback) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003083 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003084 // -- ecx : key
ager@chromium.org5c838252010-02-19 08:53:10 +00003085 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003086 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003087 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003088 Label miss;
3089
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003090 Counters* counters = isolate()->counters();
3091 __ IncrementCounter(counters->keyed_load_callback(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003092
3093 // Check that the name has not changed.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003094 __ cmp(ecx, Immediate(name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003095 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003096
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003097 GenerateLoadCallback(receiver, holder, edx, ecx, ebx, eax, edi, callback,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003098 name, &miss);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00003099
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003100 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003101 __ DecrementCounter(counters->keyed_load_callback(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003102 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3103
3104 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003105 return GetCode(Code::CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003106}
3107
3108
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003109Handle<Code> KeyedLoadStubCompiler::CompileLoadConstant(
3110 Handle<String> name,
3111 Handle<JSObject> receiver,
3112 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003113 Handle<JSFunction> value) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003114 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003115 // -- ecx : key
ager@chromium.org5c838252010-02-19 08:53:10 +00003116 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003117 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003118 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003119 Label miss;
3120
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003121 Counters* counters = isolate()->counters();
3122 __ IncrementCounter(counters->keyed_load_constant_function(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003123
3124 // Check that the name has not changed.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003125 __ cmp(ecx, Immediate(name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003126 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003127
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003128 GenerateLoadConstant(
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003129 receiver, holder, edx, ebx, eax, edi, value, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003130 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003131 __ DecrementCounter(counters->keyed_load_constant_function(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003132 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3133
3134 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003135 return GetCode(Code::CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003136}
3137
3138
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003139Handle<Code> KeyedLoadStubCompiler::CompileLoadInterceptor(
3140 Handle<JSObject> receiver,
3141 Handle<JSObject> holder,
3142 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003143 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003144 // -- ecx : key
ager@chromium.org5c838252010-02-19 08:53:10 +00003145 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003146 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003147 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003148 Label miss;
3149
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003150 Counters* counters = isolate()->counters();
3151 __ IncrementCounter(counters->keyed_load_interceptor(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003152
3153 // Check that the name has not changed.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003154 __ cmp(ecx, Immediate(name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003155 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003156
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003157 LookupResult lookup(isolate());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003158 LookupPostInterceptor(holder, name, &lookup);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003159 GenerateLoadInterceptor(receiver, holder, &lookup, edx, ecx, eax, ebx, edi,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003160 name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003161 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003162 __ DecrementCounter(counters->keyed_load_interceptor(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003163 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3164
3165 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003166 return GetCode(Code::INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003167}
3168
3169
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003170Handle<Code> KeyedLoadStubCompiler::CompileLoadArrayLength(
3171 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003172 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003173 // -- ecx : key
ager@chromium.org5c838252010-02-19 08:53:10 +00003174 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003175 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003176 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003177 Label miss;
3178
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003179 Counters* counters = isolate()->counters();
3180 __ IncrementCounter(counters->keyed_load_array_length(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003181
3182 // Check that the name has not changed.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003183 __ cmp(ecx, Immediate(name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003184 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003185
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003186 GenerateLoadArrayLength(masm(), edx, eax, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003187 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003188 __ DecrementCounter(counters->keyed_load_array_length(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003189 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3190
3191 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003192 return GetCode(Code::CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003193}
3194
3195
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003196Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength(
3197 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003198 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003199 // -- ecx : key
ager@chromium.org5c838252010-02-19 08:53:10 +00003200 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003201 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003202 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003203 Label miss;
3204
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003205 Counters* counters = isolate()->counters();
3206 __ IncrementCounter(counters->keyed_load_string_length(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003207
3208 // Check that the name has not changed.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003209 __ cmp(ecx, Immediate(name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003210 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003211
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003212 GenerateLoadStringLength(masm(), edx, eax, ebx, &miss, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003213 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003214 __ DecrementCounter(counters->keyed_load_string_length(), 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::CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003219}
3220
3221
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003222Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype(
3223 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003224 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003225 // -- ecx : key
ager@chromium.org5c838252010-02-19 08:53:10 +00003226 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003227 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003228 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003229 Label miss;
3230
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003231 Counters* counters = isolate()->counters();
3232 __ IncrementCounter(counters->keyed_load_function_prototype(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003233
3234 // Check that the name has not changed.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003235 __ cmp(ecx, Immediate(name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003236 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003237
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003238 GenerateLoadFunctionPrototype(masm(), edx, eax, ebx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003239 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003240 __ DecrementCounter(counters->keyed_load_function_prototype(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003241 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3242
3243 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003244 return GetCode(Code::CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003245}
3246
3247
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003248Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
3249 Handle<Map> receiver_map) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003250 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003251 // -- ecx : key
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003252 // -- edx : receiver
3253 // -- esp[0] : return address
3254 // -----------------------------------
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003255
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003256 ElementsKind elements_kind = receiver_map->elements_kind();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003257 Handle<Code> stub = KeyedLoadElementStub(elements_kind).GetCode();
3258
3259 __ DispatchMap(edx, receiver_map, stub, DO_SMI_CHECK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003260
3261 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3262
3263 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003264 return GetCode(Code::NORMAL, factory()->empty_string());
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003265}
3266
3267
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003268Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
3269 MapHandleList* receiver_maps,
3270 CodeHandleList* handler_ics) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003271 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003272 // -- ecx : key
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003273 // -- edx : receiver
3274 // -- esp[0] : return address
3275 // -----------------------------------
3276 Label miss;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003277 __ JumpIfSmi(edx, &miss);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003278
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003279 Register map_reg = ebx;
3280 __ mov(map_reg, FieldOperand(edx, HeapObject::kMapOffset));
3281 int receiver_count = receiver_maps->length();
3282 for (int current = 0; current < receiver_count; ++current) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003283 __ cmp(map_reg, receiver_maps->at(current));
3284 __ j(equal, handler_ics->at(current));
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003285 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003286
3287 __ bind(&miss);
3288 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3289
3290 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003291 return GetCode(Code::NORMAL, factory()->empty_string(), MEGAMORPHIC);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003292}
3293
3294
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003295// Specialized stub for constructing objects from functions which only have only
3296// simple assignments of the form this.x = ...; in their body.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003297Handle<Code> ConstructStubCompiler::CompileConstructStub(
3298 Handle<JSFunction> function) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003299 // ----------- S t a t e -------------
3300 // -- eax : argc
3301 // -- edi : constructor
3302 // -- esp[0] : return address
3303 // -- esp[4] : last argument
3304 // -----------------------------------
3305 Label generic_stub_call;
3306#ifdef ENABLE_DEBUGGER_SUPPORT
3307 // Check to see whether there are any break points in the function code. If
3308 // there are jump to the generic constructor stub which calls the actual
3309 // code for the function thereby hitting the break points.
3310 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
3311 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kDebugInfoOffset));
lrn@chromium.org7516f052011-03-30 08:52:27 +00003312 __ cmp(ebx, factory()->undefined_value());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003313 __ j(not_equal, &generic_stub_call);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003314#endif
3315
3316 // Load the initial map and verify that it is in fact a map.
3317 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
3318 // Will both indicate a NULL and a Smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003319 __ JumpIfSmi(ebx, &generic_stub_call);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003320 __ CmpObjectType(ebx, MAP_TYPE, ecx);
3321 __ j(not_equal, &generic_stub_call);
3322
3323#ifdef DEBUG
3324 // Cannot construct functions this way.
3325 // edi: constructor
3326 // ebx: initial map
3327 __ CmpInstanceType(ebx, JS_FUNCTION_TYPE);
3328 __ Assert(not_equal, "Function constructed by construct stub.");
3329#endif
3330
3331 // Now allocate the JSObject on the heap by moving the new space allocation
3332 // top forward.
3333 // edi: constructor
3334 // ebx: initial map
3335 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset));
3336 __ shl(ecx, kPointerSizeLog2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003337 __ AllocateInNewSpace(ecx, edx, ecx, no_reg,
3338 &generic_stub_call, NO_ALLOCATION_FLAGS);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003339
3340 // Allocated the JSObject, now initialize the fields and add the heap tag.
3341 // ebx: initial map
3342 // edx: JSObject (untagged)
3343 __ mov(Operand(edx, JSObject::kMapOffset), ebx);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003344 __ mov(ebx, factory()->empty_fixed_array());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003345 __ mov(Operand(edx, JSObject::kPropertiesOffset), ebx);
3346 __ mov(Operand(edx, JSObject::kElementsOffset), ebx);
3347
3348 // Push the allocated object to the stack. This is the object that will be
3349 // returned (after it is tagged).
3350 __ push(edx);
3351
3352 // eax: argc
3353 // edx: JSObject (untagged)
3354 // Load the address of the first in-object property into edx.
3355 __ lea(edx, Operand(edx, JSObject::kHeaderSize));
3356 // Calculate the location of the first argument. The stack contains the
3357 // allocated object and the return address on top of the argc arguments.
3358 __ lea(ecx, Operand(esp, eax, times_4, 1 * kPointerSize));
3359
3360 // Use edi for holding undefined which is used in several places below.
lrn@chromium.org7516f052011-03-30 08:52:27 +00003361 __ mov(edi, factory()->undefined_value());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003362
3363 // eax: argc
3364 // ecx: first argument
3365 // edx: first in-object property of the JSObject
3366 // edi: undefined
3367 // Fill the initialized properties with a constant value or a passed argument
3368 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003369 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003370 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3371 if (shared->IsThisPropertyAssignmentArgument(i)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003372 // Check if the argument assigned to the property is actually passed.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003373 // If argument is not passed the property is set to undefined,
3374 // otherwise find it on the stack.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003375 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003376 __ mov(ebx, edi);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003377 __ cmp(eax, arg_number);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003378 if (CpuFeatures::IsSupported(CMOV)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003379 CpuFeatures::Scope use_cmov(CMOV);
3380 __ cmov(above, ebx, Operand(ecx, arg_number * -kPointerSize));
3381 } else {
3382 Label not_passed;
3383 __ j(below_equal, &not_passed);
3384 __ mov(ebx, Operand(ecx, arg_number * -kPointerSize));
3385 __ bind(&not_passed);
3386 }
3387 // Store value in the property.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003388 __ mov(Operand(edx, i * kPointerSize), ebx);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003389 } else {
3390 // Set the property to the constant value.
3391 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
3392 __ mov(Operand(edx, i * kPointerSize), Immediate(constant));
3393 }
3394 }
3395
3396 // Fill the unused in-object property fields with undefined.
ager@chromium.orgbeb25712010-11-29 08:02:25 +00003397 ASSERT(function->has_initial_map());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003398 for (int i = shared->this_property_assignments_count();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00003399 i < function->initial_map()->inobject_properties();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003400 i++) {
3401 __ mov(Operand(edx, i * kPointerSize), edi);
3402 }
3403
3404 // Move argc to ebx and retrieve and tag the JSObject to return.
3405 __ mov(ebx, eax);
3406 __ pop(eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003407 __ or_(eax, Immediate(kHeapObjectTag));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003408
3409 // Remove caller arguments and receiver from the stack and return.
3410 __ pop(ecx);
3411 __ lea(esp, Operand(esp, ebx, times_pointer_size, 1 * kPointerSize));
3412 __ push(ecx);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003413 Counters* counters = isolate()->counters();
3414 __ IncrementCounter(counters->constructed_objects(), 1);
3415 __ IncrementCounter(counters->constructed_objects_stub(), 1);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003416 __ ret(0);
3417
3418 // Jump to the generic stub in case the specialized code cannot handle the
3419 // construction.
3420 __ bind(&generic_stub_call);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003421 Handle<Code> code = isolate()->builtins()->JSConstructStubGeneric();
3422 __ jmp(code, RelocInfo::CODE_TARGET);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003423
3424 // Return the generated code.
3425 return GetCode();
3426}
3427
3428
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003429#undef __
3430#define __ ACCESS_MASM(masm)
3431
3432
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003433void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3434 MacroAssembler* masm) {
3435 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003436 // -- ecx : key
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003437 // -- edx : receiver
3438 // -- esp[0] : return address
3439 // -----------------------------------
3440 Label slow, miss_force_generic;
3441
3442 // This stub is meant to be tail-jumped to, the receiver must already
3443 // have been verified by the caller to not be a smi.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003444 __ JumpIfNotSmi(ecx, &miss_force_generic);
3445 __ mov(ebx, ecx);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003446 __ SmiUntag(ebx);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003447 __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset));
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003448
3449 // Push receiver on the stack to free up a register for the dictionary
3450 // probing.
3451 __ push(edx);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003452 __ LoadFromNumberDictionary(&slow, eax, ecx, ebx, edx, edi, eax);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003453 // Pop receiver before returning.
3454 __ pop(edx);
3455 __ ret(0);
3456
3457 __ bind(&slow);
3458 __ pop(edx);
3459
3460 // ----------- S t a t e -------------
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003461 // -- ecx : key
3462 // -- edx : receiver
3463 // -- esp[0] : return address
3464 // -----------------------------------
3465
3466 Handle<Code> slow_ic =
3467 masm->isolate()->builtins()->KeyedLoadIC_Slow();
3468 __ jmp(slow_ic, RelocInfo::CODE_TARGET);
3469
3470 __ bind(&miss_force_generic);
3471 // ----------- S t a t e -------------
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003472 // -- ecx : key
3473 // -- edx : receiver
3474 // -- esp[0] : return address
3475 // -----------------------------------
3476
3477 Handle<Code> miss_force_generic_ic =
3478 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3479 __ jmp(miss_force_generic_ic, RelocInfo::CODE_TARGET);
3480}
3481
3482
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003483static void GenerateSmiKeyCheck(MacroAssembler* masm,
3484 Register key,
3485 Register scratch,
3486 XMMRegister xmm_scratch0,
3487 XMMRegister xmm_scratch1,
3488 Label* fail) {
3489 // Check that key is a smi and if SSE2 is available a heap number
3490 // containing a smi and branch if the check fails.
3491 if (CpuFeatures::IsSupported(SSE2)) {
3492 CpuFeatures::Scope use_sse2(SSE2);
3493 Label key_ok;
3494 __ JumpIfSmi(key, &key_ok);
3495 __ cmp(FieldOperand(key, HeapObject::kMapOffset),
3496 Immediate(Handle<Map>(masm->isolate()->heap()->heap_number_map())));
3497 __ j(not_equal, fail);
3498 __ movdbl(xmm_scratch0, FieldOperand(key, HeapNumber::kValueOffset));
3499 __ cvttsd2si(scratch, Operand(xmm_scratch0));
3500 __ cvtsi2sd(xmm_scratch1, scratch);
3501 __ ucomisd(xmm_scratch1, xmm_scratch0);
3502 __ j(not_equal, fail);
3503 __ j(parity_even, fail); // NaN.
3504 // Check if the key fits in the smi range.
3505 __ cmp(scratch, 0xc0000000);
3506 __ j(sign, fail);
3507 __ SmiTag(scratch);
3508 __ mov(key, scratch);
3509 __ bind(&key_ok);
3510 } else {
3511 __ JumpIfNotSmi(key, fail);
3512 }
3513}
3514
3515
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003516void KeyedLoadStubCompiler::GenerateLoadExternalArray(
3517 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003518 ElementsKind elements_kind) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003519 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003520 // -- ecx : key
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003521 // -- edx : receiver
3522 // -- esp[0] : return address
3523 // -----------------------------------
3524 Label miss_force_generic, failed_allocation, slow;
3525
3526 // This stub is meant to be tail-jumped to, the receiver must already
3527 // have been verified by the caller to not be a smi.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003528
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003529 // Check that the key is a smi or a heap number convertible to a smi.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003530 GenerateSmiKeyCheck(masm, ecx, eax, xmm0, xmm1, &miss_force_generic);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003531
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003532 // Check that the index is in range.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003533 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003534 __ cmp(ecx, FieldOperand(ebx, ExternalArray::kLengthOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003535 // Unsigned comparison catches both negative and too-large values.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003536 __ j(above_equal, &miss_force_generic);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003537 __ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset));
3538 // ebx: base pointer of external storage
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003539 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003540 case EXTERNAL_BYTE_ELEMENTS:
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003541 __ SmiUntag(ecx); // Untag the index.
3542 __ movsx_b(eax, Operand(ebx, ecx, times_1, 0));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003543 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003544 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3545 case EXTERNAL_PIXEL_ELEMENTS:
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003546 __ SmiUntag(ecx); // Untag the index.
3547 __ movzx_b(eax, Operand(ebx, ecx, times_1, 0));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003548 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003549 case EXTERNAL_SHORT_ELEMENTS:
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003550 __ movsx_w(eax, Operand(ebx, ecx, times_1, 0));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003551 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003552 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003553 __ movzx_w(eax, Operand(ebx, ecx, times_1, 0));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003554 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003555 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3556 case EXTERNAL_INT_ELEMENTS:
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003557 __ mov(eax, Operand(ebx, ecx, times_2, 0));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003558 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003559 case EXTERNAL_FLOAT_ELEMENTS:
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003560 __ fld_s(Operand(ebx, ecx, times_2, 0));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003561 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003562 case EXTERNAL_DOUBLE_ELEMENTS:
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003563 __ fld_d(Operand(ebx, ecx, times_4, 0));
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003564 break;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003565 default:
3566 UNREACHABLE();
3567 break;
3568 }
3569
3570 // For integer array types:
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003571 // eax: value
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003572 // For floating-point array type:
3573 // FP(0): value
3574
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003575 if (elements_kind == EXTERNAL_INT_ELEMENTS ||
3576 elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003577 // For the Int and UnsignedInt array types, we need to see whether
3578 // the value can be represented in a Smi. If not, we need to convert
3579 // it to a HeapNumber.
3580 Label box_int;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003581 if (elements_kind == EXTERNAL_INT_ELEMENTS) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003582 __ cmp(eax, 0xc0000000);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003583 __ j(sign, &box_int);
3584 } else {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003585 ASSERT_EQ(EXTERNAL_UNSIGNED_INT_ELEMENTS, elements_kind);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003586 // The test is different for unsigned int values. Since we need
3587 // the value to be in the range of a positive smi, we can't
3588 // handle either of the top two bits being set in the value.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003589 __ test(eax, Immediate(0xc0000000));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003590 __ j(not_zero, &box_int);
3591 }
3592
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003593 __ SmiTag(eax);
3594 __ ret(0);
3595
3596 __ bind(&box_int);
3597
3598 // Allocate a HeapNumber for the int and perform int-to-double
3599 // conversion.
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003600 if (elements_kind == EXTERNAL_INT_ELEMENTS) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003601 __ push(eax);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003602 __ fild_s(Operand(esp, 0));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003603 __ pop(eax);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003604 } else {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003605 ASSERT_EQ(EXTERNAL_UNSIGNED_INT_ELEMENTS, elements_kind);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003606 // Need to zero-extend the value.
3607 // There's no fild variant for unsigned values, so zero-extend
3608 // to a 64-bit int manually.
3609 __ push(Immediate(0));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003610 __ push(eax);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003611 __ fild_d(Operand(esp, 0));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003612 __ pop(eax);
3613 __ pop(eax);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003614 }
3615 // FP(0): value
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003616 __ AllocateHeapNumber(eax, ebx, edi, &failed_allocation);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003617 // Set the value.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003618 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
3619 __ ret(0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003620 } else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
3621 elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003622 // For the floating-point array type, we need to always allocate a
3623 // HeapNumber.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003624 __ AllocateHeapNumber(eax, ebx, edi, &failed_allocation);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003625 // Set the value.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003626 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
3627 __ ret(0);
3628 } else {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003629 __ SmiTag(eax);
3630 __ ret(0);
3631 }
3632
3633 // If we fail allocation of the HeapNumber, we still have a value on
3634 // top of the FPU stack. Remove it.
3635 __ bind(&failed_allocation);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003636 __ fstp(0);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003637 // Fall through to slow case.
3638
3639 // Slow case: Jump to runtime.
3640 __ bind(&slow);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003641 Counters* counters = masm->isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003642 __ IncrementCounter(counters->keyed_load_external_array_slow(), 1);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003643
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003644 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003645 // -- ecx : key
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003646 // -- edx : receiver
3647 // -- esp[0] : return address
3648 // -----------------------------------
3649
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003650 Handle<Code> ic = masm->isolate()->builtins()->KeyedLoadIC_Slow();
3651 __ jmp(ic, RelocInfo::CODE_TARGET);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003652
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003653 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003654 // -- ecx : key
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003655 // -- edx : receiver
3656 // -- esp[0] : return address
3657 // -----------------------------------
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003658
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003659 // Miss case: Jump to runtime.
3660 __ bind(&miss_force_generic);
3661 Handle<Code> miss_ic =
3662 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3663 __ jmp(miss_ic, RelocInfo::CODE_TARGET);
3664}
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003665
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003666
3667void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3668 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003669 ElementsKind elements_kind) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003670 // ----------- S t a t e -------------
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003671 // -- eax : value
3672 // -- ecx : key
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003673 // -- edx : receiver
3674 // -- esp[0] : return address
3675 // -----------------------------------
3676 Label miss_force_generic, slow, check_heap_number;
3677
3678 // This stub is meant to be tail-jumped to, the receiver must already
3679 // have been verified by the caller to not be a smi.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003680
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003681 // Check that the key is a smi or a heap number convertible to a smi.
3682 GenerateSmiKeyCheck(masm, ecx, ebx, xmm0, xmm1, &miss_force_generic);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003683
3684 // Check that the index is in range.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003685 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003686 __ cmp(ecx, FieldOperand(edi, ExternalArray::kLengthOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003687 // Unsigned comparison catches both negative and too-large values.
3688 __ j(above_equal, &slow);
3689
3690 // Handle both smis and HeapNumbers in the fast path. Go to the
3691 // runtime for all other kinds of values.
3692 // eax: value
3693 // edx: receiver
3694 // ecx: key
3695 // edi: elements array
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003696 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00003697 __ JumpIfNotSmi(eax, &slow);
3698 } else {
3699 __ JumpIfNotSmi(eax, &check_heap_number);
3700 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003701
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003702 // smi case
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003703 __ mov(ebx, eax); // Preserve the value in eax as the return value.
3704 __ SmiUntag(ebx);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003705 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003706 // edi: base pointer of external storage
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003707 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003708 case EXTERNAL_PIXEL_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003709 __ ClampUint8(ebx);
3710 __ SmiUntag(ecx);
3711 __ mov_b(Operand(edi, ecx, times_1, 0), ebx);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003712 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003713 case EXTERNAL_BYTE_ELEMENTS:
3714 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003715 __ SmiUntag(ecx);
3716 __ mov_b(Operand(edi, ecx, times_1, 0), ebx);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003717 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003718 case EXTERNAL_SHORT_ELEMENTS:
3719 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003720 __ mov_w(Operand(edi, ecx, times_1, 0), ebx);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003721 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003722 case EXTERNAL_INT_ELEMENTS:
3723 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003724 __ mov(Operand(edi, ecx, times_2, 0), ebx);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003725 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003726 case EXTERNAL_FLOAT_ELEMENTS:
3727 case EXTERNAL_DOUBLE_ELEMENTS:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003728 // Need to perform int-to-float conversion.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003729 __ push(ebx);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003730 __ fild_s(Operand(esp, 0));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003731 __ pop(ebx);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003732 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003733 __ fstp_s(Operand(edi, ecx, times_2, 0));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003734 } else { // elements_kind == EXTERNAL_DOUBLE_ELEMENTS.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003735 __ fstp_d(Operand(edi, ecx, times_4, 0));
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003736 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003737 break;
3738 default:
3739 UNREACHABLE();
3740 break;
3741 }
3742 __ ret(0); // Return the original value.
3743
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003744 // TODO(danno): handle heap number -> pixel array conversion
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003745 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003746 __ bind(&check_heap_number);
3747 // eax: value
3748 // edx: receiver
3749 // ecx: key
3750 // edi: elements array
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003751 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003752 Immediate(masm->isolate()->factory()->heap_number_map()));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003753 __ j(not_equal, &slow);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003754
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003755 // The WebGL specification leaves the behavior of storing NaN and
3756 // +/-Infinity into integer arrays basically undefined. For more
3757 // reproducible behavior, convert these to zero.
3758 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003759 // edi: base pointer of external storage
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003760 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003761 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003762 __ fstp_s(Operand(edi, ecx, times_2, 0));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003763 __ ret(0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003764 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003765 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003766 __ fstp_d(Operand(edi, ecx, times_4, 0));
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003767 __ ret(0);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003768 } else {
3769 // Perform float-to-int conversion with truncation (round-to-zero)
3770 // behavior.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003771
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003772 // For the moment we make the slow call to the runtime on
3773 // processors that don't support SSE2. The code in IntegerConvert
3774 // (code-stubs-ia32.cc) is roughly what is needed here though the
3775 // conversion failure case does not need to be handled.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003776 if (CpuFeatures::IsSupported(SSE2)) {
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003777 if ((elements_kind == EXTERNAL_INT_ELEMENTS ||
3778 elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) &&
3779 CpuFeatures::IsSupported(SSE3)) {
3780 CpuFeatures::Scope scope(SSE3);
3781 // fisttp stores values as signed integers. To represent the
3782 // entire range of int and unsigned int arrays, store as a
3783 // 64-bit int and discard the high 32 bits.
3784 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
3785 __ sub(esp, Immediate(2 * kPointerSize));
3786 __ fisttp_d(Operand(esp, 0));
3787
3788 // If conversion failed (NaN, infinity, or a number outside
3789 // signed int64 range), the result is 0x8000000000000000, and
3790 // we must handle this case in the runtime.
3791 Label ok;
3792 __ cmp(Operand(esp, kPointerSize), Immediate(0x80000000u));
3793 __ j(not_equal, &ok);
3794 __ cmp(Operand(esp, 0), Immediate(0));
3795 __ j(not_equal, &ok);
3796 __ add(esp, Immediate(2 * kPointerSize)); // Restore the stack.
3797 __ jmp(&slow);
3798
3799 __ bind(&ok);
3800 __ pop(ebx);
3801 __ add(esp, Immediate(kPointerSize));
3802 __ mov(Operand(edi, ecx, times_2, 0), ebx);
3803 } else {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003804 ASSERT(CpuFeatures::IsSupported(SSE2));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003805 CpuFeatures::Scope scope(SSE2);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003806 __ cvttsd2si(ebx, FieldOperand(eax, HeapNumber::kValueOffset));
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003807 __ cmp(ebx, 0x80000000u);
3808 __ j(equal, &slow);
3809 // ebx: untagged integer value
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003810 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003811 case EXTERNAL_PIXEL_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003812 __ ClampUint8(ebx);
3813 // Fall through.
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003814 case EXTERNAL_BYTE_ELEMENTS:
3815 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003816 __ SmiUntag(ecx);
3817 __ mov_b(Operand(edi, ecx, times_1, 0), ebx);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003818 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003819 case EXTERNAL_SHORT_ELEMENTS:
3820 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003821 __ mov_w(Operand(edi, ecx, times_1, 0), ebx);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003822 break;
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003823 case EXTERNAL_INT_ELEMENTS:
3824 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3825 __ mov(Operand(edi, ecx, times_2, 0), ebx);
3826 break;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003827 default:
3828 UNREACHABLE();
3829 break;
3830 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003831 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003832 __ ret(0); // Return original value.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003833 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003834 }
3835 }
3836
3837 // Slow case: call runtime.
3838 __ bind(&slow);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003839 Counters* counters = masm->isolate()->counters();
3840 __ IncrementCounter(counters->keyed_store_external_array_slow(), 1);
3841
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003842 // ----------- S t a t e -------------
3843 // -- eax : value
3844 // -- ecx : key
3845 // -- edx : receiver
3846 // -- esp[0] : return address
3847 // -----------------------------------
3848
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003849 Handle<Code> ic = masm->isolate()->builtins()->KeyedStoreIC_Slow();
3850 __ jmp(ic, RelocInfo::CODE_TARGET);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003851
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003852 // ----------- S t a t e -------------
3853 // -- eax : value
3854 // -- ecx : key
3855 // -- edx : receiver
3856 // -- esp[0] : return address
3857 // -----------------------------------
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003858
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003859 __ bind(&miss_force_generic);
3860 Handle<Code> miss_ic =
3861 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
3862 __ jmp(miss_ic, RelocInfo::CODE_TARGET);
3863}
3864
3865
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003866void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
3867 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003868 // -- ecx : key
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003869 // -- edx : receiver
3870 // -- esp[0] : return address
3871 // -----------------------------------
3872 Label miss_force_generic;
3873
3874 // This stub is meant to be tail-jumped to, the receiver must already
3875 // have been verified by the caller to not be a smi.
3876
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003877 // Check that the key is a smi or a heap number convertible to a smi.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003878 GenerateSmiKeyCheck(masm, ecx, eax, xmm0, xmm1, &miss_force_generic);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003879
3880 // Get the elements array.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003881 __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset));
3882 __ AssertFastElements(eax);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003883
3884 // Check that the key is within bounds.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003885 __ cmp(ecx, FieldOperand(eax, FixedArray::kLengthOffset));
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003886 __ j(above_equal, &miss_force_generic);
3887
3888 // Load the result and make sure it's not the hole.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003889 __ mov(ebx, Operand(eax, ecx, times_2,
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003890 FixedArray::kHeaderSize - kHeapObjectTag));
3891 __ cmp(ebx, masm->isolate()->factory()->the_hole_value());
3892 __ j(equal, &miss_force_generic);
3893 __ mov(eax, ebx);
3894 __ ret(0);
3895
3896 __ bind(&miss_force_generic);
3897 Handle<Code> miss_ic =
3898 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3899 __ jmp(miss_ic, RelocInfo::CODE_TARGET);
3900}
3901
3902
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003903void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
3904 MacroAssembler* masm) {
3905 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003906 // -- ecx : key
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003907 // -- edx : receiver
3908 // -- esp[0] : return address
3909 // -----------------------------------
3910 Label miss_force_generic, slow_allocate_heapnumber;
3911
3912 // This stub is meant to be tail-jumped to, the receiver must already
3913 // have been verified by the caller to not be a smi.
3914
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003915 // Check that the key is a smi or a heap number convertible to a smi.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003916 GenerateSmiKeyCheck(masm, ecx, eax, xmm0, xmm1, &miss_force_generic);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003917
3918 // Get the elements array.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003919 __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset));
3920 __ AssertFastElements(eax);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003921
3922 // Check that the key is within bounds.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003923 __ cmp(ecx, FieldOperand(eax, FixedDoubleArray::kLengthOffset));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003924 __ j(above_equal, &miss_force_generic);
3925
3926 // Check for the hole
3927 uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003928 __ cmp(FieldOperand(eax, ecx, times_4, offset), Immediate(kHoleNanUpper32));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003929 __ j(equal, &miss_force_generic);
3930
3931 // Always allocate a heap number for the result.
3932 if (CpuFeatures::IsSupported(SSE2)) {
3933 CpuFeatures::Scope use_sse2(SSE2);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003934 __ movdbl(xmm0, FieldOperand(eax, ecx, times_4,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003935 FixedDoubleArray::kHeaderSize));
3936 } else {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003937 __ fld_d(FieldOperand(eax, ecx, times_4, FixedDoubleArray::kHeaderSize));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003938 }
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003939 __ AllocateHeapNumber(eax, ebx, edi, &slow_allocate_heapnumber);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003940 // Set the value.
3941 if (CpuFeatures::IsSupported(SSE2)) {
3942 CpuFeatures::Scope use_sse2(SSE2);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003943 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003944 } else {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003945 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003946 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003947 __ ret(0);
3948
3949 __ bind(&slow_allocate_heapnumber);
3950 // A value was pushed on the floating point stack before the allocation, if
3951 // the allocation fails it needs to be removed.
3952 if (!CpuFeatures::IsSupported(SSE2)) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003953 __ fstp(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003954 }
3955 Handle<Code> slow_ic =
3956 masm->isolate()->builtins()->KeyedLoadIC_Slow();
3957 __ jmp(slow_ic, RelocInfo::CODE_TARGET);
3958
3959 __ bind(&miss_force_generic);
3960 Handle<Code> miss_ic =
3961 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3962 __ jmp(miss_ic, RelocInfo::CODE_TARGET);
3963}
3964
3965
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003966void KeyedStoreStubCompiler::GenerateStoreFastElement(
3967 MacroAssembler* masm,
3968 bool is_js_array,
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003969 ElementsKind elements_kind,
3970 KeyedAccessGrowMode grow_mode) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003971 // ----------- S t a t e -------------
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003972 // -- eax : value
3973 // -- ecx : key
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003974 // -- edx : receiver
3975 // -- esp[0] : return address
3976 // -----------------------------------
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003977 Label miss_force_generic, grow, slow, transition_elements_kind;
3978 Label check_capacity, prepare_slow, finish_store, commit_backing_store;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003979
3980 // This stub is meant to be tail-jumped to, the receiver must already
3981 // have been verified by the caller to not be a smi.
3982
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003983 // Check that the key is a smi or a heap number convertible to a smi.
3984 GenerateSmiKeyCheck(masm, ecx, ebx, xmm0, xmm1, &miss_force_generic);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003985
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003986 if (IsFastSmiElementsKind(elements_kind)) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003987 __ JumpIfNotSmi(eax, &transition_elements_kind);
3988 }
3989
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003990 // Get the elements array and make sure it is a fast element array, not 'cow'.
3991 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003992 if (is_js_array) {
3993 // Check that the key is within bounds.
3994 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // smis.
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003995 if (grow_mode == ALLOW_JSARRAY_GROWTH) {
3996 __ j(above_equal, &grow);
3997 } else {
3998 __ j(above_equal, &miss_force_generic);
3999 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00004000 } else {
4001 // Check that the key is within bounds.
4002 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); // smis.
4003 __ j(above_equal, &miss_force_generic);
4004 }
4005
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004006 __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
4007 Immediate(masm->isolate()->factory()->fixed_array_map()));
4008 __ j(not_equal, &miss_force_generic);
4009
4010 __ bind(&finish_store);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004011 if (IsFastSmiElementsKind(elements_kind)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004012 // ecx is a smi, use times_half_pointer_size instead of
4013 // times_pointer_size
4014 __ mov(FieldOperand(edi,
4015 ecx,
4016 times_half_pointer_size,
4017 FixedArray::kHeaderSize), eax);
4018 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004019 ASSERT(IsFastObjectElementsKind(elements_kind));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004020 // Do the store and update the write barrier.
4021 // ecx is a smi, use times_half_pointer_size instead of
4022 // times_pointer_size
4023 __ lea(ecx, FieldOperand(edi,
4024 ecx,
4025 times_half_pointer_size,
4026 FixedArray::kHeaderSize));
4027 __ mov(Operand(ecx, 0), eax);
4028 // Make sure to preserve the value in register eax.
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004029 __ mov(ebx, eax);
4030 __ RecordWrite(edi, ecx, ebx, kDontSaveFPRegs);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004031 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00004032
4033 // Done.
4034 __ ret(0);
4035
4036 // Handle store cache miss, replacing the ic with the generic stub.
4037 __ bind(&miss_force_generic);
4038 Handle<Code> ic_force_generic =
4039 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4040 __ jmp(ic_force_generic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004041
4042 // Handle transition to other elements kinds without using the generic stub.
4043 __ bind(&transition_elements_kind);
4044 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4045 __ jmp(ic_miss, RelocInfo::CODE_TARGET);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004046
4047 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4048 // Handle transition requiring the array to grow.
4049 __ bind(&grow);
4050
4051 // Make sure the array is only growing by a single element, anything else
4052 // must be handled by the runtime. Flags are already set by previous
4053 // compare.
4054 __ j(not_equal, &miss_force_generic);
4055
4056 // Check for the empty array, and preallocate a small backing store if
4057 // possible.
4058 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
4059 __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array()));
4060 __ j(not_equal, &check_capacity);
4061
4062 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
4063 __ AllocateInNewSpace(size, edi, ebx, ecx, &prepare_slow, TAG_OBJECT);
4064 // Restore the key, which is known to be the array length.
4065
4066 // eax: value
4067 // ecx: key
4068 // edx: receiver
4069 // edi: elements
4070 // Make sure that the backing store can hold additional elements.
4071 __ mov(FieldOperand(edi, JSObject::kMapOffset),
4072 Immediate(masm->isolate()->factory()->fixed_array_map()));
4073 __ mov(FieldOperand(edi, FixedArray::kLengthOffset),
4074 Immediate(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4075 __ mov(ebx, Immediate(masm->isolate()->factory()->the_hole_value()));
4076 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
4077 __ mov(FieldOperand(edi, FixedArray::SizeFor(i)), ebx);
4078 }
4079
4080 // Store the element at index zero.
4081 __ mov(FieldOperand(edi, FixedArray::SizeFor(0)), eax);
4082
4083 // Install the new backing store in the JSArray.
4084 __ mov(FieldOperand(edx, JSObject::kElementsOffset), edi);
4085 __ RecordWriteField(edx, JSObject::kElementsOffset, edi, ebx,
4086 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4087
4088 // Increment the length of the array.
4089 __ mov(FieldOperand(edx, JSArray::kLengthOffset),
4090 Immediate(Smi::FromInt(1)));
4091 __ ret(0);
4092
4093 __ bind(&check_capacity);
4094 __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
4095 Immediate(masm->isolate()->factory()->fixed_cow_array_map()));
4096 __ j(equal, &miss_force_generic);
4097
4098 // eax: value
4099 // ecx: key
4100 // edx: receiver
4101 // edi: elements
4102 // Make sure that the backing store can hold additional elements.
4103 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
4104 __ j(above_equal, &slow);
4105
4106 // Grow the array and finish the store.
4107 __ add(FieldOperand(edx, JSArray::kLengthOffset),
4108 Immediate(Smi::FromInt(1)));
4109 __ jmp(&finish_store);
4110
4111 __ bind(&prepare_slow);
4112 // Restore the key, which is known to be the array length.
4113 __ mov(ecx, Immediate(0));
4114
4115 __ bind(&slow);
4116 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4117 __ jmp(ic_slow, RelocInfo::CODE_TARGET);
4118 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004119}
4120
4121
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004122void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
4123 MacroAssembler* masm,
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004124 bool is_js_array,
4125 KeyedAccessGrowMode grow_mode) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004126 // ----------- S t a t e -------------
4127 // -- eax : value
4128 // -- ecx : key
4129 // -- edx : receiver
4130 // -- esp[0] : return address
4131 // -----------------------------------
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004132 Label miss_force_generic, transition_elements_kind, grow, slow;
4133 Label check_capacity, prepare_slow, finish_store, commit_backing_store;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004134
4135 // This stub is meant to be tail-jumped to, the receiver must already
4136 // have been verified by the caller to not be a smi.
4137
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00004138 // Check that the key is a smi or a heap number convertible to a smi.
4139 GenerateSmiKeyCheck(masm, ecx, ebx, xmm0, xmm1, &miss_force_generic);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004140
4141 // Get the elements array.
4142 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
4143 __ AssertFastElements(edi);
4144
4145 if (is_js_array) {
4146 // Check that the key is within bounds.
4147 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // smis.
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004148 if (grow_mode == ALLOW_JSARRAY_GROWTH) {
4149 __ j(above_equal, &grow);
4150 } else {
4151 __ j(above_equal, &miss_force_generic);
4152 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004153 } else {
4154 // Check that the key is within bounds.
4155 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); // smis.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004156 __ j(above_equal, &miss_force_generic);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004157 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004158
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004159 __ bind(&finish_store);
4160 __ StoreNumberToDoubleElements(eax, edi, ecx, edx, xmm0,
4161 &transition_elements_kind, true);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004162 __ ret(0);
4163
4164 // Handle store cache miss, replacing the ic with the generic stub.
4165 __ bind(&miss_force_generic);
4166 Handle<Code> ic_force_generic =
4167 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4168 __ jmp(ic_force_generic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004169
4170 // Handle transition to other elements kinds without using the generic stub.
4171 __ bind(&transition_elements_kind);
4172 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4173 __ jmp(ic_miss, RelocInfo::CODE_TARGET);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004174
4175 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4176 // Handle transition requiring the array to grow.
4177 __ bind(&grow);
4178
4179 // Make sure the array is only growing by a single element, anything else
4180 // must be handled by the runtime. Flags are already set by previous
4181 // compare.
4182 __ j(not_equal, &miss_force_generic);
4183
4184 // Transition on values that can't be stored in a FixedDoubleArray.
4185 Label value_is_smi;
4186 __ JumpIfSmi(eax, &value_is_smi);
4187 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
4188 Immediate(Handle<Map>(masm->isolate()->heap()->heap_number_map())));
4189 __ j(not_equal, &transition_elements_kind);
4190 __ bind(&value_is_smi);
4191
4192 // Check for the empty array, and preallocate a small backing store if
4193 // possible.
4194 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
4195 __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array()));
4196 __ j(not_equal, &check_capacity);
4197
4198 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
4199 __ AllocateInNewSpace(size, edi, ebx, ecx, &prepare_slow, TAG_OBJECT);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004200
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004201 // Restore the key, which is known to be the array length.
4202 __ mov(ecx, Immediate(0));
4203
4204 // eax: value
4205 // ecx: key
4206 // edx: receiver
4207 // edi: elements
4208 // Initialize the new FixedDoubleArray. Leave elements unitialized for
4209 // efficiency, they are guaranteed to be initialized before use.
4210 __ mov(FieldOperand(edi, JSObject::kMapOffset),
4211 Immediate(masm->isolate()->factory()->fixed_double_array_map()));
4212 __ mov(FieldOperand(edi, FixedDoubleArray::kLengthOffset),
4213 Immediate(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4214
4215 // Install the new backing store in the JSArray.
4216 __ mov(FieldOperand(edx, JSObject::kElementsOffset), edi);
4217 __ RecordWriteField(edx, JSObject::kElementsOffset, edi, ebx,
4218 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4219
4220 // Increment the length of the array.
4221 __ add(FieldOperand(edx, JSArray::kLengthOffset),
4222 Immediate(Smi::FromInt(1)));
yangguo@chromium.org56454712012-02-16 15:33:53 +00004223 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004224 __ jmp(&finish_store);
4225
4226 __ bind(&check_capacity);
4227 // eax: value
4228 // ecx: key
4229 // edx: receiver
4230 // edi: elements
4231 // Make sure that the backing store can hold additional elements.
4232 __ cmp(ecx, FieldOperand(edi, FixedDoubleArray::kLengthOffset));
4233 __ j(above_equal, &slow);
4234
4235 // Grow the array and finish the store.
4236 __ add(FieldOperand(edx, JSArray::kLengthOffset),
4237 Immediate(Smi::FromInt(1)));
4238 __ jmp(&finish_store);
4239
4240 __ bind(&prepare_slow);
4241 // Restore the key, which is known to be the array length.
4242 __ mov(ecx, Immediate(0));
4243
4244 __ bind(&slow);
4245 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4246 __ jmp(ic_slow, RelocInfo::CODE_TARGET);
4247 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004248}
4249
4250
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004251#undef __
4252
4253} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004254
4255#endif // V8_TARGET_ARCH_IA32