blob: 9623b9a5203c5ccf44b4f27b23f81d917a22039a [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.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000144// Name must be unique 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,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000148 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000149 Register r0,
150 Register r1) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000151 ASSERT(name->IsUniqueName());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000152 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;
ulan@chromium.org750145a2013-03-07 15:14:13 +0000180 NameDictionaryLookupStub::GenerateNegativeLookup(masm,
181 miss_label,
182 &done,
183 properties,
184 name,
185 r1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000186 __ 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.org750145a2013-03-07 15:14:13 +0000230 __ mov(offset, FieldOperand(name, Name::kHashFieldOffset));
ulan@chromium.org812308e2012-02-29 15:58:45 +0000231 __ 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.org750145a2013-03-07 15:14:13 +0000244 __ mov(offset, FieldOperand(name, Name::kHashFieldOffset));
ulan@chromium.org812308e2012-02-29 15:58:45 +0000245 __ add(offset, FieldOperand(receiver, HeapObject::kMapOffset));
246 __ xor_(offset, flags);
247 __ and_(offset, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
248 __ sub(offset, name);
249 __ add(offset, Immediate(flags));
250 __ and_(offset, (kSecondaryTableSize - 1) << kHeapObjectTagSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000251
252 // Probe the secondary table.
ulan@chromium.org812308e2012-02-29 15:58:45 +0000253 ProbeTable(
254 isolate(), masm, flags, kSecondary, name, receiver, offset, extra);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000255
256 // Cache miss: Fall-through and let caller handle the miss by
257 // entering the runtime system.
258 __ bind(&miss);
ulan@chromium.org812308e2012-02-29 15:58:45 +0000259 __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000260}
261
262
263void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
264 int index,
265 Register prototype) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000266 __ LoadGlobalFunction(index, prototype);
267 __ LoadGlobalFunctionInitialMap(prototype, prototype);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000268 // Load the prototype from the initial map.
269 __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
270}
271
272
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000273void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000274 MacroAssembler* masm,
275 int index,
276 Register prototype,
277 Label* miss) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000278 // Check we're still in the same context.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000279 __ cmp(Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)),
280 masm->isolate()->global_object());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000281 __ j(not_equal, miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000282 // Get the global function with the given index.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000283 Handle<JSFunction> function(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000284 JSFunction::cast(masm->isolate()->native_context()->get(index)));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000285 // Load its initial map. The global functions all have initial maps.
286 __ Set(prototype, Immediate(Handle<Map>(function->initial_map())));
287 // Load the prototype from the initial map.
288 __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
289}
290
291
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000292void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
293 Register receiver,
294 Register scratch,
295 Label* miss_label) {
296 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000297 __ JumpIfSmi(receiver, miss_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000298
299 // Check that the object is a JS array.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000300 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000301 __ j(not_equal, miss_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000302
303 // Load length directly from the JS array.
304 __ mov(eax, FieldOperand(receiver, JSArray::kLengthOffset));
305 __ ret(0);
306}
307
308
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000309// Generate code to check if an object is a string. If the object is
310// a string, the map's instance type is left in the scratch register.
311static void GenerateStringCheck(MacroAssembler* masm,
312 Register receiver,
313 Register scratch,
314 Label* smi,
315 Label* non_string_object) {
316 // Check that the object isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000317 __ JumpIfSmi(receiver, smi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000318
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000319 // Check that the object is a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000320 __ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
321 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000322 STATIC_ASSERT(kNotStringTag != 0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000323 __ test(scratch, Immediate(kNotStringTag));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000324 __ j(not_zero, non_string_object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000325}
326
327
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000328void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
329 Register receiver,
ager@chromium.org5c838252010-02-19 08:53:10 +0000330 Register scratch1,
331 Register scratch2,
ager@chromium.org378b34e2011-01-28 08:04:38 +0000332 Label* miss,
333 bool support_wrappers) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000334 Label check_wrapper;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000335
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000336 // Check if the object is a string leaving the instance type in the
337 // scratch register.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000338 GenerateStringCheck(masm, receiver, scratch1, miss,
339 support_wrappers ? &check_wrapper : miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000340
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000341 // Load length from the string and convert to a smi.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000342 __ mov(eax, FieldOperand(receiver, String::kLengthOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000343 __ ret(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000344
ager@chromium.org378b34e2011-01-28 08:04:38 +0000345 if (support_wrappers) {
346 // Check if the object is a JSValue wrapper.
347 __ bind(&check_wrapper);
348 __ cmp(scratch1, JS_VALUE_TYPE);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000349 __ j(not_equal, miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000350
ager@chromium.org378b34e2011-01-28 08:04:38 +0000351 // Check if the wrapped value is a string and load the length
352 // directly if it is.
353 __ mov(scratch2, FieldOperand(receiver, JSValue::kValueOffset));
354 GenerateStringCheck(masm, scratch2, scratch1, miss, miss);
355 __ mov(eax, FieldOperand(scratch2, String::kLengthOffset));
356 __ ret(0);
357 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000358}
359
360
361void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
362 Register receiver,
363 Register scratch1,
364 Register scratch2,
365 Label* miss_label) {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000366 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000367 __ mov(eax, scratch1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000368 __ ret(0);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000369}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000370
ager@chromium.org7c537e22008-10-16 08:43:32 +0000371
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000372void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
373 Register dst,
374 Register src,
375 bool inobject,
376 int index,
377 Representation representation) {
378 ASSERT(!FLAG_track_double_fields || !representation.IsDouble());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000379 int offset = index * kPointerSize;
380 if (!inobject) {
381 // Calculate the offset into the properties array.
382 offset = offset + FixedArray::kHeaderSize;
383 __ mov(dst, FieldOperand(src, JSObject::kPropertiesOffset));
384 src = dst;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000385 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000386 __ mov(dst, FieldOperand(src, offset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000387}
388
389
ager@chromium.org5c838252010-02-19 08:53:10 +0000390static void PushInterceptorArguments(MacroAssembler* masm,
391 Register receiver,
392 Register holder,
393 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000394 Handle<JSObject> holder_obj) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000395 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000396 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
397 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000398 Register scratch = name;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000399 __ mov(scratch, Immediate(interceptor));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000400 __ push(scratch);
ager@chromium.org5c838252010-02-19 08:53:10 +0000401 __ push(receiver);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000402 __ push(holder);
403 __ push(FieldOperand(scratch, InterceptorInfo::kDataOffset));
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000404 __ push(Immediate(reinterpret_cast<int>(masm->isolate())));
ager@chromium.org5c838252010-02-19 08:53:10 +0000405}
406
407
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000408static void CompileCallLoadPropertyWithInterceptor(
409 MacroAssembler* masm,
410 Register receiver,
411 Register holder,
412 Register name,
413 Handle<JSObject> holder_obj) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000414 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
ager@chromium.org5c838252010-02-19 08:53:10 +0000415 __ CallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000416 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
417 masm->isolate()),
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000418 6);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000419}
420
421
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000422// Number of pointers to be reserved on stack for fast API call.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000423static const int kFastApiCallArguments = 4;
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000424
425
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000426// Reserves space for the extra arguments to API function in the
ager@chromium.org5c838252010-02-19 08:53:10 +0000427// caller's frame.
428//
429// These arguments are set by CheckPrototypes and GenerateFastApiCall.
430static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
431 // ----------- S t a t e -------------
432 // -- esp[0] : return address
433 // -- esp[4] : last argument in the internal frame of the caller
434 // -----------------------------------
435 __ pop(scratch);
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000436 for (int i = 0; i < kFastApiCallArguments; i++) {
437 __ push(Immediate(Smi::FromInt(0)));
438 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000439 __ push(scratch);
440}
441
442
443// Undoes the effects of ReserveSpaceForFastApiCall.
444static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
445 // ----------- S t a t e -------------
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000446 // -- esp[0] : return address.
447 // -- esp[4] : last fast api call extra argument.
ager@chromium.org5c838252010-02-19 08:53:10 +0000448 // -- ...
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000449 // -- esp[kFastApiCallArguments * 4] : first fast api call extra argument.
450 // -- esp[kFastApiCallArguments * 4 + 4] : last argument in the internal
451 // frame.
ager@chromium.org5c838252010-02-19 08:53:10 +0000452 // -----------------------------------
453 __ pop(scratch);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000454 __ add(esp, Immediate(kPointerSize * kFastApiCallArguments));
ager@chromium.org5c838252010-02-19 08:53:10 +0000455 __ push(scratch);
456}
457
458
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000459// Generates call to API function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000460static void GenerateFastApiCall(MacroAssembler* masm,
461 const CallOptimization& optimization,
462 int argc) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000463 // ----------- S t a t e -------------
464 // -- esp[0] : return address
465 // -- esp[4] : object passing the type check
466 // (last fast api call extra argument,
467 // set by CheckPrototypes)
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000468 // -- esp[8] : api function
ager@chromium.org5c838252010-02-19 08:53:10 +0000469 // (first fast api call extra argument)
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000470 // -- esp[12] : api call data
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000471 // -- esp[16] : isolate
472 // -- esp[20] : last argument
ager@chromium.org5c838252010-02-19 08:53:10 +0000473 // -- ...
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000474 // -- esp[(argc + 4) * 4] : first argument
475 // -- esp[(argc + 5) * 4] : receiver
ager@chromium.org5c838252010-02-19 08:53:10 +0000476 // -----------------------------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000477 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000478 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000479 __ LoadHeapObject(edi, function);
ager@chromium.org5c838252010-02-19 08:53:10 +0000480 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
481
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000482 // Pass the additional arguments.
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000483 __ mov(Operand(esp, 2 * kPointerSize), edi);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000484 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000485 Handle<Object> call_data(api_call_info->data(), masm->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000486 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
487 __ mov(ecx, api_call_info);
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000488 __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kDataOffset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000489 __ mov(Operand(esp, 3 * kPointerSize), ebx);
490 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000491 __ mov(Operand(esp, 3 * kPointerSize), Immediate(call_data));
ager@chromium.org5c838252010-02-19 08:53:10 +0000492 }
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000493 __ mov(Operand(esp, 4 * kPointerSize),
494 Immediate(reinterpret_cast<int>(masm->isolate())));
ager@chromium.org5c838252010-02-19 08:53:10 +0000495
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000496 // Prepare arguments.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000497 __ lea(eax, Operand(esp, 4 * kPointerSize));
ager@chromium.org5c838252010-02-19 08:53:10 +0000498
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000499 const int kApiArgc = 1; // API function gets reference to the v8::Arguments.
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000500
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000501 // Allocate the v8::Arguments structure in the arguments' space since
502 // it's not controlled by GC.
503 const int kApiStackSpace = 4;
504
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000505 __ PrepareCallApiFunction(kApiArgc + kApiStackSpace);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000506
507 __ mov(ApiParameterOperand(1), eax); // v8::Arguments::implicit_args_.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000508 __ add(eax, Immediate(argc * kPointerSize));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000509 __ mov(ApiParameterOperand(2), eax); // v8::Arguments::values_.
510 __ Set(ApiParameterOperand(3), Immediate(argc)); // v8::Arguments::length_.
511 // v8::Arguments::is_construct_call_.
512 __ Set(ApiParameterOperand(4), Immediate(0));
513
514 // v8::InvocationCallback's argument.
515 __ lea(eax, ApiParameterOperand(1));
516 __ mov(ApiParameterOperand(0), eax);
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000517
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000518 // Function address is a foreign pointer outside V8's heap.
519 Address function_address = v8::ToCData<Address>(api_call_info->callback());
520 __ CallApiFunctionAndReturn(function_address,
521 argc + kFastApiCallArguments + 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000522}
523
524
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000525class CallInterceptorCompiler BASE_EMBEDDED {
526 public:
ager@chromium.org5c838252010-02-19 08:53:10 +0000527 CallInterceptorCompiler(StubCompiler* stub_compiler,
528 const ParameterCount& arguments,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000529 Register name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000530 Code::ExtraICState extra_state)
ager@chromium.org5c838252010-02-19 08:53:10 +0000531 : stub_compiler_(stub_compiler),
532 arguments_(arguments),
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000533 name_(name),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000534 extra_state_(extra_state) {}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000535
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000536 void Compile(MacroAssembler* masm,
537 Handle<JSObject> object,
538 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000539 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000540 LookupResult* lookup,
541 Register receiver,
542 Register scratch1,
543 Register scratch2,
544 Register scratch3,
545 Label* miss) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000546 ASSERT(holder->HasNamedInterceptor());
547 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
548
549 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000550 __ JumpIfSmi(receiver, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000551
552 CallOptimization optimization(lookup);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000553 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000554 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
555 holder, lookup, name, optimization, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000556 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000557 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
558 name, holder, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000559 }
560 }
561
562 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000563 void CompileCacheable(MacroAssembler* masm,
564 Handle<JSObject> object,
565 Register receiver,
566 Register scratch1,
567 Register scratch2,
568 Register scratch3,
569 Handle<JSObject> interceptor_holder,
570 LookupResult* lookup,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000571 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000572 const CallOptimization& optimization,
573 Label* miss_label) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000574 ASSERT(optimization.is_constant_call());
575 ASSERT(!lookup->holder()->IsGlobalObject());
576
577 int depth1 = kInvalidProtoDepth;
578 int depth2 = kInvalidProtoDepth;
579 bool can_do_fast_api_call = false;
580 if (optimization.is_simple_api_call() &&
581 !lookup->holder()->IsGlobalObject()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000582 depth1 = optimization.GetPrototypeDepthOfExpectedType(
583 object, interceptor_holder);
ager@chromium.org5c838252010-02-19 08:53:10 +0000584 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000585 depth2 = optimization.GetPrototypeDepthOfExpectedType(
586 interceptor_holder, Handle<JSObject>(lookup->holder()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000587 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000588 can_do_fast_api_call =
589 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000590 }
591
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000592 Counters* counters = masm->isolate()->counters();
593 __ IncrementCounter(counters->call_const_interceptor(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000594
595 if (can_do_fast_api_call) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000596 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000597 ReserveSpaceForFastApiCall(masm, scratch1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000598 }
599
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000600 // Check that the maps from receiver to interceptor's holder
601 // haven't changed and thus we can invoke interceptor.
ager@chromium.org5c838252010-02-19 08:53:10 +0000602 Label miss_cleanup;
603 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
604 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000605 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
606 scratch1, scratch2, scratch3,
607 name, depth1, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000608
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000609 // Invoke an interceptor and if it provides a value,
610 // branch to |regular_invoke|.
ager@chromium.org5c838252010-02-19 08:53:10 +0000611 Label regular_invoke;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000612 LoadWithInterceptor(masm, receiver, holder, interceptor_holder,
613 &regular_invoke);
ager@chromium.org5c838252010-02-19 08:53:10 +0000614
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000615 // Interceptor returned nothing for this property. Try to use cached
616 // constant function.
ager@chromium.org5c838252010-02-19 08:53:10 +0000617
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000618 // Check that the maps from interceptor's holder to constant function's
619 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000620 if (*interceptor_holder != lookup->holder()) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000621 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000622 Handle<JSObject>(lookup->holder()),
623 scratch1, scratch2, scratch3,
624 name, depth2, miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000625 } else {
626 // CheckPrototypes has a side effect of fetching a 'holder'
627 // for API (object which is instanceof for the signature). It's
628 // safe to omit it here, as if present, it should be fetched
629 // by the previous CheckPrototypes.
630 ASSERT(depth2 == kInvalidProtoDepth);
631 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000632
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000633 // Invoke function.
ager@chromium.org5c838252010-02-19 08:53:10 +0000634 if (can_do_fast_api_call) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000635 GenerateFastApiCall(masm, optimization, arguments_.immediate());
ager@chromium.org5c838252010-02-19 08:53:10 +0000636 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000637 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000638 ? CALL_AS_FUNCTION
639 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000640 Handle<JSFunction> function = optimization.constant_function();
641 ParameterCount expected(function);
642 __ InvokeFunction(function, expected, arguments_,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000643 JUMP_FUNCTION, NullCallWrapper(), call_kind);
ager@chromium.org5c838252010-02-19 08:53:10 +0000644 }
645
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000646 // Deferred code for fast API call case---clean preallocated space.
ager@chromium.org5c838252010-02-19 08:53:10 +0000647 if (can_do_fast_api_call) {
648 __ bind(&miss_cleanup);
649 FreeSpaceForFastApiCall(masm, scratch1);
650 __ jmp(miss_label);
651 }
652
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000653 // Invoke a regular function.
ager@chromium.org5c838252010-02-19 08:53:10 +0000654 __ bind(&regular_invoke);
655 if (can_do_fast_api_call) {
656 FreeSpaceForFastApiCall(masm, scratch1);
657 }
658 }
659
660 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000661 Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +0000662 Register receiver,
663 Register scratch1,
664 Register scratch2,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000665 Register scratch3,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000666 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000667 Handle<JSObject> interceptor_holder,
ager@chromium.org5c838252010-02-19 08:53:10 +0000668 Label* miss_label) {
669 Register holder =
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000670 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000671 scratch1, scratch2, scratch3,
672 name, miss_label);
ager@chromium.org5c838252010-02-19 08:53:10 +0000673
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000674 FrameScope scope(masm, StackFrame::INTERNAL);
ager@chromium.org5c838252010-02-19 08:53:10 +0000675 // Save the name_ register across the call.
676 __ push(name_);
677
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000678 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
ager@chromium.org5c838252010-02-19 08:53:10 +0000679
680 __ CallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000681 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
682 masm->isolate()),
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000683 6);
ager@chromium.org5c838252010-02-19 08:53:10 +0000684
685 // Restore the name_ register.
686 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000687
688 // Leave the internal frame.
ager@chromium.org5c838252010-02-19 08:53:10 +0000689 }
690
691 void LoadWithInterceptor(MacroAssembler* masm,
692 Register receiver,
693 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000694 Handle<JSObject> holder_obj,
ager@chromium.org5c838252010-02-19 08:53:10 +0000695 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000696 {
697 FrameScope scope(masm, StackFrame::INTERNAL);
698 __ push(holder); // Save the holder.
699 __ push(name_); // Save the name.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000700
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000701 CompileCallLoadPropertyWithInterceptor(masm,
702 receiver,
703 holder,
704 name_,
705 holder_obj);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000706
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000707 __ pop(name_); // Restore the name.
708 __ pop(receiver); // Restore the holder.
709 // Leave the internal frame.
710 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000711
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000712 __ cmp(eax, masm->isolate()->factory()->no_interceptor_result_sentinel());
ager@chromium.org5c838252010-02-19 08:53:10 +0000713 __ j(not_equal, interceptor_succeeded);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000714 }
715
ager@chromium.org5c838252010-02-19 08:53:10 +0000716 StubCompiler* stub_compiler_;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000717 const ParameterCount& arguments_;
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000718 Register name_;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000719 Code::ExtraICState extra_state_;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000720};
721
722
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000723void BaseStoreStubCompiler::GenerateRestoreName(MacroAssembler* masm,
724 Label* label,
725 Handle<Name> name) {
726 if (!label->is_unused()) {
727 __ bind(label);
728 __ mov(this->name(), Immediate(name));
729 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000730}
731
732
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000733// Generate code to check that a global property cell is empty. Create
734// the property cell at compilation time if no cell exists for the
735// property.
736static void GenerateCheckPropertyCell(MacroAssembler* masm,
737 Handle<GlobalObject> global,
738 Handle<Name> name,
739 Register scratch,
740 Label* miss) {
741 Handle<JSGlobalPropertyCell> cell =
742 GlobalObject::EnsurePropertyCell(global, name);
743 ASSERT(cell->value()->IsTheHole());
744 Handle<Oddball> the_hole = masm->isolate()->factory()->the_hole_value();
745 if (Serializer::enabled()) {
746 __ mov(scratch, Immediate(cell));
747 __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
748 Immediate(the_hole));
749 } else {
750 __ cmp(Operand::Cell(cell), Immediate(the_hole));
751 }
752 __ j(not_equal, miss);
753}
754
755
ager@chromium.org5c838252010-02-19 08:53:10 +0000756// Both name_reg and receiver_reg are preserved on jumps to miss_label,
757// but may be destroyed if store is successful.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000758void StubCompiler::GenerateStoreTransition(MacroAssembler* masm,
759 Handle<JSObject> object,
760 LookupResult* lookup,
761 Handle<Map> transition,
762 Handle<Name> name,
763 Register receiver_reg,
764 Register name_reg,
765 Register value_reg,
766 Register scratch1,
767 Register scratch2,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000768 Register unused,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000769 Label* miss_label,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000770 Label* miss_restore_name,
771 Label* slow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000772 // Check that the map of the object hasn't changed.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000773 __ CheckMap(receiver_reg, Handle<Map>(object->map()),
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000774 miss_label, DO_SMI_CHECK, REQUIRE_EXACT_MAP);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000775
776 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000777 if (object->IsJSGlobalProxy()) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000778 __ CheckAccessGlobalProxy(receiver_reg, scratch1, scratch2, miss_label);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000779 }
780
danno@chromium.orgf005df62013-04-30 16:36:45 +0000781 int descriptor = transition->LastAdded();
782 DescriptorArray* descriptors = transition->instance_descriptors();
783 PropertyDetails details = descriptors->GetDetails(descriptor);
784 Representation representation = details.representation();
785 ASSERT(!representation.IsNone());
786
787 // Ensure no transitions to deprecated maps are followed.
788 __ CheckMapDeprecated(transition, scratch1, miss_label);
789
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000790 // Check that we are allowed to write this.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000791 if (object->GetPrototype()->IsJSObject()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000792 JSObject* holder;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000793 // holder == object indicates that no property was found.
794 if (lookup->holder() != *object) {
795 holder = lookup->holder();
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000796 } else {
797 // Find the top object.
798 holder = *object;
799 do {
800 holder = JSObject::cast(holder->GetPrototype());
801 } while (holder->GetPrototype()->IsJSObject());
802 }
803 // We need an extra register, push
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000804 Register holder_reg = CheckPrototypes(
805 object, receiver_reg, Handle<JSObject>(holder), name_reg,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000806 scratch1, scratch2, name, miss_restore_name, SKIP_RECEIVER);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000807 // If no property was found, and the holder (the last object in the
808 // prototype chain) is in slow mode, we need to do a negative lookup on the
809 // holder.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000810 if (lookup->holder() == *object) {
811 if (holder->IsJSGlobalObject()) {
812 GenerateCheckPropertyCell(
813 masm,
814 Handle<GlobalObject>(GlobalObject::cast(holder)),
815 name,
816 scratch1,
817 miss_restore_name);
818 } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
819 GenerateDictionaryNegativeLookup(
820 masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
821 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000822 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000823 }
824
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000825 Register storage_reg = name_reg;
826
827 if (FLAG_track_fields && representation.IsSmi()) {
828 __ JumpIfNotSmi(value_reg, miss_restore_name);
829 } else if (FLAG_track_double_fields && representation.IsDouble()) {
830 Label do_store, heap_number;
831 __ AllocateHeapNumber(storage_reg, scratch1, scratch2, slow);
832
833 __ JumpIfNotSmi(value_reg, &heap_number);
834 __ SmiUntag(value_reg);
835 if (CpuFeatures::IsSupported(SSE2)) {
836 CpuFeatureScope use_sse2(masm, SSE2);
837 __ cvtsi2sd(xmm0, value_reg);
838 } else {
839 __ push(value_reg);
840 __ fild_s(Operand(esp, 0));
841 __ pop(value_reg);
842 }
843 __ SmiTag(value_reg);
844 __ jmp(&do_store);
845
846 __ bind(&heap_number);
847 __ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(),
848 miss_restore_name, DONT_DO_SMI_CHECK, REQUIRE_EXACT_MAP);
849 if (CpuFeatures::IsSupported(SSE2)) {
850 CpuFeatureScope use_sse2(masm, SSE2);
851 __ movdbl(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset));
852 } else {
853 __ fld_d(FieldOperand(value_reg, HeapNumber::kValueOffset));
854 }
855
856 __ bind(&do_store);
857 if (CpuFeatures::IsSupported(SSE2)) {
858 CpuFeatureScope use_sse2(masm, SSE2);
859 __ movdbl(FieldOperand(storage_reg, HeapNumber::kValueOffset), xmm0);
860 } else {
861 __ fstp_d(FieldOperand(storage_reg, HeapNumber::kValueOffset));
862 }
863 }
864
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000865 // Stub never generated for non-global objects that require access
866 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000867 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000868
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000869 // Perform map transition for the receiver if necessary.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000870 if (object->map()->unused_property_fields() == 0) {
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000871 // The properties must be extended before we can store the value.
ager@chromium.org32912102009-01-16 10:38:43 +0000872 // We jump to a runtime call that extends the properties array.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000873 __ pop(scratch1); // Return address.
ager@chromium.org5c838252010-02-19 08:53:10 +0000874 __ push(receiver_reg);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000875 __ push(Immediate(transition));
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000876 __ push(value_reg);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000877 __ push(scratch1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000878 __ TailCallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000879 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
880 masm->isolate()),
881 3,
882 1);
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000883 return;
884 }
885
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000886 // Update the map of the object.
887 __ mov(scratch1, Immediate(transition));
888 __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1);
verwaest@chromium.org37141392012-05-31 13:27:02 +0000889
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000890 // Update the write barrier for the map field.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000891 __ RecordWriteField(receiver_reg,
892 HeapObject::kMapOffset,
893 scratch1,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000894 scratch2,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000895 kDontSaveFPRegs,
896 OMIT_REMEMBERED_SET,
897 OMIT_SMI_CHECK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000898
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000899 int index = transition->instance_descriptors()->GetFieldIndex(
900 transition->LastAdded());
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000901
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000902 // Adjust for the number of properties stored in the object. Even in the
903 // face of a transition we can use the old map here because the size of the
904 // object and the number of in-object properties is not going to change.
905 index -= object->map()->inobject_properties();
906
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000907 // TODO(verwaest): Share this code as a code stub.
ager@chromium.org7c537e22008-10-16 08:43:32 +0000908 if (index < 0) {
909 // Set the property straight into the object.
910 int offset = object->map()->instance_size() + (index * kPointerSize);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000911 if (FLAG_track_double_fields && representation.IsDouble()) {
912 __ mov(FieldOperand(receiver_reg, offset), storage_reg);
913 } else {
914 __ mov(FieldOperand(receiver_reg, offset), value_reg);
915 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000916
danno@chromium.orgf005df62013-04-30 16:36:45 +0000917 if (!FLAG_track_fields || !representation.IsSmi()) {
918 // Update the write barrier for the array address.
919 // Pass the value being stored in the now unused name_reg.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000920 if (!FLAG_track_double_fields || !representation.IsDouble()) {
921 __ mov(name_reg, value_reg);
922 } else {
923 ASSERT(storage_reg.is(name_reg));
924 }
danno@chromium.orgf005df62013-04-30 16:36:45 +0000925 __ RecordWriteField(receiver_reg,
926 offset,
927 name_reg,
928 scratch1,
929 kDontSaveFPRegs);
930 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000931 } else {
932 // Write to the properties array.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000933 int offset = index * kPointerSize + FixedArray::kHeaderSize;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000934 // Get the properties array (optimistically).
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000935 __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000936 if (FLAG_track_double_fields && representation.IsDouble()) {
937 __ mov(FieldOperand(scratch1, offset), storage_reg);
938 } else {
939 __ mov(FieldOperand(scratch1, offset), value_reg);
940 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000941
danno@chromium.orgf005df62013-04-30 16:36:45 +0000942 if (!FLAG_track_fields || !representation.IsSmi()) {
943 // Update the write barrier for the array address.
944 // Pass the value being stored in the now unused name_reg.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000945 if (!FLAG_track_double_fields || !representation.IsDouble()) {
946 __ mov(name_reg, value_reg);
947 } else {
948 ASSERT(storage_reg.is(name_reg));
949 }
danno@chromium.orgf005df62013-04-30 16:36:45 +0000950 __ RecordWriteField(scratch1,
951 offset,
952 name_reg,
953 receiver_reg,
954 kDontSaveFPRegs);
955 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000956 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000957
958 // Return the value (register eax).
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000959 ASSERT(value_reg.is(eax));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000960 __ ret(0);
961}
962
963
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000964// Both name_reg and receiver_reg are preserved on jumps to miss_label,
965// but may be destroyed if store is successful.
966void StubCompiler::GenerateStoreField(MacroAssembler* masm,
967 Handle<JSObject> object,
968 LookupResult* lookup,
969 Register receiver_reg,
970 Register name_reg,
971 Register value_reg,
972 Register scratch1,
973 Register scratch2,
974 Label* miss_label) {
975 // Check that the map of the object hasn't changed.
976 __ CheckMap(receiver_reg, Handle<Map>(object->map()),
977 miss_label, DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
978
979 // Perform global security token check if needed.
980 if (object->IsJSGlobalProxy()) {
981 __ CheckAccessGlobalProxy(receiver_reg, scratch1, scratch2, miss_label);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000982 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000983
984 // Stub never generated for non-global objects that require access
985 // checks.
986 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
987
988 int index = lookup->GetFieldIndex().field_index();
989
990 // Adjust for the number of properties stored in the object. Even in the
991 // face of a transition we can use the old map here because the size of the
992 // object and the number of in-object properties is not going to change.
993 index -= object->map()->inobject_properties();
994
danno@chromium.orgf005df62013-04-30 16:36:45 +0000995 Representation representation = lookup->representation();
996 ASSERT(!representation.IsNone());
997 if (FLAG_track_fields && representation.IsSmi()) {
998 __ JumpIfNotSmi(value_reg, miss_label);
999 } else if (FLAG_track_double_fields && representation.IsDouble()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001000 // Load the double storage.
1001 if (index < 0) {
1002 int offset = object->map()->instance_size() + (index * kPointerSize);
1003 __ mov(scratch1, FieldOperand(receiver_reg, offset));
1004 } else {
1005 __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
1006 int offset = index * kPointerSize + FixedArray::kHeaderSize;
1007 __ mov(scratch1, FieldOperand(scratch1, offset));
1008 }
1009
1010 // Store the value into the storage.
1011 Label do_store, heap_number;
1012 __ JumpIfNotSmi(value_reg, &heap_number);
1013 __ SmiUntag(value_reg);
1014 if (CpuFeatures::IsSupported(SSE2)) {
1015 CpuFeatureScope use_sse2(masm, SSE2);
1016 __ cvtsi2sd(xmm0, value_reg);
1017 } else {
1018 __ push(value_reg);
1019 __ fild_s(Operand(esp, 0));
1020 __ pop(value_reg);
1021 }
1022 __ SmiTag(value_reg);
1023 __ jmp(&do_store);
1024 __ bind(&heap_number);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001025 __ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(),
1026 miss_label, DONT_DO_SMI_CHECK, REQUIRE_EXACT_MAP);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001027 if (CpuFeatures::IsSupported(SSE2)) {
1028 CpuFeatureScope use_sse2(masm, SSE2);
1029 __ movdbl(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset));
1030 } else {
1031 __ fld_d(FieldOperand(value_reg, HeapNumber::kValueOffset));
1032 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00001033 __ bind(&do_store);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001034 if (CpuFeatures::IsSupported(SSE2)) {
1035 CpuFeatureScope use_sse2(masm, SSE2);
1036 __ movdbl(FieldOperand(scratch1, HeapNumber::kValueOffset), xmm0);
1037 } else {
1038 __ fstp_d(FieldOperand(scratch1, HeapNumber::kValueOffset));
1039 }
1040 // Return the value (register eax).
1041 ASSERT(value_reg.is(eax));
1042 __ ret(0);
1043 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +00001044 }
1045
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001046 ASSERT(!FLAG_track_double_fields || !representation.IsDouble());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001047 // TODO(verwaest): Share this code as a code stub.
1048 if (index < 0) {
1049 // Set the property straight into the object.
1050 int offset = object->map()->instance_size() + (index * kPointerSize);
1051 __ mov(FieldOperand(receiver_reg, offset), value_reg);
1052
danno@chromium.orgf005df62013-04-30 16:36:45 +00001053 if (!FLAG_track_fields || !representation.IsSmi()) {
1054 // Update the write barrier for the array address.
1055 // Pass the value being stored in the now unused name_reg.
1056 __ mov(name_reg, value_reg);
1057 __ RecordWriteField(receiver_reg,
1058 offset,
1059 name_reg,
1060 scratch1,
1061 kDontSaveFPRegs);
1062 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001063 } else {
1064 // Write to the properties array.
1065 int offset = index * kPointerSize + FixedArray::kHeaderSize;
1066 // Get the properties array (optimistically).
1067 __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001068 __ mov(FieldOperand(scratch1, offset), value_reg);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001069
danno@chromium.orgf005df62013-04-30 16:36:45 +00001070 if (!FLAG_track_fields || !representation.IsSmi()) {
1071 // Update the write barrier for the array address.
1072 // Pass the value being stored in the now unused name_reg.
1073 __ mov(name_reg, value_reg);
1074 __ RecordWriteField(scratch1,
1075 offset,
1076 name_reg,
1077 receiver_reg,
1078 kDontSaveFPRegs);
1079 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001080 }
1081
1082 // Return the value (register eax).
1083 ASSERT(value_reg.is(eax));
1084 __ ret(0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001085}
1086
1087
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001088// Calls GenerateCheckPropertyCell for each global object in the prototype chain
1089// from object to (but not including) holder.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001090static void GenerateCheckPropertyCells(MacroAssembler* masm,
1091 Handle<JSObject> object,
1092 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001093 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001094 Register scratch,
1095 Label* miss) {
1096 Handle<JSObject> current = object;
1097 while (!current.is_identical_to(holder)) {
1098 if (current->IsGlobalObject()) {
1099 GenerateCheckPropertyCell(masm,
1100 Handle<GlobalObject>::cast(current),
1101 name,
1102 scratch,
1103 miss);
1104 }
1105 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
1106 }
1107}
1108
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001109
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001110void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001111 __ jmp(code, RelocInfo::CODE_TARGET);
1112}
1113
1114
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001115#undef __
1116#define __ ACCESS_MASM(masm())
1117
1118
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001119Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
1120 Register object_reg,
1121 Handle<JSObject> holder,
1122 Register holder_reg,
1123 Register scratch1,
1124 Register scratch2,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001125 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001126 int save_at_depth,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001127 Label* miss,
1128 PrototypeCheckType check) {
1129 Handle<JSObject> first = object;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001130 // Make sure there's no overlap between holder and object registers.
1131 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1132 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1133 && !scratch2.is(scratch1));
1134
1135 // Keep track of the current object in register reg.
1136 Register reg = object_reg;
1137 Handle<JSObject> current = object;
1138 int depth = 0;
1139
1140 if (save_at_depth == depth) {
1141 __ mov(Operand(esp, kPointerSize), reg);
1142 }
1143
1144 // Traverse the prototype chain and check the maps in the prototype chain for
1145 // fast and global objects or do negative lookup for normal objects.
1146 while (!current.is_identical_to(holder)) {
1147 ++depth;
1148
1149 // Only global objects and objects that do not require access
1150 // checks are allowed in stubs.
1151 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1152
1153 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
1154 if (!current->HasFastProperties() &&
1155 !current->IsJSGlobalObject() &&
1156 !current->IsJSGlobalProxy()) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001157 if (!name->IsUniqueName()) {
1158 ASSERT(name->IsString());
1159 name = factory()->InternalizeString(Handle<String>::cast(name));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001160 }
1161 ASSERT(current->property_dictionary()->FindEntry(*name) ==
ulan@chromium.org750145a2013-03-07 15:14:13 +00001162 NameDictionary::kNotFound);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001163
1164 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1165 scratch1, scratch2);
1166
1167 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
1168 reg = holder_reg; // From now on the object will be in holder_reg.
1169 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
1170 } else {
1171 bool in_new_space = heap()->InNewSpace(*prototype);
1172 Handle<Map> current_map(current->map());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001173 if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) {
1174 __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK,
1175 ALLOW_ELEMENT_TRANSITION_MAPS);
1176 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001177
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001178 // Check access rights to the global object. This has to happen after
1179 // the map check so that we know that the object is actually a global
1180 // object.
1181 if (current->IsJSGlobalProxy()) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001182 __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001183 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001184
1185 if (in_new_space) {
1186 // Save the map in scratch1 for later.
1187 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
1188 }
1189
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001190 reg = holder_reg; // From now on the object will be in holder_reg.
1191
1192 if (in_new_space) {
1193 // The prototype is in new space; we cannot store a reference to it
1194 // in the code. Load it from the map.
1195 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
1196 } else {
1197 // The prototype is in old space; load it directly.
1198 __ mov(reg, prototype);
1199 }
1200 }
1201
1202 if (save_at_depth == depth) {
1203 __ mov(Operand(esp, kPointerSize), reg);
1204 }
1205
1206 // Go to the next object in the prototype chain.
1207 current = prototype;
1208 }
1209 ASSERT(current.is_identical_to(holder));
1210
1211 // Log the check depth.
1212 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
1213
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001214 if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) {
1215 // Check the holder map.
1216 __ CheckMap(reg, Handle<Map>(holder->map()),
1217 miss, DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
1218 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001219
1220 // Perform security check for access to the global object.
1221 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1222 if (holder->IsJSGlobalProxy()) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001223 __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001224 }
1225
1226 // If we've skipped any global objects, it's not enough to verify that
1227 // their maps haven't changed. We also need to check that the property
1228 // cell for the property is still empty.
1229 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1230
1231 // Return the register containing the holder.
1232 return reg;
1233}
1234
1235
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001236void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success,
1237 Label* miss) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001238 if (!miss->is_unused()) {
1239 __ jmp(success);
1240 __ bind(miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001241 TailCallBuiltin(masm(), MissBuiltin(kind()));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001242 }
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001243}
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001244
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001245
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001246Register BaseLoadStubCompiler::CallbackHandlerFrontend(
1247 Handle<JSObject> object,
1248 Register object_reg,
1249 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001250 Handle<Name> name,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001251 Label* success,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001252 Handle<ExecutableAccessorInfo> callback) {
1253 Label miss;
1254
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001255 Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001256
1257 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
1258 ASSERT(!reg.is(scratch2()));
1259 ASSERT(!reg.is(scratch3()));
1260 Register dictionary = scratch1();
1261 bool must_preserve_dictionary_reg = reg.is(dictionary);
1262
1263 // Load the properties dictionary.
1264 if (must_preserve_dictionary_reg) {
1265 __ push(dictionary);
1266 }
1267 __ mov(dictionary, FieldOperand(reg, JSObject::kPropertiesOffset));
1268
1269 // Probe the dictionary.
1270 Label probe_done, pop_and_miss;
ulan@chromium.org750145a2013-03-07 15:14:13 +00001271 NameDictionaryLookupStub::GeneratePositiveLookup(masm(),
1272 &pop_and_miss,
1273 &probe_done,
1274 dictionary,
1275 this->name(),
1276 scratch2(),
1277 scratch3());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001278 __ bind(&pop_and_miss);
1279 if (must_preserve_dictionary_reg) {
1280 __ pop(dictionary);
1281 }
1282 __ jmp(&miss);
1283 __ bind(&probe_done);
1284
1285 // If probing finds an entry in the dictionary, scratch2 contains the
1286 // index into the dictionary. Check that the value is the callback.
1287 Register index = scratch2();
1288 const int kElementsStartOffset =
ulan@chromium.org750145a2013-03-07 15:14:13 +00001289 NameDictionary::kHeaderSize +
1290 NameDictionary::kElementsStartIndex * kPointerSize;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001291 const int kValueOffset = kElementsStartOffset + kPointerSize;
1292 __ mov(scratch3(),
1293 Operand(dictionary, index, times_4, kValueOffset - kHeapObjectTag));
1294 if (must_preserve_dictionary_reg) {
1295 __ pop(dictionary);
1296 }
1297 __ cmp(scratch3(), callback);
1298 __ j(not_equal, &miss);
1299 }
1300
1301 HandlerFrontendFooter(success, &miss);
1302 return reg;
1303}
1304
1305
1306void BaseLoadStubCompiler::NonexistentHandlerFrontend(
1307 Handle<JSObject> object,
1308 Handle<JSObject> last,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001309 Handle<Name> name,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001310 Label* success,
1311 Handle<GlobalObject> global) {
1312 Label miss;
1313
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001314 HandlerFrontendHeader(object, receiver(), last, name, &miss);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001315
1316 // If the last object in the prototype chain is a global object,
1317 // check that the global property cell is empty.
1318 if (!global.is_null()) {
1319 GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
1320 }
1321
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001322 HandlerFrontendFooter(success, &miss);
1323}
1324
1325
1326void BaseLoadStubCompiler::GenerateLoadField(Register reg,
1327 Handle<JSObject> holder,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001328 PropertyIndex field,
1329 Representation representation) {
1330 if (!reg.is(receiver())) __ mov(receiver(), reg);
1331 if (kind() == Code::LOAD_IC) {
1332 LoadFieldStub stub(field.is_inobject(holder),
1333 field.translate(holder),
1334 representation);
1335 GenerateTailCall(masm(), stub.GetCode(isolate()));
1336 } else {
1337 KeyedLoadFieldStub stub(field.is_inobject(holder),
1338 field.translate(holder),
1339 representation);
1340 GenerateTailCall(masm(), stub.GetCode(isolate()));
1341 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001342}
1343
1344
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001345void BaseLoadStubCompiler::GenerateLoadCallback(
1346 Register reg,
1347 Handle<ExecutableAccessorInfo> callback) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001348 // Insert additional parameters into the stack frame above return address.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001349 ASSERT(!scratch3().is(reg));
1350 __ pop(scratch3()); // Get return address to place it below.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001351
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001352 __ push(receiver()); // receiver
1353 __ mov(scratch2(), esp);
1354 ASSERT(!scratch2().is(reg));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001355 __ push(reg); // holder
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001356 // Push data from ExecutableAccessorInfo.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001357 if (isolate()->heap()->InNewSpace(callback->data())) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001358 __ mov(scratch1(), Immediate(callback));
1359 __ push(FieldOperand(scratch1(), ExecutableAccessorInfo::kDataOffset));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001360 } else {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001361 __ push(Immediate(Handle<Object>(callback->data(), isolate())));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001362 }
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001363 __ push(Immediate(reinterpret_cast<int>(isolate())));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001364
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001365 // Save a pointer to where we pushed the arguments pointer. This will be
1366 // passed as the const ExecutableAccessorInfo& to the C++ callback.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001367 __ push(scratch2());
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001368
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001369 __ push(name()); // name
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001370 __ mov(ebx, esp); // esp points to reference to name (handler).
1371
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001372 __ push(scratch3()); // Restore return address.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001373
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001374 // 4 elements array for v8::Arguments::values_, handler for name and pointer
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001375 // to the values (it considered as smi in GC).
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001376 const int kStackSpace = 6;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001377 const int kApiArgc = 2;
1378
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001379 __ PrepareCallApiFunction(kApiArgc);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001380 __ mov(ApiParameterOperand(0), ebx); // name.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001381 __ add(ebx, Immediate(kPointerSize));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001382 __ mov(ApiParameterOperand(1), ebx); // arguments pointer.
1383
kmillikin@chromium.org2d5475f2009-12-20 18:15:52 +00001384 // Emitting a stub call may try to allocate (if the code is not
1385 // already generated). Do not allow the assembler to perform a
1386 // garbage collection but instead return the allocation failure
1387 // object.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001388 Address getter_address = v8::ToCData<Address>(callback->getter());
1389 __ CallApiFunctionAndReturn(getter_address, kStackSpace);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001390}
1391
1392
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001393void BaseLoadStubCompiler::GenerateLoadConstant(Handle<JSFunction> value) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001394 // Return the constant value.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001395 __ LoadHeapObject(eax, value);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001396 __ ret(0);
1397}
1398
1399
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001400void BaseLoadStubCompiler::GenerateLoadInterceptor(
1401 Register holder_reg,
1402 Handle<JSObject> object,
1403 Handle<JSObject> interceptor_holder,
1404 LookupResult* lookup,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001405 Handle<Name> name) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001406 ASSERT(interceptor_holder->HasNamedInterceptor());
1407 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1408
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001409 // So far the most popular follow ups for interceptor loads are FIELD
1410 // and CALLBACKS, so inline only them, other cases may be added
1411 // later.
1412 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001413 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001414 if (lookup->IsField()) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001415 compile_followup_inline = true;
1416 } else if (lookup->type() == CALLBACKS &&
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001417 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
1418 ExecutableAccessorInfo* callback =
1419 ExecutableAccessorInfo::cast(lookup->GetCallbackObject());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001420 compile_followup_inline = callback->getter() != NULL &&
1421 callback->IsCompatibleReceiver(*object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001422 }
1423 }
1424
1425 if (compile_followup_inline) {
1426 // Compile the interceptor call, followed by inline code to load the
1427 // property from further up the prototype chain if the call fails.
1428 // Check that the maps haven't changed.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001429 ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001430
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001431 // Preserve the receiver register explicitly whenever it is different from
1432 // the holder and it is needed should the interceptor return without any
1433 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1434 // the FIELD case might cause a miss during the prototype check.
1435 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001436 bool must_preserve_receiver_reg = !receiver().is(holder_reg) &&
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001437 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1438
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001439 // Save necessary data before invoking an interceptor.
1440 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001441 {
1442 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001443
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001444 if (must_preserve_receiver_reg) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001445 __ push(receiver());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001446 }
1447 __ push(holder_reg);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001448 __ push(this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001449
1450 // Invoke an interceptor. Note: map checks from receiver to
1451 // interceptor's holder has been compiled before (see a caller
1452 // of this method.)
1453 CompileCallLoadPropertyWithInterceptor(masm(),
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001454 receiver(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001455 holder_reg,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001456 this->name(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001457 interceptor_holder);
1458
1459 // Check if interceptor provided a value for property. If it's
1460 // the case, return immediately.
1461 Label interceptor_failed;
1462 __ cmp(eax, factory()->no_interceptor_result_sentinel());
1463 __ j(equal, &interceptor_failed);
1464 frame_scope.GenerateLeaveFrame();
1465 __ ret(0);
1466
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001467 // Clobber registers when generating debug-code to provoke errors.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001468 __ bind(&interceptor_failed);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001469 if (FLAG_debug_code) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001470 __ mov(receiver(), Immediate(BitCast<int32_t>(kZapValue)));
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001471 __ mov(holder_reg, Immediate(BitCast<int32_t>(kZapValue)));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001472 __ mov(this->name(), Immediate(BitCast<int32_t>(kZapValue)));
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001473 }
1474
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001475 __ pop(this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001476 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001477 if (must_preserve_receiver_reg) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001478 __ pop(receiver());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001479 }
1480
1481 // Leave the internal frame.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001482 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001483
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001484 GenerateLoadPostInterceptor(holder_reg, interceptor_holder, name, lookup);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001485 } else { // !compile_followup_inline
1486 // Call the runtime system to load the interceptor.
1487 // Check that the maps haven't changed.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001488 __ pop(scratch2()); // save old return address
1489 PushInterceptorArguments(masm(), receiver(), holder_reg,
1490 this->name(), interceptor_holder);
1491 __ push(scratch2()); // restore old return address
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001492
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001493 ExternalReference ref =
1494 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001495 isolate());
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001496 __ TailCallExternalReference(ref, 6, 1);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001497 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001498}
1499
1500
ulan@chromium.org750145a2013-03-07 15:14:13 +00001501void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001502 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001503 __ cmp(ecx, Immediate(name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001504 __ j(not_equal, miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001505 }
1506}
1507
1508
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001509void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1510 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001511 Handle<Name> name,
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001512 Label* miss) {
1513 ASSERT(holder->IsGlobalObject());
1514
1515 // Get the number of arguments.
1516 const int argc = arguments().immediate();
1517
1518 // Get the receiver from the stack.
1519 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1520
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001521
1522 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001523 __ JumpIfSmi(edx, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001524 CheckPrototypes(object, edx, holder, ebx, eax, edi, name, miss);
1525}
1526
1527
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001528void CallStubCompiler::GenerateLoadFunctionFromCell(
1529 Handle<JSGlobalPropertyCell> cell,
1530 Handle<JSFunction> function,
1531 Label* miss) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001532 // Get the value from the cell.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001533 if (Serializer::enabled()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001534 __ mov(edi, Immediate(cell));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001535 __ mov(edi, FieldOperand(edi, JSGlobalPropertyCell::kValueOffset));
1536 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001537 __ mov(edi, Operand::Cell(cell));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001538 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001539
1540 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001541 if (isolate()->heap()->InNewSpace(*function)) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001542 // We can't embed a pointer to a function in new space so we have
1543 // to verify that the shared function info is unchanged. This has
1544 // the nice side effect that multiple closures based on the same
1545 // function can all use this call IC. Before we load through the
1546 // function, we have to verify that it still is a function.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001547 __ JumpIfSmi(edi, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001548 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001549 __ j(not_equal, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001550
1551 // Check the shared function info. Make sure it hasn't changed.
1552 __ cmp(FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset),
1553 Immediate(Handle<SharedFunctionInfo>(function->shared())));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001554 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001555 __ cmp(edi, Immediate(function));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001556 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001557 __ j(not_equal, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001558}
1559
1560
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001561void CallStubCompiler::GenerateMissBranch() {
1562 Handle<Code> code =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001563 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
danno@chromium.org40cb8782011-05-25 07:58:50 +00001564 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001565 extra_state_);
1566 __ jmp(code, RelocInfo::CODE_TARGET);
1567}
1568
1569
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001570Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1571 Handle<JSObject> holder,
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00001572 PropertyIndex index,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001573 Handle<Name> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001574 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001575 // -- ecx : name
1576 // -- esp[0] : return address
1577 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1578 // -- ...
1579 // -- esp[(argc + 1) * 4] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001580 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001581 Label miss;
1582
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001583 GenerateNameCheck(name, &miss);
1584
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001585 // Get the receiver from the stack.
1586 const int argc = arguments().immediate();
1587 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1588
1589 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001590 __ JumpIfSmi(edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001591
1592 // Do the right check and compute the holder register.
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001593 Register reg = CheckPrototypes(object, edx, holder, ebx, eax, edi,
1594 name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001595
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001596 GenerateFastPropertyLoad(
1597 masm(), edi, reg, index.is_inobject(holder),
1598 index.translate(holder), Representation::Tagged());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001599
1600 // Check that the function really is a function.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001601 __ JumpIfSmi(edi, &miss);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001602 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001603 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001604
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001605 // Patch the receiver on the stack with the global proxy if
1606 // necessary.
1607 if (object->IsGlobalObject()) {
1608 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
1609 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
1610 }
1611
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001612 // Invoke the function.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001613 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001614 ? CALL_AS_FUNCTION
1615 : CALL_AS_METHOD;
1616 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION,
1617 NullCallWrapper(), call_kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001618
1619 // Handle call cache miss.
1620 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001621 GenerateMissBranch();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001622
1623 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001624 return GetCode(Code::FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001625}
1626
1627
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001628Handle<Code> CallStubCompiler::CompileArrayPushCall(
1629 Handle<Object> object,
1630 Handle<JSObject> holder,
1631 Handle<JSGlobalPropertyCell> cell,
1632 Handle<JSFunction> function,
1633 Handle<String> name) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001634 // ----------- S t a t e -------------
1635 // -- ecx : name
1636 // -- esp[0] : return address
1637 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1638 // -- ...
1639 // -- esp[(argc + 1) * 4] : receiver
1640 // -----------------------------------
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001641
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001642 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001643 if (!object->IsJSArray() || !cell.is_null()) {
1644 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001645 }
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001646
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001647 Label miss;
1648
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001649 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001650
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001651 // Get the receiver from the stack.
1652 const int argc = arguments().immediate();
1653 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1654
1655 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001656 __ JumpIfSmi(edx, &miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001657
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001658 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
1659 name, &miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001660
1661 if (argc == 0) {
1662 // Noop, return the length.
1663 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
1664 __ ret((argc + 1) * kPointerSize);
1665 } else {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001666 Label call_builtin;
1667
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001668 if (argc == 1) { // Otherwise fall through to call builtin.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001669 Label attempt_to_grow_elements, with_write_barrier, check_double;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001670
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001671 // Get the elements array of the object.
1672 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset));
1673
1674 // Check that the elements are in fast mode and writable.
1675 __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
1676 Immediate(factory()->fixed_array_map()));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001677 __ j(not_equal, &check_double);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001678
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001679 // Get the array's length into eax and calculate new length.
1680 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
1681 STATIC_ASSERT(kSmiTagSize == 1);
1682 STATIC_ASSERT(kSmiTag == 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001683 __ add(eax, Immediate(Smi::FromInt(argc)));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001684
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001685 // Get the elements' length into ecx.
1686 __ mov(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001687
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001688 // Check if we could survive without allocation.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001689 __ cmp(eax, ecx);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001690 __ j(greater, &attempt_to_grow_elements);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001691
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001692 // Check if value is a smi.
1693 __ mov(ecx, Operand(esp, argc * kPointerSize));
1694 __ JumpIfNotSmi(ecx, &with_write_barrier);
1695
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001696 // Save new length.
1697 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1698
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001699 // Store the value.
1700 __ mov(FieldOperand(edi,
1701 eax,
1702 times_half_pointer_size,
1703 FixedArray::kHeaderSize - argc * kPointerSize),
1704 ecx);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001705
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001706 __ ret((argc + 1) * kPointerSize);
1707
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001708 __ bind(&check_double);
1709
1710
1711 // Check that the elements are in double mode.
1712 __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
1713 Immediate(factory()->fixed_double_array_map()));
1714 __ j(not_equal, &call_builtin);
1715
1716 // Get the array's length into eax and calculate new length.
1717 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
1718 STATIC_ASSERT(kSmiTagSize == 1);
1719 STATIC_ASSERT(kSmiTag == 0);
1720 __ add(eax, Immediate(Smi::FromInt(argc)));
1721
1722 // Get the elements' length into ecx.
1723 __ mov(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
1724
1725 // Check if we could survive without allocation.
1726 __ cmp(eax, ecx);
1727 __ j(greater, &call_builtin);
1728
1729 __ mov(ecx, Operand(esp, argc * kPointerSize));
1730 __ StoreNumberToDoubleElements(
1731 ecx, edi, eax, ecx, xmm0, &call_builtin, true, argc * kDoubleSize);
1732
1733 // Save new length.
1734 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1735 __ ret((argc + 1) * kPointerSize);
1736
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001737 __ bind(&with_write_barrier);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001738
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001739 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
1740
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001741 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001742 Label fast_object, not_fast_object;
1743 __ CheckFastObjectElements(ebx, &not_fast_object, Label::kNear);
1744 __ jmp(&fast_object);
1745 // In case of fast smi-only, convert to fast object, otherwise bail out.
1746 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001747 __ CheckFastSmiElements(ebx, &call_builtin);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001748 __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
1749 Immediate(factory()->heap_number_map()));
1750 __ j(equal, &call_builtin);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001751 // edi: elements array
1752 // edx: receiver
1753 // ebx: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001754 Label try_holey_map;
1755 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001756 FAST_ELEMENTS,
1757 ebx,
1758 edi,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001759 &try_holey_map);
1760
1761 ElementsTransitionGenerator::
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001762 GenerateMapChangeElementsTransition(masm(),
1763 DONT_TRACK_ALLOCATION_SITE,
1764 NULL);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001765 // Restore edi.
1766 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset));
1767 __ jmp(&fast_object);
1768
1769 __ bind(&try_holey_map);
1770 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1771 FAST_HOLEY_ELEMENTS,
1772 ebx,
1773 edi,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001774 &call_builtin);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001775 ElementsTransitionGenerator::
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001776 GenerateMapChangeElementsTransition(masm(),
1777 DONT_TRACK_ALLOCATION_SITE,
1778 NULL);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001779 // Restore edi.
1780 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset));
1781 __ bind(&fast_object);
1782 } else {
1783 __ CheckFastObjectElements(ebx, &call_builtin);
1784 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001785
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001786 // Save new length.
1787 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1788
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001789 // Store the value.
1790 __ lea(edx, FieldOperand(edi,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001791 eax, times_half_pointer_size,
1792 FixedArray::kHeaderSize - argc * kPointerSize));
1793 __ mov(Operand(edx, 0), ecx);
1794
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001795 __ RecordWrite(edi, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001796 OMIT_SMI_CHECK);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001797
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001798 __ ret((argc + 1) * kPointerSize);
1799
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001800 __ bind(&attempt_to_grow_elements);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001801 if (!FLAG_inline_new) {
1802 __ jmp(&call_builtin);
1803 }
1804
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001805 __ mov(ebx, Operand(esp, argc * kPointerSize));
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001806 // Growing elements that are SMI-only requires special handling in case
1807 // the new element is non-Smi. For now, delegate to the builtin.
1808 Label no_fast_elements_check;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001809 __ JumpIfSmi(ebx, &no_fast_elements_check);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001810 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
1811 __ CheckFastObjectElements(ecx, &call_builtin, Label::kFar);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001812 __ bind(&no_fast_elements_check);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001813
1814 // We could be lucky and the elements array could be at the top of
1815 // new-space. In this case we can just grow it in place by moving the
1816 // allocation pointer up.
1817
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001818 ExternalReference new_space_allocation_top =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001819 ExternalReference::new_space_allocation_top_address(isolate());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001820 ExternalReference new_space_allocation_limit =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001821 ExternalReference::new_space_allocation_limit_address(isolate());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001822
1823 const int kAllocationDelta = 4;
1824 // Load top.
1825 __ mov(ecx, Operand::StaticVariable(new_space_allocation_top));
1826
1827 // Check if it's the end of elements.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001828 __ lea(edx, FieldOperand(edi,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001829 eax, times_half_pointer_size,
1830 FixedArray::kHeaderSize - argc * kPointerSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001831 __ cmp(edx, ecx);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001832 __ j(not_equal, &call_builtin);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001833 __ add(ecx, Immediate(kAllocationDelta * kPointerSize));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001834 __ cmp(ecx, Operand::StaticVariable(new_space_allocation_limit));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001835 __ j(above, &call_builtin);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001836
1837 // We fit and could grow elements.
1838 __ mov(Operand::StaticVariable(new_space_allocation_top), ecx);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001839
1840 // Push the argument...
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001841 __ mov(Operand(edx, 0), ebx);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001842 // ... and fill the rest with holes.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001843 for (int i = 1; i < kAllocationDelta; i++) {
1844 __ mov(Operand(edx, i * kPointerSize),
lrn@chromium.org7516f052011-03-30 08:52:27 +00001845 Immediate(factory()->the_hole_value()));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001846 }
1847
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001848 // We know the elements array is in new space so we don't need the
1849 // remembered set, but we just pushed a value onto it so we may have to
1850 // tell the incremental marker to rescan the object that we just grew. We
1851 // don't need to worry about the holes because they are in old space and
1852 // already marked black.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001853 __ RecordWrite(edi, edx, ebx, kDontSaveFPRegs, OMIT_REMEMBERED_SET);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001854
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001855 // Restore receiver to edx as finish sequence assumes it's here.
1856 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1857
1858 // Increment element's and array's sizes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001859 __ add(FieldOperand(edi, FixedArray::kLengthOffset),
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001860 Immediate(Smi::FromInt(kAllocationDelta)));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001861
1862 // NOTE: This only happen in new-space, where we don't
1863 // care about the black-byte-count on pages. Otherwise we should
1864 // update that too if the object is black.
1865
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001866 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1867
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001868 __ ret((argc + 1) * kPointerSize);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001869 }
1870
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001871 __ bind(&call_builtin);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001872 __ TailCallExternalReference(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001873 ExternalReference(Builtins::c_ArrayPush, isolate()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001874 argc + 1,
1875 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001876 }
1877
1878 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001879 GenerateMissBranch();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001880
1881 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001882 return GetCode(function);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001883}
1884
1885
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001886Handle<Code> CallStubCompiler::CompileArrayPopCall(
1887 Handle<Object> object,
1888 Handle<JSObject> holder,
1889 Handle<JSGlobalPropertyCell> cell,
1890 Handle<JSFunction> function,
1891 Handle<String> name) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001892 // ----------- S t a t e -------------
1893 // -- ecx : name
1894 // -- esp[0] : return address
1895 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1896 // -- ...
1897 // -- esp[(argc + 1) * 4] : receiver
1898 // -----------------------------------
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001899
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001900 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001901 if (!object->IsJSArray() || !cell.is_null()) {
1902 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001903 }
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001904
ager@chromium.orgac091b72010-05-05 07:34:42 +00001905 Label miss, return_undefined, call_builtin;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001906
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001907 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001908
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001909 // Get the receiver from the stack.
1910 const int argc = arguments().immediate();
1911 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1912
1913 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001914 __ JumpIfSmi(edx, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001915 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
1916 name, &miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001917
1918 // Get the elements array of the object.
1919 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset));
1920
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001921 // Check that the elements are in fast mode and writable.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001922 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
lrn@chromium.org7516f052011-03-30 08:52:27 +00001923 Immediate(factory()->fixed_array_map()));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001924 __ j(not_equal, &call_builtin);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001925
1926 // Get the array's length into ecx and calculate new length.
1927 __ mov(ecx, FieldOperand(edx, JSArray::kLengthOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001928 __ sub(ecx, Immediate(Smi::FromInt(1)));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001929 __ j(negative, &return_undefined);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001930
1931 // Get the last element.
1932 STATIC_ASSERT(kSmiTagSize == 1);
1933 STATIC_ASSERT(kSmiTag == 0);
1934 __ mov(eax, FieldOperand(ebx,
1935 ecx, times_half_pointer_size,
1936 FixedArray::kHeaderSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001937 __ cmp(eax, Immediate(factory()->the_hole_value()));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001938 __ j(equal, &call_builtin);
1939
1940 // Set the array's length.
1941 __ mov(FieldOperand(edx, JSArray::kLengthOffset), ecx);
1942
1943 // Fill with the hole.
1944 __ mov(FieldOperand(ebx,
1945 ecx, times_half_pointer_size,
1946 FixedArray::kHeaderSize),
lrn@chromium.org7516f052011-03-30 08:52:27 +00001947 Immediate(factory()->the_hole_value()));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001948 __ ret((argc + 1) * kPointerSize);
1949
ager@chromium.orgac091b72010-05-05 07:34:42 +00001950 __ bind(&return_undefined);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001951 __ mov(eax, Immediate(factory()->undefined_value()));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001952 __ ret((argc + 1) * kPointerSize);
1953
1954 __ bind(&call_builtin);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001955 __ TailCallExternalReference(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001956 ExternalReference(Builtins::c_ArrayPop, isolate()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001957 argc + 1,
1958 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001959
1960 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001961 GenerateMissBranch();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001962
1963 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001964 return GetCode(function);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001965}
1966
1967
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001968Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1969 Handle<Object> object,
1970 Handle<JSObject> holder,
1971 Handle<JSGlobalPropertyCell> cell,
1972 Handle<JSFunction> function,
1973 Handle<String> name) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001974 // ----------- S t a t e -------------
1975 // -- ecx : function name
1976 // -- esp[0] : return address
1977 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1978 // -- ...
1979 // -- esp[(argc + 1) * 4] : receiver
1980 // -----------------------------------
1981
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001982 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001983 if (!object->IsString() || !cell.is_null()) {
1984 return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001985 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001986
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001987 const int argc = arguments().immediate();
1988
1989 Label miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001990 Label name_miss;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001991 Label index_out_of_range;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001992 Label* index_out_of_range_label = &index_out_of_range;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001993
danno@chromium.org40cb8782011-05-25 07:58:50 +00001994 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001995 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001996 DEFAULT_STRING_STUB)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001997 index_out_of_range_label = &miss;
1998 }
1999
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002000 GenerateNameCheck(name, &name_miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002001
2002 // Check that the maps starting from the prototype haven't changed.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002003 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2004 Context::STRING_FUNCTION_INDEX,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002005 eax,
2006 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002007 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002008 CheckPrototypes(
2009 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2010 eax, holder, ebx, edx, edi, name, &miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002011
2012 Register receiver = ebx;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002013 Register index = edi;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002014 Register result = eax;
2015 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize));
2016 if (argc > 0) {
2017 __ mov(index, Operand(esp, (argc - 0) * kPointerSize));
2018 } else {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002019 __ Set(index, Immediate(factory()->undefined_value()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002020 }
2021
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002022 StringCharCodeAtGenerator generator(receiver,
2023 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002024 result,
2025 &miss, // When not a string.
2026 &miss, // When not a number.
2027 index_out_of_range_label,
2028 STRING_INDEX_IS_NUMBER);
2029 generator.GenerateFast(masm());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002030 __ ret((argc + 1) * kPointerSize);
2031
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002032 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002033 generator.GenerateSlow(masm(), call_helper);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002034
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002035 if (index_out_of_range.is_linked()) {
2036 __ bind(&index_out_of_range);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002037 __ Set(eax, Immediate(factory()->nan_value()));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002038 __ ret((argc + 1) * kPointerSize);
2039 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002040
2041 __ bind(&miss);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002042 // Restore function name in ecx.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002043 __ Set(ecx, Immediate(name));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002044 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002045 GenerateMissBranch();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002046
2047 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002048 return GetCode(function);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002049}
2050
2051
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002052Handle<Code> CallStubCompiler::CompileStringCharAtCall(
2053 Handle<Object> object,
2054 Handle<JSObject> holder,
2055 Handle<JSGlobalPropertyCell> cell,
2056 Handle<JSFunction> function,
2057 Handle<String> name) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002058 // ----------- S t a t e -------------
2059 // -- ecx : function name
2060 // -- esp[0] : return address
2061 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2062 // -- ...
2063 // -- esp[(argc + 1) * 4] : receiver
2064 // -----------------------------------
2065
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002066 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002067 if (!object->IsString() || !cell.is_null()) {
2068 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002069 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002070
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002071 const int argc = arguments().immediate();
2072
2073 Label miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002074 Label name_miss;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002075 Label index_out_of_range;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002076 Label* index_out_of_range_label = &index_out_of_range;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002077
danno@chromium.org40cb8782011-05-25 07:58:50 +00002078 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002079 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002080 DEFAULT_STRING_STUB)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002081 index_out_of_range_label = &miss;
2082 }
2083
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002084 GenerateNameCheck(name, &name_miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002085
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002086 // Check that the maps starting from the prototype haven't changed.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002087 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2088 Context::STRING_FUNCTION_INDEX,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002089 eax,
2090 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002091 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002092 CheckPrototypes(
2093 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2094 eax, holder, ebx, edx, edi, name, &miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002095
2096 Register receiver = eax;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002097 Register index = edi;
danno@chromium.orgc612e022011-11-10 11:38:15 +00002098 Register scratch = edx;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002099 Register result = eax;
2100 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize));
2101 if (argc > 0) {
2102 __ mov(index, Operand(esp, (argc - 0) * kPointerSize));
2103 } else {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002104 __ Set(index, Immediate(factory()->undefined_value()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002105 }
2106
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002107 StringCharAtGenerator generator(receiver,
2108 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00002109 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002110 result,
2111 &miss, // When not a string.
2112 &miss, // When not a number.
2113 index_out_of_range_label,
2114 STRING_INDEX_IS_NUMBER);
2115 generator.GenerateFast(masm());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002116 __ ret((argc + 1) * kPointerSize);
2117
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002118 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002119 generator.GenerateSlow(masm(), call_helper);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002120
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002121 if (index_out_of_range.is_linked()) {
2122 __ bind(&index_out_of_range);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002123 __ Set(eax, Immediate(factory()->empty_string()));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002124 __ ret((argc + 1) * kPointerSize);
2125 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002126
2127 __ bind(&miss);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002128 // Restore function name in ecx.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002129 __ Set(ecx, Immediate(name));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002130 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002131 GenerateMissBranch();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002132
2133 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002134 return GetCode(function);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002135}
2136
2137
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002138Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
2139 Handle<Object> object,
2140 Handle<JSObject> holder,
2141 Handle<JSGlobalPropertyCell> cell,
2142 Handle<JSFunction> function,
2143 Handle<String> name) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002144 // ----------- S t a t e -------------
2145 // -- ecx : function name
2146 // -- esp[0] : return address
2147 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2148 // -- ...
2149 // -- esp[(argc + 1) * 4] : receiver
2150 // -----------------------------------
2151
2152 const int argc = arguments().immediate();
2153
2154 // If the object is not a JSObject or we got an unexpected number of
2155 // arguments, bail out to the regular call.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002156 if (!object->IsJSObject() || argc != 1) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002157 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002158 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002159
2160 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002161 GenerateNameCheck(name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002162
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002163 if (cell.is_null()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002164 __ mov(edx, Operand(esp, 2 * kPointerSize));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002165 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002166 __ JumpIfSmi(edx, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002167 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2168 name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002169 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002170 ASSERT(cell->value() == *function);
2171 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2172 &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002173 GenerateLoadFunctionFromCell(cell, function, &miss);
2174 }
2175
2176 // Load the char code argument.
2177 Register code = ebx;
2178 __ mov(code, Operand(esp, 1 * kPointerSize));
2179
2180 // Check the code is a smi.
2181 Label slow;
2182 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002183 __ JumpIfNotSmi(code, &slow);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002184
2185 // Convert the smi code to uint16.
2186 __ and_(code, Immediate(Smi::FromInt(0xffff)));
2187
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002188 StringCharFromCodeGenerator generator(code, eax);
2189 generator.GenerateFast(masm());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002190 __ ret(2 * kPointerSize);
2191
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002192 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002193 generator.GenerateSlow(masm(), call_helper);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002194
2195 // Tail call the full function. We do not have to patch the receiver
2196 // because the function makes no use of it.
2197 __ bind(&slow);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002198 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002199 ? CALL_AS_FUNCTION
2200 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002201 ParameterCount expected(function);
2202 __ InvokeFunction(function, expected, arguments(),
2203 JUMP_FUNCTION, NullCallWrapper(), call_kind);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002204
2205 __ bind(&miss);
2206 // ecx: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002207 GenerateMissBranch();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002208
2209 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002210 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002211}
2212
2213
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002214Handle<Code> CallStubCompiler::CompileMathFloorCall(
2215 Handle<Object> object,
2216 Handle<JSObject> holder,
2217 Handle<JSGlobalPropertyCell> cell,
2218 Handle<JSFunction> function,
2219 Handle<String> name) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002220 // ----------- S t a t e -------------
2221 // -- ecx : name
2222 // -- esp[0] : return address
2223 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2224 // -- ...
2225 // -- esp[(argc + 1) * 4] : receiver
2226 // -----------------------------------
2227
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002228 if (!CpuFeatures::IsSupported(SSE2)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002229 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002230 }
2231
ulan@chromium.org750145a2013-03-07 15:14:13 +00002232 CpuFeatureScope use_sse2(masm(), SSE2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002233
2234 const int argc = arguments().immediate();
2235
2236 // If the object is not a JSObject or we got an unexpected number of
2237 // arguments, bail out to the regular call.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002238 if (!object->IsJSObject() || argc != 1) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002239 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002240 }
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002241
2242 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002243 GenerateNameCheck(name, &miss);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002244
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002245 if (cell.is_null()) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002246 __ mov(edx, Operand(esp, 2 * kPointerSize));
2247
2248 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002249 __ JumpIfSmi(edx, &miss);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002250
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002251 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2252 name, &miss);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002253 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002254 ASSERT(cell->value() == *function);
2255 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2256 &miss);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002257 GenerateLoadFunctionFromCell(cell, function, &miss);
2258 }
2259
2260 // Load the (only) argument into eax.
2261 __ mov(eax, Operand(esp, 1 * kPointerSize));
2262
2263 // Check if the argument is a smi.
2264 Label smi;
2265 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002266 __ JumpIfSmi(eax, &smi);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002267
2268 // Check if the argument is a heap number and load its value into xmm0.
2269 Label slow;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002270 __ CheckMap(eax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002271 __ movdbl(xmm0, FieldOperand(eax, HeapNumber::kValueOffset));
2272
2273 // Check if the argument is strictly positive. Note this also
2274 // discards NaN.
2275 __ xorpd(xmm1, xmm1);
2276 __ ucomisd(xmm0, xmm1);
2277 __ j(below_equal, &slow);
2278
2279 // Do a truncating conversion.
2280 __ cvttsd2si(eax, Operand(xmm0));
2281
2282 // Check if the result fits into a smi. Note this also checks for
2283 // 0x80000000 which signals a failed conversion.
2284 Label wont_fit_into_smi;
2285 __ test(eax, Immediate(0xc0000000));
2286 __ j(not_zero, &wont_fit_into_smi);
2287
2288 // Smi tag and return.
2289 __ SmiTag(eax);
2290 __ bind(&smi);
2291 __ ret(2 * kPointerSize);
2292
2293 // Check if the argument is < 2^kMantissaBits.
2294 Label already_round;
2295 __ bind(&wont_fit_into_smi);
2296 __ LoadPowerOf2(xmm1, ebx, HeapNumber::kMantissaBits);
2297 __ ucomisd(xmm0, xmm1);
2298 __ j(above_equal, &already_round);
2299
2300 // Save a copy of the argument.
2301 __ movaps(xmm2, xmm0);
2302
2303 // Compute (argument + 2^kMantissaBits) - 2^kMantissaBits.
2304 __ addsd(xmm0, xmm1);
2305 __ subsd(xmm0, xmm1);
2306
2307 // Compare the argument and the tentative result to get the right mask:
2308 // if xmm2 < xmm0:
2309 // xmm2 = 1...1
2310 // else:
2311 // xmm2 = 0...0
2312 __ cmpltsd(xmm2, xmm0);
2313
2314 // Subtract 1 if the argument was less than the tentative result.
2315 __ LoadPowerOf2(xmm1, ebx, 0);
2316 __ andpd(xmm1, xmm2);
2317 __ subsd(xmm0, xmm1);
2318
2319 // Return a new heap number.
2320 __ AllocateHeapNumber(eax, ebx, edx, &slow);
2321 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
2322 __ ret(2 * kPointerSize);
2323
2324 // Return the argument (when it's an already round heap number).
2325 __ bind(&already_round);
2326 __ mov(eax, Operand(esp, 1 * kPointerSize));
2327 __ ret(2 * kPointerSize);
2328
2329 // Tail call the full function. We do not have to patch the receiver
2330 // because the function makes no use of it.
2331 __ bind(&slow);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002332 ParameterCount expected(function);
2333 __ InvokeFunction(function, expected, arguments(),
2334 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002335
2336 __ bind(&miss);
2337 // ecx: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002338 GenerateMissBranch();
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002339
2340 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002341 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002342}
2343
2344
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002345Handle<Code> CallStubCompiler::CompileMathAbsCall(
2346 Handle<Object> object,
2347 Handle<JSObject> holder,
2348 Handle<JSGlobalPropertyCell> cell,
2349 Handle<JSFunction> function,
2350 Handle<String> name) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002351 // ----------- S t a t e -------------
2352 // -- ecx : name
2353 // -- esp[0] : return address
2354 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2355 // -- ...
2356 // -- esp[(argc + 1) * 4] : receiver
2357 // -----------------------------------
2358
2359 const int argc = arguments().immediate();
2360
2361 // If the object is not a JSObject or we got an unexpected number of
2362 // arguments, bail out to the regular call.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002363 if (!object->IsJSObject() || argc != 1) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002364 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002365 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002366
2367 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002368 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002369
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002370 if (cell.is_null()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002371 __ mov(edx, Operand(esp, 2 * kPointerSize));
2372
2373 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002374 __ JumpIfSmi(edx, &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002375
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002376 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2377 name, &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002378 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002379 ASSERT(cell->value() == *function);
2380 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2381 &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002382 GenerateLoadFunctionFromCell(cell, function, &miss);
2383 }
2384
2385 // Load the (only) argument into eax.
2386 __ mov(eax, Operand(esp, 1 * kPointerSize));
2387
2388 // Check if the argument is a smi.
2389 Label not_smi;
2390 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002391 __ JumpIfNotSmi(eax, &not_smi);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002392
2393 // Set ebx to 1...1 (== -1) if the argument is negative, or to 0...0
2394 // otherwise.
2395 __ mov(ebx, eax);
2396 __ sar(ebx, kBitsPerInt - 1);
2397
2398 // Do bitwise not or do nothing depending on ebx.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002399 __ xor_(eax, ebx);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002400
2401 // Add 1 or do nothing depending on ebx.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002402 __ sub(eax, ebx);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002403
2404 // If the result is still negative, go to the slow case.
2405 // This only happens for the most negative smi.
2406 Label slow;
2407 __ j(negative, &slow);
2408
2409 // Smi case done.
2410 __ ret(2 * kPointerSize);
2411
2412 // Check if the argument is a heap number and load its exponent and
2413 // sign into ebx.
2414 __ bind(&not_smi);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002415 __ CheckMap(eax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002416 __ mov(ebx, FieldOperand(eax, HeapNumber::kExponentOffset));
2417
2418 // Check the sign of the argument. If the argument is positive,
2419 // just return it.
2420 Label negative_sign;
2421 __ test(ebx, Immediate(HeapNumber::kSignMask));
2422 __ j(not_zero, &negative_sign);
2423 __ ret(2 * kPointerSize);
2424
2425 // If the argument is negative, clear the sign, and return a new
2426 // number.
2427 __ bind(&negative_sign);
2428 __ and_(ebx, ~HeapNumber::kSignMask);
2429 __ mov(ecx, FieldOperand(eax, HeapNumber::kMantissaOffset));
2430 __ AllocateHeapNumber(eax, edi, edx, &slow);
2431 __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), ebx);
2432 __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx);
2433 __ ret(2 * kPointerSize);
2434
2435 // Tail call the full function. We do not have to patch the receiver
2436 // because the function makes no use of it.
2437 __ bind(&slow);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002438 ParameterCount expected(function);
2439 __ InvokeFunction(function, expected, arguments(),
2440 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002441
2442 __ bind(&miss);
2443 // ecx: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002444 GenerateMissBranch();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002445
2446 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002447 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002448}
2449
2450
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002451Handle<Code> CallStubCompiler::CompileFastApiCall(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002452 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002453 Handle<Object> object,
2454 Handle<JSObject> holder,
2455 Handle<JSGlobalPropertyCell> cell,
2456 Handle<JSFunction> function,
2457 Handle<String> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002458 ASSERT(optimization.is_simple_api_call());
2459 // Bail out if object is a global object as we don't want to
2460 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002461 if (object->IsGlobalObject()) return Handle<Code>::null();
2462 if (!cell.is_null()) return Handle<Code>::null();
2463 if (!object->IsJSObject()) return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002464 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002465 Handle<JSObject>::cast(object), holder);
2466 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002467
2468 Label miss, miss_before_stack_reserved;
2469
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002470 GenerateNameCheck(name, &miss_before_stack_reserved);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002471
2472 // Get the receiver from the stack.
2473 const int argc = arguments().immediate();
2474 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
2475
2476 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002477 __ JumpIfSmi(edx, &miss_before_stack_reserved);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002478
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002479 Counters* counters = isolate()->counters();
2480 __ IncrementCounter(counters->call_const(), 1);
2481 __ IncrementCounter(counters->call_const_fast_api(), 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002482
2483 // Allocate space for v8::Arguments implicit values. Must be initialized
2484 // before calling any runtime function.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002485 __ sub(esp, Immediate(kFastApiCallArguments * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002486
2487 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002488 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2489 name, depth, &miss);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002490
2491 // Move the return address on top of the stack.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00002492 __ mov(eax, Operand(esp, 4 * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002493 __ mov(Operand(esp, 0 * kPointerSize), eax);
2494
2495 // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains
2496 // duplicate of return address and will be overwritten.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002497 GenerateFastApiCall(masm(), optimization, argc);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002498
2499 __ bind(&miss);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002500 __ add(esp, Immediate(kFastApiCallArguments * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002501
2502 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002503 GenerateMissBranch();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002504
2505 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002506 return GetCode(function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002507}
2508
2509
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002510void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
2511 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002512 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002513 CheckType check,
2514 Label* success) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002515 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00002516 // -- ecx : name
2517 // -- esp[0] : return address
2518 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2519 // -- ...
2520 // -- esp[(argc + 1) * 4] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002521 // -----------------------------------
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002522 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002523 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002524
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002525 // Get the receiver from the stack.
2526 const int argc = arguments().immediate();
2527 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
2528
2529 // Check that the receiver isn't a smi.
2530 if (check != NUMBER_CHECK) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00002531 __ JumpIfSmi(edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002532 }
2533
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002534 // Make sure that it's okay not to patch the on stack receiver
2535 // unless we're doing a receiver map check.
2536 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002537 switch (check) {
2538 case RECEIVER_MAP_CHECK:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002539 __ IncrementCounter(isolate()->counters()->call_const(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00002540
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002541 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002542 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax,
2543 edi, name, &miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002544
2545 // Patch the receiver on the stack with the global proxy if
2546 // necessary.
2547 if (object->IsGlobalObject()) {
2548 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
2549 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
2550 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002551 break;
2552
2553 case STRING_CHECK:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002554 // Check that the object is a string.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002555 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, eax);
2556 __ j(above_equal, &miss);
2557 // Check that the maps starting from the prototype haven't changed.
2558 GenerateDirectLoadGlobalFunctionPrototype(
2559 masm(), Context::STRING_FUNCTION_INDEX, eax, &miss);
2560 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002561 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002562 eax, holder, ebx, edx, edi, name, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002563 break;
2564
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002565 case SYMBOL_CHECK:
2566 // Check that the object is a symbol.
2567 __ CmpObjectType(edx, SYMBOL_TYPE, eax);
2568 __ j(not_equal, &miss);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002569 // Check that the maps starting from the prototype haven't changed.
2570 GenerateDirectLoadGlobalFunctionPrototype(
2571 masm(), Context::SYMBOL_FUNCTION_INDEX, eax, &miss);
2572 CheckPrototypes(
2573 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2574 eax, holder, ebx, edx, edi, name, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002575 break;
2576
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002577 case NUMBER_CHECK: {
2578 Label fast;
2579 // Check that the object is a smi or a heap number.
2580 __ JumpIfSmi(edx, &fast);
2581 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, eax);
2582 __ j(not_equal, &miss);
2583 __ bind(&fast);
2584 // Check that the maps starting from the prototype haven't changed.
2585 GenerateDirectLoadGlobalFunctionPrototype(
2586 masm(), Context::NUMBER_FUNCTION_INDEX, eax, &miss);
2587 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002588 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002589 eax, holder, ebx, edx, edi, name, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002590 break;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002591 }
2592 case BOOLEAN_CHECK: {
2593 Label fast;
2594 // Check that the object is a boolean.
2595 __ cmp(edx, factory()->true_value());
2596 __ j(equal, &fast);
2597 __ cmp(edx, factory()->false_value());
2598 __ j(not_equal, &miss);
2599 __ bind(&fast);
2600 // Check that the maps starting from the prototype haven't changed.
2601 GenerateDirectLoadGlobalFunctionPrototype(
2602 masm(), Context::BOOLEAN_FUNCTION_INDEX, eax, &miss);
2603 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002604 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002605 eax, holder, ebx, edx, edi, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002606 break;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002607 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002608 }
2609
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002610 __ jmp(success);
2611
2612 // Handle call cache miss.
2613 __ bind(&miss);
2614 GenerateMissBranch();
2615}
2616
2617
2618void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002619 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002620 ? CALL_AS_FUNCTION
2621 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002622 ParameterCount expected(function);
2623 __ InvokeFunction(function, expected, arguments(),
2624 JUMP_FUNCTION, NullCallWrapper(), call_kind);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002625}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002626
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002627
2628Handle<Code> CallStubCompiler::CompileCallConstant(
2629 Handle<Object> object,
2630 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002631 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002632 CheckType check,
2633 Handle<JSFunction> function) {
2634
2635 if (HasCustomCallGenerator(function)) {
2636 Handle<Code> code = CompileCustomCall(object, holder,
2637 Handle<JSGlobalPropertyCell>::null(),
ulan@chromium.org750145a2013-03-07 15:14:13 +00002638 function, Handle<String>::cast(name));
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002639 // A null handle means bail out to the regular compiler code below.
2640 if (!code.is_null()) return code;
2641 }
2642
2643 Label success;
2644
2645 CompileHandlerFrontend(object, holder, name, check, &success);
2646 __ bind(&success);
2647 CompileHandlerBackend(function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002648
2649 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002650 return GetCode(function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002651}
2652
2653
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002654Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2655 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002656 Handle<Name> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002657 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00002658 // -- ecx : name
2659 // -- esp[0] : return address
2660 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2661 // -- ...
2662 // -- esp[(argc + 1) * 4] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002663 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002664 Label miss;
2665
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002666 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002667
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002668 // Get the number of arguments.
2669 const int argc = arguments().immediate();
2670
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002671 LookupResult lookup(isolate());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002672 LookupPostInterceptor(holder, name, &lookup);
2673
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002674 // Get the receiver from the stack.
2675 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002676
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002677 CallInterceptorCompiler compiler(this, arguments(), ecx, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002678 compiler.Compile(masm(), object, holder, name, &lookup, edx, ebx, edi, eax,
2679 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002680
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002681 // Restore receiver.
2682 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002683
2684 // Check that the function really is a function.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002685 __ JumpIfSmi(eax, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002686 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002687 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002688
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002689 // Patch the receiver on the stack with the global proxy if
2690 // necessary.
2691 if (object->IsGlobalObject()) {
2692 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
2693 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
2694 }
2695
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002696 // Invoke the function.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002697 __ mov(edi, eax);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002698 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002699 ? CALL_AS_FUNCTION
2700 : CALL_AS_METHOD;
2701 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION,
2702 NullCallWrapper(), call_kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002703
2704 // Handle load cache miss.
2705 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002706 GenerateMissBranch();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002707
2708 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002709 return GetCode(Code::INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002710}
2711
2712
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002713Handle<Code> CallStubCompiler::CompileCallGlobal(
2714 Handle<JSObject> object,
2715 Handle<GlobalObject> holder,
2716 Handle<JSGlobalPropertyCell> cell,
2717 Handle<JSFunction> function,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002718 Handle<Name> name) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002719 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00002720 // -- ecx : name
2721 // -- esp[0] : return address
2722 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2723 // -- ...
2724 // -- esp[(argc + 1) * 4] : receiver
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002725 // -----------------------------------
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002726
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002727 if (HasCustomCallGenerator(function)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00002728 Handle<Code> code = CompileCustomCall(
2729 object, holder, cell, function, Handle<String>::cast(name));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002730 // A null handle means bail out to the regular compiler code below.
2731 if (!code.is_null()) return code;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002732 }
2733
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002734 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002735 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002736
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002737 // Get the number of arguments.
2738 const int argc = arguments().immediate();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002739 GenerateGlobalReceiverCheck(object, holder, name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002740 GenerateLoadFunctionFromCell(cell, function, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002741
2742 // Patch the receiver on the stack with the global proxy.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002743 if (object->IsGlobalObject()) {
2744 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
2745 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
2746 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002747
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002748 // Set up the context (function already in edi).
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002749 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
2750
2751 // Jump to the cached code (tail call).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002752 Counters* counters = isolate()->counters();
2753 __ IncrementCounter(counters->call_global_inline(), 1);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002754 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002755 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002756 ? CALL_AS_FUNCTION
2757 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002758 // We call indirectly through the code field in the function to
2759 // allow recompilation to take effect without changing any of the
2760 // call sites.
2761 __ InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset),
2762 expected, arguments(), JUMP_FUNCTION,
2763 NullCallWrapper(), call_kind);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002764
2765 // Handle call cache miss.
2766 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002767 __ IncrementCounter(counters->call_global_inline_miss(), 1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002768 GenerateMissBranch();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002769
2770 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002771 return GetCode(Code::NORMAL, name);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002772}
2773
2774
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002775Handle<Code> StoreStubCompiler::CompileStoreCallback(
ulan@chromium.org750145a2013-03-07 15:14:13 +00002776 Handle<Name> name,
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002777 Handle<JSObject> object,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002778 Handle<JSObject> holder,
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002779 Handle<ExecutableAccessorInfo> callback) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002780 Label miss, miss_restore_name;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002781 // Check that the maps haven't changed, preserving the value register.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002782 __ JumpIfSmi(receiver(), &miss);
2783 CheckPrototypes(object, receiver(), holder,
2784 scratch1(), this->name(), scratch2(),
2785 name, &miss_restore_name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002786
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002787 // Stub never generated for non-global objects that require access checks.
2788 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002789
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002790 __ pop(scratch1()); // remove the return address
2791 __ push(receiver());
2792 __ Push(callback);
2793 __ Push(name);
2794 __ push(value());
2795 __ push(scratch1()); // restore return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002796
mads.s.ager31e71382008-08-13 09:32:07 +00002797 // Do tail-call to the runtime system.
2798 ExternalReference store_callback_property =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002799 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002800 __ TailCallExternalReference(store_callback_property, 4, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002801
2802 // Handle store cache miss.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002803 GenerateRestoreName(masm(), &miss_restore_name, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002804 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002805 TailCallBuiltin(masm(), MissBuiltin(kind()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002806
2807 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002808 return GetICCode(kind(), Code::CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002809}
2810
2811
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002812#undef __
2813#define __ ACCESS_MASM(masm)
2814
2815
2816void StoreStubCompiler::GenerateStoreViaSetter(
2817 MacroAssembler* masm,
2818 Handle<JSFunction> setter) {
2819 // ----------- S t a t e -------------
2820 // -- eax : value
2821 // -- ecx : name
2822 // -- edx : receiver
2823 // -- esp[0] : return address
2824 // -----------------------------------
2825 {
2826 FrameScope scope(masm, StackFrame::INTERNAL);
2827
2828 // Save value register, so we can restore it later.
2829 __ push(eax);
2830
2831 if (!setter.is_null()) {
2832 // Call the JavaScript setter with receiver and value on the stack.
2833 __ push(edx);
2834 __ push(eax);
2835 ParameterCount actual(1);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002836 ParameterCount expected(setter);
2837 __ InvokeFunction(setter, expected, actual,
2838 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002839 } else {
2840 // If we generate a global code snippet for deoptimization only, remember
2841 // the place to continue after deoptimization.
2842 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2843 }
2844
2845 // We have to return the passed value, not the return value of the setter.
2846 __ pop(eax);
2847
2848 // Restore context register.
2849 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
2850 }
2851 __ ret(0);
2852}
2853
2854
2855#undef __
2856#define __ ACCESS_MASM(masm())
2857
2858
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002859Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002860 Handle<JSObject> object,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002861 Handle<Name> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002862 Label miss;
2863
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002864 // Check that the map of the object hasn't changed.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002865 __ CheckMap(receiver(), Handle<Map>(object->map()),
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002866 &miss, DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002867
2868 // Perform global security token check if needed.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002869 if (object->IsJSGlobalProxy()) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002870 __ CheckAccessGlobalProxy(receiver(), scratch1(), scratch2(), &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002871 }
2872
2873 // Stub never generated for non-global objects that require access
2874 // checks.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002875 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002876
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002877 __ pop(scratch1()); // remove the return address
2878 __ push(receiver());
2879 __ push(this->name());
2880 __ push(value());
2881 __ push(Immediate(Smi::FromInt(strict_mode())));
2882 __ push(scratch1()); // restore return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002883
mads.s.ager31e71382008-08-13 09:32:07 +00002884 // Do tail-call to the runtime system.
2885 ExternalReference store_ic_property =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002886 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002887 __ TailCallExternalReference(store_ic_property, 4, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002888
2889 // Handle store cache miss.
2890 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002891 TailCallBuiltin(masm(), MissBuiltin(kind()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002892
2893 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002894 return GetICCode(kind(), Code::INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002895}
2896
2897
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002898Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2899 Handle<GlobalObject> object,
2900 Handle<JSGlobalPropertyCell> cell,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002901 Handle<Name> name) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002902 Label miss;
2903
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002904 // Check that the map of the global has not changed.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002905 __ cmp(FieldOperand(receiver(), HeapObject::kMapOffset),
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002906 Immediate(Handle<Map>(object->map())));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002907 __ j(not_equal, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002908
ager@chromium.org378b34e2011-01-28 08:04:38 +00002909 // Compute the cell operand to use.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002910 __ mov(scratch1(), Immediate(cell));
2911 Operand cell_operand =
2912 FieldOperand(scratch1(), JSGlobalPropertyCell::kValueOffset);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002913
ager@chromium.org378b34e2011-01-28 08:04:38 +00002914 // Check that the value in the cell is not the hole. If it is, this
2915 // cell could have been deleted and reintroducing the global needs
2916 // to update the property details in the property dictionary of the
2917 // global object. We bail out to the runtime system to do that.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002918 __ cmp(cell_operand, factory()->the_hole_value());
ager@chromium.org378b34e2011-01-28 08:04:38 +00002919 __ j(equal, &miss);
2920
2921 // Store the value in the cell.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002922 __ mov(cell_operand, value());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002923 // No write barrier here, because cells are always rescanned.
ager@chromium.org378b34e2011-01-28 08:04:38 +00002924
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002925 // Return the value (register eax).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002926 Counters* counters = isolate()->counters();
2927 __ IncrementCounter(counters->named_store_global_inline(), 1);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002928 __ ret(0);
2929
2930 // Handle store cache miss.
2931 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002932 __ IncrementCounter(counters->named_store_global_inline_miss(), 1);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002933 TailCallBuiltin(masm(), MissBuiltin(kind()));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002934
2935 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002936 return GetICCode(kind(), Code::NORMAL, name);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002937}
2938
2939
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002940Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
2941 MapHandleList* receiver_maps,
2942 CodeHandleList* handler_stubs,
2943 MapHandleList* transitioned_maps) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002944 Label miss;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002945 __ JumpIfSmi(receiver(), &miss, Label::kNear);
2946 __ mov(scratch1(), FieldOperand(receiver(), HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002947 for (int i = 0; i < receiver_maps->length(); ++i) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002948 __ cmp(scratch1(), receiver_maps->at(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002949 if (transitioned_maps->at(i).is_null()) {
2950 __ j(equal, handler_stubs->at(i));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002951 } else {
2952 Label next_map;
2953 __ j(not_equal, &next_map, Label::kNear);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002954 __ mov(transition_map(), Immediate(transitioned_maps->at(i)));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002955 __ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002956 __ bind(&next_map);
2957 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002958 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002959 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002960 TailCallBuiltin(masm(), MissBuiltin(kind()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002961
2962 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002963 return GetICCode(
2964 kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002965}
2966
2967
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00002968Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00002969 Handle<JSObject> object,
2970 Handle<JSObject> last,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002971 Handle<Name> name,
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00002972 Handle<GlobalObject> global) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002973 Label success;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002974
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002975 NonexistentHandlerFrontend(object, last, name, &success, global);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002976
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002977 __ bind(&success);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002978 // Return undefined if maps of the full prototype chain are still the
2979 // same and no global property with this name contains a value.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002980 __ mov(eax, isolate()->factory()->undefined_value());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002981 __ ret(0);
2982
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002983 // Return the generated code.
ulan@chromium.org750145a2013-03-07 15:14:13 +00002984 return GetCode(kind(), Code::NONEXISTENT, name);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002985}
2986
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002987
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002988Register* LoadStubCompiler::registers() {
2989 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2990 static Register registers[] = { edx, ecx, ebx, eax, edi, no_reg };
2991 return registers;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002992}
2993
2994
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002995Register* KeyedLoadStubCompiler::registers() {
2996 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2997 static Register registers[] = { edx, ecx, ebx, eax, edi, no_reg };
2998 return registers;
2999}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003000
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003001
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003002Register* StoreStubCompiler::registers() {
3003 // receiver, name, value, scratch1, scratch2, scratch3.
3004 static Register registers[] = { edx, ecx, eax, ebx, edi, no_reg };
3005 return registers;
3006}
3007
3008
3009Register* KeyedStoreStubCompiler::registers() {
3010 // receiver, name, value, scratch1, scratch2, scratch3.
3011 static Register registers[] = { edx, ecx, eax, ebx, edi, no_reg };
3012 return registers;
3013}
3014
3015
ulan@chromium.org750145a2013-03-07 15:14:13 +00003016void KeyedLoadStubCompiler::GenerateNameCheck(Handle<Name> name,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00003017 Register name_reg,
3018 Label* miss) {
3019 __ cmp(name_reg, Immediate(name));
3020 __ j(not_equal, miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003021}
3022
3023
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003024void KeyedStoreStubCompiler::GenerateNameCheck(Handle<Name> name,
3025 Register name_reg,
3026 Label* miss) {
3027 __ cmp(name_reg, Immediate(name));
3028 __ j(not_equal, miss);
3029}
3030
3031
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003032#undef __
3033#define __ ACCESS_MASM(masm)
3034
3035
3036void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
3037 Handle<JSFunction> getter) {
3038 // ----------- S t a t e -------------
3039 // -- ecx : name
3040 // -- edx : receiver
3041 // -- esp[0] : return address
3042 // -----------------------------------
3043 {
3044 FrameScope scope(masm, StackFrame::INTERNAL);
3045
3046 if (!getter.is_null()) {
3047 // Call the JavaScript getter with the receiver on the stack.
3048 __ push(edx);
3049 ParameterCount actual(0);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003050 ParameterCount expected(getter);
3051 __ InvokeFunction(getter, expected, actual,
3052 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003053 } else {
3054 // If we generate a global code snippet for deoptimization only, remember
3055 // the place to continue after deoptimization.
3056 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
3057 }
3058
3059 // Restore context register.
3060 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
3061 }
3062 __ ret(0);
3063}
3064
3065
3066#undef __
3067#define __ ACCESS_MASM(masm())
3068
3069
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003070Handle<Code> LoadStubCompiler::CompileLoadGlobal(
3071 Handle<JSObject> object,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003072 Handle<GlobalObject> global,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003073 Handle<JSGlobalPropertyCell> cell,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003074 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003075 bool is_dont_delete) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003076 Label success, miss;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003077
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003078 __ CheckMap(receiver(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
3079 HandlerFrontendHeader(
3080 object, receiver(), Handle<JSObject>::cast(global), name, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003081 // Get the value from the cell.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003082 if (Serializer::enabled()) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003083 __ mov(eax, Immediate(cell));
3084 __ mov(eax, FieldOperand(eax, JSGlobalPropertyCell::kValueOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003085 } else {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003086 __ mov(eax, Operand::Cell(cell));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003087 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003088
3089 // Check for deleted property if property can actually be deleted.
3090 if (!is_dont_delete) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003091 __ cmp(eax, factory()->the_hole_value());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003092 __ j(equal, &miss);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003093 } else if (FLAG_debug_code) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003094 __ cmp(eax, factory()->the_hole_value());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003095 __ Check(not_equal, "DontDelete cells can't contain the hole");
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003096 }
3097
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003098 HandlerFrontendFooter(&success, &miss);
3099 __ bind(&success);
3100
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003101 Counters* counters = isolate()->counters();
3102 __ IncrementCounter(counters->named_load_global_stub(), 1);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003103 // The code above already loads the result into the return register.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003104 __ ret(0);
3105
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003106 // Return the generated code.
ulan@chromium.org750145a2013-03-07 15:14:13 +00003107 return GetICCode(kind(), Code::NORMAL, name);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003108}
3109
3110
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003111Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003112 MapHandleList* receiver_maps,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003113 CodeHandleList* handlers,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003114 Handle<Name> name,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003115 Code::StubType type,
3116 IcCheckType check) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003117 Label miss;
3118
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003119 if (check == PROPERTY) {
3120 GenerateNameCheck(name, this->name(), &miss);
3121 }
3122
3123 __ JumpIfSmi(receiver(), &miss);
3124 Register map_reg = scratch1();
3125 __ mov(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset));
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003126 int receiver_count = receiver_maps->length();
danno@chromium.orgf005df62013-04-30 16:36:45 +00003127 int number_of_handled_maps = 0;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003128 for (int current = 0; current < receiver_count; ++current) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00003129 Handle<Map> map = receiver_maps->at(current);
3130 if (!map->is_deprecated()) {
3131 number_of_handled_maps++;
3132 __ cmp(map_reg, map);
3133 __ j(equal, handlers->at(current));
3134 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003135 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00003136 ASSERT(number_of_handled_maps != 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003137
3138 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003139 TailCallBuiltin(masm(), MissBuiltin(kind()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003140
3141 // Return the generated code.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003142 InlineCacheState state =
danno@chromium.orgf005df62013-04-30 16:36:45 +00003143 number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC;
ulan@chromium.org750145a2013-03-07 15:14:13 +00003144 return GetICCode(kind(), type, name, state);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003145}
3146
3147
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003148// Specialized stub for constructing objects from functions which only have only
3149// simple assignments of the form this.x = ...; in their body.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003150Handle<Code> ConstructStubCompiler::CompileConstructStub(
3151 Handle<JSFunction> function) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003152 // ----------- S t a t e -------------
3153 // -- eax : argc
3154 // -- edi : constructor
3155 // -- esp[0] : return address
3156 // -- esp[4] : last argument
3157 // -----------------------------------
3158 Label generic_stub_call;
3159#ifdef ENABLE_DEBUGGER_SUPPORT
3160 // Check to see whether there are any break points in the function code. If
3161 // there are jump to the generic constructor stub which calls the actual
3162 // code for the function thereby hitting the break points.
3163 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
3164 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kDebugInfoOffset));
lrn@chromium.org7516f052011-03-30 08:52:27 +00003165 __ cmp(ebx, factory()->undefined_value());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003166 __ j(not_equal, &generic_stub_call);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003167#endif
3168
3169 // Load the initial map and verify that it is in fact a map.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003170 // edi: constructor
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003171 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
3172 // Will both indicate a NULL and a Smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003173 __ JumpIfSmi(ebx, &generic_stub_call);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003174 __ CmpObjectType(ebx, MAP_TYPE, ecx);
3175 __ j(not_equal, &generic_stub_call);
3176
3177#ifdef DEBUG
3178 // Cannot construct functions this way.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003179 // ebx: initial map
3180 __ CmpInstanceType(ebx, JS_FUNCTION_TYPE);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003181 __ Check(not_equal, "Function constructed by construct stub.");
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003182#endif
3183
3184 // Now allocate the JSObject on the heap by moving the new space allocation
3185 // top forward.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003186 // ebx: initial map
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003187 ASSERT(function->has_initial_map());
3188 int instance_size = function->initial_map()->instance_size();
3189#ifdef DEBUG
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003190 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset));
3191 __ shl(ecx, kPointerSizeLog2);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003192 __ cmp(ecx, Immediate(instance_size));
3193 __ Check(equal, "Instance size of initial map changed.");
3194#endif
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003195 __ Allocate(instance_size, edx, ecx, no_reg, &generic_stub_call,
3196 NO_ALLOCATION_FLAGS);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003197
3198 // Allocated the JSObject, now initialize the fields and add the heap tag.
3199 // ebx: initial map
3200 // edx: JSObject (untagged)
3201 __ mov(Operand(edx, JSObject::kMapOffset), ebx);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003202 __ mov(ebx, factory()->empty_fixed_array());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003203 __ mov(Operand(edx, JSObject::kPropertiesOffset), ebx);
3204 __ mov(Operand(edx, JSObject::kElementsOffset), ebx);
3205
3206 // Push the allocated object to the stack. This is the object that will be
3207 // returned (after it is tagged).
3208 __ push(edx);
3209
3210 // eax: argc
3211 // edx: JSObject (untagged)
3212 // Load the address of the first in-object property into edx.
3213 __ lea(edx, Operand(edx, JSObject::kHeaderSize));
3214 // Calculate the location of the first argument. The stack contains the
3215 // allocated object and the return address on top of the argc arguments.
3216 __ lea(ecx, Operand(esp, eax, times_4, 1 * kPointerSize));
3217
3218 // Use edi for holding undefined which is used in several places below.
lrn@chromium.org7516f052011-03-30 08:52:27 +00003219 __ mov(edi, factory()->undefined_value());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003220
3221 // eax: argc
3222 // ecx: first argument
3223 // edx: first in-object property of the JSObject
3224 // edi: undefined
3225 // Fill the initialized properties with a constant value or a passed argument
3226 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003227 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003228 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3229 if (shared->IsThisPropertyAssignmentArgument(i)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003230 // Check if the argument assigned to the property is actually passed.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003231 // If argument is not passed the property is set to undefined,
3232 // otherwise find it on the stack.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003233 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003234 __ mov(ebx, edi);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003235 __ cmp(eax, arg_number);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003236 if (CpuFeatures::IsSupported(CMOV)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003237 CpuFeatureScope use_cmov(masm(), CMOV);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003238 __ cmov(above, ebx, Operand(ecx, arg_number * -kPointerSize));
3239 } else {
3240 Label not_passed;
3241 __ j(below_equal, &not_passed);
3242 __ mov(ebx, Operand(ecx, arg_number * -kPointerSize));
3243 __ bind(&not_passed);
3244 }
3245 // Store value in the property.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003246 __ mov(Operand(edx, i * kPointerSize), ebx);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003247 } else {
3248 // Set the property to the constant value.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003249 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i),
3250 isolate());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003251 __ mov(Operand(edx, i * kPointerSize), Immediate(constant));
3252 }
3253 }
3254
3255 // Fill the unused in-object property fields with undefined.
3256 for (int i = shared->this_property_assignments_count();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00003257 i < function->initial_map()->inobject_properties();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003258 i++) {
3259 __ mov(Operand(edx, i * kPointerSize), edi);
3260 }
3261
3262 // Move argc to ebx and retrieve and tag the JSObject to return.
3263 __ mov(ebx, eax);
3264 __ pop(eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003265 __ or_(eax, Immediate(kHeapObjectTag));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003266
3267 // Remove caller arguments and receiver from the stack and return.
3268 __ pop(ecx);
3269 __ lea(esp, Operand(esp, ebx, times_pointer_size, 1 * kPointerSize));
3270 __ push(ecx);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003271 Counters* counters = isolate()->counters();
3272 __ IncrementCounter(counters->constructed_objects(), 1);
3273 __ IncrementCounter(counters->constructed_objects_stub(), 1);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003274 __ ret(0);
3275
3276 // Jump to the generic stub in case the specialized code cannot handle the
3277 // construction.
3278 __ bind(&generic_stub_call);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003279 Handle<Code> code = isolate()->builtins()->JSConstructStubGeneric();
3280 __ jmp(code, RelocInfo::CODE_TARGET);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003281
3282 // Return the generated code.
3283 return GetCode();
3284}
3285
3286
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003287#undef __
3288#define __ ACCESS_MASM(masm)
3289
3290
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003291void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3292 MacroAssembler* masm) {
3293 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003294 // -- ecx : key
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003295 // -- edx : receiver
3296 // -- esp[0] : return address
3297 // -----------------------------------
3298 Label slow, miss_force_generic;
3299
3300 // This stub is meant to be tail-jumped to, the receiver must already
3301 // have been verified by the caller to not be a smi.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003302 __ JumpIfNotSmi(ecx, &miss_force_generic);
3303 __ mov(ebx, ecx);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003304 __ SmiUntag(ebx);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003305 __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset));
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003306
3307 // Push receiver on the stack to free up a register for the dictionary
3308 // probing.
3309 __ push(edx);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003310 __ LoadFromNumberDictionary(&slow, eax, ecx, ebx, edx, edi, eax);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003311 // Pop receiver before returning.
3312 __ pop(edx);
3313 __ ret(0);
3314
3315 __ bind(&slow);
3316 __ pop(edx);
3317
3318 // ----------- S t a t e -------------
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003319 // -- ecx : key
3320 // -- edx : receiver
3321 // -- esp[0] : return address
3322 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003323 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003324
3325 __ bind(&miss_force_generic);
3326 // ----------- S t a t e -------------
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003327 // -- ecx : key
3328 // -- edx : receiver
3329 // -- esp[0] : return address
3330 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003331 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_MissForceGeneric);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003332}
3333
3334
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003335static void GenerateSmiKeyCheck(MacroAssembler* masm,
3336 Register key,
3337 Register scratch,
3338 XMMRegister xmm_scratch0,
3339 XMMRegister xmm_scratch1,
3340 Label* fail) {
3341 // Check that key is a smi and if SSE2 is available a heap number
3342 // containing a smi and branch if the check fails.
3343 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003344 CpuFeatureScope use_sse2(masm, SSE2);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003345 Label key_ok;
3346 __ JumpIfSmi(key, &key_ok);
3347 __ cmp(FieldOperand(key, HeapObject::kMapOffset),
3348 Immediate(Handle<Map>(masm->isolate()->heap()->heap_number_map())));
3349 __ j(not_equal, fail);
3350 __ movdbl(xmm_scratch0, FieldOperand(key, HeapNumber::kValueOffset));
3351 __ cvttsd2si(scratch, Operand(xmm_scratch0));
3352 __ cvtsi2sd(xmm_scratch1, scratch);
3353 __ ucomisd(xmm_scratch1, xmm_scratch0);
3354 __ j(not_equal, fail);
3355 __ j(parity_even, fail); // NaN.
3356 // Check if the key fits in the smi range.
3357 __ cmp(scratch, 0xc0000000);
3358 __ j(sign, fail);
3359 __ SmiTag(scratch);
3360 __ mov(key, scratch);
3361 __ bind(&key_ok);
3362 } else {
3363 __ JumpIfNotSmi(key, fail);
3364 }
3365}
3366
3367
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003368void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3369 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003370 ElementsKind elements_kind) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003371 // ----------- S t a t e -------------
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003372 // -- eax : value
3373 // -- ecx : key
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003374 // -- edx : receiver
3375 // -- esp[0] : return address
3376 // -----------------------------------
3377 Label miss_force_generic, slow, check_heap_number;
3378
3379 // This stub is meant to be tail-jumped to, the receiver must already
3380 // have been verified by the caller to not be a smi.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003381
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003382 // Check that the key is a smi or a heap number convertible to a smi.
3383 GenerateSmiKeyCheck(masm, ecx, ebx, xmm0, xmm1, &miss_force_generic);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003384
3385 // Check that the index is in range.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003386 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003387 __ cmp(ecx, FieldOperand(edi, ExternalArray::kLengthOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003388 // Unsigned comparison catches both negative and too-large values.
3389 __ j(above_equal, &slow);
3390
3391 // Handle both smis and HeapNumbers in the fast path. Go to the
3392 // runtime for all other kinds of values.
3393 // eax: value
3394 // edx: receiver
3395 // ecx: key
3396 // edi: elements array
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003397 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00003398 __ JumpIfNotSmi(eax, &slow);
3399 } else {
3400 __ JumpIfNotSmi(eax, &check_heap_number);
3401 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003402
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003403 // smi case
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003404 __ mov(ebx, eax); // Preserve the value in eax as the return value.
3405 __ SmiUntag(ebx);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003406 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003407 // edi: base pointer of external storage
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003408 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003409 case EXTERNAL_PIXEL_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003410 __ ClampUint8(ebx);
3411 __ SmiUntag(ecx);
3412 __ mov_b(Operand(edi, ecx, times_1, 0), ebx);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003413 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003414 case EXTERNAL_BYTE_ELEMENTS:
3415 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003416 __ SmiUntag(ecx);
3417 __ mov_b(Operand(edi, ecx, times_1, 0), ebx);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003418 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003419 case EXTERNAL_SHORT_ELEMENTS:
3420 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003421 __ mov_w(Operand(edi, ecx, times_1, 0), ebx);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003422 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003423 case EXTERNAL_INT_ELEMENTS:
3424 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003425 __ mov(Operand(edi, ecx, times_2, 0), ebx);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003426 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003427 case EXTERNAL_FLOAT_ELEMENTS:
3428 case EXTERNAL_DOUBLE_ELEMENTS:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003429 // Need to perform int-to-float conversion.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003430 __ push(ebx);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003431 __ fild_s(Operand(esp, 0));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003432 __ pop(ebx);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003433 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003434 __ fstp_s(Operand(edi, ecx, times_2, 0));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003435 } else { // elements_kind == EXTERNAL_DOUBLE_ELEMENTS.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003436 __ fstp_d(Operand(edi, ecx, times_4, 0));
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003437 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003438 break;
3439 default:
3440 UNREACHABLE();
3441 break;
3442 }
3443 __ ret(0); // Return the original value.
3444
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003445 // TODO(danno): handle heap number -> pixel array conversion
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003446 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003447 __ bind(&check_heap_number);
3448 // eax: value
3449 // edx: receiver
3450 // ecx: key
3451 // edi: elements array
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003452 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003453 Immediate(masm->isolate()->factory()->heap_number_map()));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003454 __ j(not_equal, &slow);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003455
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003456 // The WebGL specification leaves the behavior of storing NaN and
3457 // +/-Infinity into integer arrays basically undefined. For more
3458 // reproducible behavior, convert these to zero.
3459 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003460 // edi: base pointer of external storage
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003461 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003462 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003463 __ fstp_s(Operand(edi, ecx, times_2, 0));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003464 __ ret(0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003465 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003466 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003467 __ fstp_d(Operand(edi, ecx, times_4, 0));
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003468 __ ret(0);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003469 } else {
3470 // Perform float-to-int conversion with truncation (round-to-zero)
3471 // behavior.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003472
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003473 // For the moment we make the slow call to the runtime on
3474 // processors that don't support SSE2. The code in IntegerConvert
3475 // (code-stubs-ia32.cc) is roughly what is needed here though the
3476 // conversion failure case does not need to be handled.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003477 if (CpuFeatures::IsSupported(SSE2)) {
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003478 if ((elements_kind == EXTERNAL_INT_ELEMENTS ||
3479 elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) &&
3480 CpuFeatures::IsSupported(SSE3)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003481 CpuFeatureScope scope(masm, SSE3);
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003482 // fisttp stores values as signed integers. To represent the
3483 // entire range of int and unsigned int arrays, store as a
3484 // 64-bit int and discard the high 32 bits.
3485 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
3486 __ sub(esp, Immediate(2 * kPointerSize));
3487 __ fisttp_d(Operand(esp, 0));
3488
3489 // If conversion failed (NaN, infinity, or a number outside
3490 // signed int64 range), the result is 0x8000000000000000, and
3491 // we must handle this case in the runtime.
3492 Label ok;
3493 __ cmp(Operand(esp, kPointerSize), Immediate(0x80000000u));
3494 __ j(not_equal, &ok);
3495 __ cmp(Operand(esp, 0), Immediate(0));
3496 __ j(not_equal, &ok);
3497 __ add(esp, Immediate(2 * kPointerSize)); // Restore the stack.
3498 __ jmp(&slow);
3499
3500 __ bind(&ok);
3501 __ pop(ebx);
3502 __ add(esp, Immediate(kPointerSize));
3503 __ mov(Operand(edi, ecx, times_2, 0), ebx);
3504 } else {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003505 ASSERT(CpuFeatures::IsSupported(SSE2));
ulan@chromium.org750145a2013-03-07 15:14:13 +00003506 CpuFeatureScope scope(masm, SSE2);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003507 __ cvttsd2si(ebx, FieldOperand(eax, HeapNumber::kValueOffset));
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003508 __ cmp(ebx, 0x80000000u);
3509 __ j(equal, &slow);
3510 // ebx: untagged integer value
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003511 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003512 case EXTERNAL_PIXEL_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003513 __ ClampUint8(ebx);
3514 // Fall through.
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003515 case EXTERNAL_BYTE_ELEMENTS:
3516 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003517 __ SmiUntag(ecx);
3518 __ mov_b(Operand(edi, ecx, times_1, 0), ebx);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003519 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003520 case EXTERNAL_SHORT_ELEMENTS:
3521 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003522 __ mov_w(Operand(edi, ecx, times_1, 0), ebx);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003523 break;
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003524 case EXTERNAL_INT_ELEMENTS:
3525 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3526 __ mov(Operand(edi, ecx, times_2, 0), ebx);
3527 break;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003528 default:
3529 UNREACHABLE();
3530 break;
3531 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003532 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003533 __ ret(0); // Return original value.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003534 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003535 }
3536 }
3537
3538 // Slow case: call runtime.
3539 __ bind(&slow);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003540 Counters* counters = masm->isolate()->counters();
3541 __ IncrementCounter(counters->keyed_store_external_array_slow(), 1);
3542
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003543 // ----------- S t a t e -------------
3544 // -- eax : value
3545 // -- ecx : key
3546 // -- edx : receiver
3547 // -- esp[0] : return address
3548 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003549 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003550
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003551 // ----------- S t a t e -------------
3552 // -- eax : value
3553 // -- ecx : key
3554 // -- edx : receiver
3555 // -- esp[0] : return address
3556 // -----------------------------------
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003557
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003558 __ bind(&miss_force_generic);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003559 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003560}
3561
3562
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003563void KeyedStoreStubCompiler::GenerateStoreFastElement(
3564 MacroAssembler* masm,
3565 bool is_js_array,
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003566 ElementsKind elements_kind,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003567 KeyedAccessStoreMode store_mode) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003568 // ----------- S t a t e -------------
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003569 // -- eax : value
3570 // -- ecx : key
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003571 // -- edx : receiver
3572 // -- esp[0] : return address
3573 // -----------------------------------
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003574 Label miss_force_generic, grow, slow, transition_elements_kind;
3575 Label check_capacity, prepare_slow, finish_store, commit_backing_store;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003576
3577 // This stub is meant to be tail-jumped to, the receiver must already
3578 // have been verified by the caller to not be a smi.
3579
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003580 // Check that the key is a smi or a heap number convertible to a smi.
3581 GenerateSmiKeyCheck(masm, ecx, ebx, xmm0, xmm1, &miss_force_generic);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003582
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003583 if (IsFastSmiElementsKind(elements_kind)) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003584 __ JumpIfNotSmi(eax, &transition_elements_kind);
3585 }
3586
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003587 // Get the elements array and make sure it is a fast element array, not 'cow'.
3588 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003589 if (is_js_array) {
3590 // Check that the key is within bounds.
3591 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // smis.
ulan@chromium.org750145a2013-03-07 15:14:13 +00003592 if (IsGrowStoreMode(store_mode)) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003593 __ j(above_equal, &grow);
3594 } else {
3595 __ j(above_equal, &miss_force_generic);
3596 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003597 } else {
3598 // Check that the key is within bounds.
3599 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); // smis.
3600 __ j(above_equal, &miss_force_generic);
3601 }
3602
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003603 __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
3604 Immediate(masm->isolate()->factory()->fixed_array_map()));
3605 __ j(not_equal, &miss_force_generic);
3606
3607 __ bind(&finish_store);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003608 if (IsFastSmiElementsKind(elements_kind)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003609 // ecx is a smi, use times_half_pointer_size instead of
3610 // times_pointer_size
3611 __ mov(FieldOperand(edi,
3612 ecx,
3613 times_half_pointer_size,
3614 FixedArray::kHeaderSize), eax);
3615 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003616 ASSERT(IsFastObjectElementsKind(elements_kind));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003617 // Do the store and update the write barrier.
3618 // ecx is a smi, use times_half_pointer_size instead of
3619 // times_pointer_size
3620 __ lea(ecx, FieldOperand(edi,
3621 ecx,
3622 times_half_pointer_size,
3623 FixedArray::kHeaderSize));
3624 __ mov(Operand(ecx, 0), eax);
3625 // Make sure to preserve the value in register eax.
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003626 __ mov(ebx, eax);
3627 __ RecordWrite(edi, ecx, ebx, kDontSaveFPRegs);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003628 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003629
3630 // Done.
3631 __ ret(0);
3632
3633 // Handle store cache miss, replacing the ic with the generic stub.
3634 __ bind(&miss_force_generic);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003635 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003636
3637 // Handle transition to other elements kinds without using the generic stub.
3638 __ bind(&transition_elements_kind);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003639 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003640
ulan@chromium.org750145a2013-03-07 15:14:13 +00003641 if (is_js_array && IsGrowStoreMode(store_mode)) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003642 // Handle transition requiring the array to grow.
3643 __ bind(&grow);
3644
3645 // Make sure the array is only growing by a single element, anything else
3646 // must be handled by the runtime. Flags are already set by previous
3647 // compare.
3648 __ j(not_equal, &miss_force_generic);
3649
3650 // Check for the empty array, and preallocate a small backing store if
3651 // possible.
3652 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
3653 __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array()));
3654 __ j(not_equal, &check_capacity);
3655
3656 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003657 __ Allocate(size, edi, ebx, ecx, &prepare_slow, TAG_OBJECT);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003658 // Restore the key, which is known to be the array length.
3659
3660 // eax: value
3661 // ecx: key
3662 // edx: receiver
3663 // edi: elements
3664 // Make sure that the backing store can hold additional elements.
3665 __ mov(FieldOperand(edi, JSObject::kMapOffset),
3666 Immediate(masm->isolate()->factory()->fixed_array_map()));
3667 __ mov(FieldOperand(edi, FixedArray::kLengthOffset),
3668 Immediate(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
3669 __ mov(ebx, Immediate(masm->isolate()->factory()->the_hole_value()));
3670 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
3671 __ mov(FieldOperand(edi, FixedArray::SizeFor(i)), ebx);
3672 }
3673
3674 // Store the element at index zero.
3675 __ mov(FieldOperand(edi, FixedArray::SizeFor(0)), eax);
3676
3677 // Install the new backing store in the JSArray.
3678 __ mov(FieldOperand(edx, JSObject::kElementsOffset), edi);
3679 __ RecordWriteField(edx, JSObject::kElementsOffset, edi, ebx,
3680 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3681
3682 // Increment the length of the array.
3683 __ mov(FieldOperand(edx, JSArray::kLengthOffset),
3684 Immediate(Smi::FromInt(1)));
3685 __ ret(0);
3686
3687 __ bind(&check_capacity);
3688 __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
3689 Immediate(masm->isolate()->factory()->fixed_cow_array_map()));
3690 __ j(equal, &miss_force_generic);
3691
3692 // eax: value
3693 // ecx: key
3694 // edx: receiver
3695 // edi: elements
3696 // Make sure that the backing store can hold additional elements.
3697 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
3698 __ j(above_equal, &slow);
3699
3700 // Grow the array and finish the store.
3701 __ add(FieldOperand(edx, JSArray::kLengthOffset),
3702 Immediate(Smi::FromInt(1)));
3703 __ jmp(&finish_store);
3704
3705 __ bind(&prepare_slow);
3706 // Restore the key, which is known to be the array length.
3707 __ mov(ecx, Immediate(0));
3708
3709 __ bind(&slow);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003710 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003711 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003712}
3713
3714
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003715void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
3716 MacroAssembler* masm,
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003717 bool is_js_array,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003718 KeyedAccessStoreMode store_mode) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003719 // ----------- S t a t e -------------
3720 // -- eax : value
3721 // -- ecx : key
3722 // -- edx : receiver
3723 // -- esp[0] : return address
3724 // -----------------------------------
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003725 Label miss_force_generic, transition_elements_kind, grow, slow;
3726 Label check_capacity, prepare_slow, finish_store, commit_backing_store;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003727
3728 // This stub is meant to be tail-jumped to, the receiver must already
3729 // have been verified by the caller to not be a smi.
3730
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003731 // Check that the key is a smi or a heap number convertible to a smi.
3732 GenerateSmiKeyCheck(masm, ecx, ebx, xmm0, xmm1, &miss_force_generic);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003733
3734 // Get the elements array.
3735 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
3736 __ AssertFastElements(edi);
3737
3738 if (is_js_array) {
3739 // Check that the key is within bounds.
3740 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // smis.
ulan@chromium.org750145a2013-03-07 15:14:13 +00003741 if (IsGrowStoreMode(store_mode)) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003742 __ j(above_equal, &grow);
3743 } else {
3744 __ j(above_equal, &miss_force_generic);
3745 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003746 } else {
3747 // Check that the key is within bounds.
3748 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); // smis.
yangguo@chromium.org56454712012-02-16 15:33:53 +00003749 __ j(above_equal, &miss_force_generic);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003750 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003751
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003752 __ bind(&finish_store);
3753 __ StoreNumberToDoubleElements(eax, edi, ecx, edx, xmm0,
3754 &transition_elements_kind, true);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003755 __ ret(0);
3756
3757 // Handle store cache miss, replacing the ic with the generic stub.
3758 __ bind(&miss_force_generic);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003759 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003760
3761 // Handle transition to other elements kinds without using the generic stub.
3762 __ bind(&transition_elements_kind);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003763 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003764
ulan@chromium.org750145a2013-03-07 15:14:13 +00003765 if (is_js_array && IsGrowStoreMode(store_mode)) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003766 // Handle transition requiring the array to grow.
3767 __ bind(&grow);
3768
3769 // Make sure the array is only growing by a single element, anything else
3770 // must be handled by the runtime. Flags are already set by previous
3771 // compare.
3772 __ j(not_equal, &miss_force_generic);
3773
3774 // Transition on values that can't be stored in a FixedDoubleArray.
3775 Label value_is_smi;
3776 __ JumpIfSmi(eax, &value_is_smi);
3777 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
3778 Immediate(Handle<Map>(masm->isolate()->heap()->heap_number_map())));
3779 __ j(not_equal, &transition_elements_kind);
3780 __ bind(&value_is_smi);
3781
3782 // Check for the empty array, and preallocate a small backing store if
3783 // possible.
3784 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
3785 __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array()));
3786 __ j(not_equal, &check_capacity);
3787
3788 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003789 __ Allocate(size, edi, ebx, ecx, &prepare_slow, TAG_OBJECT);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003790
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003791 // Restore the key, which is known to be the array length.
3792 __ mov(ecx, Immediate(0));
3793
3794 // eax: value
3795 // ecx: key
3796 // edx: receiver
3797 // edi: elements
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003798 // Initialize the new FixedDoubleArray.
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003799 __ mov(FieldOperand(edi, JSObject::kMapOffset),
3800 Immediate(masm->isolate()->factory()->fixed_double_array_map()));
3801 __ mov(FieldOperand(edi, FixedDoubleArray::kLengthOffset),
3802 Immediate(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
3803
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003804 __ StoreNumberToDoubleElements(eax, edi, ecx, ebx, xmm0,
3805 &transition_elements_kind, true);
3806
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003807 for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) {
3808 int offset = FixedDoubleArray::OffsetOfElementAt(i);
3809 __ mov(FieldOperand(edi, offset), Immediate(kHoleNanLower32));
3810 __ mov(FieldOperand(edi, offset + kPointerSize),
3811 Immediate(kHoleNanUpper32));
3812 }
3813
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003814 // Install the new backing store in the JSArray.
3815 __ mov(FieldOperand(edx, JSObject::kElementsOffset), edi);
3816 __ RecordWriteField(edx, JSObject::kElementsOffset, edi, ebx,
3817 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3818
3819 // Increment the length of the array.
3820 __ add(FieldOperand(edx, JSArray::kLengthOffset),
3821 Immediate(Smi::FromInt(1)));
yangguo@chromium.org56454712012-02-16 15:33:53 +00003822 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003823 __ ret(0);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003824
3825 __ bind(&check_capacity);
3826 // eax: value
3827 // ecx: key
3828 // edx: receiver
3829 // edi: elements
3830 // Make sure that the backing store can hold additional elements.
3831 __ cmp(ecx, FieldOperand(edi, FixedDoubleArray::kLengthOffset));
3832 __ j(above_equal, &slow);
3833
3834 // Grow the array and finish the store.
3835 __ add(FieldOperand(edx, JSArray::kLengthOffset),
3836 Immediate(Smi::FromInt(1)));
3837 __ jmp(&finish_store);
3838
3839 __ bind(&prepare_slow);
3840 // Restore the key, which is known to be the array length.
3841 __ mov(ecx, Immediate(0));
3842
3843 __ bind(&slow);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003844 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003845 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003846}
3847
3848
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003849#undef __
3850
3851} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003852
3853#endif // V8_TARGET_ARCH_IA32