blob: 7cb7811e22685547c9c90f6b75725b0e90b0f6bf [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.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000423static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength;
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
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000472 // -- esp[20] : ReturnValue
473 // -- esp[24] : last argument
ager@chromium.org5c838252010-02-19 08:53:10 +0000474 // -- ...
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000475 // -- esp[(argc + 5) * 4] : first argument
476 // -- esp[(argc + 6) * 4] : receiver
ager@chromium.org5c838252010-02-19 08:53:10 +0000477 // -----------------------------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000478 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000479 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000480 __ LoadHeapObject(edi, function);
ager@chromium.org5c838252010-02-19 08:53:10 +0000481 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
482
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000483 // Pass the additional arguments.
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000484 __ mov(Operand(esp, 2 * kPointerSize), edi);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000485 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000486 Handle<Object> call_data(api_call_info->data(), masm->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000487 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
488 __ mov(ecx, api_call_info);
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000489 __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kDataOffset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000490 __ mov(Operand(esp, 3 * kPointerSize), ebx);
491 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000492 __ mov(Operand(esp, 3 * kPointerSize), Immediate(call_data));
ager@chromium.org5c838252010-02-19 08:53:10 +0000493 }
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000494 __ mov(Operand(esp, 4 * kPointerSize),
495 Immediate(reinterpret_cast<int>(masm->isolate())));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000496 __ mov(Operand(esp, 5 * kPointerSize),
497 masm->isolate()->factory()->undefined_value());
ager@chromium.org5c838252010-02-19 08:53:10 +0000498
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000499 // Prepare arguments.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000500 STATIC_ASSERT(kFastApiCallArguments == 5);
501 __ lea(eax, Operand(esp, kFastApiCallArguments * kPointerSize));
ager@chromium.org5c838252010-02-19 08:53:10 +0000502
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000503 const int kApiArgc = 1; // API function gets reference to the v8::Arguments.
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000504
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000505 // Allocate the v8::Arguments structure in the arguments' space since
506 // it's not controlled by GC.
507 const int kApiStackSpace = 4;
508
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000509 // Function address is a foreign pointer outside V8's heap.
510 Address function_address = v8::ToCData<Address>(api_call_info->callback());
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000511 bool returns_handle =
512 !CallbackTable::ReturnsVoid(masm->isolate(),
513 reinterpret_cast<void*>(function_address));
514 __ PrepareCallApiFunction(kApiArgc + kApiStackSpace, returns_handle);
515
516 // v8::Arguments::implicit_args_.
517 __ mov(ApiParameterOperand(1, returns_handle), eax);
518 __ add(eax, Immediate(argc * kPointerSize));
519 // v8::Arguments::values_.
520 __ mov(ApiParameterOperand(2, returns_handle), eax);
521 // v8::Arguments::length_.
522 __ Set(ApiParameterOperand(3, returns_handle), Immediate(argc));
523 // v8::Arguments::is_construct_call_.
524 __ Set(ApiParameterOperand(4, returns_handle), Immediate(0));
525
526 // v8::InvocationCallback's argument.
527 __ lea(eax, ApiParameterOperand(1, returns_handle));
528 __ mov(ApiParameterOperand(0, returns_handle), eax);
529
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000530 __ CallApiFunctionAndReturn(function_address,
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000531 argc + kFastApiCallArguments + 1,
532 returns_handle,
533 kFastApiCallArguments + 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000534}
535
536
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000537class CallInterceptorCompiler BASE_EMBEDDED {
538 public:
ager@chromium.org5c838252010-02-19 08:53:10 +0000539 CallInterceptorCompiler(StubCompiler* stub_compiler,
540 const ParameterCount& arguments,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000541 Register name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000542 Code::ExtraICState extra_state)
ager@chromium.org5c838252010-02-19 08:53:10 +0000543 : stub_compiler_(stub_compiler),
544 arguments_(arguments),
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000545 name_(name),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000546 extra_state_(extra_state) {}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000547
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000548 void Compile(MacroAssembler* masm,
549 Handle<JSObject> object,
550 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000551 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000552 LookupResult* lookup,
553 Register receiver,
554 Register scratch1,
555 Register scratch2,
556 Register scratch3,
557 Label* miss) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000558 ASSERT(holder->HasNamedInterceptor());
559 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
560
561 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000562 __ JumpIfSmi(receiver, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000563
564 CallOptimization optimization(lookup);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000565 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000566 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
567 holder, lookup, name, optimization, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000568 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000569 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
570 name, holder, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000571 }
572 }
573
574 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000575 void CompileCacheable(MacroAssembler* masm,
576 Handle<JSObject> object,
577 Register receiver,
578 Register scratch1,
579 Register scratch2,
580 Register scratch3,
581 Handle<JSObject> interceptor_holder,
582 LookupResult* lookup,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000583 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000584 const CallOptimization& optimization,
585 Label* miss_label) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000586 ASSERT(optimization.is_constant_call());
587 ASSERT(!lookup->holder()->IsGlobalObject());
588
589 int depth1 = kInvalidProtoDepth;
590 int depth2 = kInvalidProtoDepth;
591 bool can_do_fast_api_call = false;
592 if (optimization.is_simple_api_call() &&
593 !lookup->holder()->IsGlobalObject()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000594 depth1 = optimization.GetPrototypeDepthOfExpectedType(
595 object, interceptor_holder);
ager@chromium.org5c838252010-02-19 08:53:10 +0000596 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000597 depth2 = optimization.GetPrototypeDepthOfExpectedType(
598 interceptor_holder, Handle<JSObject>(lookup->holder()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000599 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000600 can_do_fast_api_call =
601 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000602 }
603
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000604 Counters* counters = masm->isolate()->counters();
605 __ IncrementCounter(counters->call_const_interceptor(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000606
607 if (can_do_fast_api_call) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000608 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000609 ReserveSpaceForFastApiCall(masm, scratch1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000610 }
611
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000612 // Check that the maps from receiver to interceptor's holder
613 // haven't changed and thus we can invoke interceptor.
ager@chromium.org5c838252010-02-19 08:53:10 +0000614 Label miss_cleanup;
615 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
616 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000617 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
618 scratch1, scratch2, scratch3,
619 name, depth1, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000620
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000621 // Invoke an interceptor and if it provides a value,
622 // branch to |regular_invoke|.
ager@chromium.org5c838252010-02-19 08:53:10 +0000623 Label regular_invoke;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000624 LoadWithInterceptor(masm, receiver, holder, interceptor_holder,
625 &regular_invoke);
ager@chromium.org5c838252010-02-19 08:53:10 +0000626
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000627 // Interceptor returned nothing for this property. Try to use cached
628 // constant function.
ager@chromium.org5c838252010-02-19 08:53:10 +0000629
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000630 // Check that the maps from interceptor's holder to constant function's
631 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000632 if (*interceptor_holder != lookup->holder()) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000633 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000634 Handle<JSObject>(lookup->holder()),
635 scratch1, scratch2, scratch3,
636 name, depth2, miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000637 } else {
638 // CheckPrototypes has a side effect of fetching a 'holder'
639 // for API (object which is instanceof for the signature). It's
640 // safe to omit it here, as if present, it should be fetched
641 // by the previous CheckPrototypes.
642 ASSERT(depth2 == kInvalidProtoDepth);
643 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000644
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000645 // Invoke function.
ager@chromium.org5c838252010-02-19 08:53:10 +0000646 if (can_do_fast_api_call) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000647 GenerateFastApiCall(masm, optimization, arguments_.immediate());
ager@chromium.org5c838252010-02-19 08:53:10 +0000648 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000649 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000650 ? CALL_AS_FUNCTION
651 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000652 Handle<JSFunction> function = optimization.constant_function();
653 ParameterCount expected(function);
654 __ InvokeFunction(function, expected, arguments_,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000655 JUMP_FUNCTION, NullCallWrapper(), call_kind);
ager@chromium.org5c838252010-02-19 08:53:10 +0000656 }
657
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000658 // Deferred code for fast API call case---clean preallocated space.
ager@chromium.org5c838252010-02-19 08:53:10 +0000659 if (can_do_fast_api_call) {
660 __ bind(&miss_cleanup);
661 FreeSpaceForFastApiCall(masm, scratch1);
662 __ jmp(miss_label);
663 }
664
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000665 // Invoke a regular function.
ager@chromium.org5c838252010-02-19 08:53:10 +0000666 __ bind(&regular_invoke);
667 if (can_do_fast_api_call) {
668 FreeSpaceForFastApiCall(masm, scratch1);
669 }
670 }
671
672 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000673 Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +0000674 Register receiver,
675 Register scratch1,
676 Register scratch2,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000677 Register scratch3,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000678 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000679 Handle<JSObject> interceptor_holder,
ager@chromium.org5c838252010-02-19 08:53:10 +0000680 Label* miss_label) {
681 Register holder =
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000682 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000683 scratch1, scratch2, scratch3,
684 name, miss_label);
ager@chromium.org5c838252010-02-19 08:53:10 +0000685
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000686 FrameScope scope(masm, StackFrame::INTERNAL);
ager@chromium.org5c838252010-02-19 08:53:10 +0000687 // Save the name_ register across the call.
688 __ push(name_);
689
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000690 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
ager@chromium.org5c838252010-02-19 08:53:10 +0000691
692 __ CallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000693 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
694 masm->isolate()),
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000695 6);
ager@chromium.org5c838252010-02-19 08:53:10 +0000696
697 // Restore the name_ register.
698 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000699
700 // Leave the internal frame.
ager@chromium.org5c838252010-02-19 08:53:10 +0000701 }
702
703 void LoadWithInterceptor(MacroAssembler* masm,
704 Register receiver,
705 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000706 Handle<JSObject> holder_obj,
ager@chromium.org5c838252010-02-19 08:53:10 +0000707 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000708 {
709 FrameScope scope(masm, StackFrame::INTERNAL);
710 __ push(holder); // Save the holder.
711 __ push(name_); // Save the name.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000712
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000713 CompileCallLoadPropertyWithInterceptor(masm,
714 receiver,
715 holder,
716 name_,
717 holder_obj);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000718
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000719 __ pop(name_); // Restore the name.
720 __ pop(receiver); // Restore the holder.
721 // Leave the internal frame.
722 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000723
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000724 __ cmp(eax, masm->isolate()->factory()->no_interceptor_result_sentinel());
ager@chromium.org5c838252010-02-19 08:53:10 +0000725 __ j(not_equal, interceptor_succeeded);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000726 }
727
ager@chromium.org5c838252010-02-19 08:53:10 +0000728 StubCompiler* stub_compiler_;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000729 const ParameterCount& arguments_;
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000730 Register name_;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000731 Code::ExtraICState extra_state_;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000732};
733
734
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000735void BaseStoreStubCompiler::GenerateRestoreName(MacroAssembler* masm,
736 Label* label,
737 Handle<Name> name) {
738 if (!label->is_unused()) {
739 __ bind(label);
740 __ mov(this->name(), Immediate(name));
741 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000742}
743
744
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000745// Generate code to check that a global property cell is empty. Create
746// the property cell at compilation time if no cell exists for the
747// property.
748static void GenerateCheckPropertyCell(MacroAssembler* masm,
749 Handle<GlobalObject> global,
750 Handle<Name> name,
751 Register scratch,
752 Label* miss) {
753 Handle<JSGlobalPropertyCell> cell =
754 GlobalObject::EnsurePropertyCell(global, name);
755 ASSERT(cell->value()->IsTheHole());
756 Handle<Oddball> the_hole = masm->isolate()->factory()->the_hole_value();
757 if (Serializer::enabled()) {
758 __ mov(scratch, Immediate(cell));
759 __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
760 Immediate(the_hole));
761 } else {
762 __ cmp(Operand::Cell(cell), Immediate(the_hole));
763 }
764 __ j(not_equal, miss);
765}
766
767
ager@chromium.org5c838252010-02-19 08:53:10 +0000768// Both name_reg and receiver_reg are preserved on jumps to miss_label,
769// but may be destroyed if store is successful.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000770void StubCompiler::GenerateStoreTransition(MacroAssembler* masm,
771 Handle<JSObject> object,
772 LookupResult* lookup,
773 Handle<Map> transition,
774 Handle<Name> name,
775 Register receiver_reg,
776 Register name_reg,
777 Register value_reg,
778 Register scratch1,
779 Register scratch2,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000780 Register unused,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000781 Label* miss_label,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000782 Label* miss_restore_name,
783 Label* slow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000784 // Check that the map of the object hasn't changed.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000785 __ CheckMap(receiver_reg, Handle<Map>(object->map()),
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000786 miss_label, DO_SMI_CHECK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000787
788 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000789 if (object->IsJSGlobalProxy()) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000790 __ CheckAccessGlobalProxy(receiver_reg, scratch1, scratch2, miss_label);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000791 }
792
danno@chromium.orgf005df62013-04-30 16:36:45 +0000793 int descriptor = transition->LastAdded();
794 DescriptorArray* descriptors = transition->instance_descriptors();
795 PropertyDetails details = descriptors->GetDetails(descriptor);
796 Representation representation = details.representation();
797 ASSERT(!representation.IsNone());
798
799 // Ensure no transitions to deprecated maps are followed.
800 __ CheckMapDeprecated(transition, scratch1, miss_label);
801
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000802 // Check that we are allowed to write this.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000803 if (object->GetPrototype()->IsJSObject()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000804 JSObject* holder;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000805 // holder == object indicates that no property was found.
806 if (lookup->holder() != *object) {
807 holder = lookup->holder();
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000808 } else {
809 // Find the top object.
810 holder = *object;
811 do {
812 holder = JSObject::cast(holder->GetPrototype());
813 } while (holder->GetPrototype()->IsJSObject());
814 }
815 // We need an extra register, push
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000816 Register holder_reg = CheckPrototypes(
817 object, receiver_reg, Handle<JSObject>(holder), name_reg,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000818 scratch1, scratch2, name, miss_restore_name, SKIP_RECEIVER);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000819 // If no property was found, and the holder (the last object in the
820 // prototype chain) is in slow mode, we need to do a negative lookup on the
821 // holder.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000822 if (lookup->holder() == *object) {
823 if (holder->IsJSGlobalObject()) {
824 GenerateCheckPropertyCell(
825 masm,
826 Handle<GlobalObject>(GlobalObject::cast(holder)),
827 name,
828 scratch1,
829 miss_restore_name);
830 } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
831 GenerateDictionaryNegativeLookup(
832 masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
833 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000834 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000835 }
836
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000837 Register storage_reg = name_reg;
838
839 if (FLAG_track_fields && representation.IsSmi()) {
840 __ JumpIfNotSmi(value_reg, miss_restore_name);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +0000841 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
842 __ JumpIfSmi(value_reg, miss_restore_name);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000843 } else if (FLAG_track_double_fields && representation.IsDouble()) {
844 Label do_store, heap_number;
845 __ AllocateHeapNumber(storage_reg, scratch1, scratch2, slow);
846
847 __ JumpIfNotSmi(value_reg, &heap_number);
848 __ SmiUntag(value_reg);
849 if (CpuFeatures::IsSupported(SSE2)) {
850 CpuFeatureScope use_sse2(masm, SSE2);
851 __ cvtsi2sd(xmm0, value_reg);
852 } else {
853 __ push(value_reg);
854 __ fild_s(Operand(esp, 0));
855 __ pop(value_reg);
856 }
857 __ SmiTag(value_reg);
858 __ jmp(&do_store);
859
860 __ bind(&heap_number);
861 __ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(),
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000862 miss_restore_name, DONT_DO_SMI_CHECK);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000863 if (CpuFeatures::IsSupported(SSE2)) {
864 CpuFeatureScope use_sse2(masm, SSE2);
865 __ movdbl(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset));
866 } else {
867 __ fld_d(FieldOperand(value_reg, HeapNumber::kValueOffset));
868 }
869
870 __ bind(&do_store);
871 if (CpuFeatures::IsSupported(SSE2)) {
872 CpuFeatureScope use_sse2(masm, SSE2);
873 __ movdbl(FieldOperand(storage_reg, HeapNumber::kValueOffset), xmm0);
874 } else {
875 __ fstp_d(FieldOperand(storage_reg, HeapNumber::kValueOffset));
876 }
877 }
878
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000879 // Stub never generated for non-global objects that require access
880 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000881 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000882
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000883 // Perform map transition for the receiver if necessary.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000884 if (object->map()->unused_property_fields() == 0) {
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000885 // The properties must be extended before we can store the value.
ager@chromium.org32912102009-01-16 10:38:43 +0000886 // We jump to a runtime call that extends the properties array.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000887 __ pop(scratch1); // Return address.
ager@chromium.org5c838252010-02-19 08:53:10 +0000888 __ push(receiver_reg);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000889 __ push(Immediate(transition));
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000890 __ push(value_reg);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000891 __ push(scratch1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000892 __ TailCallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000893 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
894 masm->isolate()),
895 3,
896 1);
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000897 return;
898 }
899
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000900 // Update the map of the object.
901 __ mov(scratch1, Immediate(transition));
902 __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1);
verwaest@chromium.org37141392012-05-31 13:27:02 +0000903
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000904 // Update the write barrier for the map field.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000905 __ RecordWriteField(receiver_reg,
906 HeapObject::kMapOffset,
907 scratch1,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000908 scratch2,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000909 kDontSaveFPRegs,
910 OMIT_REMEMBERED_SET,
911 OMIT_SMI_CHECK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000912
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000913 int index = transition->instance_descriptors()->GetFieldIndex(
914 transition->LastAdded());
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000915
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000916 // Adjust for the number of properties stored in the object. Even in the
917 // face of a transition we can use the old map here because the size of the
918 // object and the number of in-object properties is not going to change.
919 index -= object->map()->inobject_properties();
920
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000921 SmiCheck smi_check = representation.IsTagged()
922 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000923 // TODO(verwaest): Share this code as a code stub.
ager@chromium.org7c537e22008-10-16 08:43:32 +0000924 if (index < 0) {
925 // Set the property straight into the object.
926 int offset = object->map()->instance_size() + (index * kPointerSize);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000927 if (FLAG_track_double_fields && representation.IsDouble()) {
928 __ mov(FieldOperand(receiver_reg, offset), storage_reg);
929 } else {
930 __ mov(FieldOperand(receiver_reg, offset), value_reg);
931 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000932
danno@chromium.orgf005df62013-04-30 16:36:45 +0000933 if (!FLAG_track_fields || !representation.IsSmi()) {
934 // Update the write barrier for the array address.
935 // Pass the value being stored in the now unused name_reg.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000936 if (!FLAG_track_double_fields || !representation.IsDouble()) {
937 __ mov(name_reg, value_reg);
938 } else {
939 ASSERT(storage_reg.is(name_reg));
940 }
danno@chromium.orgf005df62013-04-30 16:36:45 +0000941 __ RecordWriteField(receiver_reg,
942 offset,
943 name_reg,
944 scratch1,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000945 kDontSaveFPRegs,
946 EMIT_REMEMBERED_SET,
947 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000948 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000949 } else {
950 // Write to the properties array.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000951 int offset = index * kPointerSize + FixedArray::kHeaderSize;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000952 // Get the properties array (optimistically).
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000953 __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000954 if (FLAG_track_double_fields && representation.IsDouble()) {
955 __ mov(FieldOperand(scratch1, offset), storage_reg);
956 } else {
957 __ mov(FieldOperand(scratch1, offset), value_reg);
958 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000959
danno@chromium.orgf005df62013-04-30 16:36:45 +0000960 if (!FLAG_track_fields || !representation.IsSmi()) {
961 // Update the write barrier for the array address.
962 // Pass the value being stored in the now unused name_reg.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000963 if (!FLAG_track_double_fields || !representation.IsDouble()) {
964 __ mov(name_reg, value_reg);
965 } else {
966 ASSERT(storage_reg.is(name_reg));
967 }
danno@chromium.orgf005df62013-04-30 16:36:45 +0000968 __ RecordWriteField(scratch1,
969 offset,
970 name_reg,
971 receiver_reg,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000972 kDontSaveFPRegs,
973 EMIT_REMEMBERED_SET,
974 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000975 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000976 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000977
978 // Return the value (register eax).
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000979 ASSERT(value_reg.is(eax));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000980 __ ret(0);
981}
982
983
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000984// Both name_reg and receiver_reg are preserved on jumps to miss_label,
985// but may be destroyed if store is successful.
986void StubCompiler::GenerateStoreField(MacroAssembler* masm,
987 Handle<JSObject> object,
988 LookupResult* lookup,
989 Register receiver_reg,
990 Register name_reg,
991 Register value_reg,
992 Register scratch1,
993 Register scratch2,
994 Label* miss_label) {
995 // Check that the map of the object hasn't changed.
996 __ CheckMap(receiver_reg, Handle<Map>(object->map()),
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000997 miss_label, DO_SMI_CHECK);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000998
999 // Perform global security token check if needed.
1000 if (object->IsJSGlobalProxy()) {
1001 __ CheckAccessGlobalProxy(receiver_reg, scratch1, scratch2, miss_label);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001002 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001003
1004 // Stub never generated for non-global objects that require access
1005 // checks.
1006 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
1007
1008 int index = lookup->GetFieldIndex().field_index();
1009
1010 // Adjust for the number of properties stored in the object. Even in the
1011 // face of a transition we can use the old map here because the size of the
1012 // object and the number of in-object properties is not going to change.
1013 index -= object->map()->inobject_properties();
1014
danno@chromium.orgf005df62013-04-30 16:36:45 +00001015 Representation representation = lookup->representation();
1016 ASSERT(!representation.IsNone());
1017 if (FLAG_track_fields && representation.IsSmi()) {
1018 __ JumpIfNotSmi(value_reg, miss_label);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001019 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
1020 __ JumpIfSmi(value_reg, miss_label);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001021 } else if (FLAG_track_double_fields && representation.IsDouble()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001022 // Load the double storage.
1023 if (index < 0) {
1024 int offset = object->map()->instance_size() + (index * kPointerSize);
1025 __ mov(scratch1, FieldOperand(receiver_reg, offset));
1026 } else {
1027 __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
1028 int offset = index * kPointerSize + FixedArray::kHeaderSize;
1029 __ mov(scratch1, FieldOperand(scratch1, offset));
1030 }
1031
1032 // Store the value into the storage.
1033 Label do_store, heap_number;
1034 __ JumpIfNotSmi(value_reg, &heap_number);
1035 __ SmiUntag(value_reg);
1036 if (CpuFeatures::IsSupported(SSE2)) {
1037 CpuFeatureScope use_sse2(masm, SSE2);
1038 __ cvtsi2sd(xmm0, value_reg);
1039 } else {
1040 __ push(value_reg);
1041 __ fild_s(Operand(esp, 0));
1042 __ pop(value_reg);
1043 }
1044 __ SmiTag(value_reg);
1045 __ jmp(&do_store);
1046 __ bind(&heap_number);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001047 __ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(),
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001048 miss_label, DONT_DO_SMI_CHECK);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001049 if (CpuFeatures::IsSupported(SSE2)) {
1050 CpuFeatureScope use_sse2(masm, SSE2);
1051 __ movdbl(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset));
1052 } else {
1053 __ fld_d(FieldOperand(value_reg, HeapNumber::kValueOffset));
1054 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00001055 __ bind(&do_store);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001056 if (CpuFeatures::IsSupported(SSE2)) {
1057 CpuFeatureScope use_sse2(masm, SSE2);
1058 __ movdbl(FieldOperand(scratch1, HeapNumber::kValueOffset), xmm0);
1059 } else {
1060 __ fstp_d(FieldOperand(scratch1, HeapNumber::kValueOffset));
1061 }
1062 // Return the value (register eax).
1063 ASSERT(value_reg.is(eax));
1064 __ ret(0);
1065 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +00001066 }
1067
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001068 ASSERT(!FLAG_track_double_fields || !representation.IsDouble());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001069 // TODO(verwaest): Share this code as a code stub.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001070 SmiCheck smi_check = representation.IsTagged()
1071 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001072 if (index < 0) {
1073 // Set the property straight into the object.
1074 int offset = object->map()->instance_size() + (index * kPointerSize);
1075 __ mov(FieldOperand(receiver_reg, offset), value_reg);
1076
danno@chromium.orgf005df62013-04-30 16:36:45 +00001077 if (!FLAG_track_fields || !representation.IsSmi()) {
1078 // Update the write barrier for the array address.
1079 // Pass the value being stored in the now unused name_reg.
1080 __ mov(name_reg, value_reg);
1081 __ RecordWriteField(receiver_reg,
1082 offset,
1083 name_reg,
1084 scratch1,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001085 kDontSaveFPRegs,
1086 EMIT_REMEMBERED_SET,
1087 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001088 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001089 } else {
1090 // Write to the properties array.
1091 int offset = index * kPointerSize + FixedArray::kHeaderSize;
1092 // Get the properties array (optimistically).
1093 __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001094 __ mov(FieldOperand(scratch1, offset), value_reg);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001095
danno@chromium.orgf005df62013-04-30 16:36:45 +00001096 if (!FLAG_track_fields || !representation.IsSmi()) {
1097 // Update the write barrier for the array address.
1098 // Pass the value being stored in the now unused name_reg.
1099 __ mov(name_reg, value_reg);
1100 __ RecordWriteField(scratch1,
1101 offset,
1102 name_reg,
1103 receiver_reg,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001104 kDontSaveFPRegs,
1105 EMIT_REMEMBERED_SET,
1106 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001107 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001108 }
1109
1110 // Return the value (register eax).
1111 ASSERT(value_reg.is(eax));
1112 __ ret(0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001113}
1114
1115
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001116// Calls GenerateCheckPropertyCell for each global object in the prototype chain
1117// from object to (but not including) holder.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001118static void GenerateCheckPropertyCells(MacroAssembler* masm,
1119 Handle<JSObject> object,
1120 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001121 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001122 Register scratch,
1123 Label* miss) {
1124 Handle<JSObject> current = object;
1125 while (!current.is_identical_to(holder)) {
1126 if (current->IsGlobalObject()) {
1127 GenerateCheckPropertyCell(masm,
1128 Handle<GlobalObject>::cast(current),
1129 name,
1130 scratch,
1131 miss);
1132 }
1133 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
1134 }
1135}
1136
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001137
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001138void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001139 __ jmp(code, RelocInfo::CODE_TARGET);
1140}
1141
1142
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001143#undef __
1144#define __ ACCESS_MASM(masm())
1145
1146
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001147Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
1148 Register object_reg,
1149 Handle<JSObject> holder,
1150 Register holder_reg,
1151 Register scratch1,
1152 Register scratch2,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001153 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001154 int save_at_depth,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001155 Label* miss,
1156 PrototypeCheckType check) {
1157 Handle<JSObject> first = object;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001158 // Make sure there's no overlap between holder and object registers.
1159 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1160 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1161 && !scratch2.is(scratch1));
1162
1163 // Keep track of the current object in register reg.
1164 Register reg = object_reg;
1165 Handle<JSObject> current = object;
1166 int depth = 0;
1167
1168 if (save_at_depth == depth) {
1169 __ mov(Operand(esp, kPointerSize), reg);
1170 }
1171
1172 // Traverse the prototype chain and check the maps in the prototype chain for
1173 // fast and global objects or do negative lookup for normal objects.
1174 while (!current.is_identical_to(holder)) {
1175 ++depth;
1176
1177 // Only global objects and objects that do not require access
1178 // checks are allowed in stubs.
1179 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1180
1181 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
1182 if (!current->HasFastProperties() &&
1183 !current->IsJSGlobalObject() &&
1184 !current->IsJSGlobalProxy()) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001185 if (!name->IsUniqueName()) {
1186 ASSERT(name->IsString());
1187 name = factory()->InternalizeString(Handle<String>::cast(name));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001188 }
1189 ASSERT(current->property_dictionary()->FindEntry(*name) ==
ulan@chromium.org750145a2013-03-07 15:14:13 +00001190 NameDictionary::kNotFound);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001191
1192 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1193 scratch1, scratch2);
1194
1195 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
1196 reg = holder_reg; // From now on the object will be in holder_reg.
1197 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
1198 } else {
1199 bool in_new_space = heap()->InNewSpace(*prototype);
1200 Handle<Map> current_map(current->map());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001201 if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001202 __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001203 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001204
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001205 // Check access rights to the global object. This has to happen after
1206 // the map check so that we know that the object is actually a global
1207 // object.
1208 if (current->IsJSGlobalProxy()) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001209 __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001210 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001211
1212 if (in_new_space) {
1213 // Save the map in scratch1 for later.
1214 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
1215 }
1216
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001217 reg = holder_reg; // From now on the object will be in holder_reg.
1218
1219 if (in_new_space) {
1220 // The prototype is in new space; we cannot store a reference to it
1221 // in the code. Load it from the map.
1222 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
1223 } else {
1224 // The prototype is in old space; load it directly.
1225 __ mov(reg, prototype);
1226 }
1227 }
1228
1229 if (save_at_depth == depth) {
1230 __ mov(Operand(esp, kPointerSize), reg);
1231 }
1232
1233 // Go to the next object in the prototype chain.
1234 current = prototype;
1235 }
1236 ASSERT(current.is_identical_to(holder));
1237
1238 // Log the check depth.
1239 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
1240
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001241 if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) {
1242 // Check the holder map.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001243 __ CheckMap(reg, Handle<Map>(holder->map()), miss, DONT_DO_SMI_CHECK);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001244 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001245
1246 // Perform security check for access to the global object.
1247 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1248 if (holder->IsJSGlobalProxy()) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001249 __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001250 }
1251
1252 // If we've skipped any global objects, it's not enough to verify that
1253 // their maps haven't changed. We also need to check that the property
1254 // cell for the property is still empty.
1255 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1256
1257 // Return the register containing the holder.
1258 return reg;
1259}
1260
1261
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001262void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success,
1263 Label* miss) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001264 if (!miss->is_unused()) {
1265 __ jmp(success);
1266 __ bind(miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001267 TailCallBuiltin(masm(), MissBuiltin(kind()));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001268 }
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001269}
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001270
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001271
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001272Register BaseLoadStubCompiler::CallbackHandlerFrontend(
1273 Handle<JSObject> object,
1274 Register object_reg,
1275 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001276 Handle<Name> name,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001277 Label* success,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001278 Handle<ExecutableAccessorInfo> callback) {
1279 Label miss;
1280
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001281 Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001282
1283 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
1284 ASSERT(!reg.is(scratch2()));
1285 ASSERT(!reg.is(scratch3()));
1286 Register dictionary = scratch1();
1287 bool must_preserve_dictionary_reg = reg.is(dictionary);
1288
1289 // Load the properties dictionary.
1290 if (must_preserve_dictionary_reg) {
1291 __ push(dictionary);
1292 }
1293 __ mov(dictionary, FieldOperand(reg, JSObject::kPropertiesOffset));
1294
1295 // Probe the dictionary.
1296 Label probe_done, pop_and_miss;
ulan@chromium.org750145a2013-03-07 15:14:13 +00001297 NameDictionaryLookupStub::GeneratePositiveLookup(masm(),
1298 &pop_and_miss,
1299 &probe_done,
1300 dictionary,
1301 this->name(),
1302 scratch2(),
1303 scratch3());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001304 __ bind(&pop_and_miss);
1305 if (must_preserve_dictionary_reg) {
1306 __ pop(dictionary);
1307 }
1308 __ jmp(&miss);
1309 __ bind(&probe_done);
1310
1311 // If probing finds an entry in the dictionary, scratch2 contains the
1312 // index into the dictionary. Check that the value is the callback.
1313 Register index = scratch2();
1314 const int kElementsStartOffset =
ulan@chromium.org750145a2013-03-07 15:14:13 +00001315 NameDictionary::kHeaderSize +
1316 NameDictionary::kElementsStartIndex * kPointerSize;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001317 const int kValueOffset = kElementsStartOffset + kPointerSize;
1318 __ mov(scratch3(),
1319 Operand(dictionary, index, times_4, kValueOffset - kHeapObjectTag));
1320 if (must_preserve_dictionary_reg) {
1321 __ pop(dictionary);
1322 }
1323 __ cmp(scratch3(), callback);
1324 __ j(not_equal, &miss);
1325 }
1326
1327 HandlerFrontendFooter(success, &miss);
1328 return reg;
1329}
1330
1331
1332void BaseLoadStubCompiler::NonexistentHandlerFrontend(
1333 Handle<JSObject> object,
1334 Handle<JSObject> last,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001335 Handle<Name> name,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001336 Label* success,
1337 Handle<GlobalObject> global) {
1338 Label miss;
1339
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001340 HandlerFrontendHeader(object, receiver(), last, name, &miss);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001341
1342 // If the last object in the prototype chain is a global object,
1343 // check that the global property cell is empty.
1344 if (!global.is_null()) {
1345 GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
1346 }
1347
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001348 HandlerFrontendFooter(success, &miss);
1349}
1350
1351
1352void BaseLoadStubCompiler::GenerateLoadField(Register reg,
1353 Handle<JSObject> holder,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001354 PropertyIndex field,
1355 Representation representation) {
1356 if (!reg.is(receiver())) __ mov(receiver(), reg);
1357 if (kind() == Code::LOAD_IC) {
1358 LoadFieldStub stub(field.is_inobject(holder),
1359 field.translate(holder),
1360 representation);
1361 GenerateTailCall(masm(), stub.GetCode(isolate()));
1362 } else {
1363 KeyedLoadFieldStub stub(field.is_inobject(holder),
1364 field.translate(holder),
1365 representation);
1366 GenerateTailCall(masm(), stub.GetCode(isolate()));
1367 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001368}
1369
1370
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001371void BaseLoadStubCompiler::GenerateLoadCallback(
1372 Register reg,
1373 Handle<ExecutableAccessorInfo> callback) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001374 // Insert additional parameters into the stack frame above return address.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001375 ASSERT(!scratch3().is(reg));
1376 __ pop(scratch3()); // Get return address to place it below.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001377
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001378 __ push(receiver()); // receiver
1379 __ mov(scratch2(), esp);
1380 ASSERT(!scratch2().is(reg));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001381 __ push(reg); // holder
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001382 // Push data from ExecutableAccessorInfo.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001383 if (isolate()->heap()->InNewSpace(callback->data())) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001384 __ mov(scratch1(), Immediate(callback));
1385 __ push(FieldOperand(scratch1(), ExecutableAccessorInfo::kDataOffset));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001386 } else {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001387 __ push(Immediate(Handle<Object>(callback->data(), isolate())));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001388 }
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001389 __ push(Immediate(isolate()->factory()->undefined_value())); // ReturnValue
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00001390 __ push(Immediate(reinterpret_cast<int>(isolate())));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001391
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001392 // Save a pointer to where we pushed the arguments pointer. This will be
1393 // passed as the const ExecutableAccessorInfo& to the C++ callback.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001394 __ push(scratch2());
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001395
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001396 __ push(name()); // name
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001397 __ mov(ebx, esp); // esp points to reference to name (handler).
1398
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001399 __ push(scratch3()); // Restore return address.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001400
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001401 // array for v8::Arguments::values_, handler for name and pointer
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001402 // to the values (it considered as smi in GC).
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001403 const int kStackSpace = PropertyCallbackArguments::kArgsLength + 2;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001404 const int kApiArgc = 2;
1405
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001406 Address getter_address = v8::ToCData<Address>(callback->getter());
1407 bool returns_handle =
1408 !CallbackTable::ReturnsVoid(isolate(),
1409 reinterpret_cast<void*>(getter_address));
1410 __ PrepareCallApiFunction(kApiArgc, returns_handle);
1411 __ mov(ApiParameterOperand(0, returns_handle), ebx); // name.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001412 __ add(ebx, Immediate(kPointerSize));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001413 __ mov(ApiParameterOperand(1, returns_handle), ebx); // arguments pointer.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001414
kmillikin@chromium.org2d5475f2009-12-20 18:15:52 +00001415 // Emitting a stub call may try to allocate (if the code is not
1416 // already generated). Do not allow the assembler to perform a
1417 // garbage collection but instead return the allocation failure
1418 // object.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001419
1420 __ CallApiFunctionAndReturn(getter_address,
1421 kStackSpace,
1422 returns_handle,
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00001423 5);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001424}
1425
1426
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001427void BaseLoadStubCompiler::GenerateLoadConstant(Handle<JSFunction> value) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001428 // Return the constant value.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001429 __ LoadHeapObject(eax, value);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001430 __ ret(0);
1431}
1432
1433
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001434void BaseLoadStubCompiler::GenerateLoadInterceptor(
1435 Register holder_reg,
1436 Handle<JSObject> object,
1437 Handle<JSObject> interceptor_holder,
1438 LookupResult* lookup,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001439 Handle<Name> name) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001440 ASSERT(interceptor_holder->HasNamedInterceptor());
1441 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1442
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001443 // So far the most popular follow ups for interceptor loads are FIELD
1444 // and CALLBACKS, so inline only them, other cases may be added
1445 // later.
1446 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001447 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001448 if (lookup->IsField()) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001449 compile_followup_inline = true;
1450 } else if (lookup->type() == CALLBACKS &&
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001451 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
1452 ExecutableAccessorInfo* callback =
1453 ExecutableAccessorInfo::cast(lookup->GetCallbackObject());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001454 compile_followup_inline = callback->getter() != NULL &&
1455 callback->IsCompatibleReceiver(*object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001456 }
1457 }
1458
1459 if (compile_followup_inline) {
1460 // Compile the interceptor call, followed by inline code to load the
1461 // property from further up the prototype chain if the call fails.
1462 // Check that the maps haven't changed.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001463 ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001464
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001465 // Preserve the receiver register explicitly whenever it is different from
1466 // the holder and it is needed should the interceptor return without any
1467 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1468 // the FIELD case might cause a miss during the prototype check.
1469 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001470 bool must_preserve_receiver_reg = !receiver().is(holder_reg) &&
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001471 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1472
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001473 // Save necessary data before invoking an interceptor.
1474 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001475 {
1476 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001477
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001478 if (must_preserve_receiver_reg) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001479 __ push(receiver());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001480 }
1481 __ push(holder_reg);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001482 __ push(this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001483
1484 // Invoke an interceptor. Note: map checks from receiver to
1485 // interceptor's holder has been compiled before (see a caller
1486 // of this method.)
1487 CompileCallLoadPropertyWithInterceptor(masm(),
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001488 receiver(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001489 holder_reg,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001490 this->name(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001491 interceptor_holder);
1492
1493 // Check if interceptor provided a value for property. If it's
1494 // the case, return immediately.
1495 Label interceptor_failed;
1496 __ cmp(eax, factory()->no_interceptor_result_sentinel());
1497 __ j(equal, &interceptor_failed);
1498 frame_scope.GenerateLeaveFrame();
1499 __ ret(0);
1500
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001501 // Clobber registers when generating debug-code to provoke errors.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001502 __ bind(&interceptor_failed);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001503 if (FLAG_debug_code) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001504 __ mov(receiver(), Immediate(BitCast<int32_t>(kZapValue)));
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001505 __ mov(holder_reg, Immediate(BitCast<int32_t>(kZapValue)));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001506 __ mov(this->name(), Immediate(BitCast<int32_t>(kZapValue)));
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001507 }
1508
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001509 __ pop(this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001510 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001511 if (must_preserve_receiver_reg) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001512 __ pop(receiver());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001513 }
1514
1515 // Leave the internal frame.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001516 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001517
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001518 GenerateLoadPostInterceptor(holder_reg, interceptor_holder, name, lookup);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001519 } else { // !compile_followup_inline
1520 // Call the runtime system to load the interceptor.
1521 // Check that the maps haven't changed.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001522 __ pop(scratch2()); // save old return address
1523 PushInterceptorArguments(masm(), receiver(), holder_reg,
1524 this->name(), interceptor_holder);
1525 __ push(scratch2()); // restore old return address
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001526
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001527 ExternalReference ref =
1528 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001529 isolate());
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001530 __ TailCallExternalReference(ref, 6, 1);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001531 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001532}
1533
1534
ulan@chromium.org750145a2013-03-07 15:14:13 +00001535void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001536 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001537 __ cmp(ecx, Immediate(name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001538 __ j(not_equal, miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001539 }
1540}
1541
1542
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001543void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1544 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001545 Handle<Name> name,
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001546 Label* miss) {
1547 ASSERT(holder->IsGlobalObject());
1548
1549 // Get the number of arguments.
1550 const int argc = arguments().immediate();
1551
1552 // Get the receiver from the stack.
1553 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1554
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001555
1556 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001557 __ JumpIfSmi(edx, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001558 CheckPrototypes(object, edx, holder, ebx, eax, edi, name, miss);
1559}
1560
1561
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001562void CallStubCompiler::GenerateLoadFunctionFromCell(
1563 Handle<JSGlobalPropertyCell> cell,
1564 Handle<JSFunction> function,
1565 Label* miss) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001566 // Get the value from the cell.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001567 if (Serializer::enabled()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001568 __ mov(edi, Immediate(cell));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001569 __ mov(edi, FieldOperand(edi, JSGlobalPropertyCell::kValueOffset));
1570 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001571 __ mov(edi, Operand::Cell(cell));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001572 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001573
1574 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001575 if (isolate()->heap()->InNewSpace(*function)) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001576 // We can't embed a pointer to a function in new space so we have
1577 // to verify that the shared function info is unchanged. This has
1578 // the nice side effect that multiple closures based on the same
1579 // function can all use this call IC. Before we load through the
1580 // function, we have to verify that it still is a function.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001581 __ JumpIfSmi(edi, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001582 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001583 __ j(not_equal, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001584
1585 // Check the shared function info. Make sure it hasn't changed.
1586 __ cmp(FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset),
1587 Immediate(Handle<SharedFunctionInfo>(function->shared())));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001588 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001589 __ cmp(edi, Immediate(function));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001590 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001591 __ j(not_equal, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001592}
1593
1594
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001595void CallStubCompiler::GenerateMissBranch() {
1596 Handle<Code> code =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001597 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
danno@chromium.org40cb8782011-05-25 07:58:50 +00001598 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001599 extra_state_);
1600 __ jmp(code, RelocInfo::CODE_TARGET);
1601}
1602
1603
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001604Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1605 Handle<JSObject> holder,
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00001606 PropertyIndex index,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001607 Handle<Name> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001608 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001609 // -- ecx : name
1610 // -- esp[0] : return address
1611 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1612 // -- ...
1613 // -- esp[(argc + 1) * 4] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001614 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001615 Label miss;
1616
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001617 GenerateNameCheck(name, &miss);
1618
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001619 // Get the receiver from the stack.
1620 const int argc = arguments().immediate();
1621 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1622
1623 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001624 __ JumpIfSmi(edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001625
1626 // Do the right check and compute the holder register.
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001627 Register reg = CheckPrototypes(object, edx, holder, ebx, eax, edi,
1628 name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001629
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001630 GenerateFastPropertyLoad(
1631 masm(), edi, reg, index.is_inobject(holder),
1632 index.translate(holder), Representation::Tagged());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001633
1634 // Check that the function really is a function.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001635 __ JumpIfSmi(edi, &miss);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001636 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001637 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001638
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001639 // Patch the receiver on the stack with the global proxy if
1640 // necessary.
1641 if (object->IsGlobalObject()) {
1642 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
1643 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
1644 }
1645
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001646 // Invoke the function.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001647 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001648 ? CALL_AS_FUNCTION
1649 : CALL_AS_METHOD;
1650 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION,
1651 NullCallWrapper(), call_kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001652
1653 // Handle call cache miss.
1654 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001655 GenerateMissBranch();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001656
1657 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001658 return GetCode(Code::FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001659}
1660
1661
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001662Handle<Code> CallStubCompiler::CompileArrayPushCall(
1663 Handle<Object> object,
1664 Handle<JSObject> holder,
1665 Handle<JSGlobalPropertyCell> cell,
1666 Handle<JSFunction> function,
1667 Handle<String> name) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001668 // ----------- S t a t e -------------
1669 // -- ecx : name
1670 // -- esp[0] : return address
1671 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1672 // -- ...
1673 // -- esp[(argc + 1) * 4] : receiver
1674 // -----------------------------------
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001675
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001676 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001677 if (!object->IsJSArray() || !cell.is_null()) {
1678 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001679 }
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001680
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001681 Label miss;
1682
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001683 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001684
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001685 // Get the receiver from the stack.
1686 const int argc = arguments().immediate();
1687 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1688
1689 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001690 __ JumpIfSmi(edx, &miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001691
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001692 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
1693 name, &miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001694
1695 if (argc == 0) {
1696 // Noop, return the length.
1697 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
1698 __ ret((argc + 1) * kPointerSize);
1699 } else {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001700 Label call_builtin;
1701
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001702 if (argc == 1) { // Otherwise fall through to call builtin.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001703 Label attempt_to_grow_elements, with_write_barrier, check_double;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001704
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001705 // Get the elements array of the object.
1706 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset));
1707
1708 // Check that the elements are in fast mode and writable.
1709 __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
1710 Immediate(factory()->fixed_array_map()));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001711 __ j(not_equal, &check_double);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001712
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001713 // Get the array's length into eax and calculate new length.
1714 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
1715 STATIC_ASSERT(kSmiTagSize == 1);
1716 STATIC_ASSERT(kSmiTag == 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001717 __ add(eax, Immediate(Smi::FromInt(argc)));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001718
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001719 // Get the elements' length into ecx.
1720 __ mov(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001721
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001722 // Check if we could survive without allocation.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001723 __ cmp(eax, ecx);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001724 __ j(greater, &attempt_to_grow_elements);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001725
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001726 // Check if value is a smi.
1727 __ mov(ecx, Operand(esp, argc * kPointerSize));
1728 __ JumpIfNotSmi(ecx, &with_write_barrier);
1729
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001730 // Save new length.
1731 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1732
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001733 // Store the value.
1734 __ mov(FieldOperand(edi,
1735 eax,
1736 times_half_pointer_size,
1737 FixedArray::kHeaderSize - argc * kPointerSize),
1738 ecx);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001739
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001740 __ ret((argc + 1) * kPointerSize);
1741
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001742 __ bind(&check_double);
1743
1744
1745 // Check that the elements are in double mode.
1746 __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
1747 Immediate(factory()->fixed_double_array_map()));
1748 __ j(not_equal, &call_builtin);
1749
1750 // Get the array's length into eax and calculate new length.
1751 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
1752 STATIC_ASSERT(kSmiTagSize == 1);
1753 STATIC_ASSERT(kSmiTag == 0);
1754 __ add(eax, Immediate(Smi::FromInt(argc)));
1755
1756 // Get the elements' length into ecx.
1757 __ mov(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
1758
1759 // Check if we could survive without allocation.
1760 __ cmp(eax, ecx);
1761 __ j(greater, &call_builtin);
1762
1763 __ mov(ecx, Operand(esp, argc * kPointerSize));
1764 __ StoreNumberToDoubleElements(
1765 ecx, edi, eax, ecx, xmm0, &call_builtin, true, argc * kDoubleSize);
1766
1767 // Save new length.
1768 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1769 __ ret((argc + 1) * kPointerSize);
1770
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001771 __ bind(&with_write_barrier);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001772
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001773 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
1774
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001775 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001776 Label fast_object, not_fast_object;
1777 __ CheckFastObjectElements(ebx, &not_fast_object, Label::kNear);
1778 __ jmp(&fast_object);
1779 // In case of fast smi-only, convert to fast object, otherwise bail out.
1780 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001781 __ CheckFastSmiElements(ebx, &call_builtin);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001782 __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
1783 Immediate(factory()->heap_number_map()));
1784 __ j(equal, &call_builtin);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001785 // edi: elements array
1786 // edx: receiver
1787 // ebx: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001788 Label try_holey_map;
1789 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001790 FAST_ELEMENTS,
1791 ebx,
1792 edi,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001793 &try_holey_map);
1794
1795 ElementsTransitionGenerator::
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001796 GenerateMapChangeElementsTransition(masm(),
1797 DONT_TRACK_ALLOCATION_SITE,
1798 NULL);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001799 // Restore edi.
1800 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset));
1801 __ jmp(&fast_object);
1802
1803 __ bind(&try_holey_map);
1804 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1805 FAST_HOLEY_ELEMENTS,
1806 ebx,
1807 edi,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001808 &call_builtin);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001809 ElementsTransitionGenerator::
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001810 GenerateMapChangeElementsTransition(masm(),
1811 DONT_TRACK_ALLOCATION_SITE,
1812 NULL);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001813 // Restore edi.
1814 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset));
1815 __ bind(&fast_object);
1816 } else {
1817 __ CheckFastObjectElements(ebx, &call_builtin);
1818 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001819
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001820 // Save new length.
1821 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1822
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001823 // Store the value.
1824 __ lea(edx, FieldOperand(edi,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001825 eax, times_half_pointer_size,
1826 FixedArray::kHeaderSize - argc * kPointerSize));
1827 __ mov(Operand(edx, 0), ecx);
1828
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001829 __ RecordWrite(edi, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001830 OMIT_SMI_CHECK);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001831
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001832 __ ret((argc + 1) * kPointerSize);
1833
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001834 __ bind(&attempt_to_grow_elements);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001835 if (!FLAG_inline_new) {
1836 __ jmp(&call_builtin);
1837 }
1838
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001839 __ mov(ebx, Operand(esp, argc * kPointerSize));
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001840 // Growing elements that are SMI-only requires special handling in case
1841 // the new element is non-Smi. For now, delegate to the builtin.
1842 Label no_fast_elements_check;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001843 __ JumpIfSmi(ebx, &no_fast_elements_check);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001844 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
1845 __ CheckFastObjectElements(ecx, &call_builtin, Label::kFar);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001846 __ bind(&no_fast_elements_check);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001847
1848 // We could be lucky and the elements array could be at the top of
1849 // new-space. In this case we can just grow it in place by moving the
1850 // allocation pointer up.
1851
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001852 ExternalReference new_space_allocation_top =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001853 ExternalReference::new_space_allocation_top_address(isolate());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001854 ExternalReference new_space_allocation_limit =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001855 ExternalReference::new_space_allocation_limit_address(isolate());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001856
1857 const int kAllocationDelta = 4;
1858 // Load top.
1859 __ mov(ecx, Operand::StaticVariable(new_space_allocation_top));
1860
1861 // Check if it's the end of elements.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001862 __ lea(edx, FieldOperand(edi,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001863 eax, times_half_pointer_size,
1864 FixedArray::kHeaderSize - argc * kPointerSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001865 __ cmp(edx, ecx);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001866 __ j(not_equal, &call_builtin);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001867 __ add(ecx, Immediate(kAllocationDelta * kPointerSize));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001868 __ cmp(ecx, Operand::StaticVariable(new_space_allocation_limit));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001869 __ j(above, &call_builtin);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001870
1871 // We fit and could grow elements.
1872 __ mov(Operand::StaticVariable(new_space_allocation_top), ecx);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001873
1874 // Push the argument...
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001875 __ mov(Operand(edx, 0), ebx);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001876 // ... and fill the rest with holes.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001877 for (int i = 1; i < kAllocationDelta; i++) {
1878 __ mov(Operand(edx, i * kPointerSize),
lrn@chromium.org7516f052011-03-30 08:52:27 +00001879 Immediate(factory()->the_hole_value()));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001880 }
1881
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001882 // We know the elements array is in new space so we don't need the
1883 // remembered set, but we just pushed a value onto it so we may have to
1884 // tell the incremental marker to rescan the object that we just grew. We
1885 // don't need to worry about the holes because they are in old space and
1886 // already marked black.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001887 __ RecordWrite(edi, edx, ebx, kDontSaveFPRegs, OMIT_REMEMBERED_SET);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001888
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001889 // Restore receiver to edx as finish sequence assumes it's here.
1890 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1891
1892 // Increment element's and array's sizes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001893 __ add(FieldOperand(edi, FixedArray::kLengthOffset),
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001894 Immediate(Smi::FromInt(kAllocationDelta)));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001895
1896 // NOTE: This only happen in new-space, where we don't
1897 // care about the black-byte-count on pages. Otherwise we should
1898 // update that too if the object is black.
1899
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001900 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1901
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001902 __ ret((argc + 1) * kPointerSize);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001903 }
1904
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001905 __ bind(&call_builtin);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001906 __ TailCallExternalReference(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001907 ExternalReference(Builtins::c_ArrayPush, isolate()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001908 argc + 1,
1909 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001910 }
1911
1912 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001913 GenerateMissBranch();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001914
1915 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001916 return GetCode(function);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001917}
1918
1919
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001920Handle<Code> CallStubCompiler::CompileArrayPopCall(
1921 Handle<Object> object,
1922 Handle<JSObject> holder,
1923 Handle<JSGlobalPropertyCell> cell,
1924 Handle<JSFunction> function,
1925 Handle<String> name) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001926 // ----------- S t a t e -------------
1927 // -- ecx : name
1928 // -- esp[0] : return address
1929 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1930 // -- ...
1931 // -- esp[(argc + 1) * 4] : receiver
1932 // -----------------------------------
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001933
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001934 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001935 if (!object->IsJSArray() || !cell.is_null()) {
1936 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001937 }
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001938
ager@chromium.orgac091b72010-05-05 07:34:42 +00001939 Label miss, return_undefined, call_builtin;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001940
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001941 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001942
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001943 // Get the receiver from the stack.
1944 const int argc = arguments().immediate();
1945 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1946
1947 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001948 __ JumpIfSmi(edx, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001949 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
1950 name, &miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001951
1952 // Get the elements array of the object.
1953 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset));
1954
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001955 // Check that the elements are in fast mode and writable.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001956 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
lrn@chromium.org7516f052011-03-30 08:52:27 +00001957 Immediate(factory()->fixed_array_map()));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001958 __ j(not_equal, &call_builtin);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001959
1960 // Get the array's length into ecx and calculate new length.
1961 __ mov(ecx, FieldOperand(edx, JSArray::kLengthOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001962 __ sub(ecx, Immediate(Smi::FromInt(1)));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001963 __ j(negative, &return_undefined);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001964
1965 // Get the last element.
1966 STATIC_ASSERT(kSmiTagSize == 1);
1967 STATIC_ASSERT(kSmiTag == 0);
1968 __ mov(eax, FieldOperand(ebx,
1969 ecx, times_half_pointer_size,
1970 FixedArray::kHeaderSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001971 __ cmp(eax, Immediate(factory()->the_hole_value()));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001972 __ j(equal, &call_builtin);
1973
1974 // Set the array's length.
1975 __ mov(FieldOperand(edx, JSArray::kLengthOffset), ecx);
1976
1977 // Fill with the hole.
1978 __ mov(FieldOperand(ebx,
1979 ecx, times_half_pointer_size,
1980 FixedArray::kHeaderSize),
lrn@chromium.org7516f052011-03-30 08:52:27 +00001981 Immediate(factory()->the_hole_value()));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001982 __ ret((argc + 1) * kPointerSize);
1983
ager@chromium.orgac091b72010-05-05 07:34:42 +00001984 __ bind(&return_undefined);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001985 __ mov(eax, Immediate(factory()->undefined_value()));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001986 __ ret((argc + 1) * kPointerSize);
1987
1988 __ bind(&call_builtin);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001989 __ TailCallExternalReference(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001990 ExternalReference(Builtins::c_ArrayPop, isolate()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001991 argc + 1,
1992 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001993
1994 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001995 GenerateMissBranch();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001996
1997 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001998 return GetCode(function);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001999}
2000
2001
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002002Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
2003 Handle<Object> object,
2004 Handle<JSObject> holder,
2005 Handle<JSGlobalPropertyCell> cell,
2006 Handle<JSFunction> function,
2007 Handle<String> name) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002008 // ----------- S t a t e -------------
2009 // -- ecx : function name
2010 // -- esp[0] : return address
2011 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2012 // -- ...
2013 // -- esp[(argc + 1) * 4] : receiver
2014 // -----------------------------------
2015
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002016 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002017 if (!object->IsString() || !cell.is_null()) {
2018 return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002019 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002020
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002021 const int argc = arguments().immediate();
2022
2023 Label miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002024 Label name_miss;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002025 Label index_out_of_range;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002026 Label* index_out_of_range_label = &index_out_of_range;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002027
danno@chromium.org40cb8782011-05-25 07:58:50 +00002028 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002029 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002030 DEFAULT_STRING_STUB)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002031 index_out_of_range_label = &miss;
2032 }
2033
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002034 GenerateNameCheck(name, &name_miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002035
2036 // Check that the maps starting from the prototype haven't changed.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002037 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2038 Context::STRING_FUNCTION_INDEX,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002039 eax,
2040 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002041 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002042 CheckPrototypes(
2043 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2044 eax, holder, ebx, edx, edi, name, &miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002045
2046 Register receiver = ebx;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002047 Register index = edi;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002048 Register result = eax;
2049 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize));
2050 if (argc > 0) {
2051 __ mov(index, Operand(esp, (argc - 0) * kPointerSize));
2052 } else {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002053 __ Set(index, Immediate(factory()->undefined_value()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002054 }
2055
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002056 StringCharCodeAtGenerator generator(receiver,
2057 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002058 result,
2059 &miss, // When not a string.
2060 &miss, // When not a number.
2061 index_out_of_range_label,
2062 STRING_INDEX_IS_NUMBER);
2063 generator.GenerateFast(masm());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002064 __ ret((argc + 1) * kPointerSize);
2065
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002066 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002067 generator.GenerateSlow(masm(), call_helper);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002068
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002069 if (index_out_of_range.is_linked()) {
2070 __ bind(&index_out_of_range);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002071 __ Set(eax, Immediate(factory()->nan_value()));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002072 __ ret((argc + 1) * kPointerSize);
2073 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002074
2075 __ bind(&miss);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002076 // Restore function name in ecx.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002077 __ Set(ecx, Immediate(name));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002078 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002079 GenerateMissBranch();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002080
2081 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002082 return GetCode(function);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002083}
2084
2085
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002086Handle<Code> CallStubCompiler::CompileStringCharAtCall(
2087 Handle<Object> object,
2088 Handle<JSObject> holder,
2089 Handle<JSGlobalPropertyCell> cell,
2090 Handle<JSFunction> function,
2091 Handle<String> name) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002092 // ----------- S t a t e -------------
2093 // -- ecx : function name
2094 // -- esp[0] : return address
2095 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2096 // -- ...
2097 // -- esp[(argc + 1) * 4] : receiver
2098 // -----------------------------------
2099
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002100 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002101 if (!object->IsString() || !cell.is_null()) {
2102 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002103 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002104
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002105 const int argc = arguments().immediate();
2106
2107 Label miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002108 Label name_miss;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002109 Label index_out_of_range;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002110 Label* index_out_of_range_label = &index_out_of_range;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002111
danno@chromium.org40cb8782011-05-25 07:58:50 +00002112 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002113 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002114 DEFAULT_STRING_STUB)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002115 index_out_of_range_label = &miss;
2116 }
2117
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002118 GenerateNameCheck(name, &name_miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002119
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002120 // Check that the maps starting from the prototype haven't changed.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002121 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2122 Context::STRING_FUNCTION_INDEX,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002123 eax,
2124 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002125 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002126 CheckPrototypes(
2127 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2128 eax, holder, ebx, edx, edi, name, &miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002129
2130 Register receiver = eax;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002131 Register index = edi;
danno@chromium.orgc612e022011-11-10 11:38:15 +00002132 Register scratch = edx;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002133 Register result = eax;
2134 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize));
2135 if (argc > 0) {
2136 __ mov(index, Operand(esp, (argc - 0) * kPointerSize));
2137 } else {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002138 __ Set(index, Immediate(factory()->undefined_value()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002139 }
2140
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002141 StringCharAtGenerator generator(receiver,
2142 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00002143 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002144 result,
2145 &miss, // When not a string.
2146 &miss, // When not a number.
2147 index_out_of_range_label,
2148 STRING_INDEX_IS_NUMBER);
2149 generator.GenerateFast(masm());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002150 __ ret((argc + 1) * kPointerSize);
2151
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002152 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002153 generator.GenerateSlow(masm(), call_helper);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002154
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002155 if (index_out_of_range.is_linked()) {
2156 __ bind(&index_out_of_range);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002157 __ Set(eax, Immediate(factory()->empty_string()));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002158 __ ret((argc + 1) * kPointerSize);
2159 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002160
2161 __ bind(&miss);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002162 // Restore function name in ecx.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002163 __ Set(ecx, Immediate(name));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002164 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002165 GenerateMissBranch();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002166
2167 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002168 return GetCode(function);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002169}
2170
2171
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002172Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
2173 Handle<Object> object,
2174 Handle<JSObject> holder,
2175 Handle<JSGlobalPropertyCell> cell,
2176 Handle<JSFunction> function,
2177 Handle<String> name) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002178 // ----------- S t a t e -------------
2179 // -- ecx : function name
2180 // -- esp[0] : return address
2181 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2182 // -- ...
2183 // -- esp[(argc + 1) * 4] : receiver
2184 // -----------------------------------
2185
2186 const int argc = arguments().immediate();
2187
2188 // If the object is not a JSObject or we got an unexpected number of
2189 // arguments, bail out to the regular call.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002190 if (!object->IsJSObject() || argc != 1) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002191 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002192 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002193
2194 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002195 GenerateNameCheck(name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002196
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002197 if (cell.is_null()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002198 __ mov(edx, Operand(esp, 2 * kPointerSize));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002199 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002200 __ JumpIfSmi(edx, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002201 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2202 name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002203 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002204 ASSERT(cell->value() == *function);
2205 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2206 &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002207 GenerateLoadFunctionFromCell(cell, function, &miss);
2208 }
2209
2210 // Load the char code argument.
2211 Register code = ebx;
2212 __ mov(code, Operand(esp, 1 * kPointerSize));
2213
2214 // Check the code is a smi.
2215 Label slow;
2216 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002217 __ JumpIfNotSmi(code, &slow);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002218
2219 // Convert the smi code to uint16.
2220 __ and_(code, Immediate(Smi::FromInt(0xffff)));
2221
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002222 StringCharFromCodeGenerator generator(code, eax);
2223 generator.GenerateFast(masm());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002224 __ ret(2 * kPointerSize);
2225
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002226 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002227 generator.GenerateSlow(masm(), call_helper);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002228
2229 // Tail call the full function. We do not have to patch the receiver
2230 // because the function makes no use of it.
2231 __ bind(&slow);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002232 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002233 ? CALL_AS_FUNCTION
2234 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002235 ParameterCount expected(function);
2236 __ InvokeFunction(function, expected, arguments(),
2237 JUMP_FUNCTION, NullCallWrapper(), call_kind);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002238
2239 __ bind(&miss);
2240 // ecx: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002241 GenerateMissBranch();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002242
2243 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002244 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002245}
2246
2247
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002248Handle<Code> CallStubCompiler::CompileMathFloorCall(
2249 Handle<Object> object,
2250 Handle<JSObject> holder,
2251 Handle<JSGlobalPropertyCell> cell,
2252 Handle<JSFunction> function,
2253 Handle<String> name) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002254 // ----------- S t a t e -------------
2255 // -- ecx : name
2256 // -- esp[0] : return address
2257 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2258 // -- ...
2259 // -- esp[(argc + 1) * 4] : receiver
2260 // -----------------------------------
2261
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002262 if (!CpuFeatures::IsSupported(SSE2)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002263 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002264 }
2265
ulan@chromium.org750145a2013-03-07 15:14:13 +00002266 CpuFeatureScope use_sse2(masm(), SSE2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002267
2268 const int argc = arguments().immediate();
2269
2270 // If the object is not a JSObject or we got an unexpected number of
2271 // arguments, bail out to the regular call.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002272 if (!object->IsJSObject() || argc != 1) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002273 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002274 }
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002275
2276 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002277 GenerateNameCheck(name, &miss);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002278
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002279 if (cell.is_null()) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002280 __ mov(edx, Operand(esp, 2 * kPointerSize));
2281
2282 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002283 __ JumpIfSmi(edx, &miss);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002284
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002285 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2286 name, &miss);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002287 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002288 ASSERT(cell->value() == *function);
2289 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2290 &miss);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002291 GenerateLoadFunctionFromCell(cell, function, &miss);
2292 }
2293
2294 // Load the (only) argument into eax.
2295 __ mov(eax, Operand(esp, 1 * kPointerSize));
2296
2297 // Check if the argument is a smi.
2298 Label smi;
2299 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002300 __ JumpIfSmi(eax, &smi);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002301
2302 // Check if the argument is a heap number and load its value into xmm0.
2303 Label slow;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002304 __ CheckMap(eax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002305 __ movdbl(xmm0, FieldOperand(eax, HeapNumber::kValueOffset));
2306
2307 // Check if the argument is strictly positive. Note this also
2308 // discards NaN.
2309 __ xorpd(xmm1, xmm1);
2310 __ ucomisd(xmm0, xmm1);
2311 __ j(below_equal, &slow);
2312
2313 // Do a truncating conversion.
2314 __ cvttsd2si(eax, Operand(xmm0));
2315
2316 // Check if the result fits into a smi. Note this also checks for
2317 // 0x80000000 which signals a failed conversion.
2318 Label wont_fit_into_smi;
2319 __ test(eax, Immediate(0xc0000000));
2320 __ j(not_zero, &wont_fit_into_smi);
2321
2322 // Smi tag and return.
2323 __ SmiTag(eax);
2324 __ bind(&smi);
2325 __ ret(2 * kPointerSize);
2326
2327 // Check if the argument is < 2^kMantissaBits.
2328 Label already_round;
2329 __ bind(&wont_fit_into_smi);
2330 __ LoadPowerOf2(xmm1, ebx, HeapNumber::kMantissaBits);
2331 __ ucomisd(xmm0, xmm1);
2332 __ j(above_equal, &already_round);
2333
2334 // Save a copy of the argument.
2335 __ movaps(xmm2, xmm0);
2336
2337 // Compute (argument + 2^kMantissaBits) - 2^kMantissaBits.
2338 __ addsd(xmm0, xmm1);
2339 __ subsd(xmm0, xmm1);
2340
2341 // Compare the argument and the tentative result to get the right mask:
2342 // if xmm2 < xmm0:
2343 // xmm2 = 1...1
2344 // else:
2345 // xmm2 = 0...0
2346 __ cmpltsd(xmm2, xmm0);
2347
2348 // Subtract 1 if the argument was less than the tentative result.
2349 __ LoadPowerOf2(xmm1, ebx, 0);
2350 __ andpd(xmm1, xmm2);
2351 __ subsd(xmm0, xmm1);
2352
2353 // Return a new heap number.
2354 __ AllocateHeapNumber(eax, ebx, edx, &slow);
2355 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
2356 __ ret(2 * kPointerSize);
2357
2358 // Return the argument (when it's an already round heap number).
2359 __ bind(&already_round);
2360 __ mov(eax, Operand(esp, 1 * kPointerSize));
2361 __ ret(2 * kPointerSize);
2362
2363 // Tail call the full function. We do not have to patch the receiver
2364 // because the function makes no use of it.
2365 __ bind(&slow);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002366 ParameterCount expected(function);
2367 __ InvokeFunction(function, expected, arguments(),
2368 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002369
2370 __ bind(&miss);
2371 // ecx: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002372 GenerateMissBranch();
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002373
2374 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002375 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002376}
2377
2378
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002379Handle<Code> CallStubCompiler::CompileMathAbsCall(
2380 Handle<Object> object,
2381 Handle<JSObject> holder,
2382 Handle<JSGlobalPropertyCell> cell,
2383 Handle<JSFunction> function,
2384 Handle<String> name) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002385 // ----------- S t a t e -------------
2386 // -- ecx : name
2387 // -- esp[0] : return address
2388 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2389 // -- ...
2390 // -- esp[(argc + 1) * 4] : receiver
2391 // -----------------------------------
2392
2393 const int argc = arguments().immediate();
2394
2395 // If the object is not a JSObject or we got an unexpected number of
2396 // arguments, bail out to the regular call.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002397 if (!object->IsJSObject() || argc != 1) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002398 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002399 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002400
2401 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002402 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002403
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002404 if (cell.is_null()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002405 __ mov(edx, Operand(esp, 2 * kPointerSize));
2406
2407 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002408 __ JumpIfSmi(edx, &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002409
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002410 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2411 name, &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002412 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002413 ASSERT(cell->value() == *function);
2414 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2415 &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002416 GenerateLoadFunctionFromCell(cell, function, &miss);
2417 }
2418
2419 // Load the (only) argument into eax.
2420 __ mov(eax, Operand(esp, 1 * kPointerSize));
2421
2422 // Check if the argument is a smi.
2423 Label not_smi;
2424 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002425 __ JumpIfNotSmi(eax, &not_smi);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002426
2427 // Set ebx to 1...1 (== -1) if the argument is negative, or to 0...0
2428 // otherwise.
2429 __ mov(ebx, eax);
2430 __ sar(ebx, kBitsPerInt - 1);
2431
2432 // Do bitwise not or do nothing depending on ebx.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002433 __ xor_(eax, ebx);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002434
2435 // Add 1 or do nothing depending on ebx.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002436 __ sub(eax, ebx);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002437
2438 // If the result is still negative, go to the slow case.
2439 // This only happens for the most negative smi.
2440 Label slow;
2441 __ j(negative, &slow);
2442
2443 // Smi case done.
2444 __ ret(2 * kPointerSize);
2445
2446 // Check if the argument is a heap number and load its exponent and
2447 // sign into ebx.
2448 __ bind(&not_smi);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002449 __ CheckMap(eax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002450 __ mov(ebx, FieldOperand(eax, HeapNumber::kExponentOffset));
2451
2452 // Check the sign of the argument. If the argument is positive,
2453 // just return it.
2454 Label negative_sign;
2455 __ test(ebx, Immediate(HeapNumber::kSignMask));
2456 __ j(not_zero, &negative_sign);
2457 __ ret(2 * kPointerSize);
2458
2459 // If the argument is negative, clear the sign, and return a new
2460 // number.
2461 __ bind(&negative_sign);
2462 __ and_(ebx, ~HeapNumber::kSignMask);
2463 __ mov(ecx, FieldOperand(eax, HeapNumber::kMantissaOffset));
2464 __ AllocateHeapNumber(eax, edi, edx, &slow);
2465 __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), ebx);
2466 __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx);
2467 __ ret(2 * kPointerSize);
2468
2469 // Tail call the full function. We do not have to patch the receiver
2470 // because the function makes no use of it.
2471 __ bind(&slow);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002472 ParameterCount expected(function);
2473 __ InvokeFunction(function, expected, arguments(),
2474 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002475
2476 __ bind(&miss);
2477 // ecx: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002478 GenerateMissBranch();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002479
2480 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002481 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002482}
2483
2484
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002485Handle<Code> CallStubCompiler::CompileFastApiCall(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002486 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002487 Handle<Object> object,
2488 Handle<JSObject> holder,
2489 Handle<JSGlobalPropertyCell> cell,
2490 Handle<JSFunction> function,
2491 Handle<String> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002492 ASSERT(optimization.is_simple_api_call());
2493 // Bail out if object is a global object as we don't want to
2494 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002495 if (object->IsGlobalObject()) return Handle<Code>::null();
2496 if (!cell.is_null()) return Handle<Code>::null();
2497 if (!object->IsJSObject()) return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002498 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002499 Handle<JSObject>::cast(object), holder);
2500 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002501
2502 Label miss, miss_before_stack_reserved;
2503
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002504 GenerateNameCheck(name, &miss_before_stack_reserved);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002505
2506 // Get the receiver from the stack.
2507 const int argc = arguments().immediate();
2508 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
2509
2510 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002511 __ JumpIfSmi(edx, &miss_before_stack_reserved);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002512
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002513 Counters* counters = isolate()->counters();
2514 __ IncrementCounter(counters->call_const(), 1);
2515 __ IncrementCounter(counters->call_const_fast_api(), 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002516
2517 // Allocate space for v8::Arguments implicit values. Must be initialized
2518 // before calling any runtime function.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002519 __ sub(esp, Immediate(kFastApiCallArguments * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002520
2521 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002522 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2523 name, depth, &miss);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002524
2525 // Move the return address on top of the stack.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002526 __ mov(eax, Operand(esp, kFastApiCallArguments * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002527 __ mov(Operand(esp, 0 * kPointerSize), eax);
2528
2529 // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains
2530 // duplicate of return address and will be overwritten.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002531 GenerateFastApiCall(masm(), optimization, argc);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002532
2533 __ bind(&miss);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002534 __ add(esp, Immediate(kFastApiCallArguments * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002535
2536 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002537 GenerateMissBranch();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002538
2539 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002540 return GetCode(function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002541}
2542
2543
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002544void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
2545 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002546 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002547 CheckType check,
2548 Label* success) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002549 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00002550 // -- ecx : name
2551 // -- esp[0] : return address
2552 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2553 // -- ...
2554 // -- esp[(argc + 1) * 4] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002555 // -----------------------------------
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002556 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002557 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002558
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002559 // Get the receiver from the stack.
2560 const int argc = arguments().immediate();
2561 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
2562
2563 // Check that the receiver isn't a smi.
2564 if (check != NUMBER_CHECK) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00002565 __ JumpIfSmi(edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002566 }
2567
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002568 // Make sure that it's okay not to patch the on stack receiver
2569 // unless we're doing a receiver map check.
2570 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002571 switch (check) {
2572 case RECEIVER_MAP_CHECK:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002573 __ IncrementCounter(isolate()->counters()->call_const(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00002574
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002575 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002576 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax,
2577 edi, name, &miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002578
2579 // Patch the receiver on the stack with the global proxy if
2580 // necessary.
2581 if (object->IsGlobalObject()) {
2582 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
2583 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
2584 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002585 break;
2586
2587 case STRING_CHECK:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002588 // Check that the object is a string.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002589 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, eax);
2590 __ j(above_equal, &miss);
2591 // Check that the maps starting from the prototype haven't changed.
2592 GenerateDirectLoadGlobalFunctionPrototype(
2593 masm(), Context::STRING_FUNCTION_INDEX, eax, &miss);
2594 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002595 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002596 eax, holder, ebx, edx, edi, name, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002597 break;
2598
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002599 case SYMBOL_CHECK:
2600 // Check that the object is a symbol.
2601 __ CmpObjectType(edx, SYMBOL_TYPE, eax);
2602 __ j(not_equal, &miss);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002603 // Check that the maps starting from the prototype haven't changed.
2604 GenerateDirectLoadGlobalFunctionPrototype(
2605 masm(), Context::SYMBOL_FUNCTION_INDEX, eax, &miss);
2606 CheckPrototypes(
2607 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2608 eax, holder, ebx, edx, edi, name, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002609 break;
2610
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002611 case NUMBER_CHECK: {
2612 Label fast;
2613 // Check that the object is a smi or a heap number.
2614 __ JumpIfSmi(edx, &fast);
2615 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, eax);
2616 __ j(not_equal, &miss);
2617 __ bind(&fast);
2618 // Check that the maps starting from the prototype haven't changed.
2619 GenerateDirectLoadGlobalFunctionPrototype(
2620 masm(), Context::NUMBER_FUNCTION_INDEX, eax, &miss);
2621 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002622 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002623 eax, holder, ebx, edx, edi, name, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002624 break;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002625 }
2626 case BOOLEAN_CHECK: {
2627 Label fast;
2628 // Check that the object is a boolean.
2629 __ cmp(edx, factory()->true_value());
2630 __ j(equal, &fast);
2631 __ cmp(edx, factory()->false_value());
2632 __ j(not_equal, &miss);
2633 __ bind(&fast);
2634 // Check that the maps starting from the prototype haven't changed.
2635 GenerateDirectLoadGlobalFunctionPrototype(
2636 masm(), Context::BOOLEAN_FUNCTION_INDEX, eax, &miss);
2637 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002638 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002639 eax, holder, ebx, edx, edi, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002640 break;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002641 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002642 }
2643
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002644 __ jmp(success);
2645
2646 // Handle call cache miss.
2647 __ bind(&miss);
2648 GenerateMissBranch();
2649}
2650
2651
2652void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002653 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002654 ? CALL_AS_FUNCTION
2655 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002656 ParameterCount expected(function);
2657 __ InvokeFunction(function, expected, arguments(),
2658 JUMP_FUNCTION, NullCallWrapper(), call_kind);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002659}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002660
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002661
2662Handle<Code> CallStubCompiler::CompileCallConstant(
2663 Handle<Object> object,
2664 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002665 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002666 CheckType check,
2667 Handle<JSFunction> function) {
2668
2669 if (HasCustomCallGenerator(function)) {
2670 Handle<Code> code = CompileCustomCall(object, holder,
2671 Handle<JSGlobalPropertyCell>::null(),
ulan@chromium.org750145a2013-03-07 15:14:13 +00002672 function, Handle<String>::cast(name));
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002673 // A null handle means bail out to the regular compiler code below.
2674 if (!code.is_null()) return code;
2675 }
2676
2677 Label success;
2678
2679 CompileHandlerFrontend(object, holder, name, check, &success);
2680 __ bind(&success);
2681 CompileHandlerBackend(function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002682
2683 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002684 return GetCode(function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002685}
2686
2687
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002688Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2689 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002690 Handle<Name> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002691 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00002692 // -- ecx : name
2693 // -- esp[0] : return address
2694 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2695 // -- ...
2696 // -- esp[(argc + 1) * 4] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002697 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002698 Label miss;
2699
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002700 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002701
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002702 // Get the number of arguments.
2703 const int argc = arguments().immediate();
2704
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002705 LookupResult lookup(isolate());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002706 LookupPostInterceptor(holder, name, &lookup);
2707
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002708 // Get the receiver from the stack.
2709 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002710
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002711 CallInterceptorCompiler compiler(this, arguments(), ecx, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002712 compiler.Compile(masm(), object, holder, name, &lookup, edx, ebx, edi, eax,
2713 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002714
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002715 // Restore receiver.
2716 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002717
2718 // Check that the function really is a function.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002719 __ JumpIfSmi(eax, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002720 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002721 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002722
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002723 // Patch the receiver on the stack with the global proxy if
2724 // necessary.
2725 if (object->IsGlobalObject()) {
2726 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
2727 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
2728 }
2729
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002730 // Invoke the function.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002731 __ mov(edi, eax);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002732 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002733 ? CALL_AS_FUNCTION
2734 : CALL_AS_METHOD;
2735 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION,
2736 NullCallWrapper(), call_kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002737
2738 // Handle load cache miss.
2739 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002740 GenerateMissBranch();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002741
2742 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002743 return GetCode(Code::INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002744}
2745
2746
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002747Handle<Code> CallStubCompiler::CompileCallGlobal(
2748 Handle<JSObject> object,
2749 Handle<GlobalObject> holder,
2750 Handle<JSGlobalPropertyCell> cell,
2751 Handle<JSFunction> function,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002752 Handle<Name> name) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002753 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00002754 // -- ecx : name
2755 // -- esp[0] : return address
2756 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2757 // -- ...
2758 // -- esp[(argc + 1) * 4] : receiver
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002759 // -----------------------------------
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002760
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002761 if (HasCustomCallGenerator(function)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00002762 Handle<Code> code = CompileCustomCall(
2763 object, holder, cell, function, Handle<String>::cast(name));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002764 // A null handle means bail out to the regular compiler code below.
2765 if (!code.is_null()) return code;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002766 }
2767
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002768 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002769 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002770
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002771 // Get the number of arguments.
2772 const int argc = arguments().immediate();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002773 GenerateGlobalReceiverCheck(object, holder, name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002774 GenerateLoadFunctionFromCell(cell, function, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002775
2776 // Patch the receiver on the stack with the global proxy.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002777 if (object->IsGlobalObject()) {
2778 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
2779 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
2780 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002781
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002782 // Set up the context (function already in edi).
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002783 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
2784
2785 // Jump to the cached code (tail call).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002786 Counters* counters = isolate()->counters();
2787 __ IncrementCounter(counters->call_global_inline(), 1);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002788 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002789 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002790 ? CALL_AS_FUNCTION
2791 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002792 // We call indirectly through the code field in the function to
2793 // allow recompilation to take effect without changing any of the
2794 // call sites.
2795 __ InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset),
2796 expected, arguments(), JUMP_FUNCTION,
2797 NullCallWrapper(), call_kind);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002798
2799 // Handle call cache miss.
2800 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002801 __ IncrementCounter(counters->call_global_inline_miss(), 1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002802 GenerateMissBranch();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002803
2804 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002805 return GetCode(Code::NORMAL, name);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002806}
2807
2808
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002809Handle<Code> StoreStubCompiler::CompileStoreCallback(
ulan@chromium.org750145a2013-03-07 15:14:13 +00002810 Handle<Name> name,
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002811 Handle<JSObject> object,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002812 Handle<JSObject> holder,
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002813 Handle<ExecutableAccessorInfo> callback) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002814 Label miss, miss_restore_name;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002815 // Check that the maps haven't changed, preserving the value register.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002816 __ JumpIfSmi(receiver(), &miss);
2817 CheckPrototypes(object, receiver(), holder,
2818 scratch1(), this->name(), scratch2(),
2819 name, &miss_restore_name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002820
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002821 // Stub never generated for non-global objects that require access checks.
2822 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002823
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002824 __ pop(scratch1()); // remove the return address
2825 __ push(receiver());
2826 __ Push(callback);
2827 __ Push(name);
2828 __ push(value());
2829 __ push(scratch1()); // restore return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002830
mads.s.ager31e71382008-08-13 09:32:07 +00002831 // Do tail-call to the runtime system.
2832 ExternalReference store_callback_property =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002833 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002834 __ TailCallExternalReference(store_callback_property, 4, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002835
2836 // Handle store cache miss.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002837 GenerateRestoreName(masm(), &miss_restore_name, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002838 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002839 TailCallBuiltin(masm(), MissBuiltin(kind()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002840
2841 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002842 return GetICCode(kind(), Code::CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002843}
2844
2845
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002846#undef __
2847#define __ ACCESS_MASM(masm)
2848
2849
2850void StoreStubCompiler::GenerateStoreViaSetter(
2851 MacroAssembler* masm,
2852 Handle<JSFunction> setter) {
2853 // ----------- S t a t e -------------
2854 // -- eax : value
2855 // -- ecx : name
2856 // -- edx : receiver
2857 // -- esp[0] : return address
2858 // -----------------------------------
2859 {
2860 FrameScope scope(masm, StackFrame::INTERNAL);
2861
2862 // Save value register, so we can restore it later.
2863 __ push(eax);
2864
2865 if (!setter.is_null()) {
2866 // Call the JavaScript setter with receiver and value on the stack.
2867 __ push(edx);
2868 __ push(eax);
2869 ParameterCount actual(1);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002870 ParameterCount expected(setter);
2871 __ InvokeFunction(setter, expected, actual,
2872 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002873 } else {
2874 // If we generate a global code snippet for deoptimization only, remember
2875 // the place to continue after deoptimization.
2876 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2877 }
2878
2879 // We have to return the passed value, not the return value of the setter.
2880 __ pop(eax);
2881
2882 // Restore context register.
2883 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
2884 }
2885 __ ret(0);
2886}
2887
2888
2889#undef __
2890#define __ ACCESS_MASM(masm())
2891
2892
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002893Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002894 Handle<JSObject> object,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002895 Handle<Name> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002896 Label miss;
2897
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002898 // Check that the map of the object hasn't changed.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002899 __ CheckMap(receiver(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002900
2901 // Perform global security token check if needed.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002902 if (object->IsJSGlobalProxy()) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002903 __ CheckAccessGlobalProxy(receiver(), scratch1(), scratch2(), &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002904 }
2905
2906 // Stub never generated for non-global objects that require access
2907 // checks.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002908 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002909
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002910 __ pop(scratch1()); // remove the return address
2911 __ push(receiver());
2912 __ push(this->name());
2913 __ push(value());
2914 __ push(Immediate(Smi::FromInt(strict_mode())));
2915 __ push(scratch1()); // restore return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002916
mads.s.ager31e71382008-08-13 09:32:07 +00002917 // Do tail-call to the runtime system.
2918 ExternalReference store_ic_property =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002919 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002920 __ TailCallExternalReference(store_ic_property, 4, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002921
2922 // Handle store cache miss.
2923 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002924 TailCallBuiltin(masm(), MissBuiltin(kind()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002925
2926 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002927 return GetICCode(kind(), Code::INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002928}
2929
2930
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002931Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2932 Handle<GlobalObject> object,
2933 Handle<JSGlobalPropertyCell> cell,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002934 Handle<Name> name) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002935 Label miss;
2936
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002937 // Check that the map of the global has not changed.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002938 __ cmp(FieldOperand(receiver(), HeapObject::kMapOffset),
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002939 Immediate(Handle<Map>(object->map())));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002940 __ j(not_equal, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002941
ager@chromium.org378b34e2011-01-28 08:04:38 +00002942 // Compute the cell operand to use.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002943 __ mov(scratch1(), Immediate(cell));
2944 Operand cell_operand =
2945 FieldOperand(scratch1(), JSGlobalPropertyCell::kValueOffset);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002946
ager@chromium.org378b34e2011-01-28 08:04:38 +00002947 // Check that the value in the cell is not the hole. If it is, this
2948 // cell could have been deleted and reintroducing the global needs
2949 // to update the property details in the property dictionary of the
2950 // global object. We bail out to the runtime system to do that.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002951 __ cmp(cell_operand, factory()->the_hole_value());
ager@chromium.org378b34e2011-01-28 08:04:38 +00002952 __ j(equal, &miss);
2953
2954 // Store the value in the cell.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002955 __ mov(cell_operand, value());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002956 // No write barrier here, because cells are always rescanned.
ager@chromium.org378b34e2011-01-28 08:04:38 +00002957
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002958 // Return the value (register eax).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002959 Counters* counters = isolate()->counters();
2960 __ IncrementCounter(counters->named_store_global_inline(), 1);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002961 __ ret(0);
2962
2963 // Handle store cache miss.
2964 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002965 __ IncrementCounter(counters->named_store_global_inline_miss(), 1);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002966 TailCallBuiltin(masm(), MissBuiltin(kind()));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002967
2968 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002969 return GetICCode(kind(), Code::NORMAL, name);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002970}
2971
2972
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002973Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
2974 MapHandleList* receiver_maps,
2975 CodeHandleList* handler_stubs,
2976 MapHandleList* transitioned_maps) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002977 Label miss;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002978 __ JumpIfSmi(receiver(), &miss, Label::kNear);
2979 __ mov(scratch1(), FieldOperand(receiver(), HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002980 for (int i = 0; i < receiver_maps->length(); ++i) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002981 __ cmp(scratch1(), receiver_maps->at(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002982 if (transitioned_maps->at(i).is_null()) {
2983 __ j(equal, handler_stubs->at(i));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002984 } else {
2985 Label next_map;
2986 __ j(not_equal, &next_map, Label::kNear);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002987 __ mov(transition_map(), Immediate(transitioned_maps->at(i)));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002988 __ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002989 __ bind(&next_map);
2990 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002991 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002992 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002993 TailCallBuiltin(masm(), MissBuiltin(kind()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002994
2995 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002996 return GetICCode(
2997 kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002998}
2999
3000
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00003001Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00003002 Handle<JSObject> object,
3003 Handle<JSObject> last,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003004 Handle<Name> name,
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00003005 Handle<GlobalObject> global) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003006 Label success;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00003007
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003008 NonexistentHandlerFrontend(object, last, name, &success, global);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00003009
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003010 __ bind(&success);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00003011 // Return undefined if maps of the full prototype chain are still the
3012 // same and no global property with this name contains a value.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003013 __ mov(eax, isolate()->factory()->undefined_value());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00003014 __ ret(0);
3015
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00003016 // Return the generated code.
ulan@chromium.org750145a2013-03-07 15:14:13 +00003017 return GetCode(kind(), Code::NONEXISTENT, name);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00003018}
3019
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003020
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00003021Register* LoadStubCompiler::registers() {
3022 // receiver, name, scratch1, scratch2, scratch3, scratch4.
3023 static Register registers[] = { edx, ecx, ebx, eax, edi, no_reg };
3024 return registers;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003025}
3026
3027
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00003028Register* KeyedLoadStubCompiler::registers() {
3029 // receiver, name, scratch1, scratch2, scratch3, scratch4.
3030 static Register registers[] = { edx, ecx, ebx, eax, edi, no_reg };
3031 return registers;
3032}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003033
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003034
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003035Register* StoreStubCompiler::registers() {
3036 // receiver, name, value, scratch1, scratch2, scratch3.
3037 static Register registers[] = { edx, ecx, eax, ebx, edi, no_reg };
3038 return registers;
3039}
3040
3041
3042Register* KeyedStoreStubCompiler::registers() {
3043 // receiver, name, value, scratch1, scratch2, scratch3.
3044 static Register registers[] = { edx, ecx, eax, ebx, edi, no_reg };
3045 return registers;
3046}
3047
3048
ulan@chromium.org750145a2013-03-07 15:14:13 +00003049void KeyedLoadStubCompiler::GenerateNameCheck(Handle<Name> name,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00003050 Register name_reg,
3051 Label* miss) {
3052 __ cmp(name_reg, Immediate(name));
3053 __ j(not_equal, miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003054}
3055
3056
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003057void KeyedStoreStubCompiler::GenerateNameCheck(Handle<Name> name,
3058 Register name_reg,
3059 Label* miss) {
3060 __ cmp(name_reg, Immediate(name));
3061 __ j(not_equal, miss);
3062}
3063
3064
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003065#undef __
3066#define __ ACCESS_MASM(masm)
3067
3068
3069void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
3070 Handle<JSFunction> getter) {
3071 // ----------- S t a t e -------------
3072 // -- ecx : name
3073 // -- edx : receiver
3074 // -- esp[0] : return address
3075 // -----------------------------------
3076 {
3077 FrameScope scope(masm, StackFrame::INTERNAL);
3078
3079 if (!getter.is_null()) {
3080 // Call the JavaScript getter with the receiver on the stack.
3081 __ push(edx);
3082 ParameterCount actual(0);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003083 ParameterCount expected(getter);
3084 __ InvokeFunction(getter, expected, actual,
3085 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003086 } else {
3087 // If we generate a global code snippet for deoptimization only, remember
3088 // the place to continue after deoptimization.
3089 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
3090 }
3091
3092 // Restore context register.
3093 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
3094 }
3095 __ ret(0);
3096}
3097
3098
3099#undef __
3100#define __ ACCESS_MASM(masm())
3101
3102
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003103Handle<Code> LoadStubCompiler::CompileLoadGlobal(
3104 Handle<JSObject> object,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003105 Handle<GlobalObject> global,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003106 Handle<JSGlobalPropertyCell> cell,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003107 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003108 bool is_dont_delete) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003109 Label success, miss;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003110
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003111 __ CheckMap(receiver(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
3112 HandlerFrontendHeader(
3113 object, receiver(), Handle<JSObject>::cast(global), name, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003114 // Get the value from the cell.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003115 if (Serializer::enabled()) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003116 __ mov(eax, Immediate(cell));
3117 __ mov(eax, FieldOperand(eax, JSGlobalPropertyCell::kValueOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003118 } else {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003119 __ mov(eax, Operand::Cell(cell));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003120 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003121
3122 // Check for deleted property if property can actually be deleted.
3123 if (!is_dont_delete) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003124 __ cmp(eax, factory()->the_hole_value());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003125 __ j(equal, &miss);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003126 } else if (FLAG_debug_code) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003127 __ cmp(eax, factory()->the_hole_value());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003128 __ Check(not_equal, "DontDelete cells can't contain the hole");
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003129 }
3130
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003131 HandlerFrontendFooter(&success, &miss);
3132 __ bind(&success);
3133
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003134 Counters* counters = isolate()->counters();
3135 __ IncrementCounter(counters->named_load_global_stub(), 1);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003136 // The code above already loads the result into the return register.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003137 __ ret(0);
3138
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003139 // Return the generated code.
ulan@chromium.org750145a2013-03-07 15:14:13 +00003140 return GetICCode(kind(), Code::NORMAL, name);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003141}
3142
3143
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003144Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003145 MapHandleList* receiver_maps,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003146 CodeHandleList* handlers,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003147 Handle<Name> name,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003148 Code::StubType type,
3149 IcCheckType check) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003150 Label miss;
3151
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003152 if (check == PROPERTY) {
3153 GenerateNameCheck(name, this->name(), &miss);
3154 }
3155
3156 __ JumpIfSmi(receiver(), &miss);
3157 Register map_reg = scratch1();
3158 __ mov(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset));
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003159 int receiver_count = receiver_maps->length();
danno@chromium.orgf005df62013-04-30 16:36:45 +00003160 int number_of_handled_maps = 0;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003161 for (int current = 0; current < receiver_count; ++current) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00003162 Handle<Map> map = receiver_maps->at(current);
3163 if (!map->is_deprecated()) {
3164 number_of_handled_maps++;
3165 __ cmp(map_reg, map);
3166 __ j(equal, handlers->at(current));
3167 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003168 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00003169 ASSERT(number_of_handled_maps != 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003170
3171 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003172 TailCallBuiltin(masm(), MissBuiltin(kind()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003173
3174 // Return the generated code.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003175 InlineCacheState state =
danno@chromium.orgf005df62013-04-30 16:36:45 +00003176 number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC;
ulan@chromium.org750145a2013-03-07 15:14:13 +00003177 return GetICCode(kind(), type, name, state);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003178}
3179
3180
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003181// Specialized stub for constructing objects from functions which only have only
3182// simple assignments of the form this.x = ...; in their body.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003183Handle<Code> ConstructStubCompiler::CompileConstructStub(
3184 Handle<JSFunction> function) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003185 // ----------- S t a t e -------------
3186 // -- eax : argc
3187 // -- edi : constructor
3188 // -- esp[0] : return address
3189 // -- esp[4] : last argument
3190 // -----------------------------------
3191 Label generic_stub_call;
3192#ifdef ENABLE_DEBUGGER_SUPPORT
3193 // Check to see whether there are any break points in the function code. If
3194 // there are jump to the generic constructor stub which calls the actual
3195 // code for the function thereby hitting the break points.
3196 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
3197 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kDebugInfoOffset));
lrn@chromium.org7516f052011-03-30 08:52:27 +00003198 __ cmp(ebx, factory()->undefined_value());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003199 __ j(not_equal, &generic_stub_call);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003200#endif
3201
3202 // Load the initial map and verify that it is in fact a map.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003203 // edi: constructor
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003204 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
3205 // Will both indicate a NULL and a Smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003206 __ JumpIfSmi(ebx, &generic_stub_call);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003207 __ CmpObjectType(ebx, MAP_TYPE, ecx);
3208 __ j(not_equal, &generic_stub_call);
3209
3210#ifdef DEBUG
3211 // Cannot construct functions this way.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003212 // ebx: initial map
3213 __ CmpInstanceType(ebx, JS_FUNCTION_TYPE);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003214 __ Check(not_equal, "Function constructed by construct stub.");
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003215#endif
3216
3217 // Now allocate the JSObject on the heap by moving the new space allocation
3218 // top forward.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003219 // ebx: initial map
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003220 ASSERT(function->has_initial_map());
3221 int instance_size = function->initial_map()->instance_size();
3222#ifdef DEBUG
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003223 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset));
3224 __ shl(ecx, kPointerSizeLog2);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003225 __ cmp(ecx, Immediate(instance_size));
3226 __ Check(equal, "Instance size of initial map changed.");
3227#endif
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003228 __ Allocate(instance_size, edx, ecx, no_reg, &generic_stub_call,
3229 NO_ALLOCATION_FLAGS);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003230
3231 // Allocated the JSObject, now initialize the fields and add the heap tag.
3232 // ebx: initial map
3233 // edx: JSObject (untagged)
3234 __ mov(Operand(edx, JSObject::kMapOffset), ebx);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003235 __ mov(ebx, factory()->empty_fixed_array());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003236 __ mov(Operand(edx, JSObject::kPropertiesOffset), ebx);
3237 __ mov(Operand(edx, JSObject::kElementsOffset), ebx);
3238
3239 // Push the allocated object to the stack. This is the object that will be
3240 // returned (after it is tagged).
3241 __ push(edx);
3242
3243 // eax: argc
3244 // edx: JSObject (untagged)
3245 // Load the address of the first in-object property into edx.
3246 __ lea(edx, Operand(edx, JSObject::kHeaderSize));
3247 // Calculate the location of the first argument. The stack contains the
3248 // allocated object and the return address on top of the argc arguments.
3249 __ lea(ecx, Operand(esp, eax, times_4, 1 * kPointerSize));
3250
3251 // Use edi for holding undefined which is used in several places below.
lrn@chromium.org7516f052011-03-30 08:52:27 +00003252 __ mov(edi, factory()->undefined_value());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003253
3254 // eax: argc
3255 // ecx: first argument
3256 // edx: first in-object property of the JSObject
3257 // edi: undefined
3258 // Fill the initialized properties with a constant value or a passed argument
3259 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003260 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003261 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3262 if (shared->IsThisPropertyAssignmentArgument(i)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003263 // Check if the argument assigned to the property is actually passed.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003264 // If argument is not passed the property is set to undefined,
3265 // otherwise find it on the stack.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003266 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003267 __ mov(ebx, edi);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003268 __ cmp(eax, arg_number);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003269 if (CpuFeatures::IsSupported(CMOV)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003270 CpuFeatureScope use_cmov(masm(), CMOV);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003271 __ cmov(above, ebx, Operand(ecx, arg_number * -kPointerSize));
3272 } else {
3273 Label not_passed;
3274 __ j(below_equal, &not_passed);
3275 __ mov(ebx, Operand(ecx, arg_number * -kPointerSize));
3276 __ bind(&not_passed);
3277 }
3278 // Store value in the property.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003279 __ mov(Operand(edx, i * kPointerSize), ebx);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003280 } else {
3281 // Set the property to the constant value.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003282 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i),
3283 isolate());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003284 __ mov(Operand(edx, i * kPointerSize), Immediate(constant));
3285 }
3286 }
3287
3288 // Fill the unused in-object property fields with undefined.
3289 for (int i = shared->this_property_assignments_count();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00003290 i < function->initial_map()->inobject_properties();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003291 i++) {
3292 __ mov(Operand(edx, i * kPointerSize), edi);
3293 }
3294
3295 // Move argc to ebx and retrieve and tag the JSObject to return.
3296 __ mov(ebx, eax);
3297 __ pop(eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003298 __ or_(eax, Immediate(kHeapObjectTag));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003299
3300 // Remove caller arguments and receiver from the stack and return.
3301 __ pop(ecx);
3302 __ lea(esp, Operand(esp, ebx, times_pointer_size, 1 * kPointerSize));
3303 __ push(ecx);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003304 Counters* counters = isolate()->counters();
3305 __ IncrementCounter(counters->constructed_objects(), 1);
3306 __ IncrementCounter(counters->constructed_objects_stub(), 1);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003307 __ ret(0);
3308
3309 // Jump to the generic stub in case the specialized code cannot handle the
3310 // construction.
3311 __ bind(&generic_stub_call);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003312 Handle<Code> code = isolate()->builtins()->JSConstructStubGeneric();
3313 __ jmp(code, RelocInfo::CODE_TARGET);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003314
3315 // Return the generated code.
3316 return GetCode();
3317}
3318
3319
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003320#undef __
3321#define __ ACCESS_MASM(masm)
3322
3323
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003324void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3325 MacroAssembler* masm) {
3326 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003327 // -- ecx : key
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003328 // -- edx : receiver
3329 // -- esp[0] : return address
3330 // -----------------------------------
3331 Label slow, miss_force_generic;
3332
3333 // This stub is meant to be tail-jumped to, the receiver must already
3334 // have been verified by the caller to not be a smi.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003335 __ JumpIfNotSmi(ecx, &miss_force_generic);
3336 __ mov(ebx, ecx);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003337 __ SmiUntag(ebx);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003338 __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset));
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003339
3340 // Push receiver on the stack to free up a register for the dictionary
3341 // probing.
3342 __ push(edx);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003343 __ LoadFromNumberDictionary(&slow, eax, ecx, ebx, edx, edi, eax);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003344 // Pop receiver before returning.
3345 __ pop(edx);
3346 __ ret(0);
3347
3348 __ bind(&slow);
3349 __ pop(edx);
3350
3351 // ----------- S t a t e -------------
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003352 // -- ecx : key
3353 // -- edx : receiver
3354 // -- esp[0] : return address
3355 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003356 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003357
3358 __ bind(&miss_force_generic);
3359 // ----------- S t a t e -------------
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003360 // -- ecx : key
3361 // -- edx : receiver
3362 // -- esp[0] : return address
3363 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003364 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_MissForceGeneric);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003365}
3366
3367
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003368static void GenerateSmiKeyCheck(MacroAssembler* masm,
3369 Register key,
3370 Register scratch,
3371 XMMRegister xmm_scratch0,
3372 XMMRegister xmm_scratch1,
3373 Label* fail) {
3374 // Check that key is a smi and if SSE2 is available a heap number
3375 // containing a smi and branch if the check fails.
3376 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003377 CpuFeatureScope use_sse2(masm, SSE2);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003378 Label key_ok;
3379 __ JumpIfSmi(key, &key_ok);
3380 __ cmp(FieldOperand(key, HeapObject::kMapOffset),
3381 Immediate(Handle<Map>(masm->isolate()->heap()->heap_number_map())));
3382 __ j(not_equal, fail);
3383 __ movdbl(xmm_scratch0, FieldOperand(key, HeapNumber::kValueOffset));
3384 __ cvttsd2si(scratch, Operand(xmm_scratch0));
3385 __ cvtsi2sd(xmm_scratch1, scratch);
3386 __ ucomisd(xmm_scratch1, xmm_scratch0);
3387 __ j(not_equal, fail);
3388 __ j(parity_even, fail); // NaN.
3389 // Check if the key fits in the smi range.
3390 __ cmp(scratch, 0xc0000000);
3391 __ j(sign, fail);
3392 __ SmiTag(scratch);
3393 __ mov(key, scratch);
3394 __ bind(&key_ok);
3395 } else {
3396 __ JumpIfNotSmi(key, fail);
3397 }
3398}
3399
3400
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003401void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3402 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003403 ElementsKind elements_kind) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003404 // ----------- S t a t e -------------
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003405 // -- eax : value
3406 // -- ecx : key
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003407 // -- edx : receiver
3408 // -- esp[0] : return address
3409 // -----------------------------------
3410 Label miss_force_generic, slow, check_heap_number;
3411
3412 // This stub is meant to be tail-jumped to, the receiver must already
3413 // have been verified by the caller to not be a smi.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003414
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003415 // Check that the key is a smi or a heap number convertible to a smi.
3416 GenerateSmiKeyCheck(masm, ecx, ebx, xmm0, xmm1, &miss_force_generic);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003417
3418 // Check that the index is in range.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003419 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003420 __ cmp(ecx, FieldOperand(edi, ExternalArray::kLengthOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003421 // Unsigned comparison catches both negative and too-large values.
3422 __ j(above_equal, &slow);
3423
3424 // Handle both smis and HeapNumbers in the fast path. Go to the
3425 // runtime for all other kinds of values.
3426 // eax: value
3427 // edx: receiver
3428 // ecx: key
3429 // edi: elements array
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003430 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00003431 __ JumpIfNotSmi(eax, &slow);
3432 } else {
3433 __ JumpIfNotSmi(eax, &check_heap_number);
3434 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003435
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003436 // smi case
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003437 __ mov(ebx, eax); // Preserve the value in eax as the return value.
3438 __ SmiUntag(ebx);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003439 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003440 // edi: base pointer of external storage
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003441 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003442 case EXTERNAL_PIXEL_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003443 __ ClampUint8(ebx);
3444 __ SmiUntag(ecx);
3445 __ mov_b(Operand(edi, ecx, times_1, 0), ebx);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003446 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003447 case EXTERNAL_BYTE_ELEMENTS:
3448 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003449 __ SmiUntag(ecx);
3450 __ mov_b(Operand(edi, ecx, times_1, 0), ebx);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003451 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003452 case EXTERNAL_SHORT_ELEMENTS:
3453 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003454 __ mov_w(Operand(edi, ecx, times_1, 0), ebx);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003455 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003456 case EXTERNAL_INT_ELEMENTS:
3457 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003458 __ mov(Operand(edi, ecx, times_2, 0), ebx);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003459 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003460 case EXTERNAL_FLOAT_ELEMENTS:
3461 case EXTERNAL_DOUBLE_ELEMENTS:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003462 // Need to perform int-to-float conversion.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003463 __ push(ebx);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003464 __ fild_s(Operand(esp, 0));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003465 __ pop(ebx);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003466 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003467 __ fstp_s(Operand(edi, ecx, times_2, 0));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003468 } else { // elements_kind == EXTERNAL_DOUBLE_ELEMENTS.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003469 __ fstp_d(Operand(edi, ecx, times_4, 0));
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003470 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003471 break;
3472 default:
3473 UNREACHABLE();
3474 break;
3475 }
3476 __ ret(0); // Return the original value.
3477
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003478 // TODO(danno): handle heap number -> pixel array conversion
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003479 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003480 __ bind(&check_heap_number);
3481 // eax: value
3482 // edx: receiver
3483 // ecx: key
3484 // edi: elements array
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003485 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003486 Immediate(masm->isolate()->factory()->heap_number_map()));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003487 __ j(not_equal, &slow);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003488
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003489 // The WebGL specification leaves the behavior of storing NaN and
3490 // +/-Infinity into integer arrays basically undefined. For more
3491 // reproducible behavior, convert these to zero.
3492 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003493 // edi: base pointer of external storage
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003494 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003495 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003496 __ fstp_s(Operand(edi, ecx, times_2, 0));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003497 __ ret(0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003498 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003499 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003500 __ fstp_d(Operand(edi, ecx, times_4, 0));
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003501 __ ret(0);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003502 } else {
3503 // Perform float-to-int conversion with truncation (round-to-zero)
3504 // behavior.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003505
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003506 // For the moment we make the slow call to the runtime on
3507 // processors that don't support SSE2. The code in IntegerConvert
3508 // (code-stubs-ia32.cc) is roughly what is needed here though the
3509 // conversion failure case does not need to be handled.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003510 if (CpuFeatures::IsSupported(SSE2)) {
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003511 if ((elements_kind == EXTERNAL_INT_ELEMENTS ||
3512 elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) &&
3513 CpuFeatures::IsSupported(SSE3)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003514 CpuFeatureScope scope(masm, SSE3);
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003515 // fisttp stores values as signed integers. To represent the
3516 // entire range of int and unsigned int arrays, store as a
3517 // 64-bit int and discard the high 32 bits.
3518 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
3519 __ sub(esp, Immediate(2 * kPointerSize));
3520 __ fisttp_d(Operand(esp, 0));
3521
3522 // If conversion failed (NaN, infinity, or a number outside
3523 // signed int64 range), the result is 0x8000000000000000, and
3524 // we must handle this case in the runtime.
3525 Label ok;
3526 __ cmp(Operand(esp, kPointerSize), Immediate(0x80000000u));
3527 __ j(not_equal, &ok);
3528 __ cmp(Operand(esp, 0), Immediate(0));
3529 __ j(not_equal, &ok);
3530 __ add(esp, Immediate(2 * kPointerSize)); // Restore the stack.
3531 __ jmp(&slow);
3532
3533 __ bind(&ok);
3534 __ pop(ebx);
3535 __ add(esp, Immediate(kPointerSize));
3536 __ mov(Operand(edi, ecx, times_2, 0), ebx);
3537 } else {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003538 ASSERT(CpuFeatures::IsSupported(SSE2));
ulan@chromium.org750145a2013-03-07 15:14:13 +00003539 CpuFeatureScope scope(masm, SSE2);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003540 __ cvttsd2si(ebx, FieldOperand(eax, HeapNumber::kValueOffset));
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003541 __ cmp(ebx, 0x80000000u);
3542 __ j(equal, &slow);
3543 // ebx: untagged integer value
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003544 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003545 case EXTERNAL_PIXEL_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003546 __ ClampUint8(ebx);
3547 // Fall through.
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003548 case EXTERNAL_BYTE_ELEMENTS:
3549 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003550 __ SmiUntag(ecx);
3551 __ mov_b(Operand(edi, ecx, times_1, 0), ebx);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003552 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003553 case EXTERNAL_SHORT_ELEMENTS:
3554 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003555 __ mov_w(Operand(edi, ecx, times_1, 0), ebx);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003556 break;
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003557 case EXTERNAL_INT_ELEMENTS:
3558 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3559 __ mov(Operand(edi, ecx, times_2, 0), ebx);
3560 break;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003561 default:
3562 UNREACHABLE();
3563 break;
3564 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003565 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003566 __ ret(0); // Return original value.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003567 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003568 }
3569 }
3570
3571 // Slow case: call runtime.
3572 __ bind(&slow);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003573 Counters* counters = masm->isolate()->counters();
3574 __ IncrementCounter(counters->keyed_store_external_array_slow(), 1);
3575
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003576 // ----------- S t a t e -------------
3577 // -- eax : value
3578 // -- ecx : key
3579 // -- edx : receiver
3580 // -- esp[0] : return address
3581 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003582 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003583
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003584 // ----------- S t a t e -------------
3585 // -- eax : value
3586 // -- ecx : key
3587 // -- edx : receiver
3588 // -- esp[0] : return address
3589 // -----------------------------------
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003590
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003591 __ bind(&miss_force_generic);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003592 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003593}
3594
3595
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003596void KeyedStoreStubCompiler::GenerateStoreFastElement(
3597 MacroAssembler* masm,
3598 bool is_js_array,
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003599 ElementsKind elements_kind,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003600 KeyedAccessStoreMode store_mode) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003601 // ----------- S t a t e -------------
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003602 // -- eax : value
3603 // -- ecx : key
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003604 // -- edx : receiver
3605 // -- esp[0] : return address
3606 // -----------------------------------
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003607 Label miss_force_generic, grow, slow, transition_elements_kind;
3608 Label check_capacity, prepare_slow, finish_store, commit_backing_store;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003609
3610 // This stub is meant to be tail-jumped to, the receiver must already
3611 // have been verified by the caller to not be a smi.
3612
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003613 // Check that the key is a smi or a heap number convertible to a smi.
3614 GenerateSmiKeyCheck(masm, ecx, ebx, xmm0, xmm1, &miss_force_generic);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003615
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003616 if (IsFastSmiElementsKind(elements_kind)) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003617 __ JumpIfNotSmi(eax, &transition_elements_kind);
3618 }
3619
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003620 // Get the elements array and make sure it is a fast element array, not 'cow'.
3621 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003622 if (is_js_array) {
3623 // Check that the key is within bounds.
3624 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // smis.
ulan@chromium.org750145a2013-03-07 15:14:13 +00003625 if (IsGrowStoreMode(store_mode)) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003626 __ j(above_equal, &grow);
3627 } else {
3628 __ j(above_equal, &miss_force_generic);
3629 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003630 } else {
3631 // Check that the key is within bounds.
3632 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); // smis.
3633 __ j(above_equal, &miss_force_generic);
3634 }
3635
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003636 __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
3637 Immediate(masm->isolate()->factory()->fixed_array_map()));
3638 __ j(not_equal, &miss_force_generic);
3639
3640 __ bind(&finish_store);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003641 if (IsFastSmiElementsKind(elements_kind)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003642 // ecx is a smi, use times_half_pointer_size instead of
3643 // times_pointer_size
3644 __ mov(FieldOperand(edi,
3645 ecx,
3646 times_half_pointer_size,
3647 FixedArray::kHeaderSize), eax);
3648 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003649 ASSERT(IsFastObjectElementsKind(elements_kind));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003650 // Do the store and update the write barrier.
3651 // ecx is a smi, use times_half_pointer_size instead of
3652 // times_pointer_size
3653 __ lea(ecx, FieldOperand(edi,
3654 ecx,
3655 times_half_pointer_size,
3656 FixedArray::kHeaderSize));
3657 __ mov(Operand(ecx, 0), eax);
3658 // Make sure to preserve the value in register eax.
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003659 __ mov(ebx, eax);
3660 __ RecordWrite(edi, ecx, ebx, kDontSaveFPRegs);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003661 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003662
3663 // Done.
3664 __ ret(0);
3665
3666 // Handle store cache miss, replacing the ic with the generic stub.
3667 __ bind(&miss_force_generic);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003668 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003669
3670 // Handle transition to other elements kinds without using the generic stub.
3671 __ bind(&transition_elements_kind);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003672 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003673
ulan@chromium.org750145a2013-03-07 15:14:13 +00003674 if (is_js_array && IsGrowStoreMode(store_mode)) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003675 // Handle transition requiring the array to grow.
3676 __ bind(&grow);
3677
3678 // Make sure the array is only growing by a single element, anything else
3679 // must be handled by the runtime. Flags are already set by previous
3680 // compare.
3681 __ j(not_equal, &miss_force_generic);
3682
3683 // Check for the empty array, and preallocate a small backing store if
3684 // possible.
3685 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
3686 __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array()));
3687 __ j(not_equal, &check_capacity);
3688
3689 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003690 __ Allocate(size, edi, ebx, ecx, &prepare_slow, TAG_OBJECT);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003691 // Restore the key, which is known to be the array length.
3692
3693 // eax: value
3694 // ecx: key
3695 // edx: receiver
3696 // edi: elements
3697 // Make sure that the backing store can hold additional elements.
3698 __ mov(FieldOperand(edi, JSObject::kMapOffset),
3699 Immediate(masm->isolate()->factory()->fixed_array_map()));
3700 __ mov(FieldOperand(edi, FixedArray::kLengthOffset),
3701 Immediate(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
3702 __ mov(ebx, Immediate(masm->isolate()->factory()->the_hole_value()));
3703 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
3704 __ mov(FieldOperand(edi, FixedArray::SizeFor(i)), ebx);
3705 }
3706
3707 // Store the element at index zero.
3708 __ mov(FieldOperand(edi, FixedArray::SizeFor(0)), eax);
3709
3710 // Install the new backing store in the JSArray.
3711 __ mov(FieldOperand(edx, JSObject::kElementsOffset), edi);
3712 __ RecordWriteField(edx, JSObject::kElementsOffset, edi, ebx,
3713 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3714
3715 // Increment the length of the array.
3716 __ mov(FieldOperand(edx, JSArray::kLengthOffset),
3717 Immediate(Smi::FromInt(1)));
3718 __ ret(0);
3719
3720 __ bind(&check_capacity);
3721 __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
3722 Immediate(masm->isolate()->factory()->fixed_cow_array_map()));
3723 __ j(equal, &miss_force_generic);
3724
3725 // eax: value
3726 // ecx: key
3727 // edx: receiver
3728 // edi: elements
3729 // Make sure that the backing store can hold additional elements.
3730 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
3731 __ j(above_equal, &slow);
3732
3733 // Grow the array and finish the store.
3734 __ add(FieldOperand(edx, JSArray::kLengthOffset),
3735 Immediate(Smi::FromInt(1)));
3736 __ jmp(&finish_store);
3737
3738 __ bind(&prepare_slow);
3739 // Restore the key, which is known to be the array length.
3740 __ mov(ecx, Immediate(0));
3741
3742 __ bind(&slow);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003743 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003744 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003745}
3746
3747
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003748void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
3749 MacroAssembler* masm,
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003750 bool is_js_array,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003751 KeyedAccessStoreMode store_mode) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003752 // ----------- S t a t e -------------
3753 // -- eax : value
3754 // -- ecx : key
3755 // -- edx : receiver
3756 // -- esp[0] : return address
3757 // -----------------------------------
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003758 Label miss_force_generic, transition_elements_kind, grow, slow;
3759 Label check_capacity, prepare_slow, finish_store, commit_backing_store;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003760
3761 // This stub is meant to be tail-jumped to, the receiver must already
3762 // have been verified by the caller to not be a smi.
3763
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003764 // Check that the key is a smi or a heap number convertible to a smi.
3765 GenerateSmiKeyCheck(masm, ecx, ebx, xmm0, xmm1, &miss_force_generic);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003766
3767 // Get the elements array.
3768 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
3769 __ AssertFastElements(edi);
3770
3771 if (is_js_array) {
3772 // Check that the key is within bounds.
3773 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // smis.
ulan@chromium.org750145a2013-03-07 15:14:13 +00003774 if (IsGrowStoreMode(store_mode)) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003775 __ j(above_equal, &grow);
3776 } else {
3777 __ j(above_equal, &miss_force_generic);
3778 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003779 } else {
3780 // Check that the key is within bounds.
3781 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); // smis.
yangguo@chromium.org56454712012-02-16 15:33:53 +00003782 __ j(above_equal, &miss_force_generic);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003783 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003784
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003785 __ bind(&finish_store);
3786 __ StoreNumberToDoubleElements(eax, edi, ecx, edx, xmm0,
3787 &transition_elements_kind, true);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003788 __ ret(0);
3789
3790 // Handle store cache miss, replacing the ic with the generic stub.
3791 __ bind(&miss_force_generic);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003792 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003793
3794 // Handle transition to other elements kinds without using the generic stub.
3795 __ bind(&transition_elements_kind);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003796 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003797
ulan@chromium.org750145a2013-03-07 15:14:13 +00003798 if (is_js_array && IsGrowStoreMode(store_mode)) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003799 // Handle transition requiring the array to grow.
3800 __ bind(&grow);
3801
3802 // Make sure the array is only growing by a single element, anything else
3803 // must be handled by the runtime. Flags are already set by previous
3804 // compare.
3805 __ j(not_equal, &miss_force_generic);
3806
3807 // Transition on values that can't be stored in a FixedDoubleArray.
3808 Label value_is_smi;
3809 __ JumpIfSmi(eax, &value_is_smi);
3810 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
3811 Immediate(Handle<Map>(masm->isolate()->heap()->heap_number_map())));
3812 __ j(not_equal, &transition_elements_kind);
3813 __ bind(&value_is_smi);
3814
3815 // Check for the empty array, and preallocate a small backing store if
3816 // possible.
3817 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
3818 __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array()));
3819 __ j(not_equal, &check_capacity);
3820
3821 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003822 __ Allocate(size, edi, ebx, ecx, &prepare_slow, TAG_OBJECT);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003823
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003824 // Restore the key, which is known to be the array length.
3825 __ mov(ecx, Immediate(0));
3826
3827 // eax: value
3828 // ecx: key
3829 // edx: receiver
3830 // edi: elements
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003831 // Initialize the new FixedDoubleArray.
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003832 __ mov(FieldOperand(edi, JSObject::kMapOffset),
3833 Immediate(masm->isolate()->factory()->fixed_double_array_map()));
3834 __ mov(FieldOperand(edi, FixedDoubleArray::kLengthOffset),
3835 Immediate(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
3836
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003837 __ StoreNumberToDoubleElements(eax, edi, ecx, ebx, xmm0,
3838 &transition_elements_kind, true);
3839
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003840 for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) {
3841 int offset = FixedDoubleArray::OffsetOfElementAt(i);
3842 __ mov(FieldOperand(edi, offset), Immediate(kHoleNanLower32));
3843 __ mov(FieldOperand(edi, offset + kPointerSize),
3844 Immediate(kHoleNanUpper32));
3845 }
3846
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003847 // Install the new backing store in the JSArray.
3848 __ mov(FieldOperand(edx, JSObject::kElementsOffset), edi);
3849 __ RecordWriteField(edx, JSObject::kElementsOffset, edi, ebx,
3850 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3851
3852 // Increment the length of the array.
3853 __ add(FieldOperand(edx, JSArray::kLengthOffset),
3854 Immediate(Smi::FromInt(1)));
yangguo@chromium.org56454712012-02-16 15:33:53 +00003855 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003856 __ ret(0);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003857
3858 __ bind(&check_capacity);
3859 // eax: value
3860 // ecx: key
3861 // edx: receiver
3862 // edi: elements
3863 // Make sure that the backing store can hold additional elements.
3864 __ cmp(ecx, FieldOperand(edi, FixedDoubleArray::kLengthOffset));
3865 __ j(above_equal, &slow);
3866
3867 // Grow the array and finish the store.
3868 __ add(FieldOperand(edx, JSArray::kLengthOffset),
3869 Immediate(Smi::FromInt(1)));
3870 __ jmp(&finish_store);
3871
3872 __ bind(&prepare_slow);
3873 // Restore the key, which is known to be the array length.
3874 __ mov(ecx, Immediate(0));
3875
3876 __ bind(&slow);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003877 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003878 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003879}
3880
3881
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003882#undef __
3883
3884} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003885
3886#endif // V8_TARGET_ARCH_IA32