blob: 5bccea76971cb98718c7d4b0233577065a0af6ee [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
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000030#if V8_TARGET_ARCH_IA32
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000031
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,
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000332 Label* miss) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000333 Label check_wrapper;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000334
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000335 // Check if the object is a string leaving the instance type in the
336 // scratch register.
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000337 GenerateStringCheck(masm, receiver, scratch1, miss, &check_wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000338
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000339 // Load length from the string and convert to a smi.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000340 __ mov(eax, FieldOperand(receiver, String::kLengthOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000341 __ ret(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000342
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000343 // Check if the object is a JSValue wrapper.
344 __ bind(&check_wrapper);
345 __ cmp(scratch1, JS_VALUE_TYPE);
346 __ j(not_equal, miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000347
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000348 // Check if the wrapped value is a string and load the length
349 // directly if it is.
350 __ mov(scratch2, FieldOperand(receiver, JSValue::kValueOffset));
351 GenerateStringCheck(masm, scratch2, scratch1, miss, miss);
352 __ mov(eax, FieldOperand(scratch2, String::kLengthOffset));
353 __ ret(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000354}
355
356
357void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
358 Register receiver,
359 Register scratch1,
360 Register scratch2,
361 Label* miss_label) {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000362 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000363 __ mov(eax, scratch1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000364 __ ret(0);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000365}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000366
ager@chromium.org7c537e22008-10-16 08:43:32 +0000367
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000368void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
369 Register dst,
370 Register src,
371 bool inobject,
372 int index,
373 Representation representation) {
374 ASSERT(!FLAG_track_double_fields || !representation.IsDouble());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000375 int offset = index * kPointerSize;
376 if (!inobject) {
377 // Calculate the offset into the properties array.
378 offset = offset + FixedArray::kHeaderSize;
379 __ mov(dst, FieldOperand(src, JSObject::kPropertiesOffset));
380 src = dst;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000381 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000382 __ mov(dst, FieldOperand(src, offset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000383}
384
385
ager@chromium.org5c838252010-02-19 08:53:10 +0000386static void PushInterceptorArguments(MacroAssembler* masm,
387 Register receiver,
388 Register holder,
389 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000390 Handle<JSObject> holder_obj) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000391 STATIC_ASSERT(StubCache::kInterceptorArgsNameIndex == 0);
392 STATIC_ASSERT(StubCache::kInterceptorArgsInfoIndex == 1);
393 STATIC_ASSERT(StubCache::kInterceptorArgsThisIndex == 2);
394 STATIC_ASSERT(StubCache::kInterceptorArgsHolderIndex == 3);
395 STATIC_ASSERT(StubCache::kInterceptorArgsLength == 4);
ager@chromium.org5c838252010-02-19 08:53:10 +0000396 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000397 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
398 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000399 Register scratch = name;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000400 __ mov(scratch, Immediate(interceptor));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000401 __ push(scratch);
ager@chromium.org5c838252010-02-19 08:53:10 +0000402 __ push(receiver);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000403 __ push(holder);
ager@chromium.org5c838252010-02-19 08:53:10 +0000404}
405
406
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000407static void CompileCallLoadPropertyWithInterceptor(
408 MacroAssembler* masm,
409 Register receiver,
410 Register holder,
411 Register name,
412 Handle<JSObject> holder_obj) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000413 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
ager@chromium.org5c838252010-02-19 08:53:10 +0000414 __ CallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000415 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
416 masm->isolate()),
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000417 StubCache::kInterceptorArgsLength);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000418}
419
420
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000421// Number of pointers to be reserved on stack for fast API call.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000422static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength;
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000423
424
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000425// Reserves space for the extra arguments to API function in the
ager@chromium.org5c838252010-02-19 08:53:10 +0000426// caller's frame.
427//
428// These arguments are set by CheckPrototypes and GenerateFastApiCall.
429static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
430 // ----------- S t a t e -------------
431 // -- esp[0] : return address
432 // -- esp[4] : last argument in the internal frame of the caller
433 // -----------------------------------
434 __ pop(scratch);
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000435 for (int i = 0; i < kFastApiCallArguments; i++) {
436 __ push(Immediate(Smi::FromInt(0)));
437 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000438 __ push(scratch);
439}
440
441
442// Undoes the effects of ReserveSpaceForFastApiCall.
443static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
444 // ----------- S t a t e -------------
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000445 // -- esp[0] : return address.
446 // -- esp[4] : last fast api call extra argument.
ager@chromium.org5c838252010-02-19 08:53:10 +0000447 // -- ...
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000448 // -- esp[kFastApiCallArguments * 4] : first fast api call extra argument.
449 // -- esp[kFastApiCallArguments * 4 + 4] : last argument in the internal
450 // frame.
ager@chromium.org5c838252010-02-19 08:53:10 +0000451 // -----------------------------------
452 __ pop(scratch);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000453 __ add(esp, Immediate(kPointerSize * kFastApiCallArguments));
ager@chromium.org5c838252010-02-19 08:53:10 +0000454 __ push(scratch);
455}
456
457
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000458// Generates call to API function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000459static void GenerateFastApiCall(MacroAssembler* masm,
460 const CallOptimization& optimization,
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000461 int argc,
462 bool restore_context) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000463 // ----------- S t a t e -------------
464 // -- esp[0] : return address
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +0000465 // -- esp[4] - esp[28] : FunctionCallbackInfo, incl.
466 // : object passing the type check
467 // (set by CheckPrototypes)
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000468 // -- esp[32] : last argument
ager@chromium.org5c838252010-02-19 08:53:10 +0000469 // -- ...
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000470 // -- esp[(argc + 7) * 4] : first argument
471 // -- esp[(argc + 8) * 4] : receiver
ager@chromium.org5c838252010-02-19 08:53:10 +0000472 // -----------------------------------
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000473
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +0000474 typedef FunctionCallbackArguments FCA;
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000475 // Save calling context.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000476 __ mov(Operand(esp, (1 + FCA::kContextSaveIndex) * kPointerSize), esi);
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000477
ager@chromium.org5c838252010-02-19 08:53:10 +0000478 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000479 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000480 __ LoadHeapObject(edi, function);
ager@chromium.org5c838252010-02-19 08:53:10 +0000481 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
482
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +0000483 // Construct the FunctionCallbackInfo.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000484 __ mov(Operand(esp, (1 + FCA::kCalleeIndex) * kPointerSize), edi);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000485 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000486 Handle<Object> call_data(api_call_info->data(), masm->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000487 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
488 __ mov(ecx, api_call_info);
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000489 __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kDataOffset));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000490 __ mov(Operand(esp, (1 + FCA::kDataIndex) * kPointerSize), ebx);
ager@chromium.org5c838252010-02-19 08:53:10 +0000491 } else {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000492 __ mov(Operand(esp, (1 + FCA::kDataIndex) * kPointerSize),
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +0000493 Immediate(call_data));
ager@chromium.org5c838252010-02-19 08:53:10 +0000494 }
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000495 __ mov(Operand(esp, (1 + FCA::kIsolateIndex) * kPointerSize),
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000496 Immediate(reinterpret_cast<int>(masm->isolate())));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000497 __ mov(Operand(esp, (1 + FCA::kReturnValueOffset) * kPointerSize),
hpayer@chromium.org4f626d12013-09-18 07:47:45 +0000498 masm->isolate()->factory()->undefined_value());
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000499 __ mov(Operand(esp, (1 + FCA::kReturnValueDefaultValueIndex) * 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.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000503 STATIC_ASSERT(kFastApiCallArguments == 7);
504 __ lea(eax, Operand(esp, 1 * kPointerSize));
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000505
506 // API function gets reference to the v8::Arguments. If CPU profiler
507 // is enabled wrapper function will be called and we need to pass
508 // address of the callback as additional parameter, always allocate
509 // space for it.
510 const int kApiArgc = 1 + 1;
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000511
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000512 // Allocate the v8::Arguments structure in the arguments' space since
513 // it's not controlled by GC.
514 const int kApiStackSpace = 4;
515
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000516 // Function address is a foreign pointer outside V8's heap.
517 Address function_address = v8::ToCData<Address>(api_call_info->callback());
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000518 __ PrepareCallApiFunction(kApiArgc + kApiStackSpace);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000519
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000520 // FunctionCallbackInfo::implicit_args_.
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000521 __ mov(ApiParameterOperand(2), eax);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000522 __ add(eax, Immediate((argc + kFastApiCallArguments - 1) * kPointerSize));
523 // FunctionCallbackInfo::values_.
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000524 __ mov(ApiParameterOperand(3), eax);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000525 // FunctionCallbackInfo::length_.
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000526 __ Set(ApiParameterOperand(4), Immediate(argc));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000527 // FunctionCallbackInfo::is_construct_call_.
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000528 __ Set(ApiParameterOperand(5), Immediate(0));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000529
530 // v8::InvocationCallback's argument.
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000531 __ lea(eax, ApiParameterOperand(2));
532 __ mov(ApiParameterOperand(0), eax);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000533
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000534 Address thunk_address = FUNCTION_ADDR(&InvokeFunctionCallback);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000535
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000536 Operand context_restore_operand(ebp,
537 (2 + FCA::kContextSaveIndex) * kPointerSize);
538 Operand return_value_operand(ebp,
539 (2 + FCA::kReturnValueOffset) * kPointerSize);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000540 __ CallApiFunctionAndReturn(function_address,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000541 thunk_address,
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000542 ApiParameterOperand(1),
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000543 argc + kFastApiCallArguments + 1,
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000544 return_value_operand,
545 restore_context ?
546 &context_restore_operand : NULL);
ager@chromium.org5c838252010-02-19 08:53:10 +0000547}
548
549
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000550// Generate call to api function.
551static void GenerateFastApiCall(MacroAssembler* masm,
552 const CallOptimization& optimization,
553 Register receiver,
554 Register scratch,
555 int argc,
556 Register* values) {
557 ASSERT(optimization.is_simple_api_call());
558 ASSERT(!receiver.is(scratch));
559
560 const int stack_space = kFastApiCallArguments + argc + 1;
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000561 const int kHolderIndex = FunctionCallbackArguments::kHolderIndex + 1;
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000562 // Copy return value.
563 __ mov(scratch, Operand(esp, 0));
564 // Assign stack space for the call arguments.
565 __ sub(esp, Immediate(stack_space * kPointerSize));
566 // Move the return address on top of the stack.
567 __ mov(Operand(esp, 0), scratch);
568 // Write holder to stack frame.
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000569 __ mov(Operand(esp, kHolderIndex * kPointerSize), receiver);
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000570 // Write receiver to stack frame.
571 int index = stack_space;
572 __ mov(Operand(esp, index-- * kPointerSize), receiver);
573 // Write the arguments to stack frame.
574 for (int i = 0; i < argc; i++) {
575 ASSERT(!receiver.is(values[i]));
576 ASSERT(!scratch.is(values[i]));
577 __ mov(Operand(esp, index-- * kPointerSize), values[i]);
578 }
579
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000580 GenerateFastApiCall(masm, optimization, argc, true);
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000581}
582
583
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000584class CallInterceptorCompiler BASE_EMBEDDED {
585 public:
ager@chromium.org5c838252010-02-19 08:53:10 +0000586 CallInterceptorCompiler(StubCompiler* stub_compiler,
587 const ParameterCount& arguments,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000588 Register name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000589 Code::ExtraICState extra_state)
ager@chromium.org5c838252010-02-19 08:53:10 +0000590 : stub_compiler_(stub_compiler),
591 arguments_(arguments),
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000592 name_(name),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000593 extra_state_(extra_state) {}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000594
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000595 void Compile(MacroAssembler* masm,
596 Handle<JSObject> object,
597 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000598 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000599 LookupResult* lookup,
600 Register receiver,
601 Register scratch1,
602 Register scratch2,
603 Register scratch3,
604 Label* miss) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000605 ASSERT(holder->HasNamedInterceptor());
606 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
607
608 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000609 __ JumpIfSmi(receiver, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000610
611 CallOptimization optimization(lookup);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000612 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000613 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
614 holder, lookup, name, optimization, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000615 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000616 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
617 name, holder, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000618 }
619 }
620
621 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000622 void CompileCacheable(MacroAssembler* masm,
623 Handle<JSObject> object,
624 Register receiver,
625 Register scratch1,
626 Register scratch2,
627 Register scratch3,
628 Handle<JSObject> interceptor_holder,
629 LookupResult* lookup,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000630 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000631 const CallOptimization& optimization,
632 Label* miss_label) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000633 ASSERT(optimization.is_constant_call());
634 ASSERT(!lookup->holder()->IsGlobalObject());
635
636 int depth1 = kInvalidProtoDepth;
637 int depth2 = kInvalidProtoDepth;
638 bool can_do_fast_api_call = false;
639 if (optimization.is_simple_api_call() &&
640 !lookup->holder()->IsGlobalObject()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000641 depth1 = optimization.GetPrototypeDepthOfExpectedType(
642 object, interceptor_holder);
ager@chromium.org5c838252010-02-19 08:53:10 +0000643 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000644 depth2 = optimization.GetPrototypeDepthOfExpectedType(
645 interceptor_holder, Handle<JSObject>(lookup->holder()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000646 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000647 can_do_fast_api_call =
648 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000649 }
650
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000651 Counters* counters = masm->isolate()->counters();
652 __ IncrementCounter(counters->call_const_interceptor(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000653
654 if (can_do_fast_api_call) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000655 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000656 ReserveSpaceForFastApiCall(masm, scratch1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000657 }
658
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000659 // Check that the maps from receiver to interceptor's holder
660 // haven't changed and thus we can invoke interceptor.
ager@chromium.org5c838252010-02-19 08:53:10 +0000661 Label miss_cleanup;
662 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
663 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000664 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
665 scratch1, scratch2, scratch3,
666 name, depth1, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000667
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000668 // Invoke an interceptor and if it provides a value,
669 // branch to |regular_invoke|.
ager@chromium.org5c838252010-02-19 08:53:10 +0000670 Label regular_invoke;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000671 LoadWithInterceptor(masm, receiver, holder, interceptor_holder,
672 &regular_invoke);
ager@chromium.org5c838252010-02-19 08:53:10 +0000673
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000674 // Interceptor returned nothing for this property. Try to use cached
675 // constant function.
ager@chromium.org5c838252010-02-19 08:53:10 +0000676
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000677 // Check that the maps from interceptor's holder to constant function's
678 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000679 if (*interceptor_holder != lookup->holder()) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000680 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000681 Handle<JSObject>(lookup->holder()),
682 scratch1, scratch2, scratch3,
683 name, depth2, miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000684 } else {
685 // CheckPrototypes has a side effect of fetching a 'holder'
686 // for API (object which is instanceof for the signature). It's
687 // safe to omit it here, as if present, it should be fetched
688 // by the previous CheckPrototypes.
689 ASSERT(depth2 == kInvalidProtoDepth);
690 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000691
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000692 // Invoke function.
ager@chromium.org5c838252010-02-19 08:53:10 +0000693 if (can_do_fast_api_call) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000694 GenerateFastApiCall(masm, optimization, arguments_.immediate(), false);
ager@chromium.org5c838252010-02-19 08:53:10 +0000695 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000696 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000697 ? CALL_AS_FUNCTION
698 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000699 Handle<JSFunction> function = optimization.constant_function();
700 ParameterCount expected(function);
701 __ InvokeFunction(function, expected, arguments_,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000702 JUMP_FUNCTION, NullCallWrapper(), call_kind);
ager@chromium.org5c838252010-02-19 08:53:10 +0000703 }
704
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000705 // Deferred code for fast API call case---clean preallocated space.
ager@chromium.org5c838252010-02-19 08:53:10 +0000706 if (can_do_fast_api_call) {
707 __ bind(&miss_cleanup);
708 FreeSpaceForFastApiCall(masm, scratch1);
709 __ jmp(miss_label);
710 }
711
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000712 // Invoke a regular function.
ager@chromium.org5c838252010-02-19 08:53:10 +0000713 __ bind(&regular_invoke);
714 if (can_do_fast_api_call) {
715 FreeSpaceForFastApiCall(masm, scratch1);
716 }
717 }
718
719 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000720 Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +0000721 Register receiver,
722 Register scratch1,
723 Register scratch2,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000724 Register scratch3,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000725 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000726 Handle<JSObject> interceptor_holder,
ager@chromium.org5c838252010-02-19 08:53:10 +0000727 Label* miss_label) {
728 Register holder =
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000729 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000730 scratch1, scratch2, scratch3,
731 name, miss_label);
ager@chromium.org5c838252010-02-19 08:53:10 +0000732
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000733 FrameScope scope(masm, StackFrame::INTERNAL);
ager@chromium.org5c838252010-02-19 08:53:10 +0000734 // Save the name_ register across the call.
735 __ push(name_);
736
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000737 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
ager@chromium.org5c838252010-02-19 08:53:10 +0000738
739 __ CallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000740 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
741 masm->isolate()),
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000742 StubCache::kInterceptorArgsLength);
ager@chromium.org5c838252010-02-19 08:53:10 +0000743
744 // Restore the name_ register.
745 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000746
747 // Leave the internal frame.
ager@chromium.org5c838252010-02-19 08:53:10 +0000748 }
749
750 void LoadWithInterceptor(MacroAssembler* masm,
751 Register receiver,
752 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000753 Handle<JSObject> holder_obj,
ager@chromium.org5c838252010-02-19 08:53:10 +0000754 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000755 {
756 FrameScope scope(masm, StackFrame::INTERNAL);
757 __ push(holder); // Save the holder.
758 __ push(name_); // Save the name.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000759
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000760 CompileCallLoadPropertyWithInterceptor(masm,
761 receiver,
762 holder,
763 name_,
764 holder_obj);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000765
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000766 __ pop(name_); // Restore the name.
767 __ pop(receiver); // Restore the holder.
768 // Leave the internal frame.
769 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000770
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000771 __ cmp(eax, masm->isolate()->factory()->no_interceptor_result_sentinel());
ager@chromium.org5c838252010-02-19 08:53:10 +0000772 __ j(not_equal, interceptor_succeeded);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000773 }
774
ager@chromium.org5c838252010-02-19 08:53:10 +0000775 StubCompiler* stub_compiler_;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000776 const ParameterCount& arguments_;
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000777 Register name_;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000778 Code::ExtraICState extra_state_;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000779};
780
781
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000782void BaseStoreStubCompiler::GenerateRestoreName(MacroAssembler* masm,
783 Label* label,
784 Handle<Name> name) {
785 if (!label->is_unused()) {
786 __ bind(label);
787 __ mov(this->name(), Immediate(name));
788 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000789}
790
791
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000792// Generate code to check that a global property cell is empty. Create
793// the property cell at compilation time if no cell exists for the
794// property.
795static void GenerateCheckPropertyCell(MacroAssembler* masm,
796 Handle<GlobalObject> global,
797 Handle<Name> name,
798 Register scratch,
799 Label* miss) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000800 Handle<PropertyCell> cell =
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000801 GlobalObject::EnsurePropertyCell(global, name);
802 ASSERT(cell->value()->IsTheHole());
803 Handle<Oddball> the_hole = masm->isolate()->factory()->the_hole_value();
804 if (Serializer::enabled()) {
805 __ mov(scratch, Immediate(cell));
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000806 __ cmp(FieldOperand(scratch, PropertyCell::kValueOffset),
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000807 Immediate(the_hole));
808 } else {
danno@chromium.org41728482013-06-12 22:31:22 +0000809 __ cmp(Operand::ForCell(cell), Immediate(the_hole));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000810 }
811 __ j(not_equal, miss);
812}
813
814
danno@chromium.orgbee51992013-07-10 14:57:15 +0000815void BaseStoreStubCompiler::GenerateNegativeHolderLookup(
816 MacroAssembler* masm,
817 Handle<JSObject> holder,
818 Register holder_reg,
819 Handle<Name> name,
820 Label* miss) {
821 if (holder->IsJSGlobalObject()) {
822 GenerateCheckPropertyCell(
823 masm, Handle<GlobalObject>::cast(holder), name, scratch1(), miss);
824 } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
825 GenerateDictionaryNegativeLookup(
826 masm, miss, holder_reg, name, scratch1(), scratch2());
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000827 }
danno@chromium.orgbee51992013-07-10 14:57:15 +0000828}
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000829
danno@chromium.orgbee51992013-07-10 14:57:15 +0000830
831// Receiver_reg is preserved on jumps to miss_label, but may be destroyed if
832// store is successful.
833void BaseStoreStubCompiler::GenerateStoreTransition(MacroAssembler* masm,
834 Handle<JSObject> object,
835 LookupResult* lookup,
836 Handle<Map> transition,
837 Handle<Name> name,
838 Register receiver_reg,
839 Register storage_reg,
840 Register value_reg,
841 Register scratch1,
842 Register scratch2,
843 Register unused,
844 Label* miss_label,
845 Label* slow) {
danno@chromium.orgf005df62013-04-30 16:36:45 +0000846 int descriptor = transition->LastAdded();
847 DescriptorArray* descriptors = transition->instance_descriptors();
848 PropertyDetails details = descriptors->GetDetails(descriptor);
849 Representation representation = details.representation();
850 ASSERT(!representation.IsNone());
851
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000852 if (details.type() == CONSTANT) {
853 Handle<Object> constant(descriptors->GetValue(descriptor), masm->isolate());
854 __ CmpObject(value_reg, constant);
danno@chromium.orgbee51992013-07-10 14:57:15 +0000855 __ j(not_equal, miss_label);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000856 } else if (FLAG_track_fields && representation.IsSmi()) {
danno@chromium.orgbee51992013-07-10 14:57:15 +0000857 __ JumpIfNotSmi(value_reg, miss_label);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +0000858 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
danno@chromium.orgbee51992013-07-10 14:57:15 +0000859 __ JumpIfSmi(value_reg, miss_label);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000860 } else if (FLAG_track_double_fields && representation.IsDouble()) {
861 Label do_store, heap_number;
862 __ AllocateHeapNumber(storage_reg, scratch1, scratch2, slow);
863
864 __ JumpIfNotSmi(value_reg, &heap_number);
865 __ SmiUntag(value_reg);
866 if (CpuFeatures::IsSupported(SSE2)) {
867 CpuFeatureScope use_sse2(masm, SSE2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000868 __ Cvtsi2sd(xmm0, value_reg);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000869 } else {
870 __ push(value_reg);
871 __ fild_s(Operand(esp, 0));
872 __ pop(value_reg);
873 }
874 __ SmiTag(value_reg);
875 __ jmp(&do_store);
876
877 __ bind(&heap_number);
878 __ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(),
danno@chromium.orgbee51992013-07-10 14:57:15 +0000879 miss_label, DONT_DO_SMI_CHECK);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000880 if (CpuFeatures::IsSupported(SSE2)) {
881 CpuFeatureScope use_sse2(masm, SSE2);
882 __ movdbl(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset));
883 } else {
884 __ fld_d(FieldOperand(value_reg, HeapNumber::kValueOffset));
885 }
886
887 __ bind(&do_store);
888 if (CpuFeatures::IsSupported(SSE2)) {
889 CpuFeatureScope use_sse2(masm, SSE2);
890 __ movdbl(FieldOperand(storage_reg, HeapNumber::kValueOffset), xmm0);
891 } else {
892 __ fstp_d(FieldOperand(storage_reg, HeapNumber::kValueOffset));
893 }
894 }
895
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000896 // Stub never generated for non-global objects that require access
897 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000898 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000899
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000900 // Perform map transition for the receiver if necessary.
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000901 if (details.type() == FIELD &&
902 object->map()->unused_property_fields() == 0) {
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000903 // The properties must be extended before we can store the value.
ager@chromium.org32912102009-01-16 10:38:43 +0000904 // We jump to a runtime call that extends the properties array.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000905 __ pop(scratch1); // Return address.
ager@chromium.org5c838252010-02-19 08:53:10 +0000906 __ push(receiver_reg);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000907 __ push(Immediate(transition));
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000908 __ push(value_reg);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000909 __ push(scratch1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000910 __ TailCallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000911 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
912 masm->isolate()),
913 3,
914 1);
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000915 return;
916 }
917
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000918 // Update the map of the object.
919 __ mov(scratch1, Immediate(transition));
920 __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1);
verwaest@chromium.org37141392012-05-31 13:27:02 +0000921
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000922 // Update the write barrier for the map field.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000923 __ RecordWriteField(receiver_reg,
924 HeapObject::kMapOffset,
925 scratch1,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000926 scratch2,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000927 kDontSaveFPRegs,
928 OMIT_REMEMBERED_SET,
929 OMIT_SMI_CHECK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000930
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000931 if (details.type() == CONSTANT) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000932 ASSERT(value_reg.is(eax));
933 __ ret(0);
934 return;
935 }
936
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000937 int index = transition->instance_descriptors()->GetFieldIndex(
938 transition->LastAdded());
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000939
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000940 // Adjust for the number of properties stored in the object. Even in the
941 // face of a transition we can use the old map here because the size of the
942 // object and the number of in-object properties is not going to change.
943 index -= object->map()->inobject_properties();
944
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000945 SmiCheck smi_check = representation.IsTagged()
946 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000947 // TODO(verwaest): Share this code as a code stub.
ager@chromium.org7c537e22008-10-16 08:43:32 +0000948 if (index < 0) {
949 // Set the property straight into the object.
950 int offset = object->map()->instance_size() + (index * kPointerSize);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000951 if (FLAG_track_double_fields && representation.IsDouble()) {
952 __ mov(FieldOperand(receiver_reg, offset), storage_reg);
953 } else {
954 __ mov(FieldOperand(receiver_reg, offset), value_reg);
955 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000956
danno@chromium.orgf005df62013-04-30 16:36:45 +0000957 if (!FLAG_track_fields || !representation.IsSmi()) {
958 // Update the write barrier for the array address.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000959 if (!FLAG_track_double_fields || !representation.IsDouble()) {
danno@chromium.orgbee51992013-07-10 14:57:15 +0000960 __ mov(storage_reg, value_reg);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000961 }
danno@chromium.orgf005df62013-04-30 16:36:45 +0000962 __ RecordWriteField(receiver_reg,
963 offset,
danno@chromium.orgbee51992013-07-10 14:57:15 +0000964 storage_reg,
danno@chromium.orgf005df62013-04-30 16:36:45 +0000965 scratch1,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000966 kDontSaveFPRegs,
967 EMIT_REMEMBERED_SET,
968 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000969 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000970 } else {
971 // Write to the properties array.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000972 int offset = index * kPointerSize + FixedArray::kHeaderSize;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000973 // Get the properties array (optimistically).
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000974 __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000975 if (FLAG_track_double_fields && representation.IsDouble()) {
976 __ mov(FieldOperand(scratch1, offset), storage_reg);
977 } else {
978 __ mov(FieldOperand(scratch1, offset), value_reg);
979 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000980
danno@chromium.orgf005df62013-04-30 16:36:45 +0000981 if (!FLAG_track_fields || !representation.IsSmi()) {
982 // Update the write barrier for the array address.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000983 if (!FLAG_track_double_fields || !representation.IsDouble()) {
danno@chromium.orgbee51992013-07-10 14:57:15 +0000984 __ mov(storage_reg, value_reg);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000985 }
danno@chromium.orgf005df62013-04-30 16:36:45 +0000986 __ RecordWriteField(scratch1,
987 offset,
danno@chromium.orgbee51992013-07-10 14:57:15 +0000988 storage_reg,
danno@chromium.orgf005df62013-04-30 16:36:45 +0000989 receiver_reg,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000990 kDontSaveFPRegs,
991 EMIT_REMEMBERED_SET,
992 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000993 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000994 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000995
996 // Return the value (register eax).
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000997 ASSERT(value_reg.is(eax));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000998 __ ret(0);
999}
1000
1001
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001002// Both name_reg and receiver_reg are preserved on jumps to miss_label,
1003// but may be destroyed if store is successful.
danno@chromium.orgbee51992013-07-10 14:57:15 +00001004void BaseStoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
1005 Handle<JSObject> object,
1006 LookupResult* lookup,
1007 Register receiver_reg,
1008 Register name_reg,
1009 Register value_reg,
1010 Register scratch1,
1011 Register scratch2,
1012 Label* miss_label) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001013 // Stub never generated for non-global objects that require access
1014 // checks.
1015 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
1016
1017 int index = lookup->GetFieldIndex().field_index();
1018
1019 // Adjust for the number of properties stored in the object. Even in the
1020 // face of a transition we can use the old map here because the size of the
1021 // object and the number of in-object properties is not going to change.
1022 index -= object->map()->inobject_properties();
1023
danno@chromium.orgf005df62013-04-30 16:36:45 +00001024 Representation representation = lookup->representation();
1025 ASSERT(!representation.IsNone());
1026 if (FLAG_track_fields && representation.IsSmi()) {
1027 __ JumpIfNotSmi(value_reg, miss_label);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001028 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
1029 __ JumpIfSmi(value_reg, miss_label);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001030 } else if (FLAG_track_double_fields && representation.IsDouble()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001031 // Load the double storage.
1032 if (index < 0) {
1033 int offset = object->map()->instance_size() + (index * kPointerSize);
1034 __ mov(scratch1, FieldOperand(receiver_reg, offset));
1035 } else {
1036 __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
1037 int offset = index * kPointerSize + FixedArray::kHeaderSize;
1038 __ mov(scratch1, FieldOperand(scratch1, offset));
1039 }
1040
1041 // Store the value into the storage.
1042 Label do_store, heap_number;
1043 __ JumpIfNotSmi(value_reg, &heap_number);
1044 __ SmiUntag(value_reg);
1045 if (CpuFeatures::IsSupported(SSE2)) {
1046 CpuFeatureScope use_sse2(masm, SSE2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001047 __ Cvtsi2sd(xmm0, value_reg);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001048 } else {
1049 __ push(value_reg);
1050 __ fild_s(Operand(esp, 0));
1051 __ pop(value_reg);
1052 }
1053 __ SmiTag(value_reg);
1054 __ jmp(&do_store);
1055 __ bind(&heap_number);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001056 __ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(),
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001057 miss_label, DONT_DO_SMI_CHECK);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001058 if (CpuFeatures::IsSupported(SSE2)) {
1059 CpuFeatureScope use_sse2(masm, SSE2);
1060 __ movdbl(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset));
1061 } else {
1062 __ fld_d(FieldOperand(value_reg, HeapNumber::kValueOffset));
1063 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00001064 __ bind(&do_store);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001065 if (CpuFeatures::IsSupported(SSE2)) {
1066 CpuFeatureScope use_sse2(masm, SSE2);
1067 __ movdbl(FieldOperand(scratch1, HeapNumber::kValueOffset), xmm0);
1068 } else {
1069 __ fstp_d(FieldOperand(scratch1, HeapNumber::kValueOffset));
1070 }
1071 // Return the value (register eax).
1072 ASSERT(value_reg.is(eax));
1073 __ ret(0);
1074 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +00001075 }
1076
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001077 ASSERT(!FLAG_track_double_fields || !representation.IsDouble());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001078 // TODO(verwaest): Share this code as a code stub.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001079 SmiCheck smi_check = representation.IsTagged()
1080 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001081 if (index < 0) {
1082 // Set the property straight into the object.
1083 int offset = object->map()->instance_size() + (index * kPointerSize);
1084 __ mov(FieldOperand(receiver_reg, offset), value_reg);
1085
danno@chromium.orgf005df62013-04-30 16:36:45 +00001086 if (!FLAG_track_fields || !representation.IsSmi()) {
1087 // Update the write barrier for the array address.
1088 // Pass the value being stored in the now unused name_reg.
1089 __ mov(name_reg, value_reg);
1090 __ RecordWriteField(receiver_reg,
1091 offset,
1092 name_reg,
1093 scratch1,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001094 kDontSaveFPRegs,
1095 EMIT_REMEMBERED_SET,
1096 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001097 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001098 } else {
1099 // Write to the properties array.
1100 int offset = index * kPointerSize + FixedArray::kHeaderSize;
1101 // Get the properties array (optimistically).
1102 __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001103 __ mov(FieldOperand(scratch1, offset), value_reg);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001104
danno@chromium.orgf005df62013-04-30 16:36:45 +00001105 if (!FLAG_track_fields || !representation.IsSmi()) {
1106 // Update the write barrier for the array address.
1107 // Pass the value being stored in the now unused name_reg.
1108 __ mov(name_reg, value_reg);
1109 __ RecordWriteField(scratch1,
1110 offset,
1111 name_reg,
1112 receiver_reg,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001113 kDontSaveFPRegs,
1114 EMIT_REMEMBERED_SET,
1115 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001116 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001117 }
1118
1119 // Return the value (register eax).
1120 ASSERT(value_reg.is(eax));
1121 __ ret(0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001122}
1123
1124
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001125// Calls GenerateCheckPropertyCell for each global object in the prototype chain
1126// from object to (but not including) holder.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001127static void GenerateCheckPropertyCells(MacroAssembler* masm,
1128 Handle<JSObject> object,
1129 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001130 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001131 Register scratch,
1132 Label* miss) {
1133 Handle<JSObject> current = object;
1134 while (!current.is_identical_to(holder)) {
1135 if (current->IsGlobalObject()) {
1136 GenerateCheckPropertyCell(masm,
1137 Handle<GlobalObject>::cast(current),
1138 name,
1139 scratch,
1140 miss);
1141 }
1142 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
1143 }
1144}
1145
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001146
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001147void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001148 __ jmp(code, RelocInfo::CODE_TARGET);
1149}
1150
1151
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001152#undef __
1153#define __ ACCESS_MASM(masm())
1154
1155
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001156Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
1157 Register object_reg,
1158 Handle<JSObject> holder,
1159 Register holder_reg,
1160 Register scratch1,
1161 Register scratch2,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001162 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001163 int save_at_depth,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001164 Label* miss,
1165 PrototypeCheckType check) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001166 const int kHolderIndex = FunctionCallbackArguments::kHolderIndex + 1;
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001167 // Make sure that the type feedback oracle harvests the receiver map.
1168 // TODO(svenpanne) Remove this hack when all ICs are reworked.
1169 __ mov(scratch1, Handle<Map>(object->map()));
1170
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001171 Handle<JSObject> first = object;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001172 // Make sure there's no overlap between holder and object registers.
1173 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1174 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1175 && !scratch2.is(scratch1));
1176
1177 // Keep track of the current object in register reg.
1178 Register reg = object_reg;
1179 Handle<JSObject> current = object;
1180 int depth = 0;
1181
1182 if (save_at_depth == depth) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001183 __ mov(Operand(esp, kHolderIndex * kPointerSize), reg);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001184 }
1185
1186 // Traverse the prototype chain and check the maps in the prototype chain for
1187 // fast and global objects or do negative lookup for normal objects.
1188 while (!current.is_identical_to(holder)) {
1189 ++depth;
1190
1191 // Only global objects and objects that do not require access
1192 // checks are allowed in stubs.
1193 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1194
1195 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
1196 if (!current->HasFastProperties() &&
1197 !current->IsJSGlobalObject() &&
1198 !current->IsJSGlobalProxy()) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001199 if (!name->IsUniqueName()) {
1200 ASSERT(name->IsString());
1201 name = factory()->InternalizeString(Handle<String>::cast(name));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001202 }
1203 ASSERT(current->property_dictionary()->FindEntry(*name) ==
ulan@chromium.org750145a2013-03-07 15:14:13 +00001204 NameDictionary::kNotFound);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001205
1206 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1207 scratch1, scratch2);
1208
1209 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
1210 reg = holder_reg; // From now on the object will be in holder_reg.
1211 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
1212 } else {
1213 bool in_new_space = heap()->InNewSpace(*prototype);
1214 Handle<Map> current_map(current->map());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001215 if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001216 __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001217 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001218
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001219 // Check access rights to the global object. This has to happen after
1220 // the map check so that we know that the object is actually a global
1221 // object.
1222 if (current->IsJSGlobalProxy()) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001223 __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001224 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001225
1226 if (in_new_space) {
1227 // Save the map in scratch1 for later.
1228 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
1229 }
1230
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001231 reg = holder_reg; // From now on the object will be in holder_reg.
1232
1233 if (in_new_space) {
1234 // The prototype is in new space; we cannot store a reference to it
1235 // in the code. Load it from the map.
1236 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
1237 } else {
1238 // The prototype is in old space; load it directly.
1239 __ mov(reg, prototype);
1240 }
1241 }
1242
1243 if (save_at_depth == depth) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001244 __ mov(Operand(esp, kHolderIndex * kPointerSize), reg);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001245 }
1246
1247 // Go to the next object in the prototype chain.
1248 current = prototype;
1249 }
1250 ASSERT(current.is_identical_to(holder));
1251
1252 // Log the check depth.
1253 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
1254
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001255 if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) {
1256 // Check the holder map.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001257 __ CheckMap(reg, Handle<Map>(holder->map()), miss, DONT_DO_SMI_CHECK);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001258 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001259
1260 // Perform security check for access to the global object.
1261 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1262 if (holder->IsJSGlobalProxy()) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001263 __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001264 }
1265
1266 // If we've skipped any global objects, it's not enough to verify that
1267 // their maps haven't changed. We also need to check that the property
1268 // cell for the property is still empty.
1269 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1270
1271 // Return the register containing the holder.
1272 return reg;
1273}
1274
1275
danno@chromium.orgbee51992013-07-10 14:57:15 +00001276void BaseLoadStubCompiler::HandlerFrontendFooter(Handle<Name> name,
1277 Label* success,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001278 Label* miss) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001279 if (!miss->is_unused()) {
1280 __ jmp(success);
1281 __ bind(miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001282 TailCallBuiltin(masm(), MissBuiltin(kind()));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001283 }
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001284}
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001285
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001286
danno@chromium.orgbee51992013-07-10 14:57:15 +00001287void BaseStoreStubCompiler::HandlerFrontendFooter(Handle<Name> name,
1288 Label* success,
1289 Label* miss) {
1290 if (!miss->is_unused()) {
1291 __ jmp(success);
1292 GenerateRestoreName(masm(), miss, name);
1293 TailCallBuiltin(masm(), MissBuiltin(kind()));
1294 }
1295}
1296
1297
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001298Register BaseLoadStubCompiler::CallbackHandlerFrontend(
1299 Handle<JSObject> object,
1300 Register object_reg,
1301 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001302 Handle<Name> name,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001303 Label* success,
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00001304 Handle<Object> callback) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001305 Label miss;
1306
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001307 Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001308
1309 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
1310 ASSERT(!reg.is(scratch2()));
1311 ASSERT(!reg.is(scratch3()));
1312 Register dictionary = scratch1();
1313 bool must_preserve_dictionary_reg = reg.is(dictionary);
1314
1315 // Load the properties dictionary.
1316 if (must_preserve_dictionary_reg) {
1317 __ push(dictionary);
1318 }
1319 __ mov(dictionary, FieldOperand(reg, JSObject::kPropertiesOffset));
1320
1321 // Probe the dictionary.
1322 Label probe_done, pop_and_miss;
ulan@chromium.org750145a2013-03-07 15:14:13 +00001323 NameDictionaryLookupStub::GeneratePositiveLookup(masm(),
1324 &pop_and_miss,
1325 &probe_done,
1326 dictionary,
1327 this->name(),
1328 scratch2(),
1329 scratch3());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001330 __ bind(&pop_and_miss);
1331 if (must_preserve_dictionary_reg) {
1332 __ pop(dictionary);
1333 }
1334 __ jmp(&miss);
1335 __ bind(&probe_done);
1336
1337 // If probing finds an entry in the dictionary, scratch2 contains the
1338 // index into the dictionary. Check that the value is the callback.
1339 Register index = scratch2();
1340 const int kElementsStartOffset =
ulan@chromium.org750145a2013-03-07 15:14:13 +00001341 NameDictionary::kHeaderSize +
1342 NameDictionary::kElementsStartIndex * kPointerSize;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001343 const int kValueOffset = kElementsStartOffset + kPointerSize;
1344 __ mov(scratch3(),
1345 Operand(dictionary, index, times_4, kValueOffset - kHeapObjectTag));
1346 if (must_preserve_dictionary_reg) {
1347 __ pop(dictionary);
1348 }
1349 __ cmp(scratch3(), callback);
1350 __ j(not_equal, &miss);
1351 }
1352
danno@chromium.orgbee51992013-07-10 14:57:15 +00001353 HandlerFrontendFooter(name, success, &miss);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001354 return reg;
1355}
1356
1357
1358void BaseLoadStubCompiler::NonexistentHandlerFrontend(
1359 Handle<JSObject> object,
1360 Handle<JSObject> last,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001361 Handle<Name> name,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001362 Label* success,
1363 Handle<GlobalObject> global) {
1364 Label miss;
1365
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001366 HandlerFrontendHeader(object, receiver(), last, name, &miss);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001367
1368 // If the last object in the prototype chain is a global object,
1369 // check that the global property cell is empty.
1370 if (!global.is_null()) {
1371 GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
1372 }
1373
danno@chromium.orgbee51992013-07-10 14:57:15 +00001374 HandlerFrontendFooter(name, success, &miss);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001375}
1376
1377
1378void BaseLoadStubCompiler::GenerateLoadField(Register reg,
1379 Handle<JSObject> holder,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001380 PropertyIndex field,
1381 Representation representation) {
1382 if (!reg.is(receiver())) __ mov(receiver(), reg);
1383 if (kind() == Code::LOAD_IC) {
1384 LoadFieldStub stub(field.is_inobject(holder),
1385 field.translate(holder),
1386 representation);
1387 GenerateTailCall(masm(), stub.GetCode(isolate()));
1388 } else {
1389 KeyedLoadFieldStub stub(field.is_inobject(holder),
1390 field.translate(holder),
1391 representation);
1392 GenerateTailCall(masm(), stub.GetCode(isolate()));
1393 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001394}
1395
1396
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001397void BaseLoadStubCompiler::GenerateLoadCallback(
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00001398 const CallOptimization& call_optimization) {
dslomov@chromium.org639bac02013-09-09 11:58:54 +00001399 GenerateFastApiCall(
1400 masm(), call_optimization, receiver(), scratch3(), 0, NULL);
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00001401}
1402
1403
1404void BaseLoadStubCompiler::GenerateLoadCallback(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001405 Register reg,
1406 Handle<ExecutableAccessorInfo> callback) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001407 // Insert additional parameters into the stack frame above return address.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001408 ASSERT(!scratch3().is(reg));
1409 __ pop(scratch3()); // Get return address to place it below.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001410
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001411 STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0);
1412 STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1);
1413 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2);
1414 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3);
1415 STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4);
1416 STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001417 __ push(receiver()); // receiver
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001418 // Push data from ExecutableAccessorInfo.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001419 if (isolate()->heap()->InNewSpace(callback->data())) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001420 ASSERT(!scratch2().is(reg));
1421 __ mov(scratch2(), Immediate(callback));
1422 __ push(FieldOperand(scratch2(), ExecutableAccessorInfo::kDataOffset));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001423 } else {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001424 __ push(Immediate(Handle<Object>(callback->data(), isolate())));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001425 }
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001426 __ push(Immediate(isolate()->factory()->undefined_value())); // ReturnValue
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001427 // ReturnValue default value
1428 __ push(Immediate(isolate()->factory()->undefined_value()));
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00001429 __ push(Immediate(reinterpret_cast<int>(isolate())));
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00001430 __ push(reg); // holder
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001431
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001432 // Save a pointer to where we pushed the arguments. This will be
1433 // passed as the const PropertyAccessorInfo& to the C++ callback.
1434 __ push(esp);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001435
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001436 __ push(name()); // name
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001437 __ mov(ebx, esp); // esp points to reference to name (handler).
1438
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001439 __ push(scratch3()); // Restore return address.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001440
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001441 // array for v8::Arguments::values_, handler for name and pointer
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001442 // to the values (it considered as smi in GC).
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001443 const int kStackSpace = PropertyCallbackArguments::kArgsLength + 2;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001444 // Allocate space for opional callback address parameter in case
1445 // CPU profiler is active.
1446 const int kApiArgc = 2 + 1;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001447
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001448 Address getter_address = v8::ToCData<Address>(callback->getter());
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001449 __ PrepareCallApiFunction(kApiArgc);
1450 __ mov(ApiParameterOperand(0), ebx); // name.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001451 __ add(ebx, Immediate(kPointerSize));
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001452 __ mov(ApiParameterOperand(1), ebx); // arguments pointer.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001453
kmillikin@chromium.org2d5475f2009-12-20 18:15:52 +00001454 // Emitting a stub call may try to allocate (if the code is not
1455 // already generated). Do not allow the assembler to perform a
1456 // garbage collection but instead return the allocation failure
1457 // object.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001458
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001459 Address thunk_address = FUNCTION_ADDR(&InvokeAccessorGetterCallback);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001460
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001461 __ CallApiFunctionAndReturn(getter_address,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001462 thunk_address,
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001463 ApiParameterOperand(2),
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001464 kStackSpace,
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001465 Operand(ebp, 7 * kPointerSize),
1466 NULL);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001467}
1468
1469
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001470void BaseLoadStubCompiler::GenerateLoadConstant(Handle<Object> value) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001471 // Return the constant value.
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001472 __ LoadObject(eax, value);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001473 __ ret(0);
1474}
1475
1476
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001477void BaseLoadStubCompiler::GenerateLoadInterceptor(
1478 Register holder_reg,
1479 Handle<JSObject> object,
1480 Handle<JSObject> interceptor_holder,
1481 LookupResult* lookup,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001482 Handle<Name> name) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001483 ASSERT(interceptor_holder->HasNamedInterceptor());
1484 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1485
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001486 // So far the most popular follow ups for interceptor loads are FIELD
1487 // and CALLBACKS, so inline only them, other cases may be added
1488 // later.
1489 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001490 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001491 if (lookup->IsField()) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001492 compile_followup_inline = true;
1493 } else if (lookup->type() == CALLBACKS &&
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001494 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
1495 ExecutableAccessorInfo* callback =
1496 ExecutableAccessorInfo::cast(lookup->GetCallbackObject());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001497 compile_followup_inline = callback->getter() != NULL &&
1498 callback->IsCompatibleReceiver(*object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001499 }
1500 }
1501
1502 if (compile_followup_inline) {
1503 // Compile the interceptor call, followed by inline code to load the
1504 // property from further up the prototype chain if the call fails.
1505 // Check that the maps haven't changed.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001506 ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001507
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001508 // Preserve the receiver register explicitly whenever it is different from
1509 // the holder and it is needed should the interceptor return without any
1510 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1511 // the FIELD case might cause a miss during the prototype check.
1512 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001513 bool must_preserve_receiver_reg = !receiver().is(holder_reg) &&
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001514 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1515
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001516 // Save necessary data before invoking an interceptor.
1517 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001518 {
1519 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001520
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001521 if (must_preserve_receiver_reg) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001522 __ push(receiver());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001523 }
1524 __ push(holder_reg);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001525 __ push(this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001526
1527 // Invoke an interceptor. Note: map checks from receiver to
1528 // interceptor's holder has been compiled before (see a caller
1529 // of this method.)
1530 CompileCallLoadPropertyWithInterceptor(masm(),
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001531 receiver(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001532 holder_reg,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001533 this->name(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001534 interceptor_holder);
1535
1536 // Check if interceptor provided a value for property. If it's
1537 // the case, return immediately.
1538 Label interceptor_failed;
1539 __ cmp(eax, factory()->no_interceptor_result_sentinel());
1540 __ j(equal, &interceptor_failed);
1541 frame_scope.GenerateLeaveFrame();
1542 __ ret(0);
1543
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001544 // Clobber registers when generating debug-code to provoke errors.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001545 __ bind(&interceptor_failed);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001546 if (FLAG_debug_code) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001547 __ mov(receiver(), Immediate(BitCast<int32_t>(kZapValue)));
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001548 __ mov(holder_reg, Immediate(BitCast<int32_t>(kZapValue)));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001549 __ mov(this->name(), Immediate(BitCast<int32_t>(kZapValue)));
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001550 }
1551
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001552 __ pop(this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001553 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001554 if (must_preserve_receiver_reg) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001555 __ pop(receiver());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001556 }
1557
1558 // Leave the internal frame.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001559 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001560
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001561 GenerateLoadPostInterceptor(holder_reg, interceptor_holder, name, lookup);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001562 } else { // !compile_followup_inline
1563 // Call the runtime system to load the interceptor.
1564 // Check that the maps haven't changed.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001565 __ pop(scratch2()); // save old return address
1566 PushInterceptorArguments(masm(), receiver(), holder_reg,
1567 this->name(), interceptor_holder);
1568 __ push(scratch2()); // restore old return address
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001569
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001570 ExternalReference ref =
1571 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001572 isolate());
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00001573 __ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength, 1);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001574 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001575}
1576
1577
ulan@chromium.org750145a2013-03-07 15:14:13 +00001578void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001579 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001580 __ cmp(ecx, Immediate(name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001581 __ j(not_equal, miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001582 }
1583}
1584
1585
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001586void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1587 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001588 Handle<Name> name,
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001589 Label* miss) {
1590 ASSERT(holder->IsGlobalObject());
1591
1592 // Get the number of arguments.
1593 const int argc = arguments().immediate();
1594
1595 // Get the receiver from the stack.
1596 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1597
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001598
1599 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001600 __ JumpIfSmi(edx, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001601 CheckPrototypes(object, edx, holder, ebx, eax, edi, name, miss);
1602}
1603
1604
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001605void CallStubCompiler::GenerateLoadFunctionFromCell(
danno@chromium.org41728482013-06-12 22:31:22 +00001606 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001607 Handle<JSFunction> function,
1608 Label* miss) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001609 // Get the value from the cell.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001610 if (Serializer::enabled()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001611 __ mov(edi, Immediate(cell));
danno@chromium.org41728482013-06-12 22:31:22 +00001612 __ mov(edi, FieldOperand(edi, Cell::kValueOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001613 } else {
danno@chromium.org41728482013-06-12 22:31:22 +00001614 __ mov(edi, Operand::ForCell(cell));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001615 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001616
1617 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001618 if (isolate()->heap()->InNewSpace(*function)) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001619 // We can't embed a pointer to a function in new space so we have
1620 // to verify that the shared function info is unchanged. This has
1621 // the nice side effect that multiple closures based on the same
1622 // function can all use this call IC. Before we load through the
1623 // function, we have to verify that it still is a function.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001624 __ JumpIfSmi(edi, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001625 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001626 __ j(not_equal, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001627
1628 // Check the shared function info. Make sure it hasn't changed.
1629 __ cmp(FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset),
1630 Immediate(Handle<SharedFunctionInfo>(function->shared())));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001631 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001632 __ cmp(edi, Immediate(function));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001633 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001634 __ j(not_equal, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001635}
1636
1637
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001638void CallStubCompiler::GenerateMissBranch() {
1639 Handle<Code> code =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001640 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
danno@chromium.org40cb8782011-05-25 07:58:50 +00001641 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001642 extra_state_);
1643 __ jmp(code, RelocInfo::CODE_TARGET);
1644}
1645
1646
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001647Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1648 Handle<JSObject> holder,
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00001649 PropertyIndex index,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001650 Handle<Name> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001651 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001652 // -- ecx : name
1653 // -- esp[0] : return address
1654 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1655 // -- ...
1656 // -- esp[(argc + 1) * 4] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001657 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001658 Label miss;
1659
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001660 GenerateNameCheck(name, &miss);
1661
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001662 // Get the receiver from the stack.
1663 const int argc = arguments().immediate();
1664 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1665
1666 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001667 __ JumpIfSmi(edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001668
1669 // Do the right check and compute the holder register.
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001670 Register reg = CheckPrototypes(object, edx, holder, ebx, eax, edi,
1671 name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001672
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001673 GenerateFastPropertyLoad(
1674 masm(), edi, reg, index.is_inobject(holder),
1675 index.translate(holder), Representation::Tagged());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001676
1677 // Check that the function really is a function.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001678 __ JumpIfSmi(edi, &miss);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001679 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001680 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001681
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001682 // Patch the receiver on the stack with the global proxy if
1683 // necessary.
1684 if (object->IsGlobalObject()) {
1685 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
1686 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
1687 }
1688
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001689 // Invoke the function.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001690 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001691 ? CALL_AS_FUNCTION
1692 : CALL_AS_METHOD;
1693 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION,
1694 NullCallWrapper(), call_kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001695
1696 // Handle call cache miss.
1697 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001698 GenerateMissBranch();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001699
1700 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001701 return GetCode(Code::FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001702}
1703
1704
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001705Handle<Code> CallStubCompiler::CompileArrayCodeCall(
1706 Handle<Object> object,
1707 Handle<JSObject> holder,
1708 Handle<Cell> cell,
1709 Handle<JSFunction> function,
1710 Handle<String> name,
1711 Code::StubType type) {
1712 Label miss;
1713
1714 // Check that function is still array
1715 const int argc = arguments().immediate();
1716 GenerateNameCheck(name, &miss);
1717
1718 if (cell.is_null()) {
1719 // Get the receiver from the stack.
1720 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1721
1722 // Check that the receiver isn't a smi.
1723 __ JumpIfSmi(edx, &miss);
1724 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
1725 name, &miss);
1726 } else {
1727 ASSERT(cell->value() == *function);
1728 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
1729 &miss);
1730 GenerateLoadFunctionFromCell(cell, function, &miss);
1731 }
1732
danno@chromium.orgbee51992013-07-10 14:57:15 +00001733 Handle<AllocationSite> site = isolate()->factory()->NewAllocationSite();
1734 site->set_transition_info(Smi::FromInt(GetInitialFastElementsKind()));
1735 Handle<Cell> site_feedback_cell = isolate()->factory()->NewCell(site);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001736 __ mov(eax, Immediate(argc));
danno@chromium.orgbee51992013-07-10 14:57:15 +00001737 __ mov(ebx, site_feedback_cell);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001738 __ mov(edi, function);
1739
1740 ArrayConstructorStub stub(isolate());
1741 __ TailCallStub(&stub);
1742
1743 __ bind(&miss);
1744 GenerateMissBranch();
1745
1746 // Return the generated code.
1747 return GetCode(type, name);
1748}
1749
1750
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001751Handle<Code> CallStubCompiler::CompileArrayPushCall(
1752 Handle<Object> object,
1753 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00001754 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001755 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001756 Handle<String> name,
1757 Code::StubType type) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001758 // ----------- S t a t e -------------
1759 // -- ecx : name
1760 // -- esp[0] : return address
1761 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1762 // -- ...
1763 // -- esp[(argc + 1) * 4] : receiver
1764 // -----------------------------------
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001765
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001766 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001767 if (!object->IsJSArray() || !cell.is_null()) {
1768 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001769 }
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001770
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001771 Label miss;
1772
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001773 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001774
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001775 // Get the receiver from the stack.
1776 const int argc = arguments().immediate();
1777 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1778
1779 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001780 __ JumpIfSmi(edx, &miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001781
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001782 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
1783 name, &miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001784
1785 if (argc == 0) {
1786 // Noop, return the length.
1787 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
1788 __ ret((argc + 1) * kPointerSize);
1789 } else {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001790 Label call_builtin;
1791
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001792 if (argc == 1) { // Otherwise fall through to call builtin.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001793 Label attempt_to_grow_elements, with_write_barrier, check_double;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001794
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001795 // Get the elements array of the object.
1796 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset));
1797
1798 // Check that the elements are in fast mode and writable.
1799 __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
1800 Immediate(factory()->fixed_array_map()));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001801 __ j(not_equal, &check_double);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001802
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001803 // Get the array's length into eax and calculate new length.
1804 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
1805 STATIC_ASSERT(kSmiTagSize == 1);
1806 STATIC_ASSERT(kSmiTag == 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001807 __ add(eax, Immediate(Smi::FromInt(argc)));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001808
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001809 // Get the elements' length into ecx.
1810 __ mov(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001811
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001812 // Check if we could survive without allocation.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001813 __ cmp(eax, ecx);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001814 __ j(greater, &attempt_to_grow_elements);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001815
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001816 // Check if value is a smi.
1817 __ mov(ecx, Operand(esp, argc * kPointerSize));
1818 __ JumpIfNotSmi(ecx, &with_write_barrier);
1819
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001820 // Save new length.
1821 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1822
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001823 // Store the value.
1824 __ mov(FieldOperand(edi,
1825 eax,
1826 times_half_pointer_size,
1827 FixedArray::kHeaderSize - argc * kPointerSize),
1828 ecx);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001829
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001830 __ ret((argc + 1) * kPointerSize);
1831
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001832 __ bind(&check_double);
1833
1834
1835 // Check that the elements are in double mode.
1836 __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
1837 Immediate(factory()->fixed_double_array_map()));
1838 __ j(not_equal, &call_builtin);
1839
1840 // Get the array's length into eax and calculate new length.
1841 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
1842 STATIC_ASSERT(kSmiTagSize == 1);
1843 STATIC_ASSERT(kSmiTag == 0);
1844 __ add(eax, Immediate(Smi::FromInt(argc)));
1845
1846 // Get the elements' length into ecx.
1847 __ mov(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
1848
1849 // Check if we could survive without allocation.
1850 __ cmp(eax, ecx);
1851 __ j(greater, &call_builtin);
1852
1853 __ mov(ecx, Operand(esp, argc * kPointerSize));
1854 __ StoreNumberToDoubleElements(
1855 ecx, edi, eax, ecx, xmm0, &call_builtin, true, argc * kDoubleSize);
1856
1857 // Save new length.
1858 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1859 __ ret((argc + 1) * kPointerSize);
1860
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001861 __ bind(&with_write_barrier);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001862
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001863 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
1864
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001865 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001866 Label fast_object, not_fast_object;
1867 __ CheckFastObjectElements(ebx, &not_fast_object, Label::kNear);
1868 __ jmp(&fast_object);
1869 // In case of fast smi-only, convert to fast object, otherwise bail out.
1870 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001871 __ CheckFastSmiElements(ebx, &call_builtin);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001872 __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
1873 Immediate(factory()->heap_number_map()));
1874 __ j(equal, &call_builtin);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001875 // edi: elements array
1876 // edx: receiver
1877 // ebx: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001878 Label try_holey_map;
1879 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001880 FAST_ELEMENTS,
1881 ebx,
1882 edi,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001883 &try_holey_map);
1884
1885 ElementsTransitionGenerator::
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001886 GenerateMapChangeElementsTransition(masm(),
1887 DONT_TRACK_ALLOCATION_SITE,
1888 NULL);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001889 // Restore edi.
1890 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset));
1891 __ jmp(&fast_object);
1892
1893 __ bind(&try_holey_map);
1894 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1895 FAST_HOLEY_ELEMENTS,
1896 ebx,
1897 edi,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001898 &call_builtin);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001899 ElementsTransitionGenerator::
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001900 GenerateMapChangeElementsTransition(masm(),
1901 DONT_TRACK_ALLOCATION_SITE,
1902 NULL);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001903 // Restore edi.
1904 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset));
1905 __ bind(&fast_object);
1906 } else {
1907 __ CheckFastObjectElements(ebx, &call_builtin);
1908 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001909
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001910 // Save new length.
1911 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1912
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001913 // Store the value.
1914 __ lea(edx, FieldOperand(edi,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001915 eax, times_half_pointer_size,
1916 FixedArray::kHeaderSize - argc * kPointerSize));
1917 __ mov(Operand(edx, 0), ecx);
1918
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001919 __ RecordWrite(edi, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001920 OMIT_SMI_CHECK);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001921
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001922 __ ret((argc + 1) * kPointerSize);
1923
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001924 __ bind(&attempt_to_grow_elements);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001925 if (!FLAG_inline_new) {
1926 __ jmp(&call_builtin);
1927 }
1928
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001929 __ mov(ebx, Operand(esp, argc * kPointerSize));
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001930 // Growing elements that are SMI-only requires special handling in case
1931 // the new element is non-Smi. For now, delegate to the builtin.
1932 Label no_fast_elements_check;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001933 __ JumpIfSmi(ebx, &no_fast_elements_check);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001934 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
1935 __ CheckFastObjectElements(ecx, &call_builtin, Label::kFar);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001936 __ bind(&no_fast_elements_check);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001937
1938 // We could be lucky and the elements array could be at the top of
1939 // new-space. In this case we can just grow it in place by moving the
1940 // allocation pointer up.
1941
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001942 ExternalReference new_space_allocation_top =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001943 ExternalReference::new_space_allocation_top_address(isolate());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001944 ExternalReference new_space_allocation_limit =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001945 ExternalReference::new_space_allocation_limit_address(isolate());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001946
1947 const int kAllocationDelta = 4;
1948 // Load top.
1949 __ mov(ecx, Operand::StaticVariable(new_space_allocation_top));
1950
1951 // Check if it's the end of elements.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001952 __ lea(edx, FieldOperand(edi,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001953 eax, times_half_pointer_size,
1954 FixedArray::kHeaderSize - argc * kPointerSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001955 __ cmp(edx, ecx);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001956 __ j(not_equal, &call_builtin);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001957 __ add(ecx, Immediate(kAllocationDelta * kPointerSize));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001958 __ cmp(ecx, Operand::StaticVariable(new_space_allocation_limit));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001959 __ j(above, &call_builtin);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001960
1961 // We fit and could grow elements.
1962 __ mov(Operand::StaticVariable(new_space_allocation_top), ecx);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001963
1964 // Push the argument...
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001965 __ mov(Operand(edx, 0), ebx);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001966 // ... and fill the rest with holes.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001967 for (int i = 1; i < kAllocationDelta; i++) {
1968 __ mov(Operand(edx, i * kPointerSize),
lrn@chromium.org7516f052011-03-30 08:52:27 +00001969 Immediate(factory()->the_hole_value()));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001970 }
1971
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001972 // We know the elements array is in new space so we don't need the
1973 // remembered set, but we just pushed a value onto it so we may have to
1974 // tell the incremental marker to rescan the object that we just grew. We
1975 // don't need to worry about the holes because they are in old space and
1976 // already marked black.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001977 __ RecordWrite(edi, edx, ebx, kDontSaveFPRegs, OMIT_REMEMBERED_SET);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001978
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001979 // Restore receiver to edx as finish sequence assumes it's here.
1980 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1981
1982 // Increment element's and array's sizes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001983 __ add(FieldOperand(edi, FixedArray::kLengthOffset),
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001984 Immediate(Smi::FromInt(kAllocationDelta)));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001985
1986 // NOTE: This only happen in new-space, where we don't
1987 // care about the black-byte-count on pages. Otherwise we should
1988 // update that too if the object is black.
1989
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001990 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1991
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001992 __ ret((argc + 1) * kPointerSize);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001993 }
1994
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001995 __ bind(&call_builtin);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001996 __ TailCallExternalReference(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001997 ExternalReference(Builtins::c_ArrayPush, isolate()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001998 argc + 1,
1999 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002000 }
2001
2002 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002003 GenerateMissBranch();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002004
2005 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002006 return GetCode(type, name);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002007}
2008
2009
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002010Handle<Code> CallStubCompiler::CompileArrayPopCall(
2011 Handle<Object> object,
2012 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002013 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002014 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002015 Handle<String> name,
2016 Code::StubType type) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002017 // ----------- S t a t e -------------
2018 // -- ecx : name
2019 // -- esp[0] : return address
2020 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2021 // -- ...
2022 // -- esp[(argc + 1) * 4] : receiver
2023 // -----------------------------------
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002024
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00002025 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002026 if (!object->IsJSArray() || !cell.is_null()) {
2027 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002028 }
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00002029
ager@chromium.orgac091b72010-05-05 07:34:42 +00002030 Label miss, return_undefined, call_builtin;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002031
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002032 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002033
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002034 // Get the receiver from the stack.
2035 const int argc = arguments().immediate();
2036 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
2037
2038 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002039 __ JumpIfSmi(edx, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002040 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2041 name, &miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002042
2043 // Get the elements array of the object.
2044 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset));
2045
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00002046 // Check that the elements are in fast mode and writable.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002047 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
lrn@chromium.org7516f052011-03-30 08:52:27 +00002048 Immediate(factory()->fixed_array_map()));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00002049 __ j(not_equal, &call_builtin);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002050
2051 // Get the array's length into ecx and calculate new length.
2052 __ mov(ecx, FieldOperand(edx, JSArray::kLengthOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002053 __ sub(ecx, Immediate(Smi::FromInt(1)));
ager@chromium.orgac091b72010-05-05 07:34:42 +00002054 __ j(negative, &return_undefined);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002055
2056 // Get the last element.
2057 STATIC_ASSERT(kSmiTagSize == 1);
2058 STATIC_ASSERT(kSmiTag == 0);
2059 __ mov(eax, FieldOperand(ebx,
2060 ecx, times_half_pointer_size,
2061 FixedArray::kHeaderSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002062 __ cmp(eax, Immediate(factory()->the_hole_value()));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002063 __ j(equal, &call_builtin);
2064
2065 // Set the array's length.
2066 __ mov(FieldOperand(edx, JSArray::kLengthOffset), ecx);
2067
2068 // Fill with the hole.
2069 __ mov(FieldOperand(ebx,
2070 ecx, times_half_pointer_size,
2071 FixedArray::kHeaderSize),
lrn@chromium.org7516f052011-03-30 08:52:27 +00002072 Immediate(factory()->the_hole_value()));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002073 __ ret((argc + 1) * kPointerSize);
2074
ager@chromium.orgac091b72010-05-05 07:34:42 +00002075 __ bind(&return_undefined);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002076 __ mov(eax, Immediate(factory()->undefined_value()));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002077 __ ret((argc + 1) * kPointerSize);
2078
2079 __ bind(&call_builtin);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002080 __ TailCallExternalReference(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002081 ExternalReference(Builtins::c_ArrayPop, isolate()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002082 argc + 1,
2083 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002084
2085 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002086 GenerateMissBranch();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002087
2088 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002089 return GetCode(type, name);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002090}
2091
2092
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002093Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
2094 Handle<Object> object,
2095 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002096 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002097 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002098 Handle<String> name,
2099 Code::StubType type) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002100 // ----------- S t a t e -------------
2101 // -- ecx : function name
2102 // -- esp[0] : return address
2103 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2104 // -- ...
2105 // -- esp[(argc + 1) * 4] : receiver
2106 // -----------------------------------
2107
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002108 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002109 if (!object->IsString() || !cell.is_null()) {
2110 return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002111 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002112
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002113 const int argc = arguments().immediate();
2114
2115 Label miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002116 Label name_miss;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002117 Label index_out_of_range;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002118 Label* index_out_of_range_label = &index_out_of_range;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002119
danno@chromium.org40cb8782011-05-25 07:58:50 +00002120 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002121 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002122 DEFAULT_STRING_STUB)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002123 index_out_of_range_label = &miss;
2124 }
2125
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002126 GenerateNameCheck(name, &name_miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002127
2128 // Check that the maps starting from the prototype haven't changed.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002129 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2130 Context::STRING_FUNCTION_INDEX,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002131 eax,
2132 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002133 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002134 CheckPrototypes(
2135 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2136 eax, holder, ebx, edx, edi, name, &miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002137
2138 Register receiver = ebx;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002139 Register index = edi;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002140 Register result = eax;
2141 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize));
2142 if (argc > 0) {
2143 __ mov(index, Operand(esp, (argc - 0) * kPointerSize));
2144 } else {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002145 __ Set(index, Immediate(factory()->undefined_value()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002146 }
2147
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002148 StringCharCodeAtGenerator generator(receiver,
2149 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002150 result,
2151 &miss, // When not a string.
2152 &miss, // When not a number.
2153 index_out_of_range_label,
2154 STRING_INDEX_IS_NUMBER);
2155 generator.GenerateFast(masm());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002156 __ ret((argc + 1) * kPointerSize);
2157
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002158 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002159 generator.GenerateSlow(masm(), call_helper);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002160
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002161 if (index_out_of_range.is_linked()) {
2162 __ bind(&index_out_of_range);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002163 __ Set(eax, Immediate(factory()->nan_value()));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002164 __ ret((argc + 1) * kPointerSize);
2165 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002166
2167 __ bind(&miss);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002168 // Restore function name in ecx.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002169 __ Set(ecx, Immediate(name));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002170 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002171 GenerateMissBranch();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002172
2173 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002174 return GetCode(type, name);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002175}
2176
2177
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002178Handle<Code> CallStubCompiler::CompileStringCharAtCall(
2179 Handle<Object> object,
2180 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002181 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002182 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002183 Handle<String> name,
2184 Code::StubType type) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002185 // ----------- S t a t e -------------
2186 // -- ecx : function name
2187 // -- esp[0] : return address
2188 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2189 // -- ...
2190 // -- esp[(argc + 1) * 4] : receiver
2191 // -----------------------------------
2192
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002193 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002194 if (!object->IsString() || !cell.is_null()) {
2195 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002196 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002197
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002198 const int argc = arguments().immediate();
2199
2200 Label miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002201 Label name_miss;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002202 Label index_out_of_range;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002203 Label* index_out_of_range_label = &index_out_of_range;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002204
danno@chromium.org40cb8782011-05-25 07:58:50 +00002205 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002206 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002207 DEFAULT_STRING_STUB)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002208 index_out_of_range_label = &miss;
2209 }
2210
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002211 GenerateNameCheck(name, &name_miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002212
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002213 // Check that the maps starting from the prototype haven't changed.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002214 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2215 Context::STRING_FUNCTION_INDEX,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002216 eax,
2217 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002218 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002219 CheckPrototypes(
2220 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2221 eax, holder, ebx, edx, edi, name, &miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002222
2223 Register receiver = eax;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002224 Register index = edi;
danno@chromium.orgc612e022011-11-10 11:38:15 +00002225 Register scratch = edx;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002226 Register result = eax;
2227 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize));
2228 if (argc > 0) {
2229 __ mov(index, Operand(esp, (argc - 0) * kPointerSize));
2230 } else {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002231 __ Set(index, Immediate(factory()->undefined_value()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002232 }
2233
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002234 StringCharAtGenerator generator(receiver,
2235 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00002236 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002237 result,
2238 &miss, // When not a string.
2239 &miss, // When not a number.
2240 index_out_of_range_label,
2241 STRING_INDEX_IS_NUMBER);
2242 generator.GenerateFast(masm());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002243 __ ret((argc + 1) * kPointerSize);
2244
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002245 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002246 generator.GenerateSlow(masm(), call_helper);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002247
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002248 if (index_out_of_range.is_linked()) {
2249 __ bind(&index_out_of_range);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002250 __ Set(eax, Immediate(factory()->empty_string()));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002251 __ ret((argc + 1) * kPointerSize);
2252 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002253
2254 __ bind(&miss);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002255 // Restore function name in ecx.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002256 __ Set(ecx, Immediate(name));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002257 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002258 GenerateMissBranch();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002259
2260 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002261 return GetCode(type, name);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002262}
2263
2264
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002265Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
2266 Handle<Object> object,
2267 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002268 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002269 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002270 Handle<String> name,
2271 Code::StubType type) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002272 // ----------- S t a t e -------------
2273 // -- ecx : function name
2274 // -- esp[0] : return address
2275 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2276 // -- ...
2277 // -- esp[(argc + 1) * 4] : receiver
2278 // -----------------------------------
2279
2280 const int argc = arguments().immediate();
2281
2282 // If the object is not a JSObject or we got an unexpected number of
2283 // arguments, bail out to the regular call.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002284 if (!object->IsJSObject() || argc != 1) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002285 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002286 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002287
2288 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002289 GenerateNameCheck(name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002290
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002291 if (cell.is_null()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002292 __ mov(edx, Operand(esp, 2 * kPointerSize));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002293 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002294 __ JumpIfSmi(edx, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002295 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2296 name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002297 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002298 ASSERT(cell->value() == *function);
2299 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2300 &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002301 GenerateLoadFunctionFromCell(cell, function, &miss);
2302 }
2303
2304 // Load the char code argument.
2305 Register code = ebx;
2306 __ mov(code, Operand(esp, 1 * kPointerSize));
2307
2308 // Check the code is a smi.
2309 Label slow;
2310 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002311 __ JumpIfNotSmi(code, &slow);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002312
2313 // Convert the smi code to uint16.
2314 __ and_(code, Immediate(Smi::FromInt(0xffff)));
2315
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002316 StringCharFromCodeGenerator generator(code, eax);
2317 generator.GenerateFast(masm());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002318 __ ret(2 * kPointerSize);
2319
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002320 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002321 generator.GenerateSlow(masm(), call_helper);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002322
2323 // Tail call the full function. We do not have to patch the receiver
2324 // because the function makes no use of it.
2325 __ bind(&slow);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002326 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002327 ? CALL_AS_FUNCTION
2328 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002329 ParameterCount expected(function);
2330 __ InvokeFunction(function, expected, arguments(),
2331 JUMP_FUNCTION, NullCallWrapper(), call_kind);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002332
2333 __ bind(&miss);
2334 // ecx: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002335 GenerateMissBranch();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002336
2337 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002338 return GetCode(type, name);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002339}
2340
2341
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002342Handle<Code> CallStubCompiler::CompileMathFloorCall(
2343 Handle<Object> object,
2344 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002345 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002346 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002347 Handle<String> name,
2348 Code::StubType type) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002349 // ----------- S t a t e -------------
2350 // -- ecx : name
2351 // -- esp[0] : return address
2352 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2353 // -- ...
2354 // -- esp[(argc + 1) * 4] : receiver
2355 // -----------------------------------
2356
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002357 if (!CpuFeatures::IsSupported(SSE2)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002358 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002359 }
2360
ulan@chromium.org750145a2013-03-07 15:14:13 +00002361 CpuFeatureScope use_sse2(masm(), SSE2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002362
2363 const int argc = arguments().immediate();
2364
2365 // If the object is not a JSObject or we got an unexpected number of
2366 // arguments, bail out to the regular call.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002367 if (!object->IsJSObject() || argc != 1) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002368 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002369 }
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002370
2371 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002372 GenerateNameCheck(name, &miss);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002373
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002374 if (cell.is_null()) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002375 __ mov(edx, Operand(esp, 2 * kPointerSize));
2376
2377 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002378 __ JumpIfSmi(edx, &miss);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002379
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002380 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2381 name, &miss);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002382 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002383 ASSERT(cell->value() == *function);
2384 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2385 &miss);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002386 GenerateLoadFunctionFromCell(cell, function, &miss);
2387 }
2388
2389 // Load the (only) argument into eax.
2390 __ mov(eax, Operand(esp, 1 * kPointerSize));
2391
2392 // Check if the argument is a smi.
2393 Label smi;
2394 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002395 __ JumpIfSmi(eax, &smi);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002396
2397 // Check if the argument is a heap number and load its value into xmm0.
2398 Label slow;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002399 __ CheckMap(eax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002400 __ movdbl(xmm0, FieldOperand(eax, HeapNumber::kValueOffset));
2401
2402 // Check if the argument is strictly positive. Note this also
2403 // discards NaN.
2404 __ xorpd(xmm1, xmm1);
2405 __ ucomisd(xmm0, xmm1);
2406 __ j(below_equal, &slow);
2407
2408 // Do a truncating conversion.
2409 __ cvttsd2si(eax, Operand(xmm0));
2410
2411 // Check if the result fits into a smi. Note this also checks for
2412 // 0x80000000 which signals a failed conversion.
2413 Label wont_fit_into_smi;
2414 __ test(eax, Immediate(0xc0000000));
2415 __ j(not_zero, &wont_fit_into_smi);
2416
2417 // Smi tag and return.
2418 __ SmiTag(eax);
2419 __ bind(&smi);
2420 __ ret(2 * kPointerSize);
2421
2422 // Check if the argument is < 2^kMantissaBits.
2423 Label already_round;
2424 __ bind(&wont_fit_into_smi);
2425 __ LoadPowerOf2(xmm1, ebx, HeapNumber::kMantissaBits);
2426 __ ucomisd(xmm0, xmm1);
2427 __ j(above_equal, &already_round);
2428
2429 // Save a copy of the argument.
2430 __ movaps(xmm2, xmm0);
2431
2432 // Compute (argument + 2^kMantissaBits) - 2^kMantissaBits.
2433 __ addsd(xmm0, xmm1);
2434 __ subsd(xmm0, xmm1);
2435
2436 // Compare the argument and the tentative result to get the right mask:
2437 // if xmm2 < xmm0:
2438 // xmm2 = 1...1
2439 // else:
2440 // xmm2 = 0...0
2441 __ cmpltsd(xmm2, xmm0);
2442
2443 // Subtract 1 if the argument was less than the tentative result.
2444 __ LoadPowerOf2(xmm1, ebx, 0);
2445 __ andpd(xmm1, xmm2);
2446 __ subsd(xmm0, xmm1);
2447
2448 // Return a new heap number.
2449 __ AllocateHeapNumber(eax, ebx, edx, &slow);
2450 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
2451 __ ret(2 * kPointerSize);
2452
2453 // Return the argument (when it's an already round heap number).
2454 __ bind(&already_round);
2455 __ mov(eax, Operand(esp, 1 * kPointerSize));
2456 __ ret(2 * kPointerSize);
2457
2458 // Tail call the full function. We do not have to patch the receiver
2459 // because the function makes no use of it.
2460 __ bind(&slow);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002461 ParameterCount expected(function);
2462 __ InvokeFunction(function, expected, arguments(),
2463 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002464
2465 __ bind(&miss);
2466 // ecx: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002467 GenerateMissBranch();
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002468
2469 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002470 return GetCode(type, name);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002471}
2472
2473
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002474Handle<Code> CallStubCompiler::CompileMathAbsCall(
2475 Handle<Object> object,
2476 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002477 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002478 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002479 Handle<String> name,
2480 Code::StubType type) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002481 // ----------- S t a t e -------------
2482 // -- ecx : name
2483 // -- esp[0] : return address
2484 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2485 // -- ...
2486 // -- esp[(argc + 1) * 4] : receiver
2487 // -----------------------------------
2488
2489 const int argc = arguments().immediate();
2490
2491 // If the object is not a JSObject or we got an unexpected number of
2492 // arguments, bail out to the regular call.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002493 if (!object->IsJSObject() || argc != 1) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002494 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002495 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002496
2497 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002498 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002499
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002500 if (cell.is_null()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002501 __ mov(edx, Operand(esp, 2 * kPointerSize));
2502
2503 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002504 __ JumpIfSmi(edx, &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002505
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002506 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2507 name, &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002508 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002509 ASSERT(cell->value() == *function);
2510 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2511 &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002512 GenerateLoadFunctionFromCell(cell, function, &miss);
2513 }
2514
2515 // Load the (only) argument into eax.
2516 __ mov(eax, Operand(esp, 1 * kPointerSize));
2517
2518 // Check if the argument is a smi.
2519 Label not_smi;
2520 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002521 __ JumpIfNotSmi(eax, &not_smi);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002522
danno@chromium.org59400602013-08-13 17:09:37 +00002523 // Branchless abs implementation, refer to below:
2524 // http://graphics.stanford.edu/~seander/bithacks.html#IntegerAbs
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002525 // Set ebx to 1...1 (== -1) if the argument is negative, or to 0...0
2526 // otherwise.
2527 __ mov(ebx, eax);
2528 __ sar(ebx, kBitsPerInt - 1);
2529
2530 // Do bitwise not or do nothing depending on ebx.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002531 __ xor_(eax, ebx);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002532
2533 // Add 1 or do nothing depending on ebx.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002534 __ sub(eax, ebx);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002535
2536 // If the result is still negative, go to the slow case.
2537 // This only happens for the most negative smi.
2538 Label slow;
2539 __ j(negative, &slow);
2540
2541 // Smi case done.
2542 __ ret(2 * kPointerSize);
2543
2544 // Check if the argument is a heap number and load its exponent and
2545 // sign into ebx.
2546 __ bind(&not_smi);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002547 __ CheckMap(eax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002548 __ mov(ebx, FieldOperand(eax, HeapNumber::kExponentOffset));
2549
2550 // Check the sign of the argument. If the argument is positive,
2551 // just return it.
2552 Label negative_sign;
2553 __ test(ebx, Immediate(HeapNumber::kSignMask));
2554 __ j(not_zero, &negative_sign);
2555 __ ret(2 * kPointerSize);
2556
2557 // If the argument is negative, clear the sign, and return a new
2558 // number.
2559 __ bind(&negative_sign);
2560 __ and_(ebx, ~HeapNumber::kSignMask);
2561 __ mov(ecx, FieldOperand(eax, HeapNumber::kMantissaOffset));
2562 __ AllocateHeapNumber(eax, edi, edx, &slow);
2563 __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), ebx);
2564 __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx);
2565 __ ret(2 * kPointerSize);
2566
2567 // Tail call the full function. We do not have to patch the receiver
2568 // because the function makes no use of it.
2569 __ bind(&slow);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002570 ParameterCount expected(function);
2571 __ InvokeFunction(function, expected, arguments(),
2572 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002573
2574 __ bind(&miss);
2575 // ecx: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002576 GenerateMissBranch();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002577
2578 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002579 return GetCode(type, name);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002580}
2581
2582
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002583Handle<Code> CallStubCompiler::CompileFastApiCall(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002584 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002585 Handle<Object> object,
2586 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002587 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002588 Handle<JSFunction> function,
2589 Handle<String> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002590 ASSERT(optimization.is_simple_api_call());
2591 // Bail out if object is a global object as we don't want to
2592 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002593 if (object->IsGlobalObject()) return Handle<Code>::null();
2594 if (!cell.is_null()) return Handle<Code>::null();
2595 if (!object->IsJSObject()) return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002596 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002597 Handle<JSObject>::cast(object), holder);
2598 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002599
2600 Label miss, miss_before_stack_reserved;
2601
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002602 GenerateNameCheck(name, &miss_before_stack_reserved);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002603
2604 // Get the receiver from the stack.
2605 const int argc = arguments().immediate();
2606 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
2607
2608 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002609 __ JumpIfSmi(edx, &miss_before_stack_reserved);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002610
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002611 Counters* counters = isolate()->counters();
2612 __ IncrementCounter(counters->call_const(), 1);
2613 __ IncrementCounter(counters->call_const_fast_api(), 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002614
2615 // Allocate space for v8::Arguments implicit values. Must be initialized
2616 // before calling any runtime function.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002617 __ sub(esp, Immediate(kFastApiCallArguments * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002618
2619 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002620 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2621 name, depth, &miss);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002622
2623 // Move the return address on top of the stack.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002624 __ mov(eax, Operand(esp, kFastApiCallArguments * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002625 __ mov(Operand(esp, 0 * kPointerSize), eax);
2626
2627 // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains
2628 // duplicate of return address and will be overwritten.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002629 GenerateFastApiCall(masm(), optimization, argc, false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002630
2631 __ bind(&miss);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002632 __ add(esp, Immediate(kFastApiCallArguments * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002633
2634 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002635 GenerateMissBranch();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002636
2637 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002638 return GetCode(function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002639}
2640
2641
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002642void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
2643 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002644 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002645 CheckType check,
2646 Label* success) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002647 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00002648 // -- ecx : name
2649 // -- esp[0] : return address
2650 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2651 // -- ...
2652 // -- esp[(argc + 1) * 4] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002653 // -----------------------------------
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002654 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002655 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002656
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002657 // Get the receiver from the stack.
2658 const int argc = arguments().immediate();
2659 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
2660
2661 // Check that the receiver isn't a smi.
2662 if (check != NUMBER_CHECK) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00002663 __ JumpIfSmi(edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002664 }
2665
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002666 // Make sure that it's okay not to patch the on stack receiver
2667 // unless we're doing a receiver map check.
2668 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002669 switch (check) {
2670 case RECEIVER_MAP_CHECK:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002671 __ IncrementCounter(isolate()->counters()->call_const(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00002672
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002673 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002674 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax,
2675 edi, name, &miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002676
2677 // Patch the receiver on the stack with the global proxy if
2678 // necessary.
2679 if (object->IsGlobalObject()) {
2680 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
2681 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
2682 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002683 break;
2684
2685 case STRING_CHECK:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002686 // Check that the object is a string.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002687 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, eax);
2688 __ j(above_equal, &miss);
2689 // Check that the maps starting from the prototype haven't changed.
2690 GenerateDirectLoadGlobalFunctionPrototype(
2691 masm(), Context::STRING_FUNCTION_INDEX, eax, &miss);
2692 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002693 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002694 eax, holder, ebx, edx, edi, name, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002695 break;
2696
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002697 case SYMBOL_CHECK:
2698 // Check that the object is a symbol.
2699 __ CmpObjectType(edx, SYMBOL_TYPE, eax);
2700 __ j(not_equal, &miss);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002701 // Check that the maps starting from the prototype haven't changed.
2702 GenerateDirectLoadGlobalFunctionPrototype(
2703 masm(), Context::SYMBOL_FUNCTION_INDEX, eax, &miss);
2704 CheckPrototypes(
2705 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2706 eax, holder, ebx, edx, edi, name, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002707 break;
2708
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002709 case NUMBER_CHECK: {
2710 Label fast;
2711 // Check that the object is a smi or a heap number.
2712 __ JumpIfSmi(edx, &fast);
2713 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, eax);
2714 __ j(not_equal, &miss);
2715 __ bind(&fast);
2716 // Check that the maps starting from the prototype haven't changed.
2717 GenerateDirectLoadGlobalFunctionPrototype(
2718 masm(), Context::NUMBER_FUNCTION_INDEX, eax, &miss);
2719 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002720 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002721 eax, holder, ebx, edx, edi, name, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002722 break;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002723 }
2724 case BOOLEAN_CHECK: {
2725 Label fast;
2726 // Check that the object is a boolean.
2727 __ cmp(edx, factory()->true_value());
2728 __ j(equal, &fast);
2729 __ cmp(edx, factory()->false_value());
2730 __ j(not_equal, &miss);
2731 __ bind(&fast);
2732 // Check that the maps starting from the prototype haven't changed.
2733 GenerateDirectLoadGlobalFunctionPrototype(
2734 masm(), Context::BOOLEAN_FUNCTION_INDEX, eax, &miss);
2735 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002736 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002737 eax, holder, ebx, edx, edi, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002738 break;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002739 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002740 }
2741
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002742 __ jmp(success);
2743
2744 // Handle call cache miss.
2745 __ bind(&miss);
2746 GenerateMissBranch();
2747}
2748
2749
2750void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002751 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002752 ? CALL_AS_FUNCTION
2753 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002754 ParameterCount expected(function);
2755 __ InvokeFunction(function, expected, arguments(),
2756 JUMP_FUNCTION, NullCallWrapper(), call_kind);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002757}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002758
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002759
2760Handle<Code> CallStubCompiler::CompileCallConstant(
2761 Handle<Object> object,
2762 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002763 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002764 CheckType check,
2765 Handle<JSFunction> function) {
2766
2767 if (HasCustomCallGenerator(function)) {
2768 Handle<Code> code = CompileCustomCall(object, holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002769 Handle<Cell>::null(),
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002770 function, Handle<String>::cast(name),
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002771 Code::CONSTANT);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002772 // A null handle means bail out to the regular compiler code below.
2773 if (!code.is_null()) return code;
2774 }
2775
2776 Label success;
2777
2778 CompileHandlerFrontend(object, holder, name, check, &success);
2779 __ bind(&success);
2780 CompileHandlerBackend(function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002781
2782 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002783 return GetCode(function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002784}
2785
2786
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002787Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2788 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002789 Handle<Name> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002790 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00002791 // -- ecx : name
2792 // -- esp[0] : return address
2793 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2794 // -- ...
2795 // -- esp[(argc + 1) * 4] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002796 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002797 Label miss;
2798
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002799 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002800
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002801 // Get the number of arguments.
2802 const int argc = arguments().immediate();
2803
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002804 LookupResult lookup(isolate());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002805 LookupPostInterceptor(holder, name, &lookup);
2806
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002807 // Get the receiver from the stack.
2808 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002809
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002810 CallInterceptorCompiler compiler(this, arguments(), ecx, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002811 compiler.Compile(masm(), object, holder, name, &lookup, edx, ebx, edi, eax,
2812 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002813
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002814 // Restore receiver.
2815 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002816
2817 // Check that the function really is a function.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002818 __ JumpIfSmi(eax, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002819 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002820 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002821
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002822 // Patch the receiver on the stack with the global proxy if
2823 // necessary.
2824 if (object->IsGlobalObject()) {
2825 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
2826 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
2827 }
2828
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002829 // Invoke the function.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002830 __ mov(edi, eax);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002831 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002832 ? CALL_AS_FUNCTION
2833 : CALL_AS_METHOD;
2834 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION,
2835 NullCallWrapper(), call_kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002836
2837 // Handle load cache miss.
2838 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002839 GenerateMissBranch();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002840
2841 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002842 return GetCode(Code::INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002843}
2844
2845
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002846Handle<Code> CallStubCompiler::CompileCallGlobal(
2847 Handle<JSObject> object,
2848 Handle<GlobalObject> holder,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002849 Handle<PropertyCell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002850 Handle<JSFunction> function,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002851 Handle<Name> name) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002852 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00002853 // -- ecx : name
2854 // -- esp[0] : return address
2855 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2856 // -- ...
2857 // -- esp[(argc + 1) * 4] : receiver
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002858 // -----------------------------------
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002859
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002860 if (HasCustomCallGenerator(function)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00002861 Handle<Code> code = CompileCustomCall(
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002862 object, holder, cell, function, Handle<String>::cast(name),
2863 Code::NORMAL);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002864 // A null handle means bail out to the regular compiler code below.
2865 if (!code.is_null()) return code;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002866 }
2867
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002868 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002869 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002870
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002871 // Get the number of arguments.
2872 const int argc = arguments().immediate();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002873 GenerateGlobalReceiverCheck(object, holder, name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002874 GenerateLoadFunctionFromCell(cell, function, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002875
2876 // Patch the receiver on the stack with the global proxy.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002877 if (object->IsGlobalObject()) {
2878 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
2879 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
2880 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002881
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002882 // Set up the context (function already in edi).
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002883 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
2884
2885 // Jump to the cached code (tail call).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002886 Counters* counters = isolate()->counters();
2887 __ IncrementCounter(counters->call_global_inline(), 1);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002888 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002889 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002890 ? CALL_AS_FUNCTION
2891 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002892 // We call indirectly through the code field in the function to
2893 // allow recompilation to take effect without changing any of the
2894 // call sites.
2895 __ InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset),
2896 expected, arguments(), JUMP_FUNCTION,
2897 NullCallWrapper(), call_kind);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002898
2899 // Handle call cache miss.
2900 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002901 __ IncrementCounter(counters->call_global_inline_miss(), 1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002902 GenerateMissBranch();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002903
2904 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002905 return GetCode(Code::NORMAL, name);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002906}
2907
2908
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002909Handle<Code> StoreStubCompiler::CompileStoreCallback(
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002910 Handle<JSObject> object,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002911 Handle<JSObject> holder,
danno@chromium.orgbee51992013-07-10 14:57:15 +00002912 Handle<Name> name,
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002913 Handle<ExecutableAccessorInfo> callback) {
danno@chromium.orgbee51992013-07-10 14:57:15 +00002914 Label success;
2915 HandlerFrontend(object, receiver(), holder, name, &success);
2916 __ bind(&success);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002917
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002918 __ pop(scratch1()); // remove the return address
2919 __ push(receiver());
2920 __ Push(callback);
2921 __ Push(name);
2922 __ push(value());
2923 __ push(scratch1()); // restore return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002924
mads.s.ager31e71382008-08-13 09:32:07 +00002925 // Do tail-call to the runtime system.
2926 ExternalReference store_callback_property =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002927 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002928 __ TailCallExternalReference(store_callback_property, 4, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002929
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002930 // Return the generated code.
danno@chromium.orgbee51992013-07-10 14:57:15 +00002931 return GetCode(kind(), Code::CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002932}
2933
2934
dslomov@chromium.org639bac02013-09-09 11:58:54 +00002935Handle<Code> StoreStubCompiler::CompileStoreCallback(
2936 Handle<JSObject> object,
2937 Handle<JSObject> holder,
2938 Handle<Name> name,
2939 const CallOptimization& call_optimization) {
2940 Label success;
2941 HandlerFrontend(object, receiver(), holder, name, &success);
2942 __ bind(&success);
2943
2944 Register values[] = { value() };
2945 GenerateFastApiCall(
2946 masm(), call_optimization, receiver(), scratch1(), 1, values);
2947
2948 // Return the generated code.
2949 return GetCode(kind(), Code::CALLBACKS, name);
2950}
2951
2952
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002953#undef __
2954#define __ ACCESS_MASM(masm)
2955
2956
2957void StoreStubCompiler::GenerateStoreViaSetter(
2958 MacroAssembler* masm,
2959 Handle<JSFunction> setter) {
2960 // ----------- S t a t e -------------
2961 // -- eax : value
2962 // -- ecx : name
2963 // -- edx : receiver
2964 // -- esp[0] : return address
2965 // -----------------------------------
2966 {
2967 FrameScope scope(masm, StackFrame::INTERNAL);
2968
2969 // Save value register, so we can restore it later.
2970 __ push(eax);
2971
2972 if (!setter.is_null()) {
2973 // Call the JavaScript setter with receiver and value on the stack.
2974 __ push(edx);
2975 __ push(eax);
2976 ParameterCount actual(1);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002977 ParameterCount expected(setter);
2978 __ InvokeFunction(setter, expected, actual,
2979 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002980 } else {
2981 // If we generate a global code snippet for deoptimization only, remember
2982 // the place to continue after deoptimization.
2983 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2984 }
2985
2986 // We have to return the passed value, not the return value of the setter.
2987 __ pop(eax);
2988
2989 // Restore context register.
2990 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
2991 }
2992 __ ret(0);
2993}
2994
2995
2996#undef __
2997#define __ ACCESS_MASM(masm())
2998
2999
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003000Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003001 Handle<JSObject> object,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003002 Handle<Name> name) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003003 __ pop(scratch1()); // remove the return address
3004 __ push(receiver());
3005 __ push(this->name());
3006 __ push(value());
3007 __ push(Immediate(Smi::FromInt(strict_mode())));
3008 __ push(scratch1()); // restore return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003009
mads.s.ager31e71382008-08-13 09:32:07 +00003010 // Do tail-call to the runtime system.
3011 ExternalReference store_ic_property =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003012 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003013 __ TailCallExternalReference(store_ic_property, 4, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003014
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003015 // Return the generated code.
danno@chromium.orgbee51992013-07-10 14:57:15 +00003016 return GetCode(kind(), Code::INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003017}
3018
3019
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003020Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
3021 MapHandleList* receiver_maps,
3022 CodeHandleList* handler_stubs,
3023 MapHandleList* transitioned_maps) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003024 Label miss;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003025 __ JumpIfSmi(receiver(), &miss, Label::kNear);
3026 __ mov(scratch1(), FieldOperand(receiver(), HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003027 for (int i = 0; i < receiver_maps->length(); ++i) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003028 __ cmp(scratch1(), receiver_maps->at(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003029 if (transitioned_maps->at(i).is_null()) {
3030 __ j(equal, handler_stubs->at(i));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003031 } else {
3032 Label next_map;
3033 __ j(not_equal, &next_map, Label::kNear);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003034 __ mov(transition_map(), Immediate(transitioned_maps->at(i)));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003035 __ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003036 __ bind(&next_map);
3037 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003038 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003039 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003040 TailCallBuiltin(masm(), MissBuiltin(kind()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003041
3042 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003043 return GetICCode(
3044 kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003045}
3046
3047
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00003048Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00003049 Handle<JSObject> object,
3050 Handle<JSObject> last,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003051 Handle<Name> name,
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00003052 Handle<GlobalObject> global) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003053 Label success;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00003054
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003055 NonexistentHandlerFrontend(object, last, name, &success, global);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00003056
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003057 __ bind(&success);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00003058 // Return undefined if maps of the full prototype chain are still the
3059 // same and no global property with this name contains a value.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003060 __ mov(eax, isolate()->factory()->undefined_value());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00003061 __ ret(0);
3062
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00003063 // Return the generated code.
ulan@chromium.org750145a2013-03-07 15:14:13 +00003064 return GetCode(kind(), Code::NONEXISTENT, name);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00003065}
3066
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003067
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00003068Register* LoadStubCompiler::registers() {
3069 // receiver, name, scratch1, scratch2, scratch3, scratch4.
3070 static Register registers[] = { edx, ecx, ebx, eax, edi, no_reg };
3071 return registers;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003072}
3073
3074
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00003075Register* KeyedLoadStubCompiler::registers() {
3076 // receiver, name, scratch1, scratch2, scratch3, scratch4.
3077 static Register registers[] = { edx, ecx, ebx, eax, edi, no_reg };
3078 return registers;
3079}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003080
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003081
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003082Register* StoreStubCompiler::registers() {
3083 // receiver, name, value, scratch1, scratch2, scratch3.
3084 static Register registers[] = { edx, ecx, eax, ebx, edi, no_reg };
3085 return registers;
3086}
3087
3088
3089Register* KeyedStoreStubCompiler::registers() {
3090 // receiver, name, value, scratch1, scratch2, scratch3.
3091 static Register registers[] = { edx, ecx, eax, ebx, edi, no_reg };
3092 return registers;
3093}
3094
3095
ulan@chromium.org750145a2013-03-07 15:14:13 +00003096void KeyedLoadStubCompiler::GenerateNameCheck(Handle<Name> name,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00003097 Register name_reg,
3098 Label* miss) {
3099 __ cmp(name_reg, Immediate(name));
3100 __ j(not_equal, miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003101}
3102
3103
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003104void KeyedStoreStubCompiler::GenerateNameCheck(Handle<Name> name,
3105 Register name_reg,
3106 Label* miss) {
3107 __ cmp(name_reg, Immediate(name));
3108 __ j(not_equal, miss);
3109}
3110
3111
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003112#undef __
3113#define __ ACCESS_MASM(masm)
3114
3115
3116void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
3117 Handle<JSFunction> getter) {
3118 // ----------- S t a t e -------------
3119 // -- ecx : name
3120 // -- edx : receiver
3121 // -- esp[0] : return address
3122 // -----------------------------------
3123 {
3124 FrameScope scope(masm, StackFrame::INTERNAL);
3125
3126 if (!getter.is_null()) {
3127 // Call the JavaScript getter with the receiver on the stack.
3128 __ push(edx);
3129 ParameterCount actual(0);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003130 ParameterCount expected(getter);
3131 __ InvokeFunction(getter, expected, actual,
3132 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003133 } else {
3134 // If we generate a global code snippet for deoptimization only, remember
3135 // the place to continue after deoptimization.
3136 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
3137 }
3138
3139 // Restore context register.
3140 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
3141 }
3142 __ ret(0);
3143}
3144
3145
3146#undef __
3147#define __ ACCESS_MASM(masm())
3148
3149
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003150Handle<Code> LoadStubCompiler::CompileLoadGlobal(
3151 Handle<JSObject> object,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003152 Handle<GlobalObject> global,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00003153 Handle<PropertyCell> cell,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003154 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003155 bool is_dont_delete) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003156 Label success, miss;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003157
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003158 __ CheckMap(receiver(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
3159 HandlerFrontendHeader(
3160 object, receiver(), Handle<JSObject>::cast(global), name, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003161 // Get the value from the cell.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003162 if (Serializer::enabled()) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003163 __ mov(eax, Immediate(cell));
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00003164 __ mov(eax, FieldOperand(eax, PropertyCell::kValueOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003165 } else {
danno@chromium.org41728482013-06-12 22:31:22 +00003166 __ mov(eax, Operand::ForCell(cell));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003167 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003168
3169 // Check for deleted property if property can actually be deleted.
3170 if (!is_dont_delete) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003171 __ cmp(eax, factory()->the_hole_value());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003172 __ j(equal, &miss);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003173 } else if (FLAG_debug_code) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003174 __ cmp(eax, factory()->the_hole_value());
danno@chromium.org59400602013-08-13 17:09:37 +00003175 __ Check(not_equal, kDontDeleteCellsCannotContainTheHole);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003176 }
3177
danno@chromium.orgbee51992013-07-10 14:57:15 +00003178 HandlerFrontendFooter(name, &success, &miss);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003179 __ bind(&success);
3180
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003181 Counters* counters = isolate()->counters();
3182 __ IncrementCounter(counters->named_load_global_stub(), 1);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003183 // The code above already loads the result into the return register.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003184 __ ret(0);
3185
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003186 // Return the generated code.
ulan@chromium.org750145a2013-03-07 15:14:13 +00003187 return GetICCode(kind(), Code::NORMAL, name);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003188}
3189
3190
danno@chromium.orgbee51992013-07-10 14:57:15 +00003191Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC(
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003192 MapHandleList* receiver_maps,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003193 CodeHandleList* handlers,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003194 Handle<Name> name,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003195 Code::StubType type,
3196 IcCheckType check) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003197 Label miss;
3198
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003199 if (check == PROPERTY) {
3200 GenerateNameCheck(name, this->name(), &miss);
3201 }
3202
3203 __ JumpIfSmi(receiver(), &miss);
3204 Register map_reg = scratch1();
3205 __ mov(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset));
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003206 int receiver_count = receiver_maps->length();
danno@chromium.orgf005df62013-04-30 16:36:45 +00003207 int number_of_handled_maps = 0;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003208 for (int current = 0; current < receiver_count; ++current) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00003209 Handle<Map> map = receiver_maps->at(current);
3210 if (!map->is_deprecated()) {
3211 number_of_handled_maps++;
3212 __ cmp(map_reg, map);
3213 __ j(equal, handlers->at(current));
3214 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003215 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00003216 ASSERT(number_of_handled_maps != 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003217
3218 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003219 TailCallBuiltin(masm(), MissBuiltin(kind()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003220
3221 // Return the generated code.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003222 InlineCacheState state =
danno@chromium.orgf005df62013-04-30 16:36:45 +00003223 number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC;
ulan@chromium.org750145a2013-03-07 15:14:13 +00003224 return GetICCode(kind(), type, name, state);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003225}
3226
3227
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003228#undef __
3229#define __ ACCESS_MASM(masm)
3230
3231
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003232void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3233 MacroAssembler* masm) {
3234 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003235 // -- ecx : key
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003236 // -- edx : receiver
3237 // -- esp[0] : return address
3238 // -----------------------------------
3239 Label slow, miss_force_generic;
3240
3241 // This stub is meant to be tail-jumped to, the receiver must already
3242 // have been verified by the caller to not be a smi.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003243 __ JumpIfNotSmi(ecx, &miss_force_generic);
3244 __ mov(ebx, ecx);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003245 __ SmiUntag(ebx);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003246 __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset));
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003247
3248 // Push receiver on the stack to free up a register for the dictionary
3249 // probing.
3250 __ push(edx);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003251 __ LoadFromNumberDictionary(&slow, eax, ecx, ebx, edx, edi, eax);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003252 // Pop receiver before returning.
3253 __ pop(edx);
3254 __ ret(0);
3255
3256 __ bind(&slow);
3257 __ pop(edx);
3258
3259 // ----------- S t a t e -------------
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003260 // -- ecx : key
3261 // -- edx : receiver
3262 // -- esp[0] : return address
3263 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003264 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003265
3266 __ bind(&miss_force_generic);
3267 // ----------- S t a t e -------------
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003268 // -- ecx : key
3269 // -- edx : receiver
3270 // -- esp[0] : return address
3271 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003272 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_MissForceGeneric);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003273}
3274
3275
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003276#undef __
3277
3278} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003279
3280#endif // V8_TARGET_ARCH_IA32