blob: 1a51016b831a3d1fa612f64b40f25cd76d6fd7b5 [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
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000472 // -- esp[20] : ReturnValue default value
473 // -- esp[24] : ReturnValue
474 // -- esp[28] : last argument
ager@chromium.org5c838252010-02-19 08:53:10 +0000475 // -- ...
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000476 // -- esp[(argc + 6) * 4] : first argument
477 // -- esp[(argc + 7) * 4] : receiver
ager@chromium.org5c838252010-02-19 08:53:10 +0000478 // -----------------------------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000479 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000480 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000481 __ LoadHeapObject(edi, function);
ager@chromium.org5c838252010-02-19 08:53:10 +0000482 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
483
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000484 // Pass the additional arguments.
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000485 __ mov(Operand(esp, 2 * kPointerSize), edi);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000486 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000487 Handle<Object> call_data(api_call_info->data(), masm->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000488 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
489 __ mov(ecx, api_call_info);
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000490 __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kDataOffset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000491 __ mov(Operand(esp, 3 * kPointerSize), ebx);
492 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000493 __ mov(Operand(esp, 3 * kPointerSize), Immediate(call_data));
ager@chromium.org5c838252010-02-19 08:53:10 +0000494 }
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000495 __ mov(Operand(esp, 4 * kPointerSize),
496 Immediate(reinterpret_cast<int>(masm->isolate())));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000497 __ mov(Operand(esp, 5 * kPointerSize),
498 masm->isolate()->factory()->undefined_value());
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000499 __ mov(Operand(esp, 6 * kPointerSize),
500 masm->isolate()->factory()->undefined_value());
ager@chromium.org5c838252010-02-19 08:53:10 +0000501
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000502 // Prepare arguments.
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000503 STATIC_ASSERT(kFastApiCallArguments == 6);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000504 __ lea(eax, Operand(esp, kFastApiCallArguments * kPointerSize));
ager@chromium.org5c838252010-02-19 08:53:10 +0000505
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000506
507 // API function gets reference to the v8::Arguments. If CPU profiler
508 // is enabled wrapper function will be called and we need to pass
509 // address of the callback as additional parameter, always allocate
510 // space for it.
511 const int kApiArgc = 1 + 1;
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000512
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000513 // Allocate the v8::Arguments structure in the arguments' space since
514 // it's not controlled by GC.
515 const int kApiStackSpace = 4;
516
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000517 // Function address is a foreign pointer outside V8's heap.
518 Address function_address = v8::ToCData<Address>(api_call_info->callback());
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000519 bool returns_handle =
520 !CallbackTable::ReturnsVoid(masm->isolate(),
521 reinterpret_cast<void*>(function_address));
522 __ PrepareCallApiFunction(kApiArgc + kApiStackSpace, returns_handle);
523
524 // v8::Arguments::implicit_args_.
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000525 __ mov(ApiParameterOperand(2, returns_handle), eax);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000526 __ add(eax, Immediate(argc * kPointerSize));
527 // v8::Arguments::values_.
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000528 __ mov(ApiParameterOperand(3, returns_handle), eax);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000529 // v8::Arguments::length_.
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000530 __ Set(ApiParameterOperand(4, returns_handle), Immediate(argc));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000531 // v8::Arguments::is_construct_call_.
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000532 __ Set(ApiParameterOperand(5, returns_handle), Immediate(0));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000533
534 // v8::InvocationCallback's argument.
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000535 __ lea(eax, ApiParameterOperand(2, returns_handle));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000536 __ mov(ApiParameterOperand(0, returns_handle), eax);
537
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000538 Address thunk_address = returns_handle
539 ? FUNCTION_ADDR(&InvokeInvocationCallback)
540 : FUNCTION_ADDR(&InvokeFunctionCallback);
541
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000542 __ CallApiFunctionAndReturn(function_address,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000543 thunk_address,
544 ApiParameterOperand(1, returns_handle),
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000545 argc + kFastApiCallArguments + 1,
546 returns_handle,
547 kFastApiCallArguments + 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000548}
549
550
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000551class CallInterceptorCompiler BASE_EMBEDDED {
552 public:
ager@chromium.org5c838252010-02-19 08:53:10 +0000553 CallInterceptorCompiler(StubCompiler* stub_compiler,
554 const ParameterCount& arguments,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000555 Register name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000556 Code::ExtraICState extra_state)
ager@chromium.org5c838252010-02-19 08:53:10 +0000557 : stub_compiler_(stub_compiler),
558 arguments_(arguments),
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000559 name_(name),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000560 extra_state_(extra_state) {}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000561
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000562 void Compile(MacroAssembler* masm,
563 Handle<JSObject> object,
564 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000565 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000566 LookupResult* lookup,
567 Register receiver,
568 Register scratch1,
569 Register scratch2,
570 Register scratch3,
571 Label* miss) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000572 ASSERT(holder->HasNamedInterceptor());
573 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
574
575 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000576 __ JumpIfSmi(receiver, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000577
578 CallOptimization optimization(lookup);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000579 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000580 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
581 holder, lookup, name, optimization, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000582 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000583 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
584 name, holder, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000585 }
586 }
587
588 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000589 void CompileCacheable(MacroAssembler* masm,
590 Handle<JSObject> object,
591 Register receiver,
592 Register scratch1,
593 Register scratch2,
594 Register scratch3,
595 Handle<JSObject> interceptor_holder,
596 LookupResult* lookup,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000597 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000598 const CallOptimization& optimization,
599 Label* miss_label) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000600 ASSERT(optimization.is_constant_call());
601 ASSERT(!lookup->holder()->IsGlobalObject());
602
603 int depth1 = kInvalidProtoDepth;
604 int depth2 = kInvalidProtoDepth;
605 bool can_do_fast_api_call = false;
606 if (optimization.is_simple_api_call() &&
607 !lookup->holder()->IsGlobalObject()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000608 depth1 = optimization.GetPrototypeDepthOfExpectedType(
609 object, interceptor_holder);
ager@chromium.org5c838252010-02-19 08:53:10 +0000610 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000611 depth2 = optimization.GetPrototypeDepthOfExpectedType(
612 interceptor_holder, Handle<JSObject>(lookup->holder()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000613 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000614 can_do_fast_api_call =
615 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000616 }
617
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000618 Counters* counters = masm->isolate()->counters();
619 __ IncrementCounter(counters->call_const_interceptor(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000620
621 if (can_do_fast_api_call) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000622 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000623 ReserveSpaceForFastApiCall(masm, scratch1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000624 }
625
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000626 // Check that the maps from receiver to interceptor's holder
627 // haven't changed and thus we can invoke interceptor.
ager@chromium.org5c838252010-02-19 08:53:10 +0000628 Label miss_cleanup;
629 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
630 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000631 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
632 scratch1, scratch2, scratch3,
633 name, depth1, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000634
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000635 // Invoke an interceptor and if it provides a value,
636 // branch to |regular_invoke|.
ager@chromium.org5c838252010-02-19 08:53:10 +0000637 Label regular_invoke;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000638 LoadWithInterceptor(masm, receiver, holder, interceptor_holder,
639 &regular_invoke);
ager@chromium.org5c838252010-02-19 08:53:10 +0000640
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000641 // Interceptor returned nothing for this property. Try to use cached
642 // constant function.
ager@chromium.org5c838252010-02-19 08:53:10 +0000643
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000644 // Check that the maps from interceptor's holder to constant function's
645 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000646 if (*interceptor_holder != lookup->holder()) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000647 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000648 Handle<JSObject>(lookup->holder()),
649 scratch1, scratch2, scratch3,
650 name, depth2, miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000651 } else {
652 // CheckPrototypes has a side effect of fetching a 'holder'
653 // for API (object which is instanceof for the signature). It's
654 // safe to omit it here, as if present, it should be fetched
655 // by the previous CheckPrototypes.
656 ASSERT(depth2 == kInvalidProtoDepth);
657 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000658
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000659 // Invoke function.
ager@chromium.org5c838252010-02-19 08:53:10 +0000660 if (can_do_fast_api_call) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000661 GenerateFastApiCall(masm, optimization, arguments_.immediate());
ager@chromium.org5c838252010-02-19 08:53:10 +0000662 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000663 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000664 ? CALL_AS_FUNCTION
665 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000666 Handle<JSFunction> function = optimization.constant_function();
667 ParameterCount expected(function);
668 __ InvokeFunction(function, expected, arguments_,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000669 JUMP_FUNCTION, NullCallWrapper(), call_kind);
ager@chromium.org5c838252010-02-19 08:53:10 +0000670 }
671
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000672 // Deferred code for fast API call case---clean preallocated space.
ager@chromium.org5c838252010-02-19 08:53:10 +0000673 if (can_do_fast_api_call) {
674 __ bind(&miss_cleanup);
675 FreeSpaceForFastApiCall(masm, scratch1);
676 __ jmp(miss_label);
677 }
678
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000679 // Invoke a regular function.
ager@chromium.org5c838252010-02-19 08:53:10 +0000680 __ bind(&regular_invoke);
681 if (can_do_fast_api_call) {
682 FreeSpaceForFastApiCall(masm, scratch1);
683 }
684 }
685
686 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000687 Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +0000688 Register receiver,
689 Register scratch1,
690 Register scratch2,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000691 Register scratch3,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000692 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000693 Handle<JSObject> interceptor_holder,
ager@chromium.org5c838252010-02-19 08:53:10 +0000694 Label* miss_label) {
695 Register holder =
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000696 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000697 scratch1, scratch2, scratch3,
698 name, miss_label);
ager@chromium.org5c838252010-02-19 08:53:10 +0000699
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000700 FrameScope scope(masm, StackFrame::INTERNAL);
ager@chromium.org5c838252010-02-19 08:53:10 +0000701 // Save the name_ register across the call.
702 __ push(name_);
703
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000704 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
ager@chromium.org5c838252010-02-19 08:53:10 +0000705
706 __ CallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000707 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
708 masm->isolate()),
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000709 6);
ager@chromium.org5c838252010-02-19 08:53:10 +0000710
711 // Restore the name_ register.
712 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000713
714 // Leave the internal frame.
ager@chromium.org5c838252010-02-19 08:53:10 +0000715 }
716
717 void LoadWithInterceptor(MacroAssembler* masm,
718 Register receiver,
719 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000720 Handle<JSObject> holder_obj,
ager@chromium.org5c838252010-02-19 08:53:10 +0000721 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000722 {
723 FrameScope scope(masm, StackFrame::INTERNAL);
724 __ push(holder); // Save the holder.
725 __ push(name_); // Save the name.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000726
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000727 CompileCallLoadPropertyWithInterceptor(masm,
728 receiver,
729 holder,
730 name_,
731 holder_obj);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000732
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000733 __ pop(name_); // Restore the name.
734 __ pop(receiver); // Restore the holder.
735 // Leave the internal frame.
736 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000737
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000738 __ cmp(eax, masm->isolate()->factory()->no_interceptor_result_sentinel());
ager@chromium.org5c838252010-02-19 08:53:10 +0000739 __ j(not_equal, interceptor_succeeded);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000740 }
741
ager@chromium.org5c838252010-02-19 08:53:10 +0000742 StubCompiler* stub_compiler_;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000743 const ParameterCount& arguments_;
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000744 Register name_;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000745 Code::ExtraICState extra_state_;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000746};
747
748
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000749void BaseStoreStubCompiler::GenerateRestoreName(MacroAssembler* masm,
750 Label* label,
751 Handle<Name> name) {
752 if (!label->is_unused()) {
753 __ bind(label);
754 __ mov(this->name(), Immediate(name));
755 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000756}
757
758
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000759// Generate code to check that a global property cell is empty. Create
760// the property cell at compilation time if no cell exists for the
761// property.
762static void GenerateCheckPropertyCell(MacroAssembler* masm,
763 Handle<GlobalObject> global,
764 Handle<Name> name,
765 Register scratch,
766 Label* miss) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000767 Handle<PropertyCell> cell =
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000768 GlobalObject::EnsurePropertyCell(global, name);
769 ASSERT(cell->value()->IsTheHole());
770 Handle<Oddball> the_hole = masm->isolate()->factory()->the_hole_value();
771 if (Serializer::enabled()) {
772 __ mov(scratch, Immediate(cell));
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000773 __ cmp(FieldOperand(scratch, PropertyCell::kValueOffset),
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000774 Immediate(the_hole));
775 } else {
danno@chromium.org41728482013-06-12 22:31:22 +0000776 __ cmp(Operand::ForCell(cell), Immediate(the_hole));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000777 }
778 __ j(not_equal, miss);
779}
780
781
ager@chromium.org5c838252010-02-19 08:53:10 +0000782// Both name_reg and receiver_reg are preserved on jumps to miss_label,
783// but may be destroyed if store is successful.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000784void StubCompiler::GenerateStoreTransition(MacroAssembler* masm,
785 Handle<JSObject> object,
786 LookupResult* lookup,
787 Handle<Map> transition,
788 Handle<Name> name,
789 Register receiver_reg,
790 Register name_reg,
791 Register value_reg,
792 Register scratch1,
793 Register scratch2,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000794 Register unused,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000795 Label* miss_label,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000796 Label* miss_restore_name,
797 Label* slow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000798 // Check that the map of the object hasn't changed.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000799 __ CheckMap(receiver_reg, Handle<Map>(object->map()),
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000800 miss_label, DO_SMI_CHECK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000801
802 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000803 if (object->IsJSGlobalProxy()) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000804 __ CheckAccessGlobalProxy(receiver_reg, scratch1, scratch2, miss_label);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000805 }
806
danno@chromium.orgf005df62013-04-30 16:36:45 +0000807 int descriptor = transition->LastAdded();
808 DescriptorArray* descriptors = transition->instance_descriptors();
809 PropertyDetails details = descriptors->GetDetails(descriptor);
810 Representation representation = details.representation();
811 ASSERT(!representation.IsNone());
812
813 // Ensure no transitions to deprecated maps are followed.
814 __ CheckMapDeprecated(transition, scratch1, miss_label);
815
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000816 // Check that we are allowed to write this.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000817 if (object->GetPrototype()->IsJSObject()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000818 JSObject* holder;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000819 // holder == object indicates that no property was found.
820 if (lookup->holder() != *object) {
821 holder = lookup->holder();
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000822 } else {
823 // Find the top object.
824 holder = *object;
825 do {
826 holder = JSObject::cast(holder->GetPrototype());
827 } while (holder->GetPrototype()->IsJSObject());
828 }
829 // We need an extra register, push
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000830 Register holder_reg = CheckPrototypes(
831 object, receiver_reg, Handle<JSObject>(holder), name_reg,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000832 scratch1, scratch2, name, miss_restore_name, SKIP_RECEIVER);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000833 // If no property was found, and the holder (the last object in the
834 // prototype chain) is in slow mode, we need to do a negative lookup on the
835 // holder.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000836 if (lookup->holder() == *object) {
837 if (holder->IsJSGlobalObject()) {
838 GenerateCheckPropertyCell(
839 masm,
840 Handle<GlobalObject>(GlobalObject::cast(holder)),
841 name,
842 scratch1,
843 miss_restore_name);
844 } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
845 GenerateDictionaryNegativeLookup(
846 masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
847 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000848 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000849 }
850
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000851 Register storage_reg = name_reg;
852
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000853 if (details.type() == CONSTANT_FUNCTION) {
854 Handle<HeapObject> constant(
855 HeapObject::cast(descriptors->GetValue(descriptor)));
856 __ LoadHeapObject(scratch1, constant);
857 __ cmp(value_reg, scratch1);
858 __ j(not_equal, miss_restore_name);
859 } else if (FLAG_track_fields && representation.IsSmi()) {
860 __ JumpIfNotSmi(value_reg, miss_restore_name);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +0000861 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
862 __ JumpIfSmi(value_reg, miss_restore_name);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000863 } else if (FLAG_track_double_fields && representation.IsDouble()) {
864 Label do_store, heap_number;
865 __ AllocateHeapNumber(storage_reg, scratch1, scratch2, slow);
866
867 __ JumpIfNotSmi(value_reg, &heap_number);
868 __ SmiUntag(value_reg);
869 if (CpuFeatures::IsSupported(SSE2)) {
870 CpuFeatureScope use_sse2(masm, SSE2);
871 __ cvtsi2sd(xmm0, value_reg);
872 } else {
873 __ push(value_reg);
874 __ fild_s(Operand(esp, 0));
875 __ pop(value_reg);
876 }
877 __ SmiTag(value_reg);
878 __ jmp(&do_store);
879
880 __ bind(&heap_number);
881 __ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(),
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000882 miss_restore_name, DONT_DO_SMI_CHECK);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000883 if (CpuFeatures::IsSupported(SSE2)) {
884 CpuFeatureScope use_sse2(masm, SSE2);
885 __ movdbl(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset));
886 } else {
887 __ fld_d(FieldOperand(value_reg, HeapNumber::kValueOffset));
888 }
889
890 __ bind(&do_store);
891 if (CpuFeatures::IsSupported(SSE2)) {
892 CpuFeatureScope use_sse2(masm, SSE2);
893 __ movdbl(FieldOperand(storage_reg, HeapNumber::kValueOffset), xmm0);
894 } else {
895 __ fstp_d(FieldOperand(storage_reg, HeapNumber::kValueOffset));
896 }
897 }
898
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000899 // Stub never generated for non-global objects that require access
900 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000901 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000902
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000903 // Perform map transition for the receiver if necessary.
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000904 if (details.type() == FIELD &&
905 object->map()->unused_property_fields() == 0) {
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000906 // The properties must be extended before we can store the value.
ager@chromium.org32912102009-01-16 10:38:43 +0000907 // We jump to a runtime call that extends the properties array.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000908 __ pop(scratch1); // Return address.
ager@chromium.org5c838252010-02-19 08:53:10 +0000909 __ push(receiver_reg);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000910 __ push(Immediate(transition));
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000911 __ push(value_reg);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000912 __ push(scratch1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000913 __ TailCallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000914 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
915 masm->isolate()),
916 3,
917 1);
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000918 return;
919 }
920
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000921 // Update the map of the object.
922 __ mov(scratch1, Immediate(transition));
923 __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1);
verwaest@chromium.org37141392012-05-31 13:27:02 +0000924
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000925 // Update the write barrier for the map field.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000926 __ RecordWriteField(receiver_reg,
927 HeapObject::kMapOffset,
928 scratch1,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000929 scratch2,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000930 kDontSaveFPRegs,
931 OMIT_REMEMBERED_SET,
932 OMIT_SMI_CHECK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000933
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000934 if (details.type() == CONSTANT_FUNCTION) {
935 ASSERT(value_reg.is(eax));
936 __ ret(0);
937 return;
938 }
939
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000940 int index = transition->instance_descriptors()->GetFieldIndex(
941 transition->LastAdded());
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000942
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000943 // Adjust for the number of properties stored in the object. Even in the
944 // face of a transition we can use the old map here because the size of the
945 // object and the number of in-object properties is not going to change.
946 index -= object->map()->inobject_properties();
947
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000948 SmiCheck smi_check = representation.IsTagged()
949 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000950 // TODO(verwaest): Share this code as a code stub.
ager@chromium.org7c537e22008-10-16 08:43:32 +0000951 if (index < 0) {
952 // Set the property straight into the object.
953 int offset = object->map()->instance_size() + (index * kPointerSize);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000954 if (FLAG_track_double_fields && representation.IsDouble()) {
955 __ mov(FieldOperand(receiver_reg, offset), storage_reg);
956 } else {
957 __ mov(FieldOperand(receiver_reg, offset), value_reg);
958 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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(receiver_reg,
969 offset,
970 name_reg,
971 scratch1,
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 } else {
977 // Write to the properties array.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000978 int offset = index * kPointerSize + FixedArray::kHeaderSize;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000979 // Get the properties array (optimistically).
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000980 __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000981 if (FLAG_track_double_fields && representation.IsDouble()) {
982 __ mov(FieldOperand(scratch1, offset), storage_reg);
983 } else {
984 __ mov(FieldOperand(scratch1, offset), value_reg);
985 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000986
danno@chromium.orgf005df62013-04-30 16:36:45 +0000987 if (!FLAG_track_fields || !representation.IsSmi()) {
988 // Update the write barrier for the array address.
989 // Pass the value being stored in the now unused name_reg.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000990 if (!FLAG_track_double_fields || !representation.IsDouble()) {
991 __ mov(name_reg, value_reg);
992 } else {
993 ASSERT(storage_reg.is(name_reg));
994 }
danno@chromium.orgf005df62013-04-30 16:36:45 +0000995 __ RecordWriteField(scratch1,
996 offset,
997 name_reg,
998 receiver_reg,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000999 kDontSaveFPRegs,
1000 EMIT_REMEMBERED_SET,
1001 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001002 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001003 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001004
1005 // Return the value (register eax).
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001006 ASSERT(value_reg.is(eax));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001007 __ ret(0);
1008}
1009
1010
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001011// Both name_reg and receiver_reg are preserved on jumps to miss_label,
1012// but may be destroyed if store is successful.
1013void StubCompiler::GenerateStoreField(MacroAssembler* masm,
1014 Handle<JSObject> object,
1015 LookupResult* lookup,
1016 Register receiver_reg,
1017 Register name_reg,
1018 Register value_reg,
1019 Register scratch1,
1020 Register scratch2,
1021 Label* miss_label) {
1022 // Check that the map of the object hasn't changed.
1023 __ CheckMap(receiver_reg, Handle<Map>(object->map()),
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001024 miss_label, DO_SMI_CHECK);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001025
1026 // Perform global security token check if needed.
1027 if (object->IsJSGlobalProxy()) {
1028 __ CheckAccessGlobalProxy(receiver_reg, scratch1, scratch2, miss_label);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001029 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001030
1031 // Stub never generated for non-global objects that require access
1032 // checks.
1033 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
1034
1035 int index = lookup->GetFieldIndex().field_index();
1036
1037 // Adjust for the number of properties stored in the object. Even in the
1038 // face of a transition we can use the old map here because the size of the
1039 // object and the number of in-object properties is not going to change.
1040 index -= object->map()->inobject_properties();
1041
danno@chromium.orgf005df62013-04-30 16:36:45 +00001042 Representation representation = lookup->representation();
1043 ASSERT(!representation.IsNone());
1044 if (FLAG_track_fields && representation.IsSmi()) {
1045 __ JumpIfNotSmi(value_reg, miss_label);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001046 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
1047 __ JumpIfSmi(value_reg, miss_label);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001048 } else if (FLAG_track_double_fields && representation.IsDouble()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001049 // Load the double storage.
1050 if (index < 0) {
1051 int offset = object->map()->instance_size() + (index * kPointerSize);
1052 __ mov(scratch1, FieldOperand(receiver_reg, offset));
1053 } else {
1054 __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
1055 int offset = index * kPointerSize + FixedArray::kHeaderSize;
1056 __ mov(scratch1, FieldOperand(scratch1, offset));
1057 }
1058
1059 // Store the value into the storage.
1060 Label do_store, heap_number;
1061 __ JumpIfNotSmi(value_reg, &heap_number);
1062 __ SmiUntag(value_reg);
1063 if (CpuFeatures::IsSupported(SSE2)) {
1064 CpuFeatureScope use_sse2(masm, SSE2);
1065 __ cvtsi2sd(xmm0, value_reg);
1066 } else {
1067 __ push(value_reg);
1068 __ fild_s(Operand(esp, 0));
1069 __ pop(value_reg);
1070 }
1071 __ SmiTag(value_reg);
1072 __ jmp(&do_store);
1073 __ bind(&heap_number);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001074 __ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(),
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001075 miss_label, DONT_DO_SMI_CHECK);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001076 if (CpuFeatures::IsSupported(SSE2)) {
1077 CpuFeatureScope use_sse2(masm, SSE2);
1078 __ movdbl(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset));
1079 } else {
1080 __ fld_d(FieldOperand(value_reg, HeapNumber::kValueOffset));
1081 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00001082 __ bind(&do_store);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001083 if (CpuFeatures::IsSupported(SSE2)) {
1084 CpuFeatureScope use_sse2(masm, SSE2);
1085 __ movdbl(FieldOperand(scratch1, HeapNumber::kValueOffset), xmm0);
1086 } else {
1087 __ fstp_d(FieldOperand(scratch1, HeapNumber::kValueOffset));
1088 }
1089 // Return the value (register eax).
1090 ASSERT(value_reg.is(eax));
1091 __ ret(0);
1092 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +00001093 }
1094
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001095 ASSERT(!FLAG_track_double_fields || !representation.IsDouble());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001096 // TODO(verwaest): Share this code as a code stub.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001097 SmiCheck smi_check = representation.IsTagged()
1098 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001099 if (index < 0) {
1100 // Set the property straight into the object.
1101 int offset = object->map()->instance_size() + (index * kPointerSize);
1102 __ mov(FieldOperand(receiver_reg, offset), value_reg);
1103
danno@chromium.orgf005df62013-04-30 16:36:45 +00001104 if (!FLAG_track_fields || !representation.IsSmi()) {
1105 // Update the write barrier for the array address.
1106 // Pass the value being stored in the now unused name_reg.
1107 __ mov(name_reg, value_reg);
1108 __ RecordWriteField(receiver_reg,
1109 offset,
1110 name_reg,
1111 scratch1,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001112 kDontSaveFPRegs,
1113 EMIT_REMEMBERED_SET,
1114 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001115 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001116 } else {
1117 // Write to the properties array.
1118 int offset = index * kPointerSize + FixedArray::kHeaderSize;
1119 // Get the properties array (optimistically).
1120 __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001121 __ mov(FieldOperand(scratch1, offset), value_reg);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001122
danno@chromium.orgf005df62013-04-30 16:36:45 +00001123 if (!FLAG_track_fields || !representation.IsSmi()) {
1124 // Update the write barrier for the array address.
1125 // Pass the value being stored in the now unused name_reg.
1126 __ mov(name_reg, value_reg);
1127 __ RecordWriteField(scratch1,
1128 offset,
1129 name_reg,
1130 receiver_reg,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001131 kDontSaveFPRegs,
1132 EMIT_REMEMBERED_SET,
1133 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001134 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001135 }
1136
1137 // Return the value (register eax).
1138 ASSERT(value_reg.is(eax));
1139 __ ret(0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001140}
1141
1142
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001143// Calls GenerateCheckPropertyCell for each global object in the prototype chain
1144// from object to (but not including) holder.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001145static void GenerateCheckPropertyCells(MacroAssembler* masm,
1146 Handle<JSObject> object,
1147 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001148 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001149 Register scratch,
1150 Label* miss) {
1151 Handle<JSObject> current = object;
1152 while (!current.is_identical_to(holder)) {
1153 if (current->IsGlobalObject()) {
1154 GenerateCheckPropertyCell(masm,
1155 Handle<GlobalObject>::cast(current),
1156 name,
1157 scratch,
1158 miss);
1159 }
1160 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
1161 }
1162}
1163
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001164
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001165void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001166 __ jmp(code, RelocInfo::CODE_TARGET);
1167}
1168
1169
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001170#undef __
1171#define __ ACCESS_MASM(masm())
1172
1173
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001174Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
1175 Register object_reg,
1176 Handle<JSObject> holder,
1177 Register holder_reg,
1178 Register scratch1,
1179 Register scratch2,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001180 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001181 int save_at_depth,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001182 Label* miss,
1183 PrototypeCheckType check) {
1184 Handle<JSObject> first = object;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001185 // Make sure there's no overlap between holder and object registers.
1186 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1187 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1188 && !scratch2.is(scratch1));
1189
1190 // Keep track of the current object in register reg.
1191 Register reg = object_reg;
1192 Handle<JSObject> current = object;
1193 int depth = 0;
1194
1195 if (save_at_depth == depth) {
1196 __ mov(Operand(esp, kPointerSize), reg);
1197 }
1198
1199 // Traverse the prototype chain and check the maps in the prototype chain for
1200 // fast and global objects or do negative lookup for normal objects.
1201 while (!current.is_identical_to(holder)) {
1202 ++depth;
1203
1204 // Only global objects and objects that do not require access
1205 // checks are allowed in stubs.
1206 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1207
1208 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
1209 if (!current->HasFastProperties() &&
1210 !current->IsJSGlobalObject() &&
1211 !current->IsJSGlobalProxy()) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001212 if (!name->IsUniqueName()) {
1213 ASSERT(name->IsString());
1214 name = factory()->InternalizeString(Handle<String>::cast(name));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001215 }
1216 ASSERT(current->property_dictionary()->FindEntry(*name) ==
ulan@chromium.org750145a2013-03-07 15:14:13 +00001217 NameDictionary::kNotFound);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001218
1219 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1220 scratch1, scratch2);
1221
1222 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
1223 reg = holder_reg; // From now on the object will be in holder_reg.
1224 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
1225 } else {
1226 bool in_new_space = heap()->InNewSpace(*prototype);
1227 Handle<Map> current_map(current->map());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001228 if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001229 __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001230 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001231
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001232 // Check access rights to the global object. This has to happen after
1233 // the map check so that we know that the object is actually a global
1234 // object.
1235 if (current->IsJSGlobalProxy()) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001236 __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001237 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001238
1239 if (in_new_space) {
1240 // Save the map in scratch1 for later.
1241 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
1242 }
1243
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001244 reg = holder_reg; // From now on the object will be in holder_reg.
1245
1246 if (in_new_space) {
1247 // The prototype is in new space; we cannot store a reference to it
1248 // in the code. Load it from the map.
1249 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
1250 } else {
1251 // The prototype is in old space; load it directly.
1252 __ mov(reg, prototype);
1253 }
1254 }
1255
1256 if (save_at_depth == depth) {
1257 __ mov(Operand(esp, kPointerSize), reg);
1258 }
1259
1260 // Go to the next object in the prototype chain.
1261 current = prototype;
1262 }
1263 ASSERT(current.is_identical_to(holder));
1264
1265 // Log the check depth.
1266 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
1267
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001268 if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) {
1269 // Check the holder map.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001270 __ CheckMap(reg, Handle<Map>(holder->map()), miss, DONT_DO_SMI_CHECK);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001271 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001272
1273 // Perform security check for access to the global object.
1274 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1275 if (holder->IsJSGlobalProxy()) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001276 __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001277 }
1278
1279 // If we've skipped any global objects, it's not enough to verify that
1280 // their maps haven't changed. We also need to check that the property
1281 // cell for the property is still empty.
1282 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1283
1284 // Return the register containing the holder.
1285 return reg;
1286}
1287
1288
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001289void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success,
1290 Label* miss) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001291 if (!miss->is_unused()) {
1292 __ jmp(success);
1293 __ bind(miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001294 TailCallBuiltin(masm(), MissBuiltin(kind()));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001295 }
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001296}
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001297
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001298
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001299Register BaseLoadStubCompiler::CallbackHandlerFrontend(
1300 Handle<JSObject> object,
1301 Register object_reg,
1302 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001303 Handle<Name> name,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001304 Label* success,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001305 Handle<ExecutableAccessorInfo> callback) {
1306 Label miss;
1307
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001308 Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001309
1310 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
1311 ASSERT(!reg.is(scratch2()));
1312 ASSERT(!reg.is(scratch3()));
1313 Register dictionary = scratch1();
1314 bool must_preserve_dictionary_reg = reg.is(dictionary);
1315
1316 // Load the properties dictionary.
1317 if (must_preserve_dictionary_reg) {
1318 __ push(dictionary);
1319 }
1320 __ mov(dictionary, FieldOperand(reg, JSObject::kPropertiesOffset));
1321
1322 // Probe the dictionary.
1323 Label probe_done, pop_and_miss;
ulan@chromium.org750145a2013-03-07 15:14:13 +00001324 NameDictionaryLookupStub::GeneratePositiveLookup(masm(),
1325 &pop_and_miss,
1326 &probe_done,
1327 dictionary,
1328 this->name(),
1329 scratch2(),
1330 scratch3());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001331 __ bind(&pop_and_miss);
1332 if (must_preserve_dictionary_reg) {
1333 __ pop(dictionary);
1334 }
1335 __ jmp(&miss);
1336 __ bind(&probe_done);
1337
1338 // If probing finds an entry in the dictionary, scratch2 contains the
1339 // index into the dictionary. Check that the value is the callback.
1340 Register index = scratch2();
1341 const int kElementsStartOffset =
ulan@chromium.org750145a2013-03-07 15:14:13 +00001342 NameDictionary::kHeaderSize +
1343 NameDictionary::kElementsStartIndex * kPointerSize;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001344 const int kValueOffset = kElementsStartOffset + kPointerSize;
1345 __ mov(scratch3(),
1346 Operand(dictionary, index, times_4, kValueOffset - kHeapObjectTag));
1347 if (must_preserve_dictionary_reg) {
1348 __ pop(dictionary);
1349 }
1350 __ cmp(scratch3(), callback);
1351 __ j(not_equal, &miss);
1352 }
1353
1354 HandlerFrontendFooter(success, &miss);
1355 return reg;
1356}
1357
1358
1359void BaseLoadStubCompiler::NonexistentHandlerFrontend(
1360 Handle<JSObject> object,
1361 Handle<JSObject> last,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001362 Handle<Name> name,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001363 Label* success,
1364 Handle<GlobalObject> global) {
1365 Label miss;
1366
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001367 HandlerFrontendHeader(object, receiver(), last, name, &miss);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001368
1369 // If the last object in the prototype chain is a global object,
1370 // check that the global property cell is empty.
1371 if (!global.is_null()) {
1372 GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
1373 }
1374
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001375 HandlerFrontendFooter(success, &miss);
1376}
1377
1378
1379void BaseLoadStubCompiler::GenerateLoadField(Register reg,
1380 Handle<JSObject> holder,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001381 PropertyIndex field,
1382 Representation representation) {
1383 if (!reg.is(receiver())) __ mov(receiver(), reg);
1384 if (kind() == Code::LOAD_IC) {
1385 LoadFieldStub stub(field.is_inobject(holder),
1386 field.translate(holder),
1387 representation);
1388 GenerateTailCall(masm(), stub.GetCode(isolate()));
1389 } else {
1390 KeyedLoadFieldStub stub(field.is_inobject(holder),
1391 field.translate(holder),
1392 representation);
1393 GenerateTailCall(masm(), stub.GetCode(isolate()));
1394 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001395}
1396
1397
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001398void BaseLoadStubCompiler::GenerateLoadCallback(
1399 Register reg,
1400 Handle<ExecutableAccessorInfo> callback) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001401 // Insert additional parameters into the stack frame above return address.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001402 ASSERT(!scratch3().is(reg));
1403 __ pop(scratch3()); // Get return address to place it below.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001404
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001405 __ push(receiver()); // receiver
1406 __ mov(scratch2(), esp);
1407 ASSERT(!scratch2().is(reg));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001408 __ push(reg); // holder
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001409 // Push data from ExecutableAccessorInfo.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001410 if (isolate()->heap()->InNewSpace(callback->data())) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001411 __ mov(scratch1(), Immediate(callback));
1412 __ push(FieldOperand(scratch1(), ExecutableAccessorInfo::kDataOffset));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001413 } else {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001414 __ push(Immediate(Handle<Object>(callback->data(), isolate())));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001415 }
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001416 __ push(Immediate(isolate()->factory()->undefined_value())); // ReturnValue
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001417 // ReturnValue default value
1418 __ push(Immediate(isolate()->factory()->undefined_value()));
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00001419 __ push(Immediate(reinterpret_cast<int>(isolate())));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001420
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001421 // Save a pointer to where we pushed the arguments pointer. This will be
1422 // passed as the const ExecutableAccessorInfo& to the C++ callback.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001423 __ push(scratch2());
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001424
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001425 __ push(name()); // name
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001426 __ mov(ebx, esp); // esp points to reference to name (handler).
1427
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001428 __ push(scratch3()); // Restore return address.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001429
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001430 // array for v8::Arguments::values_, handler for name and pointer
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001431 // to the values (it considered as smi in GC).
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001432 const int kStackSpace = PropertyCallbackArguments::kArgsLength + 2;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001433 // Allocate space for opional callback address parameter in case
1434 // CPU profiler is active.
1435 const int kApiArgc = 2 + 1;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001436
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001437 Address getter_address = v8::ToCData<Address>(callback->getter());
1438 bool returns_handle =
1439 !CallbackTable::ReturnsVoid(isolate(),
1440 reinterpret_cast<void*>(getter_address));
1441 __ PrepareCallApiFunction(kApiArgc, returns_handle);
1442 __ mov(ApiParameterOperand(0, returns_handle), ebx); // name.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001443 __ add(ebx, Immediate(kPointerSize));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001444 __ mov(ApiParameterOperand(1, returns_handle), ebx); // arguments pointer.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001445
kmillikin@chromium.org2d5475f2009-12-20 18:15:52 +00001446 // Emitting a stub call may try to allocate (if the code is not
1447 // already generated). Do not allow the assembler to perform a
1448 // garbage collection but instead return the allocation failure
1449 // object.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001450
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001451 Address thunk_address = returns_handle
1452 ? FUNCTION_ADDR(&InvokeAccessorGetter)
1453 : FUNCTION_ADDR(&InvokeAccessorGetterCallback);
1454
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001455 __ CallApiFunctionAndReturn(getter_address,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001456 thunk_address,
1457 ApiParameterOperand(2, returns_handle),
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001458 kStackSpace,
1459 returns_handle,
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001460 6);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001461}
1462
1463
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001464void BaseLoadStubCompiler::GenerateLoadConstant(Handle<JSFunction> value) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001465 // Return the constant value.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001466 __ LoadHeapObject(eax, value);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001467 __ ret(0);
1468}
1469
1470
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001471void BaseLoadStubCompiler::GenerateLoadInterceptor(
1472 Register holder_reg,
1473 Handle<JSObject> object,
1474 Handle<JSObject> interceptor_holder,
1475 LookupResult* lookup,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001476 Handle<Name> name) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001477 ASSERT(interceptor_holder->HasNamedInterceptor());
1478 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1479
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001480 // So far the most popular follow ups for interceptor loads are FIELD
1481 // and CALLBACKS, so inline only them, other cases may be added
1482 // later.
1483 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001484 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001485 if (lookup->IsField()) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001486 compile_followup_inline = true;
1487 } else if (lookup->type() == CALLBACKS &&
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001488 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
1489 ExecutableAccessorInfo* callback =
1490 ExecutableAccessorInfo::cast(lookup->GetCallbackObject());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001491 compile_followup_inline = callback->getter() != NULL &&
1492 callback->IsCompatibleReceiver(*object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001493 }
1494 }
1495
1496 if (compile_followup_inline) {
1497 // Compile the interceptor call, followed by inline code to load the
1498 // property from further up the prototype chain if the call fails.
1499 // Check that the maps haven't changed.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001500 ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001501
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001502 // Preserve the receiver register explicitly whenever it is different from
1503 // the holder and it is needed should the interceptor return without any
1504 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1505 // the FIELD case might cause a miss during the prototype check.
1506 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001507 bool must_preserve_receiver_reg = !receiver().is(holder_reg) &&
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001508 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1509
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001510 // Save necessary data before invoking an interceptor.
1511 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001512 {
1513 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001514
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001515 if (must_preserve_receiver_reg) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001516 __ push(receiver());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001517 }
1518 __ push(holder_reg);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001519 __ push(this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001520
1521 // Invoke an interceptor. Note: map checks from receiver to
1522 // interceptor's holder has been compiled before (see a caller
1523 // of this method.)
1524 CompileCallLoadPropertyWithInterceptor(masm(),
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001525 receiver(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001526 holder_reg,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001527 this->name(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001528 interceptor_holder);
1529
1530 // Check if interceptor provided a value for property. If it's
1531 // the case, return immediately.
1532 Label interceptor_failed;
1533 __ cmp(eax, factory()->no_interceptor_result_sentinel());
1534 __ j(equal, &interceptor_failed);
1535 frame_scope.GenerateLeaveFrame();
1536 __ ret(0);
1537
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001538 // Clobber registers when generating debug-code to provoke errors.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001539 __ bind(&interceptor_failed);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001540 if (FLAG_debug_code) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001541 __ mov(receiver(), Immediate(BitCast<int32_t>(kZapValue)));
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001542 __ mov(holder_reg, Immediate(BitCast<int32_t>(kZapValue)));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001543 __ mov(this->name(), Immediate(BitCast<int32_t>(kZapValue)));
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001544 }
1545
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001546 __ pop(this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001547 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001548 if (must_preserve_receiver_reg) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001549 __ pop(receiver());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001550 }
1551
1552 // Leave the internal frame.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001553 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001554
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001555 GenerateLoadPostInterceptor(holder_reg, interceptor_holder, name, lookup);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001556 } else { // !compile_followup_inline
1557 // Call the runtime system to load the interceptor.
1558 // Check that the maps haven't changed.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001559 __ pop(scratch2()); // save old return address
1560 PushInterceptorArguments(masm(), receiver(), holder_reg,
1561 this->name(), interceptor_holder);
1562 __ push(scratch2()); // restore old return address
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001563
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001564 ExternalReference ref =
1565 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001566 isolate());
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001567 __ TailCallExternalReference(ref, 6, 1);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001568 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001569}
1570
1571
ulan@chromium.org750145a2013-03-07 15:14:13 +00001572void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001573 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001574 __ cmp(ecx, Immediate(name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001575 __ j(not_equal, miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001576 }
1577}
1578
1579
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001580void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1581 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001582 Handle<Name> name,
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001583 Label* miss) {
1584 ASSERT(holder->IsGlobalObject());
1585
1586 // Get the number of arguments.
1587 const int argc = arguments().immediate();
1588
1589 // Get the receiver from the stack.
1590 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1591
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001592
1593 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001594 __ JumpIfSmi(edx, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001595 CheckPrototypes(object, edx, holder, ebx, eax, edi, name, miss);
1596}
1597
1598
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001599void CallStubCompiler::GenerateLoadFunctionFromCell(
danno@chromium.org41728482013-06-12 22:31:22 +00001600 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001601 Handle<JSFunction> function,
1602 Label* miss) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001603 // Get the value from the cell.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001604 if (Serializer::enabled()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001605 __ mov(edi, Immediate(cell));
danno@chromium.org41728482013-06-12 22:31:22 +00001606 __ mov(edi, FieldOperand(edi, Cell::kValueOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001607 } else {
danno@chromium.org41728482013-06-12 22:31:22 +00001608 __ mov(edi, Operand::ForCell(cell));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001609 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001610
1611 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001612 if (isolate()->heap()->InNewSpace(*function)) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001613 // We can't embed a pointer to a function in new space so we have
1614 // to verify that the shared function info is unchanged. This has
1615 // the nice side effect that multiple closures based on the same
1616 // function can all use this call IC. Before we load through the
1617 // function, we have to verify that it still is a function.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001618 __ JumpIfSmi(edi, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001619 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001620 __ j(not_equal, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001621
1622 // Check the shared function info. Make sure it hasn't changed.
1623 __ cmp(FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset),
1624 Immediate(Handle<SharedFunctionInfo>(function->shared())));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001625 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001626 __ cmp(edi, Immediate(function));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001627 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001628 __ j(not_equal, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001629}
1630
1631
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001632void CallStubCompiler::GenerateMissBranch() {
1633 Handle<Code> code =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001634 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
danno@chromium.org40cb8782011-05-25 07:58:50 +00001635 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001636 extra_state_);
1637 __ jmp(code, RelocInfo::CODE_TARGET);
1638}
1639
1640
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001641Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1642 Handle<JSObject> holder,
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00001643 PropertyIndex index,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001644 Handle<Name> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001645 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001646 // -- ecx : name
1647 // -- esp[0] : return address
1648 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1649 // -- ...
1650 // -- esp[(argc + 1) * 4] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001651 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001652 Label miss;
1653
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001654 GenerateNameCheck(name, &miss);
1655
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001656 // Get the receiver from the stack.
1657 const int argc = arguments().immediate();
1658 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1659
1660 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001661 __ JumpIfSmi(edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001662
1663 // Do the right check and compute the holder register.
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001664 Register reg = CheckPrototypes(object, edx, holder, ebx, eax, edi,
1665 name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001666
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001667 GenerateFastPropertyLoad(
1668 masm(), edi, reg, index.is_inobject(holder),
1669 index.translate(holder), Representation::Tagged());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001670
1671 // Check that the function really is a function.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001672 __ JumpIfSmi(edi, &miss);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001673 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001674 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001675
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001676 // Patch the receiver on the stack with the global proxy if
1677 // necessary.
1678 if (object->IsGlobalObject()) {
1679 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
1680 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
1681 }
1682
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001683 // Invoke the function.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001684 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001685 ? CALL_AS_FUNCTION
1686 : CALL_AS_METHOD;
1687 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION,
1688 NullCallWrapper(), call_kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001689
1690 // Handle call cache miss.
1691 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001692 GenerateMissBranch();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001693
1694 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001695 return GetCode(Code::FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001696}
1697
1698
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001699Handle<Code> CallStubCompiler::CompileArrayCodeCall(
1700 Handle<Object> object,
1701 Handle<JSObject> holder,
1702 Handle<Cell> cell,
1703 Handle<JSFunction> function,
1704 Handle<String> name,
1705 Code::StubType type) {
1706 Label miss;
1707
1708 // Check that function is still array
1709 const int argc = arguments().immediate();
1710 GenerateNameCheck(name, &miss);
1711
1712 if (cell.is_null()) {
1713 // Get the receiver from the stack.
1714 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1715
1716 // Check that the receiver isn't a smi.
1717 __ JumpIfSmi(edx, &miss);
1718 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
1719 name, &miss);
1720 } else {
1721 ASSERT(cell->value() == *function);
1722 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
1723 &miss);
1724 GenerateLoadFunctionFromCell(cell, function, &miss);
1725 }
1726
1727 Handle<Smi> kind(Smi::FromInt(GetInitialFastElementsKind()), isolate());
1728 Handle<Cell> kind_feedback_cell =
1729 isolate()->factory()->NewCell(kind);
1730 __ mov(eax, Immediate(argc));
1731 __ mov(ebx, kind_feedback_cell);
1732 __ mov(edi, function);
1733
1734 ArrayConstructorStub stub(isolate());
1735 __ TailCallStub(&stub);
1736
1737 __ bind(&miss);
1738 GenerateMissBranch();
1739
1740 // Return the generated code.
1741 return GetCode(type, name);
1742}
1743
1744
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001745Handle<Code> CallStubCompiler::CompileArrayPushCall(
1746 Handle<Object> object,
1747 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00001748 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001749 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001750 Handle<String> name,
1751 Code::StubType type) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001752 // ----------- S t a t e -------------
1753 // -- ecx : name
1754 // -- esp[0] : return address
1755 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1756 // -- ...
1757 // -- esp[(argc + 1) * 4] : receiver
1758 // -----------------------------------
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001759
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001760 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001761 if (!object->IsJSArray() || !cell.is_null()) {
1762 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001763 }
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001764
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001765 Label miss;
1766
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001767 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001768
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001769 // Get the receiver from the stack.
1770 const int argc = arguments().immediate();
1771 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1772
1773 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001774 __ JumpIfSmi(edx, &miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001775
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001776 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
1777 name, &miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001778
1779 if (argc == 0) {
1780 // Noop, return the length.
1781 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
1782 __ ret((argc + 1) * kPointerSize);
1783 } else {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001784 Label call_builtin;
1785
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001786 if (argc == 1) { // Otherwise fall through to call builtin.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001787 Label attempt_to_grow_elements, with_write_barrier, check_double;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001788
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001789 // Get the elements array of the object.
1790 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset));
1791
1792 // Check that the elements are in fast mode and writable.
1793 __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
1794 Immediate(factory()->fixed_array_map()));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001795 __ j(not_equal, &check_double);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001796
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001797 // Get the array's length into eax and calculate new length.
1798 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
1799 STATIC_ASSERT(kSmiTagSize == 1);
1800 STATIC_ASSERT(kSmiTag == 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001801 __ add(eax, Immediate(Smi::FromInt(argc)));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001802
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001803 // Get the elements' length into ecx.
1804 __ mov(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001805
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001806 // Check if we could survive without allocation.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001807 __ cmp(eax, ecx);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001808 __ j(greater, &attempt_to_grow_elements);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001809
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001810 // Check if value is a smi.
1811 __ mov(ecx, Operand(esp, argc * kPointerSize));
1812 __ JumpIfNotSmi(ecx, &with_write_barrier);
1813
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001814 // Save new length.
1815 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1816
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001817 // Store the value.
1818 __ mov(FieldOperand(edi,
1819 eax,
1820 times_half_pointer_size,
1821 FixedArray::kHeaderSize - argc * kPointerSize),
1822 ecx);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001823
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001824 __ ret((argc + 1) * kPointerSize);
1825
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001826 __ bind(&check_double);
1827
1828
1829 // Check that the elements are in double mode.
1830 __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
1831 Immediate(factory()->fixed_double_array_map()));
1832 __ j(not_equal, &call_builtin);
1833
1834 // Get the array's length into eax and calculate new length.
1835 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
1836 STATIC_ASSERT(kSmiTagSize == 1);
1837 STATIC_ASSERT(kSmiTag == 0);
1838 __ add(eax, Immediate(Smi::FromInt(argc)));
1839
1840 // Get the elements' length into ecx.
1841 __ mov(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
1842
1843 // Check if we could survive without allocation.
1844 __ cmp(eax, ecx);
1845 __ j(greater, &call_builtin);
1846
1847 __ mov(ecx, Operand(esp, argc * kPointerSize));
1848 __ StoreNumberToDoubleElements(
1849 ecx, edi, eax, ecx, xmm0, &call_builtin, true, argc * kDoubleSize);
1850
1851 // Save new length.
1852 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1853 __ ret((argc + 1) * kPointerSize);
1854
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001855 __ bind(&with_write_barrier);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001856
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001857 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
1858
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001859 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001860 Label fast_object, not_fast_object;
1861 __ CheckFastObjectElements(ebx, &not_fast_object, Label::kNear);
1862 __ jmp(&fast_object);
1863 // In case of fast smi-only, convert to fast object, otherwise bail out.
1864 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001865 __ CheckFastSmiElements(ebx, &call_builtin);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001866 __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
1867 Immediate(factory()->heap_number_map()));
1868 __ j(equal, &call_builtin);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001869 // edi: elements array
1870 // edx: receiver
1871 // ebx: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001872 Label try_holey_map;
1873 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001874 FAST_ELEMENTS,
1875 ebx,
1876 edi,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001877 &try_holey_map);
1878
1879 ElementsTransitionGenerator::
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001880 GenerateMapChangeElementsTransition(masm(),
1881 DONT_TRACK_ALLOCATION_SITE,
1882 NULL);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001883 // Restore edi.
1884 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset));
1885 __ jmp(&fast_object);
1886
1887 __ bind(&try_holey_map);
1888 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1889 FAST_HOLEY_ELEMENTS,
1890 ebx,
1891 edi,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001892 &call_builtin);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001893 ElementsTransitionGenerator::
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001894 GenerateMapChangeElementsTransition(masm(),
1895 DONT_TRACK_ALLOCATION_SITE,
1896 NULL);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001897 // Restore edi.
1898 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset));
1899 __ bind(&fast_object);
1900 } else {
1901 __ CheckFastObjectElements(ebx, &call_builtin);
1902 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001903
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001904 // Save new length.
1905 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1906
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001907 // Store the value.
1908 __ lea(edx, FieldOperand(edi,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001909 eax, times_half_pointer_size,
1910 FixedArray::kHeaderSize - argc * kPointerSize));
1911 __ mov(Operand(edx, 0), ecx);
1912
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001913 __ RecordWrite(edi, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001914 OMIT_SMI_CHECK);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001915
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001916 __ ret((argc + 1) * kPointerSize);
1917
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001918 __ bind(&attempt_to_grow_elements);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001919 if (!FLAG_inline_new) {
1920 __ jmp(&call_builtin);
1921 }
1922
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001923 __ mov(ebx, Operand(esp, argc * kPointerSize));
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001924 // Growing elements that are SMI-only requires special handling in case
1925 // the new element is non-Smi. For now, delegate to the builtin.
1926 Label no_fast_elements_check;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001927 __ JumpIfSmi(ebx, &no_fast_elements_check);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001928 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
1929 __ CheckFastObjectElements(ecx, &call_builtin, Label::kFar);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001930 __ bind(&no_fast_elements_check);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001931
1932 // We could be lucky and the elements array could be at the top of
1933 // new-space. In this case we can just grow it in place by moving the
1934 // allocation pointer up.
1935
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001936 ExternalReference new_space_allocation_top =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001937 ExternalReference::new_space_allocation_top_address(isolate());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001938 ExternalReference new_space_allocation_limit =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001939 ExternalReference::new_space_allocation_limit_address(isolate());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001940
1941 const int kAllocationDelta = 4;
1942 // Load top.
1943 __ mov(ecx, Operand::StaticVariable(new_space_allocation_top));
1944
1945 // Check if it's the end of elements.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001946 __ lea(edx, FieldOperand(edi,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001947 eax, times_half_pointer_size,
1948 FixedArray::kHeaderSize - argc * kPointerSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001949 __ cmp(edx, ecx);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001950 __ j(not_equal, &call_builtin);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001951 __ add(ecx, Immediate(kAllocationDelta * kPointerSize));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001952 __ cmp(ecx, Operand::StaticVariable(new_space_allocation_limit));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001953 __ j(above, &call_builtin);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001954
1955 // We fit and could grow elements.
1956 __ mov(Operand::StaticVariable(new_space_allocation_top), ecx);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001957
1958 // Push the argument...
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001959 __ mov(Operand(edx, 0), ebx);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001960 // ... and fill the rest with holes.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001961 for (int i = 1; i < kAllocationDelta; i++) {
1962 __ mov(Operand(edx, i * kPointerSize),
lrn@chromium.org7516f052011-03-30 08:52:27 +00001963 Immediate(factory()->the_hole_value()));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001964 }
1965
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001966 // We know the elements array is in new space so we don't need the
1967 // remembered set, but we just pushed a value onto it so we may have to
1968 // tell the incremental marker to rescan the object that we just grew. We
1969 // don't need to worry about the holes because they are in old space and
1970 // already marked black.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001971 __ RecordWrite(edi, edx, ebx, kDontSaveFPRegs, OMIT_REMEMBERED_SET);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001972
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001973 // Restore receiver to edx as finish sequence assumes it's here.
1974 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1975
1976 // Increment element's and array's sizes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001977 __ add(FieldOperand(edi, FixedArray::kLengthOffset),
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001978 Immediate(Smi::FromInt(kAllocationDelta)));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001979
1980 // NOTE: This only happen in new-space, where we don't
1981 // care about the black-byte-count on pages. Otherwise we should
1982 // update that too if the object is black.
1983
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001984 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1985
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001986 __ ret((argc + 1) * kPointerSize);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001987 }
1988
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001989 __ bind(&call_builtin);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001990 __ TailCallExternalReference(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001991 ExternalReference(Builtins::c_ArrayPush, isolate()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001992 argc + 1,
1993 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001994 }
1995
1996 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001997 GenerateMissBranch();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001998
1999 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002000 return GetCode(type, name);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002001}
2002
2003
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002004Handle<Code> CallStubCompiler::CompileArrayPopCall(
2005 Handle<Object> object,
2006 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002007 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002008 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002009 Handle<String> name,
2010 Code::StubType type) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002011 // ----------- S t a t e -------------
2012 // -- ecx : name
2013 // -- esp[0] : return address
2014 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2015 // -- ...
2016 // -- esp[(argc + 1) * 4] : receiver
2017 // -----------------------------------
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002018
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00002019 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002020 if (!object->IsJSArray() || !cell.is_null()) {
2021 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002022 }
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00002023
ager@chromium.orgac091b72010-05-05 07:34:42 +00002024 Label miss, return_undefined, call_builtin;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002025
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002026 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002027
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002028 // Get the receiver from the stack.
2029 const int argc = arguments().immediate();
2030 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
2031
2032 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002033 __ JumpIfSmi(edx, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002034 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2035 name, &miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002036
2037 // Get the elements array of the object.
2038 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset));
2039
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00002040 // Check that the elements are in fast mode and writable.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002041 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
lrn@chromium.org7516f052011-03-30 08:52:27 +00002042 Immediate(factory()->fixed_array_map()));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00002043 __ j(not_equal, &call_builtin);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002044
2045 // Get the array's length into ecx and calculate new length.
2046 __ mov(ecx, FieldOperand(edx, JSArray::kLengthOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002047 __ sub(ecx, Immediate(Smi::FromInt(1)));
ager@chromium.orgac091b72010-05-05 07:34:42 +00002048 __ j(negative, &return_undefined);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002049
2050 // Get the last element.
2051 STATIC_ASSERT(kSmiTagSize == 1);
2052 STATIC_ASSERT(kSmiTag == 0);
2053 __ mov(eax, FieldOperand(ebx,
2054 ecx, times_half_pointer_size,
2055 FixedArray::kHeaderSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002056 __ cmp(eax, Immediate(factory()->the_hole_value()));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002057 __ j(equal, &call_builtin);
2058
2059 // Set the array's length.
2060 __ mov(FieldOperand(edx, JSArray::kLengthOffset), ecx);
2061
2062 // Fill with the hole.
2063 __ mov(FieldOperand(ebx,
2064 ecx, times_half_pointer_size,
2065 FixedArray::kHeaderSize),
lrn@chromium.org7516f052011-03-30 08:52:27 +00002066 Immediate(factory()->the_hole_value()));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002067 __ ret((argc + 1) * kPointerSize);
2068
ager@chromium.orgac091b72010-05-05 07:34:42 +00002069 __ bind(&return_undefined);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002070 __ mov(eax, Immediate(factory()->undefined_value()));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002071 __ ret((argc + 1) * kPointerSize);
2072
2073 __ bind(&call_builtin);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002074 __ TailCallExternalReference(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002075 ExternalReference(Builtins::c_ArrayPop, isolate()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002076 argc + 1,
2077 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002078
2079 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002080 GenerateMissBranch();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002081
2082 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002083 return GetCode(type, name);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002084}
2085
2086
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002087Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
2088 Handle<Object> object,
2089 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002090 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002091 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002092 Handle<String> name,
2093 Code::StubType type) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002094 // ----------- S t a t e -------------
2095 // -- ecx : function name
2096 // -- esp[0] : return address
2097 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2098 // -- ...
2099 // -- esp[(argc + 1) * 4] : receiver
2100 // -----------------------------------
2101
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002102 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002103 if (!object->IsString() || !cell.is_null()) {
2104 return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002105 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002106
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002107 const int argc = arguments().immediate();
2108
2109 Label miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002110 Label name_miss;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002111 Label index_out_of_range;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002112 Label* index_out_of_range_label = &index_out_of_range;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002113
danno@chromium.org40cb8782011-05-25 07:58:50 +00002114 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002115 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002116 DEFAULT_STRING_STUB)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002117 index_out_of_range_label = &miss;
2118 }
2119
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002120 GenerateNameCheck(name, &name_miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002121
2122 // Check that the maps starting from the prototype haven't changed.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002123 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2124 Context::STRING_FUNCTION_INDEX,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002125 eax,
2126 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002127 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002128 CheckPrototypes(
2129 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2130 eax, holder, ebx, edx, edi, name, &miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002131
2132 Register receiver = ebx;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002133 Register index = edi;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002134 Register result = eax;
2135 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize));
2136 if (argc > 0) {
2137 __ mov(index, Operand(esp, (argc - 0) * kPointerSize));
2138 } else {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002139 __ Set(index, Immediate(factory()->undefined_value()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002140 }
2141
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002142 StringCharCodeAtGenerator generator(receiver,
2143 index,
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()->nan_value()));
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.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002168 return GetCode(type, name);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002169}
2170
2171
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002172Handle<Code> CallStubCompiler::CompileStringCharAtCall(
2173 Handle<Object> object,
2174 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002175 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002176 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002177 Handle<String> name,
2178 Code::StubType type) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002179 // ----------- S t a t e -------------
2180 // -- ecx : function name
2181 // -- esp[0] : return address
2182 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2183 // -- ...
2184 // -- esp[(argc + 1) * 4] : receiver
2185 // -----------------------------------
2186
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002187 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002188 if (!object->IsString() || !cell.is_null()) {
2189 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002190 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002191
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002192 const int argc = arguments().immediate();
2193
2194 Label miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002195 Label name_miss;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002196 Label index_out_of_range;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002197 Label* index_out_of_range_label = &index_out_of_range;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002198
danno@chromium.org40cb8782011-05-25 07:58:50 +00002199 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002200 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002201 DEFAULT_STRING_STUB)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002202 index_out_of_range_label = &miss;
2203 }
2204
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002205 GenerateNameCheck(name, &name_miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002206
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002207 // Check that the maps starting from the prototype haven't changed.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002208 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2209 Context::STRING_FUNCTION_INDEX,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002210 eax,
2211 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002212 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002213 CheckPrototypes(
2214 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2215 eax, holder, ebx, edx, edi, name, &miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002216
2217 Register receiver = eax;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002218 Register index = edi;
danno@chromium.orgc612e022011-11-10 11:38:15 +00002219 Register scratch = edx;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002220 Register result = eax;
2221 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize));
2222 if (argc > 0) {
2223 __ mov(index, Operand(esp, (argc - 0) * kPointerSize));
2224 } else {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002225 __ Set(index, Immediate(factory()->undefined_value()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002226 }
2227
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002228 StringCharAtGenerator generator(receiver,
2229 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00002230 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002231 result,
2232 &miss, // When not a string.
2233 &miss, // When not a number.
2234 index_out_of_range_label,
2235 STRING_INDEX_IS_NUMBER);
2236 generator.GenerateFast(masm());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002237 __ ret((argc + 1) * kPointerSize);
2238
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002239 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002240 generator.GenerateSlow(masm(), call_helper);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002241
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002242 if (index_out_of_range.is_linked()) {
2243 __ bind(&index_out_of_range);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002244 __ Set(eax, Immediate(factory()->empty_string()));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002245 __ ret((argc + 1) * kPointerSize);
2246 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002247
2248 __ bind(&miss);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002249 // Restore function name in ecx.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002250 __ Set(ecx, Immediate(name));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002251 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002252 GenerateMissBranch();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002253
2254 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002255 return GetCode(type, name);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002256}
2257
2258
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002259Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
2260 Handle<Object> object,
2261 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002262 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002263 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002264 Handle<String> name,
2265 Code::StubType type) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002266 // ----------- S t a t e -------------
2267 // -- ecx : function name
2268 // -- esp[0] : return address
2269 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2270 // -- ...
2271 // -- esp[(argc + 1) * 4] : receiver
2272 // -----------------------------------
2273
2274 const int argc = arguments().immediate();
2275
2276 // If the object is not a JSObject or we got an unexpected number of
2277 // arguments, bail out to the regular call.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002278 if (!object->IsJSObject() || argc != 1) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002279 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002280 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002281
2282 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002283 GenerateNameCheck(name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002284
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002285 if (cell.is_null()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002286 __ mov(edx, Operand(esp, 2 * kPointerSize));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002287 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002288 __ JumpIfSmi(edx, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002289 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2290 name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002291 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002292 ASSERT(cell->value() == *function);
2293 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2294 &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002295 GenerateLoadFunctionFromCell(cell, function, &miss);
2296 }
2297
2298 // Load the char code argument.
2299 Register code = ebx;
2300 __ mov(code, Operand(esp, 1 * kPointerSize));
2301
2302 // Check the code is a smi.
2303 Label slow;
2304 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002305 __ JumpIfNotSmi(code, &slow);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002306
2307 // Convert the smi code to uint16.
2308 __ and_(code, Immediate(Smi::FromInt(0xffff)));
2309
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002310 StringCharFromCodeGenerator generator(code, eax);
2311 generator.GenerateFast(masm());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002312 __ ret(2 * kPointerSize);
2313
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002314 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002315 generator.GenerateSlow(masm(), call_helper);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002316
2317 // Tail call the full function. We do not have to patch the receiver
2318 // because the function makes no use of it.
2319 __ bind(&slow);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002320 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002321 ? CALL_AS_FUNCTION
2322 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002323 ParameterCount expected(function);
2324 __ InvokeFunction(function, expected, arguments(),
2325 JUMP_FUNCTION, NullCallWrapper(), call_kind);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002326
2327 __ bind(&miss);
2328 // ecx: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002329 GenerateMissBranch();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002330
2331 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002332 return GetCode(type, name);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002333}
2334
2335
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002336Handle<Code> CallStubCompiler::CompileMathFloorCall(
2337 Handle<Object> object,
2338 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002339 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002340 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002341 Handle<String> name,
2342 Code::StubType type) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002343 // ----------- S t a t e -------------
2344 // -- ecx : name
2345 // -- esp[0] : return address
2346 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2347 // -- ...
2348 // -- esp[(argc + 1) * 4] : receiver
2349 // -----------------------------------
2350
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002351 if (!CpuFeatures::IsSupported(SSE2)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002352 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002353 }
2354
ulan@chromium.org750145a2013-03-07 15:14:13 +00002355 CpuFeatureScope use_sse2(masm(), SSE2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002356
2357 const int argc = arguments().immediate();
2358
2359 // If the object is not a JSObject or we got an unexpected number of
2360 // arguments, bail out to the regular call.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002361 if (!object->IsJSObject() || argc != 1) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002362 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002363 }
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002364
2365 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002366 GenerateNameCheck(name, &miss);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002367
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002368 if (cell.is_null()) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002369 __ mov(edx, Operand(esp, 2 * kPointerSize));
2370
2371 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002372 __ JumpIfSmi(edx, &miss);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002373
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002374 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2375 name, &miss);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002376 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002377 ASSERT(cell->value() == *function);
2378 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2379 &miss);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002380 GenerateLoadFunctionFromCell(cell, function, &miss);
2381 }
2382
2383 // Load the (only) argument into eax.
2384 __ mov(eax, Operand(esp, 1 * kPointerSize));
2385
2386 // Check if the argument is a smi.
2387 Label smi;
2388 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002389 __ JumpIfSmi(eax, &smi);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002390
2391 // Check if the argument is a heap number and load its value into xmm0.
2392 Label slow;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002393 __ CheckMap(eax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002394 __ movdbl(xmm0, FieldOperand(eax, HeapNumber::kValueOffset));
2395
2396 // Check if the argument is strictly positive. Note this also
2397 // discards NaN.
2398 __ xorpd(xmm1, xmm1);
2399 __ ucomisd(xmm0, xmm1);
2400 __ j(below_equal, &slow);
2401
2402 // Do a truncating conversion.
2403 __ cvttsd2si(eax, Operand(xmm0));
2404
2405 // Check if the result fits into a smi. Note this also checks for
2406 // 0x80000000 which signals a failed conversion.
2407 Label wont_fit_into_smi;
2408 __ test(eax, Immediate(0xc0000000));
2409 __ j(not_zero, &wont_fit_into_smi);
2410
2411 // Smi tag and return.
2412 __ SmiTag(eax);
2413 __ bind(&smi);
2414 __ ret(2 * kPointerSize);
2415
2416 // Check if the argument is < 2^kMantissaBits.
2417 Label already_round;
2418 __ bind(&wont_fit_into_smi);
2419 __ LoadPowerOf2(xmm1, ebx, HeapNumber::kMantissaBits);
2420 __ ucomisd(xmm0, xmm1);
2421 __ j(above_equal, &already_round);
2422
2423 // Save a copy of the argument.
2424 __ movaps(xmm2, xmm0);
2425
2426 // Compute (argument + 2^kMantissaBits) - 2^kMantissaBits.
2427 __ addsd(xmm0, xmm1);
2428 __ subsd(xmm0, xmm1);
2429
2430 // Compare the argument and the tentative result to get the right mask:
2431 // if xmm2 < xmm0:
2432 // xmm2 = 1...1
2433 // else:
2434 // xmm2 = 0...0
2435 __ cmpltsd(xmm2, xmm0);
2436
2437 // Subtract 1 if the argument was less than the tentative result.
2438 __ LoadPowerOf2(xmm1, ebx, 0);
2439 __ andpd(xmm1, xmm2);
2440 __ subsd(xmm0, xmm1);
2441
2442 // Return a new heap number.
2443 __ AllocateHeapNumber(eax, ebx, edx, &slow);
2444 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
2445 __ ret(2 * kPointerSize);
2446
2447 // Return the argument (when it's an already round heap number).
2448 __ bind(&already_round);
2449 __ mov(eax, Operand(esp, 1 * kPointerSize));
2450 __ ret(2 * kPointerSize);
2451
2452 // Tail call the full function. We do not have to patch the receiver
2453 // because the function makes no use of it.
2454 __ bind(&slow);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002455 ParameterCount expected(function);
2456 __ InvokeFunction(function, expected, arguments(),
2457 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002458
2459 __ bind(&miss);
2460 // ecx: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002461 GenerateMissBranch();
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002462
2463 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002464 return GetCode(type, name);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002465}
2466
2467
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002468Handle<Code> CallStubCompiler::CompileMathAbsCall(
2469 Handle<Object> object,
2470 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002471 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002472 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002473 Handle<String> name,
2474 Code::StubType type) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002475 // ----------- S t a t e -------------
2476 // -- ecx : name
2477 // -- esp[0] : return address
2478 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2479 // -- ...
2480 // -- esp[(argc + 1) * 4] : receiver
2481 // -----------------------------------
2482
2483 const int argc = arguments().immediate();
2484
2485 // If the object is not a JSObject or we got an unexpected number of
2486 // arguments, bail out to the regular call.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002487 if (!object->IsJSObject() || argc != 1) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002488 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002489 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002490
2491 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002492 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002493
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002494 if (cell.is_null()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002495 __ mov(edx, Operand(esp, 2 * kPointerSize));
2496
2497 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002498 __ JumpIfSmi(edx, &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002499
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002500 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2501 name, &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002502 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002503 ASSERT(cell->value() == *function);
2504 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2505 &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002506 GenerateLoadFunctionFromCell(cell, function, &miss);
2507 }
2508
2509 // Load the (only) argument into eax.
2510 __ mov(eax, Operand(esp, 1 * kPointerSize));
2511
2512 // Check if the argument is a smi.
2513 Label not_smi;
2514 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002515 __ JumpIfNotSmi(eax, &not_smi);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002516
2517 // Set ebx to 1...1 (== -1) if the argument is negative, or to 0...0
2518 // otherwise.
2519 __ mov(ebx, eax);
2520 __ sar(ebx, kBitsPerInt - 1);
2521
2522 // Do bitwise not or do nothing depending on ebx.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002523 __ xor_(eax, ebx);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002524
2525 // Add 1 or do nothing depending on ebx.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002526 __ sub(eax, ebx);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002527
2528 // If the result is still negative, go to the slow case.
2529 // This only happens for the most negative smi.
2530 Label slow;
2531 __ j(negative, &slow);
2532
2533 // Smi case done.
2534 __ ret(2 * kPointerSize);
2535
2536 // Check if the argument is a heap number and load its exponent and
2537 // sign into ebx.
2538 __ bind(&not_smi);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002539 __ CheckMap(eax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002540 __ mov(ebx, FieldOperand(eax, HeapNumber::kExponentOffset));
2541
2542 // Check the sign of the argument. If the argument is positive,
2543 // just return it.
2544 Label negative_sign;
2545 __ test(ebx, Immediate(HeapNumber::kSignMask));
2546 __ j(not_zero, &negative_sign);
2547 __ ret(2 * kPointerSize);
2548
2549 // If the argument is negative, clear the sign, and return a new
2550 // number.
2551 __ bind(&negative_sign);
2552 __ and_(ebx, ~HeapNumber::kSignMask);
2553 __ mov(ecx, FieldOperand(eax, HeapNumber::kMantissaOffset));
2554 __ AllocateHeapNumber(eax, edi, edx, &slow);
2555 __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), ebx);
2556 __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx);
2557 __ ret(2 * kPointerSize);
2558
2559 // Tail call the full function. We do not have to patch the receiver
2560 // because the function makes no use of it.
2561 __ bind(&slow);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002562 ParameterCount expected(function);
2563 __ InvokeFunction(function, expected, arguments(),
2564 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002565
2566 __ bind(&miss);
2567 // ecx: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002568 GenerateMissBranch();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002569
2570 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002571 return GetCode(type, name);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002572}
2573
2574
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002575Handle<Code> CallStubCompiler::CompileFastApiCall(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002576 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002577 Handle<Object> object,
2578 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002579 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002580 Handle<JSFunction> function,
2581 Handle<String> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002582 ASSERT(optimization.is_simple_api_call());
2583 // Bail out if object is a global object as we don't want to
2584 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002585 if (object->IsGlobalObject()) return Handle<Code>::null();
2586 if (!cell.is_null()) return Handle<Code>::null();
2587 if (!object->IsJSObject()) return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002588 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002589 Handle<JSObject>::cast(object), holder);
2590 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002591
2592 Label miss, miss_before_stack_reserved;
2593
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002594 GenerateNameCheck(name, &miss_before_stack_reserved);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002595
2596 // Get the receiver from the stack.
2597 const int argc = arguments().immediate();
2598 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
2599
2600 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002601 __ JumpIfSmi(edx, &miss_before_stack_reserved);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002602
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002603 Counters* counters = isolate()->counters();
2604 __ IncrementCounter(counters->call_const(), 1);
2605 __ IncrementCounter(counters->call_const_fast_api(), 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002606
2607 // Allocate space for v8::Arguments implicit values. Must be initialized
2608 // before calling any runtime function.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002609 __ sub(esp, Immediate(kFastApiCallArguments * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002610
2611 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002612 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2613 name, depth, &miss);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002614
2615 // Move the return address on top of the stack.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002616 __ mov(eax, Operand(esp, kFastApiCallArguments * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002617 __ mov(Operand(esp, 0 * kPointerSize), eax);
2618
2619 // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains
2620 // duplicate of return address and will be overwritten.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002621 GenerateFastApiCall(masm(), optimization, argc);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002622
2623 __ bind(&miss);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002624 __ add(esp, Immediate(kFastApiCallArguments * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002625
2626 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002627 GenerateMissBranch();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002628
2629 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002630 return GetCode(function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002631}
2632
2633
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002634void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
2635 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002636 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002637 CheckType check,
2638 Label* success) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002639 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00002640 // -- ecx : name
2641 // -- esp[0] : return address
2642 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2643 // -- ...
2644 // -- esp[(argc + 1) * 4] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002645 // -----------------------------------
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002646 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002647 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002648
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002649 // Get the receiver from the stack.
2650 const int argc = arguments().immediate();
2651 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
2652
2653 // Check that the receiver isn't a smi.
2654 if (check != NUMBER_CHECK) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00002655 __ JumpIfSmi(edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002656 }
2657
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002658 // Make sure that it's okay not to patch the on stack receiver
2659 // unless we're doing a receiver map check.
2660 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002661 switch (check) {
2662 case RECEIVER_MAP_CHECK:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002663 __ IncrementCounter(isolate()->counters()->call_const(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00002664
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002665 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002666 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax,
2667 edi, name, &miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002668
2669 // Patch the receiver on the stack with the global proxy if
2670 // necessary.
2671 if (object->IsGlobalObject()) {
2672 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
2673 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
2674 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002675 break;
2676
2677 case STRING_CHECK:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002678 // Check that the object is a string.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002679 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, eax);
2680 __ j(above_equal, &miss);
2681 // Check that the maps starting from the prototype haven't changed.
2682 GenerateDirectLoadGlobalFunctionPrototype(
2683 masm(), Context::STRING_FUNCTION_INDEX, eax, &miss);
2684 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002685 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002686 eax, holder, ebx, edx, edi, name, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002687 break;
2688
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002689 case SYMBOL_CHECK:
2690 // Check that the object is a symbol.
2691 __ CmpObjectType(edx, SYMBOL_TYPE, eax);
2692 __ j(not_equal, &miss);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002693 // Check that the maps starting from the prototype haven't changed.
2694 GenerateDirectLoadGlobalFunctionPrototype(
2695 masm(), Context::SYMBOL_FUNCTION_INDEX, eax, &miss);
2696 CheckPrototypes(
2697 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2698 eax, holder, ebx, edx, edi, name, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002699 break;
2700
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002701 case NUMBER_CHECK: {
2702 Label fast;
2703 // Check that the object is a smi or a heap number.
2704 __ JumpIfSmi(edx, &fast);
2705 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, eax);
2706 __ j(not_equal, &miss);
2707 __ bind(&fast);
2708 // Check that the maps starting from the prototype haven't changed.
2709 GenerateDirectLoadGlobalFunctionPrototype(
2710 masm(), Context::NUMBER_FUNCTION_INDEX, eax, &miss);
2711 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002712 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002713 eax, holder, ebx, edx, edi, name, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002714 break;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002715 }
2716 case BOOLEAN_CHECK: {
2717 Label fast;
2718 // Check that the object is a boolean.
2719 __ cmp(edx, factory()->true_value());
2720 __ j(equal, &fast);
2721 __ cmp(edx, factory()->false_value());
2722 __ j(not_equal, &miss);
2723 __ bind(&fast);
2724 // Check that the maps starting from the prototype haven't changed.
2725 GenerateDirectLoadGlobalFunctionPrototype(
2726 masm(), Context::BOOLEAN_FUNCTION_INDEX, eax, &miss);
2727 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002728 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002729 eax, holder, ebx, edx, edi, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002730 break;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002731 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002732 }
2733
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002734 __ jmp(success);
2735
2736 // Handle call cache miss.
2737 __ bind(&miss);
2738 GenerateMissBranch();
2739}
2740
2741
2742void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002743 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002744 ? CALL_AS_FUNCTION
2745 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002746 ParameterCount expected(function);
2747 __ InvokeFunction(function, expected, arguments(),
2748 JUMP_FUNCTION, NullCallWrapper(), call_kind);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002749}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002750
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002751
2752Handle<Code> CallStubCompiler::CompileCallConstant(
2753 Handle<Object> object,
2754 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002755 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002756 CheckType check,
2757 Handle<JSFunction> function) {
2758
2759 if (HasCustomCallGenerator(function)) {
2760 Handle<Code> code = CompileCustomCall(object, holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002761 Handle<Cell>::null(),
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002762 function, Handle<String>::cast(name),
2763 Code::CONSTANT_FUNCTION);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002764 // A null handle means bail out to the regular compiler code below.
2765 if (!code.is_null()) return code;
2766 }
2767
2768 Label success;
2769
2770 CompileHandlerFrontend(object, holder, name, check, &success);
2771 __ bind(&success);
2772 CompileHandlerBackend(function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002773
2774 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002775 return GetCode(function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002776}
2777
2778
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002779Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2780 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002781 Handle<Name> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002782 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00002783 // -- ecx : name
2784 // -- esp[0] : return address
2785 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2786 // -- ...
2787 // -- esp[(argc + 1) * 4] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002788 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002789 Label miss;
2790
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002791 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002792
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002793 // Get the number of arguments.
2794 const int argc = arguments().immediate();
2795
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002796 LookupResult lookup(isolate());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002797 LookupPostInterceptor(holder, name, &lookup);
2798
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002799 // Get the receiver from the stack.
2800 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002801
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002802 CallInterceptorCompiler compiler(this, arguments(), ecx, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002803 compiler.Compile(masm(), object, holder, name, &lookup, edx, ebx, edi, eax,
2804 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002805
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002806 // Restore receiver.
2807 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002808
2809 // Check that the function really is a function.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002810 __ JumpIfSmi(eax, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002811 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002812 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002813
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002814 // Patch the receiver on the stack with the global proxy if
2815 // necessary.
2816 if (object->IsGlobalObject()) {
2817 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
2818 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
2819 }
2820
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002821 // Invoke the function.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002822 __ mov(edi, eax);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002823 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002824 ? CALL_AS_FUNCTION
2825 : CALL_AS_METHOD;
2826 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION,
2827 NullCallWrapper(), call_kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002828
2829 // Handle load cache miss.
2830 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002831 GenerateMissBranch();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002832
2833 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002834 return GetCode(Code::INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002835}
2836
2837
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002838Handle<Code> CallStubCompiler::CompileCallGlobal(
2839 Handle<JSObject> object,
2840 Handle<GlobalObject> holder,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002841 Handle<PropertyCell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002842 Handle<JSFunction> function,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002843 Handle<Name> name) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002844 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00002845 // -- ecx : name
2846 // -- esp[0] : return address
2847 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2848 // -- ...
2849 // -- esp[(argc + 1) * 4] : receiver
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002850 // -----------------------------------
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002851
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002852 if (HasCustomCallGenerator(function)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00002853 Handle<Code> code = CompileCustomCall(
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002854 object, holder, cell, function, Handle<String>::cast(name),
2855 Code::NORMAL);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002856 // A null handle means bail out to the regular compiler code below.
2857 if (!code.is_null()) return code;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002858 }
2859
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002860 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002861 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002862
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002863 // Get the number of arguments.
2864 const int argc = arguments().immediate();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002865 GenerateGlobalReceiverCheck(object, holder, name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002866 GenerateLoadFunctionFromCell(cell, function, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002867
2868 // Patch the receiver on the stack with the global proxy.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002869 if (object->IsGlobalObject()) {
2870 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
2871 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
2872 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002873
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002874 // Set up the context (function already in edi).
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002875 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
2876
2877 // Jump to the cached code (tail call).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002878 Counters* counters = isolate()->counters();
2879 __ IncrementCounter(counters->call_global_inline(), 1);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002880 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002881 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002882 ? CALL_AS_FUNCTION
2883 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002884 // We call indirectly through the code field in the function to
2885 // allow recompilation to take effect without changing any of the
2886 // call sites.
2887 __ InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset),
2888 expected, arguments(), JUMP_FUNCTION,
2889 NullCallWrapper(), call_kind);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002890
2891 // Handle call cache miss.
2892 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002893 __ IncrementCounter(counters->call_global_inline_miss(), 1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002894 GenerateMissBranch();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002895
2896 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002897 return GetCode(Code::NORMAL, name);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002898}
2899
2900
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002901Handle<Code> StoreStubCompiler::CompileStoreCallback(
ulan@chromium.org750145a2013-03-07 15:14:13 +00002902 Handle<Name> name,
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002903 Handle<JSObject> object,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002904 Handle<JSObject> holder,
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002905 Handle<ExecutableAccessorInfo> callback) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002906 Label miss, miss_restore_name;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002907 // Check that the maps haven't changed, preserving the value register.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002908 __ JumpIfSmi(receiver(), &miss);
2909 CheckPrototypes(object, receiver(), holder,
2910 scratch1(), this->name(), scratch2(),
2911 name, &miss_restore_name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002912
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002913 // Stub never generated for non-global objects that require access checks.
2914 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002915
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002916 __ pop(scratch1()); // remove the return address
2917 __ push(receiver());
2918 __ Push(callback);
2919 __ Push(name);
2920 __ push(value());
2921 __ push(scratch1()); // restore return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002922
mads.s.ager31e71382008-08-13 09:32:07 +00002923 // Do tail-call to the runtime system.
2924 ExternalReference store_callback_property =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002925 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002926 __ TailCallExternalReference(store_callback_property, 4, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002927
2928 // Handle store cache miss.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002929 GenerateRestoreName(masm(), &miss_restore_name, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002930 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002931 TailCallBuiltin(masm(), MissBuiltin(kind()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002932
2933 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002934 return GetICCode(kind(), Code::CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002935}
2936
2937
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002938#undef __
2939#define __ ACCESS_MASM(masm)
2940
2941
2942void StoreStubCompiler::GenerateStoreViaSetter(
2943 MacroAssembler* masm,
2944 Handle<JSFunction> setter) {
2945 // ----------- S t a t e -------------
2946 // -- eax : value
2947 // -- ecx : name
2948 // -- edx : receiver
2949 // -- esp[0] : return address
2950 // -----------------------------------
2951 {
2952 FrameScope scope(masm, StackFrame::INTERNAL);
2953
2954 // Save value register, so we can restore it later.
2955 __ push(eax);
2956
2957 if (!setter.is_null()) {
2958 // Call the JavaScript setter with receiver and value on the stack.
2959 __ push(edx);
2960 __ push(eax);
2961 ParameterCount actual(1);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002962 ParameterCount expected(setter);
2963 __ InvokeFunction(setter, expected, actual,
2964 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002965 } else {
2966 // If we generate a global code snippet for deoptimization only, remember
2967 // the place to continue after deoptimization.
2968 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2969 }
2970
2971 // We have to return the passed value, not the return value of the setter.
2972 __ pop(eax);
2973
2974 // Restore context register.
2975 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
2976 }
2977 __ ret(0);
2978}
2979
2980
2981#undef __
2982#define __ ACCESS_MASM(masm())
2983
2984
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002985Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002986 Handle<JSObject> object,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002987 Handle<Name> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002988 Label miss;
2989
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002990 // Check that the map of the object hasn't changed.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002991 __ CheckMap(receiver(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002992
2993 // Perform global security token check if needed.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002994 if (object->IsJSGlobalProxy()) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002995 __ CheckAccessGlobalProxy(receiver(), scratch1(), scratch2(), &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002996 }
2997
2998 // Stub never generated for non-global objects that require access
2999 // checks.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003000 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003001
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003002 __ pop(scratch1()); // remove the return address
3003 __ push(receiver());
3004 __ push(this->name());
3005 __ push(value());
3006 __ push(Immediate(Smi::FromInt(strict_mode())));
3007 __ push(scratch1()); // restore return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003008
mads.s.ager31e71382008-08-13 09:32:07 +00003009 // Do tail-call to the runtime system.
3010 ExternalReference store_ic_property =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003011 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003012 __ TailCallExternalReference(store_ic_property, 4, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003013
3014 // Handle store cache miss.
3015 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003016 TailCallBuiltin(masm(), MissBuiltin(kind()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003017
3018 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003019 return GetICCode(kind(), Code::INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003020}
3021
3022
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003023Handle<Code> StoreStubCompiler::CompileStoreGlobal(
3024 Handle<GlobalObject> object,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00003025 Handle<PropertyCell> cell,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003026 Handle<Name> name) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003027 Label miss;
3028
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003029 // Check that the map of the global has not changed.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003030 __ cmp(FieldOperand(receiver(), HeapObject::kMapOffset),
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003031 Immediate(Handle<Map>(object->map())));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003032 __ j(not_equal, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003033
ager@chromium.org378b34e2011-01-28 08:04:38 +00003034 // Compute the cell operand to use.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003035 __ mov(scratch1(), Immediate(cell));
3036 Operand cell_operand =
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00003037 FieldOperand(scratch1(), PropertyCell::kValueOffset);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003038
ager@chromium.org378b34e2011-01-28 08:04:38 +00003039 // Check that the value in the cell is not the hole. If it is, this
3040 // cell could have been deleted and reintroducing the global needs
3041 // to update the property details in the property dictionary of the
3042 // global object. We bail out to the runtime system to do that.
lrn@chromium.org7516f052011-03-30 08:52:27 +00003043 __ cmp(cell_operand, factory()->the_hole_value());
ager@chromium.org378b34e2011-01-28 08:04:38 +00003044 __ j(equal, &miss);
3045
3046 // Store the value in the cell.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003047 __ mov(cell_operand, value());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003048 // No write barrier here, because cells are always rescanned.
ager@chromium.org378b34e2011-01-28 08:04:38 +00003049
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003050 // Return the value (register eax).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003051 Counters* counters = isolate()->counters();
3052 __ IncrementCounter(counters->named_store_global_inline(), 1);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003053 __ ret(0);
3054
3055 // Handle store cache miss.
3056 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003057 __ IncrementCounter(counters->named_store_global_inline_miss(), 1);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003058 TailCallBuiltin(masm(), MissBuiltin(kind()));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003059
3060 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003061 return GetICCode(kind(), Code::NORMAL, name);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003062}
3063
3064
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003065Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
3066 MapHandleList* receiver_maps,
3067 CodeHandleList* handler_stubs,
3068 MapHandleList* transitioned_maps) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003069 Label miss;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003070 __ JumpIfSmi(receiver(), &miss, Label::kNear);
3071 __ mov(scratch1(), FieldOperand(receiver(), HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003072 for (int i = 0; i < receiver_maps->length(); ++i) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003073 __ cmp(scratch1(), receiver_maps->at(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003074 if (transitioned_maps->at(i).is_null()) {
3075 __ j(equal, handler_stubs->at(i));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003076 } else {
3077 Label next_map;
3078 __ j(not_equal, &next_map, Label::kNear);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003079 __ mov(transition_map(), Immediate(transitioned_maps->at(i)));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003080 __ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003081 __ bind(&next_map);
3082 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003083 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003084 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003085 TailCallBuiltin(masm(), MissBuiltin(kind()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003086
3087 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003088 return GetICCode(
3089 kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003090}
3091
3092
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00003093Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00003094 Handle<JSObject> object,
3095 Handle<JSObject> last,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003096 Handle<Name> name,
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00003097 Handle<GlobalObject> global) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003098 Label success;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00003099
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003100 NonexistentHandlerFrontend(object, last, name, &success, global);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00003101
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003102 __ bind(&success);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00003103 // Return undefined if maps of the full prototype chain are still the
3104 // same and no global property with this name contains a value.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003105 __ mov(eax, isolate()->factory()->undefined_value());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00003106 __ ret(0);
3107
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00003108 // Return the generated code.
ulan@chromium.org750145a2013-03-07 15:14:13 +00003109 return GetCode(kind(), Code::NONEXISTENT, name);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00003110}
3111
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003112
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00003113Register* LoadStubCompiler::registers() {
3114 // receiver, name, scratch1, scratch2, scratch3, scratch4.
3115 static Register registers[] = { edx, ecx, ebx, eax, edi, no_reg };
3116 return registers;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003117}
3118
3119
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00003120Register* KeyedLoadStubCompiler::registers() {
3121 // receiver, name, scratch1, scratch2, scratch3, scratch4.
3122 static Register registers[] = { edx, ecx, ebx, eax, edi, no_reg };
3123 return registers;
3124}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003125
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003126
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003127Register* StoreStubCompiler::registers() {
3128 // receiver, name, value, scratch1, scratch2, scratch3.
3129 static Register registers[] = { edx, ecx, eax, ebx, edi, no_reg };
3130 return registers;
3131}
3132
3133
3134Register* KeyedStoreStubCompiler::registers() {
3135 // receiver, name, value, scratch1, scratch2, scratch3.
3136 static Register registers[] = { edx, ecx, eax, ebx, edi, no_reg };
3137 return registers;
3138}
3139
3140
ulan@chromium.org750145a2013-03-07 15:14:13 +00003141void KeyedLoadStubCompiler::GenerateNameCheck(Handle<Name> name,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00003142 Register name_reg,
3143 Label* miss) {
3144 __ cmp(name_reg, Immediate(name));
3145 __ j(not_equal, miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003146}
3147
3148
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003149void KeyedStoreStubCompiler::GenerateNameCheck(Handle<Name> name,
3150 Register name_reg,
3151 Label* miss) {
3152 __ cmp(name_reg, Immediate(name));
3153 __ j(not_equal, miss);
3154}
3155
3156
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003157#undef __
3158#define __ ACCESS_MASM(masm)
3159
3160
3161void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
3162 Handle<JSFunction> getter) {
3163 // ----------- S t a t e -------------
3164 // -- ecx : name
3165 // -- edx : receiver
3166 // -- esp[0] : return address
3167 // -----------------------------------
3168 {
3169 FrameScope scope(masm, StackFrame::INTERNAL);
3170
3171 if (!getter.is_null()) {
3172 // Call the JavaScript getter with the receiver on the stack.
3173 __ push(edx);
3174 ParameterCount actual(0);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003175 ParameterCount expected(getter);
3176 __ InvokeFunction(getter, expected, actual,
3177 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003178 } else {
3179 // If we generate a global code snippet for deoptimization only, remember
3180 // the place to continue after deoptimization.
3181 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
3182 }
3183
3184 // Restore context register.
3185 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
3186 }
3187 __ ret(0);
3188}
3189
3190
3191#undef __
3192#define __ ACCESS_MASM(masm())
3193
3194
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003195Handle<Code> LoadStubCompiler::CompileLoadGlobal(
3196 Handle<JSObject> object,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003197 Handle<GlobalObject> global,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00003198 Handle<PropertyCell> cell,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003199 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003200 bool is_dont_delete) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003201 Label success, miss;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003202
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003203 __ CheckMap(receiver(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
3204 HandlerFrontendHeader(
3205 object, receiver(), Handle<JSObject>::cast(global), name, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003206 // Get the value from the cell.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003207 if (Serializer::enabled()) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003208 __ mov(eax, Immediate(cell));
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00003209 __ mov(eax, FieldOperand(eax, PropertyCell::kValueOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003210 } else {
danno@chromium.org41728482013-06-12 22:31:22 +00003211 __ mov(eax, Operand::ForCell(cell));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003212 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003213
3214 // Check for deleted property if property can actually be deleted.
3215 if (!is_dont_delete) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003216 __ cmp(eax, factory()->the_hole_value());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003217 __ j(equal, &miss);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003218 } else if (FLAG_debug_code) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003219 __ cmp(eax, factory()->the_hole_value());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003220 __ Check(not_equal, "DontDelete cells can't contain the hole");
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003221 }
3222
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003223 HandlerFrontendFooter(&success, &miss);
3224 __ bind(&success);
3225
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003226 Counters* counters = isolate()->counters();
3227 __ IncrementCounter(counters->named_load_global_stub(), 1);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003228 // The code above already loads the result into the return register.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003229 __ ret(0);
3230
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003231 // Return the generated code.
ulan@chromium.org750145a2013-03-07 15:14:13 +00003232 return GetICCode(kind(), Code::NORMAL, name);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003233}
3234
3235
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003236Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003237 MapHandleList* receiver_maps,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003238 CodeHandleList* handlers,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003239 Handle<Name> name,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003240 Code::StubType type,
3241 IcCheckType check) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003242 Label miss;
3243
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003244 if (check == PROPERTY) {
3245 GenerateNameCheck(name, this->name(), &miss);
3246 }
3247
3248 __ JumpIfSmi(receiver(), &miss);
3249 Register map_reg = scratch1();
3250 __ mov(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset));
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003251 int receiver_count = receiver_maps->length();
danno@chromium.orgf005df62013-04-30 16:36:45 +00003252 int number_of_handled_maps = 0;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003253 for (int current = 0; current < receiver_count; ++current) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00003254 Handle<Map> map = receiver_maps->at(current);
3255 if (!map->is_deprecated()) {
3256 number_of_handled_maps++;
3257 __ cmp(map_reg, map);
3258 __ j(equal, handlers->at(current));
3259 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003260 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00003261 ASSERT(number_of_handled_maps != 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003262
3263 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003264 TailCallBuiltin(masm(), MissBuiltin(kind()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003265
3266 // Return the generated code.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003267 InlineCacheState state =
danno@chromium.orgf005df62013-04-30 16:36:45 +00003268 number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC;
ulan@chromium.org750145a2013-03-07 15:14:13 +00003269 return GetICCode(kind(), type, name, state);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003270}
3271
3272
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003273#undef __
3274#define __ ACCESS_MASM(masm)
3275
3276
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003277void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3278 MacroAssembler* masm) {
3279 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003280 // -- ecx : key
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003281 // -- edx : receiver
3282 // -- esp[0] : return address
3283 // -----------------------------------
3284 Label slow, miss_force_generic;
3285
3286 // This stub is meant to be tail-jumped to, the receiver must already
3287 // have been verified by the caller to not be a smi.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003288 __ JumpIfNotSmi(ecx, &miss_force_generic);
3289 __ mov(ebx, ecx);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003290 __ SmiUntag(ebx);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003291 __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset));
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003292
3293 // Push receiver on the stack to free up a register for the dictionary
3294 // probing.
3295 __ push(edx);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003296 __ LoadFromNumberDictionary(&slow, eax, ecx, ebx, edx, edi, eax);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003297 // Pop receiver before returning.
3298 __ pop(edx);
3299 __ ret(0);
3300
3301 __ bind(&slow);
3302 __ pop(edx);
3303
3304 // ----------- S t a t e -------------
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003305 // -- ecx : key
3306 // -- edx : receiver
3307 // -- esp[0] : return address
3308 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003309 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003310
3311 __ bind(&miss_force_generic);
3312 // ----------- S t a t e -------------
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003313 // -- ecx : key
3314 // -- edx : receiver
3315 // -- esp[0] : return address
3316 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003317 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_MissForceGeneric);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003318}
3319
3320
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003321static void GenerateSmiKeyCheck(MacroAssembler* masm,
3322 Register key,
3323 Register scratch,
3324 XMMRegister xmm_scratch0,
3325 XMMRegister xmm_scratch1,
3326 Label* fail) {
3327 // Check that key is a smi and if SSE2 is available a heap number
3328 // containing a smi and branch if the check fails.
3329 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003330 CpuFeatureScope use_sse2(masm, SSE2);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003331 Label key_ok;
3332 __ JumpIfSmi(key, &key_ok);
3333 __ cmp(FieldOperand(key, HeapObject::kMapOffset),
3334 Immediate(Handle<Map>(masm->isolate()->heap()->heap_number_map())));
3335 __ j(not_equal, fail);
3336 __ movdbl(xmm_scratch0, FieldOperand(key, HeapNumber::kValueOffset));
3337 __ cvttsd2si(scratch, Operand(xmm_scratch0));
3338 __ cvtsi2sd(xmm_scratch1, scratch);
3339 __ ucomisd(xmm_scratch1, xmm_scratch0);
3340 __ j(not_equal, fail);
3341 __ j(parity_even, fail); // NaN.
3342 // Check if the key fits in the smi range.
3343 __ cmp(scratch, 0xc0000000);
3344 __ j(sign, fail);
3345 __ SmiTag(scratch);
3346 __ mov(key, scratch);
3347 __ bind(&key_ok);
3348 } else {
3349 __ JumpIfNotSmi(key, fail);
3350 }
3351}
3352
3353
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003354void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3355 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003356 ElementsKind elements_kind) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003357 // ----------- S t a t e -------------
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003358 // -- eax : value
3359 // -- ecx : key
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003360 // -- edx : receiver
3361 // -- esp[0] : return address
3362 // -----------------------------------
3363 Label miss_force_generic, slow, check_heap_number;
3364
3365 // This stub is meant to be tail-jumped to, the receiver must already
3366 // have been verified by the caller to not be a smi.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003367
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003368 // Check that the key is a smi or a heap number convertible to a smi.
3369 GenerateSmiKeyCheck(masm, ecx, ebx, xmm0, xmm1, &miss_force_generic);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003370
3371 // Check that the index is in range.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003372 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003373 __ cmp(ecx, FieldOperand(edi, ExternalArray::kLengthOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003374 // Unsigned comparison catches both negative and too-large values.
3375 __ j(above_equal, &slow);
3376
3377 // Handle both smis and HeapNumbers in the fast path. Go to the
3378 // runtime for all other kinds of values.
3379 // eax: value
3380 // edx: receiver
3381 // ecx: key
3382 // edi: elements array
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003383 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00003384 __ JumpIfNotSmi(eax, &slow);
3385 } else {
3386 __ JumpIfNotSmi(eax, &check_heap_number);
3387 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003388
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003389 // smi case
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003390 __ mov(ebx, eax); // Preserve the value in eax as the return value.
3391 __ SmiUntag(ebx);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003392 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003393 // edi: base pointer of external storage
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003394 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003395 case EXTERNAL_PIXEL_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003396 __ ClampUint8(ebx);
3397 __ SmiUntag(ecx);
3398 __ mov_b(Operand(edi, ecx, times_1, 0), ebx);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003399 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003400 case EXTERNAL_BYTE_ELEMENTS:
3401 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003402 __ SmiUntag(ecx);
3403 __ mov_b(Operand(edi, ecx, times_1, 0), ebx);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003404 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003405 case EXTERNAL_SHORT_ELEMENTS:
3406 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003407 __ mov_w(Operand(edi, ecx, times_1, 0), ebx);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003408 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003409 case EXTERNAL_INT_ELEMENTS:
3410 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003411 __ mov(Operand(edi, ecx, times_2, 0), ebx);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003412 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003413 case EXTERNAL_FLOAT_ELEMENTS:
3414 case EXTERNAL_DOUBLE_ELEMENTS:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003415 // Need to perform int-to-float conversion.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003416 __ push(ebx);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003417 __ fild_s(Operand(esp, 0));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003418 __ pop(ebx);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003419 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003420 __ fstp_s(Operand(edi, ecx, times_2, 0));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003421 } else { // elements_kind == EXTERNAL_DOUBLE_ELEMENTS.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003422 __ fstp_d(Operand(edi, ecx, times_4, 0));
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003423 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003424 break;
3425 default:
3426 UNREACHABLE();
3427 break;
3428 }
3429 __ ret(0); // Return the original value.
3430
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003431 // TODO(danno): handle heap number -> pixel array conversion
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003432 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003433 __ bind(&check_heap_number);
3434 // eax: value
3435 // edx: receiver
3436 // ecx: key
3437 // edi: elements array
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003438 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003439 Immediate(masm->isolate()->factory()->heap_number_map()));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003440 __ j(not_equal, &slow);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003441
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003442 // The WebGL specification leaves the behavior of storing NaN and
3443 // +/-Infinity into integer arrays basically undefined. For more
3444 // reproducible behavior, convert these to zero.
3445 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003446 // edi: base pointer of external storage
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003447 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003448 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003449 __ fstp_s(Operand(edi, ecx, times_2, 0));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003450 __ ret(0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003451 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003452 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003453 __ fstp_d(Operand(edi, ecx, times_4, 0));
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003454 __ ret(0);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003455 } else {
3456 // Perform float-to-int conversion with truncation (round-to-zero)
3457 // behavior.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003458
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003459 // For the moment we make the slow call to the runtime on
3460 // processors that don't support SSE2. The code in IntegerConvert
3461 // (code-stubs-ia32.cc) is roughly what is needed here though the
3462 // conversion failure case does not need to be handled.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003463 if (CpuFeatures::IsSupported(SSE2)) {
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003464 if ((elements_kind == EXTERNAL_INT_ELEMENTS ||
3465 elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) &&
3466 CpuFeatures::IsSupported(SSE3)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003467 CpuFeatureScope scope(masm, SSE3);
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003468 // fisttp stores values as signed integers. To represent the
3469 // entire range of int and unsigned int arrays, store as a
3470 // 64-bit int and discard the high 32 bits.
3471 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
3472 __ sub(esp, Immediate(2 * kPointerSize));
3473 __ fisttp_d(Operand(esp, 0));
3474
3475 // If conversion failed (NaN, infinity, or a number outside
3476 // signed int64 range), the result is 0x8000000000000000, and
3477 // we must handle this case in the runtime.
3478 Label ok;
3479 __ cmp(Operand(esp, kPointerSize), Immediate(0x80000000u));
3480 __ j(not_equal, &ok);
3481 __ cmp(Operand(esp, 0), Immediate(0));
3482 __ j(not_equal, &ok);
3483 __ add(esp, Immediate(2 * kPointerSize)); // Restore the stack.
3484 __ jmp(&slow);
3485
3486 __ bind(&ok);
3487 __ pop(ebx);
3488 __ add(esp, Immediate(kPointerSize));
3489 __ mov(Operand(edi, ecx, times_2, 0), ebx);
3490 } else {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003491 ASSERT(CpuFeatures::IsSupported(SSE2));
ulan@chromium.org750145a2013-03-07 15:14:13 +00003492 CpuFeatureScope scope(masm, SSE2);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003493 __ cvttsd2si(ebx, FieldOperand(eax, HeapNumber::kValueOffset));
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003494 __ cmp(ebx, 0x80000000u);
3495 __ j(equal, &slow);
3496 // ebx: untagged integer value
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003497 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003498 case EXTERNAL_PIXEL_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003499 __ ClampUint8(ebx);
3500 // Fall through.
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003501 case EXTERNAL_BYTE_ELEMENTS:
3502 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003503 __ SmiUntag(ecx);
3504 __ mov_b(Operand(edi, ecx, times_1, 0), ebx);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003505 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003506 case EXTERNAL_SHORT_ELEMENTS:
3507 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003508 __ mov_w(Operand(edi, ecx, times_1, 0), ebx);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003509 break;
danno@chromium.org2c26cb12012-05-03 09:06:43 +00003510 case EXTERNAL_INT_ELEMENTS:
3511 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3512 __ mov(Operand(edi, ecx, times_2, 0), ebx);
3513 break;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003514 default:
3515 UNREACHABLE();
3516 break;
3517 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003518 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003519 __ ret(0); // Return original value.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003520 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003521 }
3522 }
3523
3524 // Slow case: call runtime.
3525 __ bind(&slow);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003526 Counters* counters = masm->isolate()->counters();
3527 __ IncrementCounter(counters->keyed_store_external_array_slow(), 1);
3528
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003529 // ----------- S t a t e -------------
3530 // -- eax : value
3531 // -- ecx : key
3532 // -- edx : receiver
3533 // -- esp[0] : return address
3534 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003535 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003536
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003537 // ----------- S t a t e -------------
3538 // -- eax : value
3539 // -- ecx : key
3540 // -- edx : receiver
3541 // -- esp[0] : return address
3542 // -----------------------------------
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003543
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003544 __ bind(&miss_force_generic);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003545 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003546}
3547
3548
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003549void KeyedStoreStubCompiler::GenerateStoreFastElement(
3550 MacroAssembler* masm,
3551 bool is_js_array,
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003552 ElementsKind elements_kind,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003553 KeyedAccessStoreMode store_mode) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003554 // ----------- S t a t e -------------
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003555 // -- eax : value
3556 // -- ecx : key
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003557 // -- edx : receiver
3558 // -- esp[0] : return address
3559 // -----------------------------------
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003560 Label miss_force_generic, grow, slow, transition_elements_kind;
3561 Label check_capacity, prepare_slow, finish_store, commit_backing_store;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003562
3563 // This stub is meant to be tail-jumped to, the receiver must already
3564 // have been verified by the caller to not be a smi.
3565
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003566 // Check that the key is a smi or a heap number convertible to a smi.
3567 GenerateSmiKeyCheck(masm, ecx, ebx, xmm0, xmm1, &miss_force_generic);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003568
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003569 if (IsFastSmiElementsKind(elements_kind)) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003570 __ JumpIfNotSmi(eax, &transition_elements_kind);
3571 }
3572
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003573 // Get the elements array and make sure it is a fast element array, not 'cow'.
3574 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003575 if (is_js_array) {
3576 // Check that the key is within bounds.
3577 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // smis.
ulan@chromium.org750145a2013-03-07 15:14:13 +00003578 if (IsGrowStoreMode(store_mode)) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003579 __ j(above_equal, &grow);
3580 } else {
3581 __ j(above_equal, &miss_force_generic);
3582 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003583 } else {
3584 // Check that the key is within bounds.
3585 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); // smis.
3586 __ j(above_equal, &miss_force_generic);
3587 }
3588
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003589 __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
3590 Immediate(masm->isolate()->factory()->fixed_array_map()));
3591 __ j(not_equal, &miss_force_generic);
3592
3593 __ bind(&finish_store);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003594 if (IsFastSmiElementsKind(elements_kind)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003595 // ecx is a smi, use times_half_pointer_size instead of
3596 // times_pointer_size
3597 __ mov(FieldOperand(edi,
3598 ecx,
3599 times_half_pointer_size,
3600 FixedArray::kHeaderSize), eax);
3601 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003602 ASSERT(IsFastObjectElementsKind(elements_kind));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003603 // Do the store and update the write barrier.
3604 // ecx is a smi, use times_half_pointer_size instead of
3605 // times_pointer_size
3606 __ lea(ecx, FieldOperand(edi,
3607 ecx,
3608 times_half_pointer_size,
3609 FixedArray::kHeaderSize));
3610 __ mov(Operand(ecx, 0), eax);
3611 // Make sure to preserve the value in register eax.
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003612 __ mov(ebx, eax);
3613 __ RecordWrite(edi, ecx, ebx, kDontSaveFPRegs);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003614 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003615
3616 // Done.
3617 __ ret(0);
3618
3619 // Handle store cache miss, replacing the ic with the generic stub.
3620 __ bind(&miss_force_generic);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003621 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003622
3623 // Handle transition to other elements kinds without using the generic stub.
3624 __ bind(&transition_elements_kind);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003625 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003626
ulan@chromium.org750145a2013-03-07 15:14:13 +00003627 if (is_js_array && IsGrowStoreMode(store_mode)) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003628 // Handle transition requiring the array to grow.
3629 __ bind(&grow);
3630
3631 // Make sure the array is only growing by a single element, anything else
3632 // must be handled by the runtime. Flags are already set by previous
3633 // compare.
3634 __ j(not_equal, &miss_force_generic);
3635
3636 // Check for the empty array, and preallocate a small backing store if
3637 // possible.
3638 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
3639 __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array()));
3640 __ j(not_equal, &check_capacity);
3641
3642 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003643 __ Allocate(size, edi, ebx, ecx, &prepare_slow, TAG_OBJECT);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003644 // Restore the key, which is known to be the array length.
3645
3646 // eax: value
3647 // ecx: key
3648 // edx: receiver
3649 // edi: elements
3650 // Make sure that the backing store can hold additional elements.
3651 __ mov(FieldOperand(edi, JSObject::kMapOffset),
3652 Immediate(masm->isolate()->factory()->fixed_array_map()));
3653 __ mov(FieldOperand(edi, FixedArray::kLengthOffset),
3654 Immediate(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
3655 __ mov(ebx, Immediate(masm->isolate()->factory()->the_hole_value()));
3656 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
3657 __ mov(FieldOperand(edi, FixedArray::SizeFor(i)), ebx);
3658 }
3659
3660 // Store the element at index zero.
3661 __ mov(FieldOperand(edi, FixedArray::SizeFor(0)), eax);
3662
3663 // Install the new backing store in the JSArray.
3664 __ mov(FieldOperand(edx, JSObject::kElementsOffset), edi);
3665 __ RecordWriteField(edx, JSObject::kElementsOffset, edi, ebx,
3666 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3667
3668 // Increment the length of the array.
3669 __ mov(FieldOperand(edx, JSArray::kLengthOffset),
3670 Immediate(Smi::FromInt(1)));
3671 __ ret(0);
3672
3673 __ bind(&check_capacity);
3674 __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
3675 Immediate(masm->isolate()->factory()->fixed_cow_array_map()));
3676 __ j(equal, &miss_force_generic);
3677
3678 // eax: value
3679 // ecx: key
3680 // edx: receiver
3681 // edi: elements
3682 // Make sure that the backing store can hold additional elements.
3683 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
3684 __ j(above_equal, &slow);
3685
3686 // Grow the array and finish the store.
3687 __ add(FieldOperand(edx, JSArray::kLengthOffset),
3688 Immediate(Smi::FromInt(1)));
3689 __ jmp(&finish_store);
3690
3691 __ bind(&prepare_slow);
3692 // Restore the key, which is known to be the array length.
3693 __ mov(ecx, Immediate(0));
3694
3695 __ bind(&slow);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003696 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003697 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003698}
3699
3700
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003701void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
3702 MacroAssembler* masm,
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003703 bool is_js_array,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003704 KeyedAccessStoreMode store_mode) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003705 // ----------- S t a t e -------------
3706 // -- eax : value
3707 // -- ecx : key
3708 // -- edx : receiver
3709 // -- esp[0] : return address
3710 // -----------------------------------
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003711 Label miss_force_generic, transition_elements_kind, grow, slow;
3712 Label check_capacity, prepare_slow, finish_store, commit_backing_store;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003713
3714 // This stub is meant to be tail-jumped to, the receiver must already
3715 // have been verified by the caller to not be a smi.
3716
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003717 // Check that the key is a smi or a heap number convertible to a smi.
3718 GenerateSmiKeyCheck(masm, ecx, ebx, xmm0, xmm1, &miss_force_generic);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003719
3720 // Get the elements array.
3721 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
3722 __ AssertFastElements(edi);
3723
3724 if (is_js_array) {
3725 // Check that the key is within bounds.
3726 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // smis.
ulan@chromium.org750145a2013-03-07 15:14:13 +00003727 if (IsGrowStoreMode(store_mode)) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003728 __ j(above_equal, &grow);
3729 } else {
3730 __ j(above_equal, &miss_force_generic);
3731 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003732 } else {
3733 // Check that the key is within bounds.
3734 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); // smis.
yangguo@chromium.org56454712012-02-16 15:33:53 +00003735 __ j(above_equal, &miss_force_generic);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003736 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003737
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003738 __ bind(&finish_store);
3739 __ StoreNumberToDoubleElements(eax, edi, ecx, edx, xmm0,
3740 &transition_elements_kind, true);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003741 __ ret(0);
3742
3743 // Handle store cache miss, replacing the ic with the generic stub.
3744 __ bind(&miss_force_generic);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003745 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003746
3747 // Handle transition to other elements kinds without using the generic stub.
3748 __ bind(&transition_elements_kind);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003749 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003750
ulan@chromium.org750145a2013-03-07 15:14:13 +00003751 if (is_js_array && IsGrowStoreMode(store_mode)) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003752 // Handle transition requiring the array to grow.
3753 __ bind(&grow);
3754
3755 // Make sure the array is only growing by a single element, anything else
3756 // must be handled by the runtime. Flags are already set by previous
3757 // compare.
3758 __ j(not_equal, &miss_force_generic);
3759
3760 // Transition on values that can't be stored in a FixedDoubleArray.
3761 Label value_is_smi;
3762 __ JumpIfSmi(eax, &value_is_smi);
3763 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
3764 Immediate(Handle<Map>(masm->isolate()->heap()->heap_number_map())));
3765 __ j(not_equal, &transition_elements_kind);
3766 __ bind(&value_is_smi);
3767
3768 // Check for the empty array, and preallocate a small backing store if
3769 // possible.
3770 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
3771 __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array()));
3772 __ j(not_equal, &check_capacity);
3773
3774 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003775 __ Allocate(size, edi, ebx, ecx, &prepare_slow, TAG_OBJECT);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003776
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003777 // Restore the key, which is known to be the array length.
3778 __ mov(ecx, Immediate(0));
3779
3780 // eax: value
3781 // ecx: key
3782 // edx: receiver
3783 // edi: elements
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003784 // Initialize the new FixedDoubleArray.
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003785 __ mov(FieldOperand(edi, JSObject::kMapOffset),
3786 Immediate(masm->isolate()->factory()->fixed_double_array_map()));
3787 __ mov(FieldOperand(edi, FixedDoubleArray::kLengthOffset),
3788 Immediate(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
3789
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003790 __ StoreNumberToDoubleElements(eax, edi, ecx, ebx, xmm0,
3791 &transition_elements_kind, true);
3792
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003793 for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) {
3794 int offset = FixedDoubleArray::OffsetOfElementAt(i);
3795 __ mov(FieldOperand(edi, offset), Immediate(kHoleNanLower32));
3796 __ mov(FieldOperand(edi, offset + kPointerSize),
3797 Immediate(kHoleNanUpper32));
3798 }
3799
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003800 // Install the new backing store in the JSArray.
3801 __ mov(FieldOperand(edx, JSObject::kElementsOffset), edi);
3802 __ RecordWriteField(edx, JSObject::kElementsOffset, edi, ebx,
3803 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3804
3805 // Increment the length of the array.
3806 __ add(FieldOperand(edx, JSArray::kLengthOffset),
3807 Immediate(Smi::FromInt(1)));
yangguo@chromium.org56454712012-02-16 15:33:53 +00003808 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003809 __ ret(0);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003810
3811 __ bind(&check_capacity);
3812 // eax: value
3813 // ecx: key
3814 // edx: receiver
3815 // edi: elements
3816 // Make sure that the backing store can hold additional elements.
3817 __ cmp(ecx, FieldOperand(edi, FixedDoubleArray::kLengthOffset));
3818 __ j(above_equal, &slow);
3819
3820 // Grow the array and finish the store.
3821 __ add(FieldOperand(edx, JSArray::kLengthOffset),
3822 Immediate(Smi::FromInt(1)));
3823 __ jmp(&finish_store);
3824
3825 __ bind(&prepare_slow);
3826 // Restore the key, which is known to be the array length.
3827 __ mov(ecx, Immediate(0));
3828
3829 __ bind(&slow);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003830 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003831 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003832}
3833
3834
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003835#undef __
3836
3837} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003838
3839#endif // V8_TARGET_ARCH_IA32