blob: a3be0a777739e071980b4b57e73138768573f38e [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
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000140void StubCompiler::GenerateDictionaryNegativeLookup(MacroAssembler* masm,
141 Label* miss_label,
142 Register receiver,
143 Handle<Name> name,
144 Register scratch0,
145 Register scratch1) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000146 ASSERT(name->IsUniqueName());
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000147 ASSERT(!receiver.is(scratch0));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000148 Counters* counters = masm->isolate()->counters();
149 __ IncrementCounter(counters->negative_lookups(), 1);
150 __ IncrementCounter(counters->negative_lookups_miss(), 1);
151
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000152 __ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000153
154 const int kInterceptorOrAccessCheckNeededMask =
155 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
156
157 // Bail out if the receiver has a named interceptor or requires access checks.
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000158 __ test_b(FieldOperand(scratch0, Map::kBitFieldOffset),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000159 kInterceptorOrAccessCheckNeededMask);
160 __ j(not_zero, miss_label);
161
162 // Check that receiver is a JSObject.
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000163 __ CmpInstanceType(scratch0, FIRST_SPEC_OBJECT_TYPE);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000164 __ j(below, miss_label);
165
166 // Load properties array.
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000167 Register properties = scratch0;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000168 __ mov(properties, FieldOperand(receiver, JSObject::kPropertiesOffset));
169
170 // Check that the properties array is a dictionary.
171 __ cmp(FieldOperand(properties, HeapObject::kMapOffset),
172 Immediate(masm->isolate()->factory()->hash_table_map()));
173 __ j(not_equal, miss_label);
174
175 Label done;
ulan@chromium.org750145a2013-03-07 15:14:13 +0000176 NameDictionaryLookupStub::GenerateNegativeLookup(masm,
177 miss_label,
178 &done,
179 properties,
180 name,
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000181 scratch1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000182 __ bind(&done);
183 __ DecrementCounter(counters->negative_lookups_miss(), 1);
184}
185
186
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000187void StubCache::GenerateProbe(MacroAssembler* masm,
188 Code::Flags flags,
189 Register receiver,
190 Register name,
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000191 Register scratch,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000192 Register extra,
ulan@chromium.org812308e2012-02-29 15:58:45 +0000193 Register extra2,
194 Register extra3) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000195 Label miss;
196
ulan@chromium.org812308e2012-02-29 15:58:45 +0000197 // Assert that code is valid. The multiplying code relies on the entry size
198 // being 12.
199 ASSERT(sizeof(Entry) == 12);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000200
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000201 // Assert the flags do not name a specific type.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000202 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
203
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000204 // Assert that there are no register conflicts.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000205 ASSERT(!scratch.is(receiver));
206 ASSERT(!scratch.is(name));
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000207 ASSERT(!extra.is(receiver));
208 ASSERT(!extra.is(name));
209 ASSERT(!extra.is(scratch));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000210
ulan@chromium.org812308e2012-02-29 15:58:45 +0000211 // Assert scratch and extra registers are valid, and extra2/3 are unused.
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000212 ASSERT(!scratch.is(no_reg));
213 ASSERT(extra2.is(no_reg));
ulan@chromium.org812308e2012-02-29 15:58:45 +0000214 ASSERT(extra3.is(no_reg));
215
216 Register offset = scratch;
217 scratch = no_reg;
218
219 Counters* counters = masm->isolate()->counters();
220 __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000221
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000222 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000223 __ JumpIfSmi(receiver, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000224
225 // Get the map of the receiver and compute the hash.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000226 __ mov(offset, FieldOperand(name, Name::kHashFieldOffset));
ulan@chromium.org812308e2012-02-29 15:58:45 +0000227 __ add(offset, FieldOperand(receiver, HeapObject::kMapOffset));
228 __ xor_(offset, flags);
229 // We mask out the last two bits because they are not part of the hash and
230 // they are always 01 for maps. Also in the two 'and' instructions below.
231 __ and_(offset, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
232 // ProbeTable expects the offset to be pointer scaled, which it is, because
233 // the heap object tag size is 2 and the pointer size log 2 is also 2.
234 ASSERT(kHeapObjectTagSize == kPointerSizeLog2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000235
236 // Probe the primary table.
ulan@chromium.org812308e2012-02-29 15:58:45 +0000237 ProbeTable(isolate(), masm, flags, kPrimary, name, receiver, offset, extra);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000238
239 // Primary miss: Compute hash for secondary probe.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000240 __ mov(offset, FieldOperand(name, Name::kHashFieldOffset));
ulan@chromium.org812308e2012-02-29 15:58:45 +0000241 __ add(offset, FieldOperand(receiver, HeapObject::kMapOffset));
242 __ xor_(offset, flags);
243 __ and_(offset, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
244 __ sub(offset, name);
245 __ add(offset, Immediate(flags));
246 __ and_(offset, (kSecondaryTableSize - 1) << kHeapObjectTagSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000247
248 // Probe the secondary table.
ulan@chromium.org812308e2012-02-29 15:58:45 +0000249 ProbeTable(
250 isolate(), masm, flags, kSecondary, name, receiver, offset, extra);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000251
252 // Cache miss: Fall-through and let caller handle the miss by
253 // entering the runtime system.
254 __ bind(&miss);
ulan@chromium.org812308e2012-02-29 15:58:45 +0000255 __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000256}
257
258
259void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
260 int index,
261 Register prototype) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000262 __ LoadGlobalFunction(index, prototype);
263 __ LoadGlobalFunctionInitialMap(prototype, prototype);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000264 // Load the prototype from the initial map.
265 __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
266}
267
268
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000269void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000270 MacroAssembler* masm,
271 int index,
272 Register prototype,
273 Label* miss) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000274 // Check we're still in the same context.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000275 __ cmp(Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)),
276 masm->isolate()->global_object());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000277 __ j(not_equal, miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000278 // Get the global function with the given index.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000279 Handle<JSFunction> function(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000280 JSFunction::cast(masm->isolate()->native_context()->get(index)));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000281 // Load its initial map. The global functions all have initial maps.
282 __ Set(prototype, Immediate(Handle<Map>(function->initial_map())));
283 // Load the prototype from the initial map.
284 __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
285}
286
287
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000288void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
289 Register receiver,
290 Register scratch,
291 Label* miss_label) {
292 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000293 __ JumpIfSmi(receiver, miss_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000294
295 // Check that the object is a JS array.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000296 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000297 __ j(not_equal, miss_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000298
299 // Load length directly from the JS array.
300 __ mov(eax, FieldOperand(receiver, JSArray::kLengthOffset));
301 __ ret(0);
302}
303
304
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000305// Generate code to check if an object is a string. If the object is
306// a string, the map's instance type is left in the scratch register.
307static void GenerateStringCheck(MacroAssembler* masm,
308 Register receiver,
309 Register scratch,
310 Label* smi,
311 Label* non_string_object) {
312 // Check that the object isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000313 __ JumpIfSmi(receiver, smi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000314
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000315 // Check that the object is a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000316 __ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
317 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000318 STATIC_ASSERT(kNotStringTag != 0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000319 __ test(scratch, Immediate(kNotStringTag));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000320 __ j(not_zero, non_string_object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000321}
322
323
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000324void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
325 Register receiver,
ager@chromium.org5c838252010-02-19 08:53:10 +0000326 Register scratch1,
327 Register scratch2,
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000328 Label* miss) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000329 Label check_wrapper;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000330
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000331 // Check if the object is a string leaving the instance type in the
332 // scratch register.
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000333 GenerateStringCheck(masm, receiver, scratch1, miss, &check_wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000334
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000335 // Load length from the string and convert to a smi.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000336 __ mov(eax, FieldOperand(receiver, String::kLengthOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000337 __ ret(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000338
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000339 // Check if the object is a JSValue wrapper.
340 __ bind(&check_wrapper);
341 __ cmp(scratch1, JS_VALUE_TYPE);
342 __ j(not_equal, miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000343
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000344 // Check if the wrapped value is a string and load the length
345 // directly if it is.
346 __ mov(scratch2, FieldOperand(receiver, JSValue::kValueOffset));
347 GenerateStringCheck(masm, scratch2, scratch1, miss, miss);
348 __ mov(eax, FieldOperand(scratch2, String::kLengthOffset));
349 __ ret(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000350}
351
352
353void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
354 Register receiver,
355 Register scratch1,
356 Register scratch2,
357 Label* miss_label) {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000358 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000359 __ mov(eax, scratch1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000360 __ ret(0);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000361}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000362
ager@chromium.org7c537e22008-10-16 08:43:32 +0000363
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000364void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
365 Register dst,
366 Register src,
367 bool inobject,
368 int index,
369 Representation representation) {
370 ASSERT(!FLAG_track_double_fields || !representation.IsDouble());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000371 int offset = index * kPointerSize;
372 if (!inobject) {
373 // Calculate the offset into the properties array.
374 offset = offset + FixedArray::kHeaderSize;
375 __ mov(dst, FieldOperand(src, JSObject::kPropertiesOffset));
376 src = dst;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000377 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000378 __ mov(dst, FieldOperand(src, offset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000379}
380
381
ager@chromium.org5c838252010-02-19 08:53:10 +0000382static void PushInterceptorArguments(MacroAssembler* masm,
383 Register receiver,
384 Register holder,
385 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000386 Handle<JSObject> holder_obj) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000387 STATIC_ASSERT(StubCache::kInterceptorArgsNameIndex == 0);
388 STATIC_ASSERT(StubCache::kInterceptorArgsInfoIndex == 1);
389 STATIC_ASSERT(StubCache::kInterceptorArgsThisIndex == 2);
390 STATIC_ASSERT(StubCache::kInterceptorArgsHolderIndex == 3);
391 STATIC_ASSERT(StubCache::kInterceptorArgsLength == 4);
ager@chromium.org5c838252010-02-19 08:53:10 +0000392 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000393 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
394 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000395 Register scratch = name;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000396 __ mov(scratch, Immediate(interceptor));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000397 __ push(scratch);
ager@chromium.org5c838252010-02-19 08:53:10 +0000398 __ push(receiver);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000399 __ push(holder);
ager@chromium.org5c838252010-02-19 08:53:10 +0000400}
401
402
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000403static void CompileCallLoadPropertyWithInterceptor(
404 MacroAssembler* masm,
405 Register receiver,
406 Register holder,
407 Register name,
408 Handle<JSObject> holder_obj) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000409 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
ager@chromium.org5c838252010-02-19 08:53:10 +0000410 __ CallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000411 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
412 masm->isolate()),
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000413 StubCache::kInterceptorArgsLength);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000414}
415
416
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000417// Number of pointers to be reserved on stack for fast API call.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000418static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength;
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000419
420
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000421// Reserves space for the extra arguments to API function in the
ager@chromium.org5c838252010-02-19 08:53:10 +0000422// caller's frame.
423//
424// These arguments are set by CheckPrototypes and GenerateFastApiCall.
425static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
426 // ----------- S t a t e -------------
427 // -- esp[0] : return address
428 // -- esp[4] : last argument in the internal frame of the caller
429 // -----------------------------------
430 __ pop(scratch);
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000431 for (int i = 0; i < kFastApiCallArguments; i++) {
432 __ push(Immediate(Smi::FromInt(0)));
433 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000434 __ push(scratch);
435}
436
437
438// Undoes the effects of ReserveSpaceForFastApiCall.
439static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
440 // ----------- S t a t e -------------
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000441 // -- esp[0] : return address.
442 // -- esp[4] : last fast api call extra argument.
ager@chromium.org5c838252010-02-19 08:53:10 +0000443 // -- ...
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000444 // -- esp[kFastApiCallArguments * 4] : first fast api call extra argument.
445 // -- esp[kFastApiCallArguments * 4 + 4] : last argument in the internal
446 // frame.
ager@chromium.org5c838252010-02-19 08:53:10 +0000447 // -----------------------------------
448 __ pop(scratch);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000449 __ add(esp, Immediate(kPointerSize * kFastApiCallArguments));
ager@chromium.org5c838252010-02-19 08:53:10 +0000450 __ push(scratch);
451}
452
453
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000454// Generates call to API function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000455static void GenerateFastApiCall(MacroAssembler* masm,
456 const CallOptimization& optimization,
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000457 int argc,
458 bool restore_context) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000459 // ----------- S t a t e -------------
460 // -- esp[0] : return address
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +0000461 // -- esp[4] - esp[28] : FunctionCallbackInfo, incl.
462 // : object passing the type check
463 // (set by CheckPrototypes)
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000464 // -- esp[32] : last argument
ager@chromium.org5c838252010-02-19 08:53:10 +0000465 // -- ...
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000466 // -- esp[(argc + 7) * 4] : first argument
467 // -- esp[(argc + 8) * 4] : receiver
ager@chromium.org5c838252010-02-19 08:53:10 +0000468 // -----------------------------------
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000469
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +0000470 typedef FunctionCallbackArguments FCA;
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000471 // Save calling context.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000472 __ mov(Operand(esp, (1 + FCA::kContextSaveIndex) * kPointerSize), esi);
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000473
ager@chromium.org5c838252010-02-19 08:53:10 +0000474 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000475 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000476 __ LoadHeapObject(edi, function);
ager@chromium.org5c838252010-02-19 08:53:10 +0000477 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
478
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +0000479 // Construct the FunctionCallbackInfo.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000480 __ mov(Operand(esp, (1 + FCA::kCalleeIndex) * kPointerSize), edi);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000481 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000482 Handle<Object> call_data(api_call_info->data(), masm->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000483 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
484 __ mov(ecx, api_call_info);
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000485 __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kDataOffset));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000486 __ mov(Operand(esp, (1 + FCA::kDataIndex) * kPointerSize), ebx);
ager@chromium.org5c838252010-02-19 08:53:10 +0000487 } else {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000488 __ mov(Operand(esp, (1 + FCA::kDataIndex) * kPointerSize),
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +0000489 Immediate(call_data));
ager@chromium.org5c838252010-02-19 08:53:10 +0000490 }
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000491 __ mov(Operand(esp, (1 + FCA::kIsolateIndex) * kPointerSize),
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000492 Immediate(reinterpret_cast<int>(masm->isolate())));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000493 __ mov(Operand(esp, (1 + FCA::kReturnValueOffset) * kPointerSize),
hpayer@chromium.org4f626d12013-09-18 07:47:45 +0000494 masm->isolate()->factory()->undefined_value());
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000495 __ mov(Operand(esp, (1 + FCA::kReturnValueDefaultValueIndex) * kPointerSize),
496 masm->isolate()->factory()->undefined_value());
ager@chromium.org5c838252010-02-19 08:53:10 +0000497
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000498 // Prepare arguments.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000499 STATIC_ASSERT(kFastApiCallArguments == 7);
500 __ lea(eax, Operand(esp, 1 * kPointerSize));
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000501
502 // API function gets reference to the v8::Arguments. If CPU profiler
503 // is enabled wrapper function will be called and we need to pass
504 // address of the callback as additional parameter, always allocate
505 // space for it.
506 const int kApiArgc = 1 + 1;
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000507
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000508 // Allocate the v8::Arguments structure in the arguments' space since
509 // it's not controlled by GC.
510 const int kApiStackSpace = 4;
511
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000512 // Function address is a foreign pointer outside V8's heap.
513 Address function_address = v8::ToCData<Address>(api_call_info->callback());
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000514 __ PrepareCallApiFunction(kApiArgc + kApiStackSpace);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000515
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000516 // FunctionCallbackInfo::implicit_args_.
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000517 __ mov(ApiParameterOperand(2), eax);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000518 __ add(eax, Immediate((argc + kFastApiCallArguments - 1) * kPointerSize));
519 // FunctionCallbackInfo::values_.
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000520 __ mov(ApiParameterOperand(3), eax);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000521 // FunctionCallbackInfo::length_.
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000522 __ Set(ApiParameterOperand(4), Immediate(argc));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000523 // FunctionCallbackInfo::is_construct_call_.
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000524 __ Set(ApiParameterOperand(5), Immediate(0));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000525
526 // v8::InvocationCallback's argument.
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000527 __ lea(eax, ApiParameterOperand(2));
528 __ mov(ApiParameterOperand(0), eax);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000529
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000530 Address thunk_address = FUNCTION_ADDR(&InvokeFunctionCallback);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000531
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000532 Operand context_restore_operand(ebp,
533 (2 + FCA::kContextSaveIndex) * kPointerSize);
534 Operand return_value_operand(ebp,
535 (2 + FCA::kReturnValueOffset) * kPointerSize);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000536 __ CallApiFunctionAndReturn(function_address,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000537 thunk_address,
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000538 ApiParameterOperand(1),
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000539 argc + kFastApiCallArguments + 1,
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000540 return_value_operand,
541 restore_context ?
542 &context_restore_operand : NULL);
ager@chromium.org5c838252010-02-19 08:53:10 +0000543}
544
545
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000546// Generate call to api function.
547static void GenerateFastApiCall(MacroAssembler* masm,
548 const CallOptimization& optimization,
549 Register receiver,
550 Register scratch,
551 int argc,
552 Register* values) {
553 ASSERT(optimization.is_simple_api_call());
554 ASSERT(!receiver.is(scratch));
555
556 const int stack_space = kFastApiCallArguments + argc + 1;
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000557 const int kHolderIndex = FunctionCallbackArguments::kHolderIndex + 1;
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000558 // Copy return value.
559 __ mov(scratch, Operand(esp, 0));
560 // Assign stack space for the call arguments.
561 __ sub(esp, Immediate(stack_space * kPointerSize));
562 // Move the return address on top of the stack.
563 __ mov(Operand(esp, 0), scratch);
564 // Write holder to stack frame.
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000565 __ mov(Operand(esp, kHolderIndex * kPointerSize), receiver);
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000566 // Write receiver to stack frame.
567 int index = stack_space;
568 __ mov(Operand(esp, index-- * kPointerSize), receiver);
569 // Write the arguments to stack frame.
570 for (int i = 0; i < argc; i++) {
571 ASSERT(!receiver.is(values[i]));
572 ASSERT(!scratch.is(values[i]));
573 __ mov(Operand(esp, index-- * kPointerSize), values[i]);
574 }
575
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000576 GenerateFastApiCall(masm, optimization, argc, true);
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000577}
578
579
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000580class CallInterceptorCompiler BASE_EMBEDDED {
581 public:
ager@chromium.org5c838252010-02-19 08:53:10 +0000582 CallInterceptorCompiler(StubCompiler* stub_compiler,
583 const ParameterCount& arguments,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000584 Register name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000585 Code::ExtraICState extra_state)
ager@chromium.org5c838252010-02-19 08:53:10 +0000586 : stub_compiler_(stub_compiler),
587 arguments_(arguments),
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000588 name_(name),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000589 extra_state_(extra_state) {}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000590
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000591 void Compile(MacroAssembler* masm,
592 Handle<JSObject> object,
593 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000594 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000595 LookupResult* lookup,
596 Register receiver,
597 Register scratch1,
598 Register scratch2,
599 Register scratch3,
600 Label* miss) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000601 ASSERT(holder->HasNamedInterceptor());
602 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
603
604 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000605 __ JumpIfSmi(receiver, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000606
607 CallOptimization optimization(lookup);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000608 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000609 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
610 holder, lookup, name, optimization, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000611 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000612 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
613 name, holder, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000614 }
615 }
616
617 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000618 void CompileCacheable(MacroAssembler* masm,
619 Handle<JSObject> object,
620 Register receiver,
621 Register scratch1,
622 Register scratch2,
623 Register scratch3,
624 Handle<JSObject> interceptor_holder,
625 LookupResult* lookup,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000626 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000627 const CallOptimization& optimization,
628 Label* miss_label) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000629 ASSERT(optimization.is_constant_call());
630 ASSERT(!lookup->holder()->IsGlobalObject());
631
632 int depth1 = kInvalidProtoDepth;
633 int depth2 = kInvalidProtoDepth;
634 bool can_do_fast_api_call = false;
635 if (optimization.is_simple_api_call() &&
636 !lookup->holder()->IsGlobalObject()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000637 depth1 = optimization.GetPrototypeDepthOfExpectedType(
638 object, interceptor_holder);
ager@chromium.org5c838252010-02-19 08:53:10 +0000639 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000640 depth2 = optimization.GetPrototypeDepthOfExpectedType(
641 interceptor_holder, Handle<JSObject>(lookup->holder()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000642 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000643 can_do_fast_api_call =
644 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000645 }
646
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000647 Counters* counters = masm->isolate()->counters();
648 __ IncrementCounter(counters->call_const_interceptor(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000649
650 if (can_do_fast_api_call) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000651 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000652 ReserveSpaceForFastApiCall(masm, scratch1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000653 }
654
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000655 // Check that the maps from receiver to interceptor's holder
656 // haven't changed and thus we can invoke interceptor.
ager@chromium.org5c838252010-02-19 08:53:10 +0000657 Label miss_cleanup;
658 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
659 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000660 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
661 scratch1, scratch2, scratch3,
662 name, depth1, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000663
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000664 // Invoke an interceptor and if it provides a value,
665 // branch to |regular_invoke|.
ager@chromium.org5c838252010-02-19 08:53:10 +0000666 Label regular_invoke;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000667 LoadWithInterceptor(masm, receiver, holder, interceptor_holder,
668 &regular_invoke);
ager@chromium.org5c838252010-02-19 08:53:10 +0000669
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000670 // Interceptor returned nothing for this property. Try to use cached
671 // constant function.
ager@chromium.org5c838252010-02-19 08:53:10 +0000672
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000673 // Check that the maps from interceptor's holder to constant function's
674 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000675 if (*interceptor_holder != lookup->holder()) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000676 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000677 Handle<JSObject>(lookup->holder()),
678 scratch1, scratch2, scratch3,
679 name, depth2, miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000680 } else {
681 // CheckPrototypes has a side effect of fetching a 'holder'
682 // for API (object which is instanceof for the signature). It's
683 // safe to omit it here, as if present, it should be fetched
684 // by the previous CheckPrototypes.
685 ASSERT(depth2 == kInvalidProtoDepth);
686 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000687
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000688 // Invoke function.
ager@chromium.org5c838252010-02-19 08:53:10 +0000689 if (can_do_fast_api_call) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000690 GenerateFastApiCall(masm, optimization, arguments_.immediate(), false);
ager@chromium.org5c838252010-02-19 08:53:10 +0000691 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000692 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000693 ? CALL_AS_FUNCTION
694 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000695 Handle<JSFunction> function = optimization.constant_function();
696 ParameterCount expected(function);
697 __ InvokeFunction(function, expected, arguments_,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000698 JUMP_FUNCTION, NullCallWrapper(), call_kind);
ager@chromium.org5c838252010-02-19 08:53:10 +0000699 }
700
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000701 // Deferred code for fast API call case---clean preallocated space.
ager@chromium.org5c838252010-02-19 08:53:10 +0000702 if (can_do_fast_api_call) {
703 __ bind(&miss_cleanup);
704 FreeSpaceForFastApiCall(masm, scratch1);
705 __ jmp(miss_label);
706 }
707
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000708 // Invoke a regular function.
ager@chromium.org5c838252010-02-19 08:53:10 +0000709 __ bind(&regular_invoke);
710 if (can_do_fast_api_call) {
711 FreeSpaceForFastApiCall(masm, scratch1);
712 }
713 }
714
715 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000716 Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +0000717 Register receiver,
718 Register scratch1,
719 Register scratch2,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000720 Register scratch3,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000721 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000722 Handle<JSObject> interceptor_holder,
ager@chromium.org5c838252010-02-19 08:53:10 +0000723 Label* miss_label) {
724 Register holder =
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000725 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000726 scratch1, scratch2, scratch3,
727 name, miss_label);
ager@chromium.org5c838252010-02-19 08:53:10 +0000728
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000729 FrameScope scope(masm, StackFrame::INTERNAL);
ager@chromium.org5c838252010-02-19 08:53:10 +0000730 // Save the name_ register across the call.
731 __ push(name_);
732
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000733 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
ager@chromium.org5c838252010-02-19 08:53:10 +0000734
735 __ CallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000736 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
737 masm->isolate()),
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000738 StubCache::kInterceptorArgsLength);
ager@chromium.org5c838252010-02-19 08:53:10 +0000739
740 // Restore the name_ register.
741 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000742
743 // Leave the internal frame.
ager@chromium.org5c838252010-02-19 08:53:10 +0000744 }
745
746 void LoadWithInterceptor(MacroAssembler* masm,
747 Register receiver,
748 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000749 Handle<JSObject> holder_obj,
ager@chromium.org5c838252010-02-19 08:53:10 +0000750 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000751 {
752 FrameScope scope(masm, StackFrame::INTERNAL);
753 __ push(holder); // Save the holder.
754 __ push(name_); // Save the name.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000755
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000756 CompileCallLoadPropertyWithInterceptor(masm,
757 receiver,
758 holder,
759 name_,
760 holder_obj);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000761
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000762 __ pop(name_); // Restore the name.
763 __ pop(receiver); // Restore the holder.
764 // Leave the internal frame.
765 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000766
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000767 __ cmp(eax, masm->isolate()->factory()->no_interceptor_result_sentinel());
ager@chromium.org5c838252010-02-19 08:53:10 +0000768 __ j(not_equal, interceptor_succeeded);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000769 }
770
ager@chromium.org5c838252010-02-19 08:53:10 +0000771 StubCompiler* stub_compiler_;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000772 const ParameterCount& arguments_;
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000773 Register name_;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000774 Code::ExtraICState extra_state_;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000775};
776
777
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +0000778void StoreStubCompiler::GenerateRestoreName(MacroAssembler* masm,
779 Label* label,
780 Handle<Name> name) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000781 if (!label->is_unused()) {
782 __ bind(label);
783 __ mov(this->name(), Immediate(name));
784 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000785}
786
787
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000788// Generate code to check that a global property cell is empty. Create
789// the property cell at compilation time if no cell exists for the
790// property.
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000791void StubCompiler::GenerateCheckPropertyCell(MacroAssembler* masm,
792 Handle<JSGlobalObject> global,
793 Handle<Name> name,
794 Register scratch,
795 Label* miss) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000796 Handle<PropertyCell> cell =
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000797 JSGlobalObject::EnsurePropertyCell(global, name);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000798 ASSERT(cell->value()->IsTheHole());
799 Handle<Oddball> the_hole = masm->isolate()->factory()->the_hole_value();
800 if (Serializer::enabled()) {
801 __ mov(scratch, Immediate(cell));
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000802 __ cmp(FieldOperand(scratch, PropertyCell::kValueOffset),
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000803 Immediate(the_hole));
804 } else {
danno@chromium.org41728482013-06-12 22:31:22 +0000805 __ cmp(Operand::ForCell(cell), Immediate(the_hole));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000806 }
807 __ j(not_equal, miss);
808}
809
810
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +0000811void StoreStubCompiler::GenerateNegativeHolderLookup(
danno@chromium.orgbee51992013-07-10 14:57:15 +0000812 MacroAssembler* masm,
813 Handle<JSObject> holder,
814 Register holder_reg,
815 Handle<Name> name,
816 Label* miss) {
817 if (holder->IsJSGlobalObject()) {
818 GenerateCheckPropertyCell(
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000819 masm, Handle<JSGlobalObject>::cast(holder), name, scratch1(), miss);
danno@chromium.orgbee51992013-07-10 14:57:15 +0000820 } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
821 GenerateDictionaryNegativeLookup(
822 masm, miss, holder_reg, name, scratch1(), scratch2());
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000823 }
danno@chromium.orgbee51992013-07-10 14:57:15 +0000824}
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000825
danno@chromium.orgbee51992013-07-10 14:57:15 +0000826
827// Receiver_reg is preserved on jumps to miss_label, but may be destroyed if
828// store is successful.
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +0000829void StoreStubCompiler::GenerateStoreTransition(MacroAssembler* masm,
830 Handle<JSObject> object,
831 LookupResult* lookup,
832 Handle<Map> transition,
833 Handle<Name> name,
834 Register receiver_reg,
835 Register storage_reg,
836 Register value_reg,
837 Register scratch1,
838 Register scratch2,
839 Register unused,
840 Label* miss_label,
841 Label* slow) {
danno@chromium.orgf005df62013-04-30 16:36:45 +0000842 int descriptor = transition->LastAdded();
843 DescriptorArray* descriptors = transition->instance_descriptors();
844 PropertyDetails details = descriptors->GetDetails(descriptor);
845 Representation representation = details.representation();
846 ASSERT(!representation.IsNone());
847
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000848 if (details.type() == CONSTANT) {
849 Handle<Object> constant(descriptors->GetValue(descriptor), masm->isolate());
850 __ CmpObject(value_reg, constant);
danno@chromium.orgbee51992013-07-10 14:57:15 +0000851 __ j(not_equal, miss_label);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000852 } else if (FLAG_track_fields && representation.IsSmi()) {
danno@chromium.orgbee51992013-07-10 14:57:15 +0000853 __ JumpIfNotSmi(value_reg, miss_label);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +0000854 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
danno@chromium.orgbee51992013-07-10 14:57:15 +0000855 __ JumpIfSmi(value_reg, miss_label);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000856 } else if (FLAG_track_double_fields && representation.IsDouble()) {
857 Label do_store, heap_number;
858 __ AllocateHeapNumber(storage_reg, scratch1, scratch2, slow);
859
860 __ JumpIfNotSmi(value_reg, &heap_number);
861 __ SmiUntag(value_reg);
862 if (CpuFeatures::IsSupported(SSE2)) {
863 CpuFeatureScope use_sse2(masm, SSE2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000864 __ Cvtsi2sd(xmm0, value_reg);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000865 } else {
866 __ push(value_reg);
867 __ fild_s(Operand(esp, 0));
868 __ pop(value_reg);
869 }
870 __ SmiTag(value_reg);
871 __ jmp(&do_store);
872
873 __ bind(&heap_number);
874 __ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(),
danno@chromium.orgbee51992013-07-10 14:57:15 +0000875 miss_label, DONT_DO_SMI_CHECK);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000876 if (CpuFeatures::IsSupported(SSE2)) {
877 CpuFeatureScope use_sse2(masm, SSE2);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000878 __ movsd(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000879 } else {
880 __ fld_d(FieldOperand(value_reg, HeapNumber::kValueOffset));
881 }
882
883 __ bind(&do_store);
884 if (CpuFeatures::IsSupported(SSE2)) {
885 CpuFeatureScope use_sse2(masm, SSE2);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000886 __ movsd(FieldOperand(storage_reg, HeapNumber::kValueOffset), xmm0);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000887 } else {
888 __ fstp_d(FieldOperand(storage_reg, HeapNumber::kValueOffset));
889 }
890 }
891
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000892 // Stub never generated for non-global objects that require access
893 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000894 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000895
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000896 // Perform map transition for the receiver if necessary.
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000897 if (details.type() == FIELD &&
898 object->map()->unused_property_fields() == 0) {
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000899 // The properties must be extended before we can store the value.
ager@chromium.org32912102009-01-16 10:38:43 +0000900 // We jump to a runtime call that extends the properties array.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000901 __ pop(scratch1); // Return address.
ager@chromium.org5c838252010-02-19 08:53:10 +0000902 __ push(receiver_reg);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000903 __ push(Immediate(transition));
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000904 __ push(value_reg);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000905 __ push(scratch1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000906 __ TailCallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000907 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
908 masm->isolate()),
909 3,
910 1);
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000911 return;
912 }
913
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000914 // Update the map of the object.
915 __ mov(scratch1, Immediate(transition));
916 __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1);
verwaest@chromium.org37141392012-05-31 13:27:02 +0000917
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000918 // Update the write barrier for the map field.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000919 __ RecordWriteField(receiver_reg,
920 HeapObject::kMapOffset,
921 scratch1,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000922 scratch2,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000923 kDontSaveFPRegs,
924 OMIT_REMEMBERED_SET,
925 OMIT_SMI_CHECK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000926
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000927 if (details.type() == CONSTANT) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000928 ASSERT(value_reg.is(eax));
929 __ ret(0);
930 return;
931 }
932
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000933 int index = transition->instance_descriptors()->GetFieldIndex(
934 transition->LastAdded());
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000935
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000936 // Adjust for the number of properties stored in the object. Even in the
937 // face of a transition we can use the old map here because the size of the
938 // object and the number of in-object properties is not going to change.
939 index -= object->map()->inobject_properties();
940
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000941 SmiCheck smi_check = representation.IsTagged()
942 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000943 // TODO(verwaest): Share this code as a code stub.
ager@chromium.org7c537e22008-10-16 08:43:32 +0000944 if (index < 0) {
945 // Set the property straight into the object.
946 int offset = object->map()->instance_size() + (index * kPointerSize);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000947 if (FLAG_track_double_fields && representation.IsDouble()) {
948 __ mov(FieldOperand(receiver_reg, offset), storage_reg);
949 } else {
950 __ mov(FieldOperand(receiver_reg, offset), value_reg);
951 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000952
danno@chromium.orgf005df62013-04-30 16:36:45 +0000953 if (!FLAG_track_fields || !representation.IsSmi()) {
954 // Update the write barrier for the array address.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000955 if (!FLAG_track_double_fields || !representation.IsDouble()) {
danno@chromium.orgbee51992013-07-10 14:57:15 +0000956 __ mov(storage_reg, value_reg);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000957 }
danno@chromium.orgf005df62013-04-30 16:36:45 +0000958 __ RecordWriteField(receiver_reg,
959 offset,
danno@chromium.orgbee51992013-07-10 14:57:15 +0000960 storage_reg,
danno@chromium.orgf005df62013-04-30 16:36:45 +0000961 scratch1,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000962 kDontSaveFPRegs,
963 EMIT_REMEMBERED_SET,
964 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000965 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000966 } else {
967 // Write to the properties array.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000968 int offset = index * kPointerSize + FixedArray::kHeaderSize;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000969 // Get the properties array (optimistically).
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000970 __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000971 if (FLAG_track_double_fields && representation.IsDouble()) {
972 __ mov(FieldOperand(scratch1, offset), storage_reg);
973 } else {
974 __ mov(FieldOperand(scratch1, offset), value_reg);
975 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000976
danno@chromium.orgf005df62013-04-30 16:36:45 +0000977 if (!FLAG_track_fields || !representation.IsSmi()) {
978 // Update the write barrier for the array address.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000979 if (!FLAG_track_double_fields || !representation.IsDouble()) {
danno@chromium.orgbee51992013-07-10 14:57:15 +0000980 __ mov(storage_reg, value_reg);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000981 }
danno@chromium.orgf005df62013-04-30 16:36:45 +0000982 __ RecordWriteField(scratch1,
983 offset,
danno@chromium.orgbee51992013-07-10 14:57:15 +0000984 storage_reg,
danno@chromium.orgf005df62013-04-30 16:36:45 +0000985 receiver_reg,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000986 kDontSaveFPRegs,
987 EMIT_REMEMBERED_SET,
988 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000989 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000990 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000991
992 // Return the value (register eax).
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000993 ASSERT(value_reg.is(eax));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000994 __ ret(0);
995}
996
997
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000998// Both name_reg and receiver_reg are preserved on jumps to miss_label,
999// but may be destroyed if store is successful.
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001000void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
1001 Handle<JSObject> object,
1002 LookupResult* lookup,
1003 Register receiver_reg,
1004 Register name_reg,
1005 Register value_reg,
1006 Register scratch1,
1007 Register scratch2,
1008 Label* miss_label) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001009 // Stub never generated for non-global objects that require access
1010 // checks.
1011 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
1012
1013 int index = lookup->GetFieldIndex().field_index();
1014
1015 // Adjust for the number of properties stored in the object. Even in the
1016 // face of a transition we can use the old map here because the size of the
1017 // object and the number of in-object properties is not going to change.
1018 index -= object->map()->inobject_properties();
1019
danno@chromium.orgf005df62013-04-30 16:36:45 +00001020 Representation representation = lookup->representation();
1021 ASSERT(!representation.IsNone());
1022 if (FLAG_track_fields && representation.IsSmi()) {
1023 __ JumpIfNotSmi(value_reg, miss_label);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001024 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
1025 __ JumpIfSmi(value_reg, miss_label);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001026 } else if (FLAG_track_double_fields && representation.IsDouble()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001027 // Load the double storage.
1028 if (index < 0) {
1029 int offset = object->map()->instance_size() + (index * kPointerSize);
1030 __ mov(scratch1, FieldOperand(receiver_reg, offset));
1031 } else {
1032 __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
1033 int offset = index * kPointerSize + FixedArray::kHeaderSize;
1034 __ mov(scratch1, FieldOperand(scratch1, offset));
1035 }
1036
1037 // Store the value into the storage.
1038 Label do_store, heap_number;
1039 __ JumpIfNotSmi(value_reg, &heap_number);
1040 __ SmiUntag(value_reg);
1041 if (CpuFeatures::IsSupported(SSE2)) {
1042 CpuFeatureScope use_sse2(masm, SSE2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001043 __ Cvtsi2sd(xmm0, value_reg);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001044 } else {
1045 __ push(value_reg);
1046 __ fild_s(Operand(esp, 0));
1047 __ pop(value_reg);
1048 }
1049 __ SmiTag(value_reg);
1050 __ jmp(&do_store);
1051 __ bind(&heap_number);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001052 __ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(),
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001053 miss_label, DONT_DO_SMI_CHECK);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001054 if (CpuFeatures::IsSupported(SSE2)) {
1055 CpuFeatureScope use_sse2(masm, SSE2);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00001056 __ movsd(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001057 } else {
1058 __ fld_d(FieldOperand(value_reg, HeapNumber::kValueOffset));
1059 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00001060 __ bind(&do_store);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001061 if (CpuFeatures::IsSupported(SSE2)) {
1062 CpuFeatureScope use_sse2(masm, SSE2);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00001063 __ movsd(FieldOperand(scratch1, HeapNumber::kValueOffset), xmm0);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001064 } else {
1065 __ fstp_d(FieldOperand(scratch1, HeapNumber::kValueOffset));
1066 }
1067 // Return the value (register eax).
1068 ASSERT(value_reg.is(eax));
1069 __ ret(0);
1070 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +00001071 }
1072
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001073 ASSERT(!FLAG_track_double_fields || !representation.IsDouble());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001074 // TODO(verwaest): Share this code as a code stub.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001075 SmiCheck smi_check = representation.IsTagged()
1076 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001077 if (index < 0) {
1078 // Set the property straight into the object.
1079 int offset = object->map()->instance_size() + (index * kPointerSize);
1080 __ mov(FieldOperand(receiver_reg, offset), value_reg);
1081
danno@chromium.orgf005df62013-04-30 16:36:45 +00001082 if (!FLAG_track_fields || !representation.IsSmi()) {
1083 // Update the write barrier for the array address.
1084 // Pass the value being stored in the now unused name_reg.
1085 __ mov(name_reg, value_reg);
1086 __ RecordWriteField(receiver_reg,
1087 offset,
1088 name_reg,
1089 scratch1,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001090 kDontSaveFPRegs,
1091 EMIT_REMEMBERED_SET,
1092 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001093 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001094 } else {
1095 // Write to the properties array.
1096 int offset = index * kPointerSize + FixedArray::kHeaderSize;
1097 // Get the properties array (optimistically).
1098 __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001099 __ mov(FieldOperand(scratch1, offset), value_reg);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001100
danno@chromium.orgf005df62013-04-30 16:36:45 +00001101 if (!FLAG_track_fields || !representation.IsSmi()) {
1102 // Update the write barrier for the array address.
1103 // Pass the value being stored in the now unused name_reg.
1104 __ mov(name_reg, value_reg);
1105 __ RecordWriteField(scratch1,
1106 offset,
1107 name_reg,
1108 receiver_reg,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001109 kDontSaveFPRegs,
1110 EMIT_REMEMBERED_SET,
1111 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001112 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001113 }
1114
1115 // Return the value (register eax).
1116 ASSERT(value_reg.is(eax));
1117 __ ret(0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001118}
1119
1120
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001121void StubCompiler::GenerateCheckPropertyCells(MacroAssembler* masm,
1122 Handle<JSObject> object,
1123 Handle<JSObject> holder,
1124 Handle<Name> name,
1125 Register scratch,
1126 Label* miss) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001127 Handle<JSObject> current = object;
1128 while (!current.is_identical_to(holder)) {
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001129 if (current->IsJSGlobalObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001130 GenerateCheckPropertyCell(masm,
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001131 Handle<JSGlobalObject>::cast(current),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001132 name,
1133 scratch,
1134 miss);
1135 }
1136 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
1137 }
1138}
1139
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001140
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001141void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001142 __ jmp(code, RelocInfo::CODE_TARGET);
1143}
1144
1145
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001146#undef __
1147#define __ ACCESS_MASM(masm())
1148
1149
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001150Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
1151 Register object_reg,
1152 Handle<JSObject> holder,
1153 Register holder_reg,
1154 Register scratch1,
1155 Register scratch2,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001156 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001157 int save_at_depth,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001158 Label* miss,
1159 PrototypeCheckType check) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001160 const int kHolderIndex = FunctionCallbackArguments::kHolderIndex + 1;
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001161 // Make sure that the type feedback oracle harvests the receiver map.
1162 // TODO(svenpanne) Remove this hack when all ICs are reworked.
1163 __ mov(scratch1, Handle<Map>(object->map()));
1164
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001165 Handle<JSObject> first = object;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001166 // Make sure there's no overlap between holder and object registers.
1167 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1168 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1169 && !scratch2.is(scratch1));
1170
1171 // Keep track of the current object in register reg.
1172 Register reg = object_reg;
1173 Handle<JSObject> current = object;
1174 int depth = 0;
1175
1176 if (save_at_depth == depth) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001177 __ mov(Operand(esp, kHolderIndex * kPointerSize), reg);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001178 }
1179
1180 // Traverse the prototype chain and check the maps in the prototype chain for
1181 // fast and global objects or do negative lookup for normal objects.
1182 while (!current.is_identical_to(holder)) {
1183 ++depth;
1184
1185 // Only global objects and objects that do not require access
1186 // checks are allowed in stubs.
1187 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1188
1189 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
1190 if (!current->HasFastProperties() &&
1191 !current->IsJSGlobalObject() &&
1192 !current->IsJSGlobalProxy()) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001193 if (!name->IsUniqueName()) {
1194 ASSERT(name->IsString());
1195 name = factory()->InternalizeString(Handle<String>::cast(name));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001196 }
1197 ASSERT(current->property_dictionary()->FindEntry(*name) ==
ulan@chromium.org750145a2013-03-07 15:14:13 +00001198 NameDictionary::kNotFound);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001199
1200 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1201 scratch1, scratch2);
1202
1203 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
1204 reg = holder_reg; // From now on the object will be in holder_reg.
1205 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
1206 } else {
1207 bool in_new_space = heap()->InNewSpace(*prototype);
1208 Handle<Map> current_map(current->map());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001209 if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001210 __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001211 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001212
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001213 // Check access rights to the global object. This has to happen after
1214 // the map check so that we know that the object is actually a global
1215 // object.
1216 if (current->IsJSGlobalProxy()) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001217 __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001218 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001219
1220 if (in_new_space) {
1221 // Save the map in scratch1 for later.
1222 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
1223 }
1224
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001225 reg = holder_reg; // From now on the object will be in holder_reg.
1226
1227 if (in_new_space) {
1228 // The prototype is in new space; we cannot store a reference to it
1229 // in the code. Load it from the map.
1230 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
1231 } else {
1232 // The prototype is in old space; load it directly.
1233 __ mov(reg, prototype);
1234 }
1235 }
1236
1237 if (save_at_depth == depth) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001238 __ mov(Operand(esp, kHolderIndex * kPointerSize), reg);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001239 }
1240
1241 // Go to the next object in the prototype chain.
1242 current = prototype;
1243 }
1244 ASSERT(current.is_identical_to(holder));
1245
1246 // Log the check depth.
1247 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
1248
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001249 if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) {
1250 // Check the holder map.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001251 __ CheckMap(reg, Handle<Map>(holder->map()), miss, DONT_DO_SMI_CHECK);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001252 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001253
1254 // Perform security check for access to the global object.
1255 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1256 if (holder->IsJSGlobalProxy()) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001257 __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001258 }
1259
1260 // If we've skipped any global objects, it's not enough to verify that
1261 // their maps haven't changed. We also need to check that the property
1262 // cell for the property is still empty.
1263 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1264
1265 // Return the register containing the holder.
1266 return reg;
1267}
1268
1269
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001270void LoadStubCompiler::HandlerFrontendFooter(Handle<Name> name, Label* miss) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001271 if (!miss->is_unused()) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001272 Label success;
1273 __ jmp(&success);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001274 __ bind(miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001275 TailCallBuiltin(masm(), MissBuiltin(kind()));
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001276 __ bind(&success);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001277 }
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001278}
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001279
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001280
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001281void StoreStubCompiler::HandlerFrontendFooter(Handle<Name> name, Label* miss) {
danno@chromium.orgbee51992013-07-10 14:57:15 +00001282 if (!miss->is_unused()) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001283 Label success;
1284 __ jmp(&success);
danno@chromium.orgbee51992013-07-10 14:57:15 +00001285 GenerateRestoreName(masm(), miss, name);
1286 TailCallBuiltin(masm(), MissBuiltin(kind()));
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001287 __ bind(&success);
danno@chromium.orgbee51992013-07-10 14:57:15 +00001288 }
1289}
1290
1291
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001292Register LoadStubCompiler::CallbackHandlerFrontend(
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001293 Handle<Object> object,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001294 Register object_reg,
1295 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001296 Handle<Name> name,
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00001297 Handle<Object> callback) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001298 Label miss;
1299
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001300 Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001301
1302 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
1303 ASSERT(!reg.is(scratch2()));
1304 ASSERT(!reg.is(scratch3()));
1305 Register dictionary = scratch1();
1306 bool must_preserve_dictionary_reg = reg.is(dictionary);
1307
1308 // Load the properties dictionary.
1309 if (must_preserve_dictionary_reg) {
1310 __ push(dictionary);
1311 }
1312 __ mov(dictionary, FieldOperand(reg, JSObject::kPropertiesOffset));
1313
1314 // Probe the dictionary.
1315 Label probe_done, pop_and_miss;
ulan@chromium.org750145a2013-03-07 15:14:13 +00001316 NameDictionaryLookupStub::GeneratePositiveLookup(masm(),
1317 &pop_and_miss,
1318 &probe_done,
1319 dictionary,
1320 this->name(),
1321 scratch2(),
1322 scratch3());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001323 __ bind(&pop_and_miss);
1324 if (must_preserve_dictionary_reg) {
1325 __ pop(dictionary);
1326 }
1327 __ jmp(&miss);
1328 __ bind(&probe_done);
1329
1330 // If probing finds an entry in the dictionary, scratch2 contains the
1331 // index into the dictionary. Check that the value is the callback.
1332 Register index = scratch2();
1333 const int kElementsStartOffset =
ulan@chromium.org750145a2013-03-07 15:14:13 +00001334 NameDictionary::kHeaderSize +
1335 NameDictionary::kElementsStartIndex * kPointerSize;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001336 const int kValueOffset = kElementsStartOffset + kPointerSize;
1337 __ mov(scratch3(),
1338 Operand(dictionary, index, times_4, kValueOffset - kHeapObjectTag));
1339 if (must_preserve_dictionary_reg) {
1340 __ pop(dictionary);
1341 }
1342 __ cmp(scratch3(), callback);
1343 __ j(not_equal, &miss);
1344 }
1345
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001346 HandlerFrontendFooter(name, &miss);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001347 return reg;
1348}
1349
1350
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001351void LoadStubCompiler::GenerateLoadField(Register reg,
1352 Handle<JSObject> holder,
1353 PropertyIndex field,
1354 Representation representation) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001355 if (!reg.is(receiver())) __ mov(receiver(), reg);
1356 if (kind() == Code::LOAD_IC) {
1357 LoadFieldStub stub(field.is_inobject(holder),
1358 field.translate(holder),
1359 representation);
1360 GenerateTailCall(masm(), stub.GetCode(isolate()));
1361 } else {
1362 KeyedLoadFieldStub stub(field.is_inobject(holder),
1363 field.translate(holder),
1364 representation);
1365 GenerateTailCall(masm(), stub.GetCode(isolate()));
1366 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001367}
1368
1369
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001370void LoadStubCompiler::GenerateLoadCallback(
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00001371 const CallOptimization& call_optimization) {
dslomov@chromium.org639bac02013-09-09 11:58:54 +00001372 GenerateFastApiCall(
1373 masm(), call_optimization, receiver(), scratch3(), 0, NULL);
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00001374}
1375
1376
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001377void LoadStubCompiler::GenerateLoadCallback(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001378 Register reg,
1379 Handle<ExecutableAccessorInfo> callback) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001380 // Insert additional parameters into the stack frame above return address.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001381 ASSERT(!scratch3().is(reg));
1382 __ pop(scratch3()); // Get return address to place it below.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001383
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001384 STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0);
1385 STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1);
1386 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2);
1387 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3);
1388 STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4);
1389 STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001390 __ push(receiver()); // receiver
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001391 // Push data from ExecutableAccessorInfo.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001392 if (isolate()->heap()->InNewSpace(callback->data())) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001393 ASSERT(!scratch2().is(reg));
1394 __ mov(scratch2(), Immediate(callback));
1395 __ push(FieldOperand(scratch2(), ExecutableAccessorInfo::kDataOffset));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001396 } else {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001397 __ push(Immediate(Handle<Object>(callback->data(), isolate())));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001398 }
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001399 __ push(Immediate(isolate()->factory()->undefined_value())); // ReturnValue
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001400 // ReturnValue default value
1401 __ push(Immediate(isolate()->factory()->undefined_value()));
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00001402 __ push(Immediate(reinterpret_cast<int>(isolate())));
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00001403 __ push(reg); // holder
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001404
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001405 // Save a pointer to where we pushed the arguments. This will be
1406 // passed as the const PropertyAccessorInfo& to the C++ callback.
1407 __ push(esp);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001408
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001409 __ push(name()); // name
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001410 __ mov(ebx, esp); // esp points to reference to name (handler).
1411
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001412 __ push(scratch3()); // Restore return address.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001413
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001414 // array for v8::Arguments::values_, handler for name and pointer
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001415 // to the values (it considered as smi in GC).
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001416 const int kStackSpace = PropertyCallbackArguments::kArgsLength + 2;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001417 // Allocate space for opional callback address parameter in case
1418 // CPU profiler is active.
1419 const int kApiArgc = 2 + 1;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001420
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001421 Address getter_address = v8::ToCData<Address>(callback->getter());
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001422 __ PrepareCallApiFunction(kApiArgc);
1423 __ mov(ApiParameterOperand(0), ebx); // name.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001424 __ add(ebx, Immediate(kPointerSize));
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001425 __ mov(ApiParameterOperand(1), ebx); // arguments pointer.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001426
kmillikin@chromium.org2d5475f2009-12-20 18:15:52 +00001427 // Emitting a stub call may try to allocate (if the code is not
1428 // already generated). Do not allow the assembler to perform a
1429 // garbage collection but instead return the allocation failure
1430 // object.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001431
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001432 Address thunk_address = FUNCTION_ADDR(&InvokeAccessorGetterCallback);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001433
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001434 __ CallApiFunctionAndReturn(getter_address,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001435 thunk_address,
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001436 ApiParameterOperand(2),
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001437 kStackSpace,
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001438 Operand(ebp, 7 * kPointerSize),
1439 NULL);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001440}
1441
1442
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001443void LoadStubCompiler::GenerateLoadConstant(Handle<Object> value) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001444 // Return the constant value.
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001445 __ LoadObject(eax, value);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001446 __ ret(0);
1447}
1448
1449
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001450void LoadStubCompiler::GenerateLoadInterceptor(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001451 Register holder_reg,
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001452 Handle<Object> object,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001453 Handle<JSObject> interceptor_holder,
1454 LookupResult* lookup,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001455 Handle<Name> name) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001456 ASSERT(interceptor_holder->HasNamedInterceptor());
1457 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1458
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001459 // So far the most popular follow ups for interceptor loads are FIELD
1460 // and CALLBACKS, so inline only them, other cases may be added
1461 // later.
1462 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001463 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001464 if (lookup->IsField()) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001465 compile_followup_inline = true;
1466 } else if (lookup->type() == CALLBACKS &&
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001467 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
1468 ExecutableAccessorInfo* callback =
1469 ExecutableAccessorInfo::cast(lookup->GetCallbackObject());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001470 compile_followup_inline = callback->getter() != NULL &&
1471 callback->IsCompatibleReceiver(*object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001472 }
1473 }
1474
1475 if (compile_followup_inline) {
1476 // Compile the interceptor call, followed by inline code to load the
1477 // property from further up the prototype chain if the call fails.
1478 // Check that the maps haven't changed.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001479 ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001480
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001481 // Preserve the receiver register explicitly whenever it is different from
1482 // the holder and it is needed should the interceptor return without any
1483 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1484 // the FIELD case might cause a miss during the prototype check.
1485 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001486 bool must_preserve_receiver_reg = !receiver().is(holder_reg) &&
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001487 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1488
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001489 // Save necessary data before invoking an interceptor.
1490 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001491 {
1492 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001493
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001494 if (must_preserve_receiver_reg) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001495 __ push(receiver());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001496 }
1497 __ push(holder_reg);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001498 __ push(this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001499
1500 // Invoke an interceptor. Note: map checks from receiver to
1501 // interceptor's holder has been compiled before (see a caller
1502 // of this method.)
1503 CompileCallLoadPropertyWithInterceptor(masm(),
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001504 receiver(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001505 holder_reg,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001506 this->name(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001507 interceptor_holder);
1508
1509 // Check if interceptor provided a value for property. If it's
1510 // the case, return immediately.
1511 Label interceptor_failed;
1512 __ cmp(eax, factory()->no_interceptor_result_sentinel());
1513 __ j(equal, &interceptor_failed);
1514 frame_scope.GenerateLeaveFrame();
1515 __ ret(0);
1516
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001517 // Clobber registers when generating debug-code to provoke errors.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001518 __ bind(&interceptor_failed);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001519 if (FLAG_debug_code) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001520 __ mov(receiver(), Immediate(BitCast<int32_t>(kZapValue)));
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001521 __ mov(holder_reg, Immediate(BitCast<int32_t>(kZapValue)));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001522 __ mov(this->name(), Immediate(BitCast<int32_t>(kZapValue)));
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001523 }
1524
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001525 __ pop(this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001526 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001527 if (must_preserve_receiver_reg) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001528 __ pop(receiver());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001529 }
1530
1531 // Leave the internal frame.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001532 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001533
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001534 GenerateLoadPostInterceptor(holder_reg, interceptor_holder, name, lookup);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001535 } else { // !compile_followup_inline
1536 // Call the runtime system to load the interceptor.
1537 // Check that the maps haven't changed.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001538 __ pop(scratch2()); // save old return address
1539 PushInterceptorArguments(masm(), receiver(), holder_reg,
1540 this->name(), interceptor_holder);
1541 __ push(scratch2()); // restore old return address
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001542
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001543 ExternalReference ref =
1544 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001545 isolate());
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00001546 __ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength, 1);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001547 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001548}
1549
1550
ulan@chromium.org750145a2013-03-07 15:14:13 +00001551void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001552 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001553 __ cmp(ecx, Immediate(name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001554 __ j(not_equal, miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001555 }
1556}
1557
1558
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001559void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1560 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001561 Handle<Name> name,
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001562 Label* miss) {
1563 ASSERT(holder->IsGlobalObject());
1564
1565 // Get the number of arguments.
1566 const int argc = arguments().immediate();
1567
1568 // Get the receiver from the stack.
1569 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1570
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001571
1572 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001573 __ JumpIfSmi(edx, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001574 CheckPrototypes(object, edx, holder, ebx, eax, edi, name, miss);
1575}
1576
1577
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001578void CallStubCompiler::GenerateLoadFunctionFromCell(
danno@chromium.org41728482013-06-12 22:31:22 +00001579 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001580 Handle<JSFunction> function,
1581 Label* miss) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001582 // Get the value from the cell.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001583 if (Serializer::enabled()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001584 __ mov(edi, Immediate(cell));
danno@chromium.org41728482013-06-12 22:31:22 +00001585 __ mov(edi, FieldOperand(edi, Cell::kValueOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001586 } else {
danno@chromium.org41728482013-06-12 22:31:22 +00001587 __ mov(edi, Operand::ForCell(cell));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001588 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001589
1590 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001591 if (isolate()->heap()->InNewSpace(*function)) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001592 // We can't embed a pointer to a function in new space so we have
1593 // to verify that the shared function info is unchanged. This has
1594 // the nice side effect that multiple closures based on the same
1595 // function can all use this call IC. Before we load through the
1596 // function, we have to verify that it still is a function.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001597 __ JumpIfSmi(edi, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001598 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001599 __ j(not_equal, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001600
1601 // Check the shared function info. Make sure it hasn't changed.
1602 __ cmp(FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset),
1603 Immediate(Handle<SharedFunctionInfo>(function->shared())));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001604 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001605 __ cmp(edi, Immediate(function));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001606 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001607 __ j(not_equal, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001608}
1609
1610
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001611void CallStubCompiler::GenerateMissBranch() {
1612 Handle<Code> code =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001613 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
danno@chromium.org40cb8782011-05-25 07:58:50 +00001614 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001615 extra_state_);
1616 __ jmp(code, RelocInfo::CODE_TARGET);
1617}
1618
1619
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001620Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1621 Handle<JSObject> holder,
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00001622 PropertyIndex index,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001623 Handle<Name> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001624 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001625 // -- ecx : name
1626 // -- esp[0] : return address
1627 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1628 // -- ...
1629 // -- esp[(argc + 1) * 4] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001630 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001631 Label miss;
1632
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001633 GenerateNameCheck(name, &miss);
1634
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001635 // Get the receiver from the stack.
1636 const int argc = arguments().immediate();
1637 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1638
1639 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001640 __ JumpIfSmi(edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001641
1642 // Do the right check and compute the holder register.
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001643 Register reg = CheckPrototypes(object, edx, holder, ebx, eax, edi,
1644 name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001645
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001646 GenerateFastPropertyLoad(
1647 masm(), edi, reg, index.is_inobject(holder),
1648 index.translate(holder), Representation::Tagged());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001649
1650 // Check that the function really is a function.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001651 __ JumpIfSmi(edi, &miss);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001652 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001653 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001654
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001655 // Patch the receiver on the stack with the global proxy if
1656 // necessary.
1657 if (object->IsGlobalObject()) {
1658 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
1659 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
1660 }
1661
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001662 // Invoke the function.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001663 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001664 ? CALL_AS_FUNCTION
1665 : CALL_AS_METHOD;
1666 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION,
1667 NullCallWrapper(), call_kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001668
1669 // Handle call cache miss.
1670 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001671 GenerateMissBranch();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001672
1673 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001674 return GetCode(Code::FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001675}
1676
1677
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001678Handle<Code> CallStubCompiler::CompileArrayCodeCall(
1679 Handle<Object> object,
1680 Handle<JSObject> holder,
1681 Handle<Cell> cell,
1682 Handle<JSFunction> function,
1683 Handle<String> name,
1684 Code::StubType type) {
1685 Label miss;
1686
1687 // Check that function is still array
1688 const int argc = arguments().immediate();
1689 GenerateNameCheck(name, &miss);
1690
1691 if (cell.is_null()) {
1692 // Get the receiver from the stack.
1693 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1694
1695 // Check that the receiver isn't a smi.
1696 __ JumpIfSmi(edx, &miss);
1697 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
1698 name, &miss);
1699 } else {
1700 ASSERT(cell->value() == *function);
1701 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
1702 &miss);
1703 GenerateLoadFunctionFromCell(cell, function, &miss);
1704 }
1705
danno@chromium.orgbee51992013-07-10 14:57:15 +00001706 Handle<AllocationSite> site = isolate()->factory()->NewAllocationSite();
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001707 site->SetElementsKind(GetInitialFastElementsKind());
danno@chromium.orgbee51992013-07-10 14:57:15 +00001708 Handle<Cell> site_feedback_cell = isolate()->factory()->NewCell(site);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001709 __ mov(eax, Immediate(argc));
danno@chromium.orgbee51992013-07-10 14:57:15 +00001710 __ mov(ebx, site_feedback_cell);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001711 __ mov(edi, function);
1712
1713 ArrayConstructorStub stub(isolate());
1714 __ TailCallStub(&stub);
1715
1716 __ bind(&miss);
1717 GenerateMissBranch();
1718
1719 // Return the generated code.
1720 return GetCode(type, name);
1721}
1722
1723
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001724Handle<Code> CallStubCompiler::CompileArrayPushCall(
1725 Handle<Object> object,
1726 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00001727 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001728 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001729 Handle<String> name,
1730 Code::StubType type) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001731 // ----------- S t a t e -------------
1732 // -- ecx : name
1733 // -- esp[0] : return address
1734 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1735 // -- ...
1736 // -- esp[(argc + 1) * 4] : receiver
1737 // -----------------------------------
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001738
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001739 // If object is not an array or is observed, bail out to regular call.
1740 if (!object->IsJSArray() ||
1741 !cell.is_null() ||
1742 Handle<JSArray>::cast(object)->map()->is_observed()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001743 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001744 }
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001745
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001746 Label miss;
1747
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001748 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001749
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001750 // Get the receiver from the stack.
1751 const int argc = arguments().immediate();
1752 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1753
1754 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001755 __ JumpIfSmi(edx, &miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001756
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001757 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
1758 name, &miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001759
1760 if (argc == 0) {
1761 // Noop, return the length.
1762 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
1763 __ ret((argc + 1) * kPointerSize);
1764 } else {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001765 Label call_builtin;
1766
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001767 if (argc == 1) { // Otherwise fall through to call builtin.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001768 Label attempt_to_grow_elements, with_write_barrier, check_double;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001769
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001770 // Get the elements array of the object.
1771 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset));
1772
1773 // Check that the elements are in fast mode and writable.
1774 __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
1775 Immediate(factory()->fixed_array_map()));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001776 __ j(not_equal, &check_double);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001777
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001778 // Get the array's length into eax and calculate new length.
1779 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
1780 STATIC_ASSERT(kSmiTagSize == 1);
1781 STATIC_ASSERT(kSmiTag == 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001782 __ add(eax, Immediate(Smi::FromInt(argc)));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001783
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001784 // Get the elements' length into ecx.
1785 __ mov(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001786
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001787 // Check if we could survive without allocation.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001788 __ cmp(eax, ecx);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001789 __ j(greater, &attempt_to_grow_elements);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001790
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001791 // Check if value is a smi.
1792 __ mov(ecx, Operand(esp, argc * kPointerSize));
1793 __ JumpIfNotSmi(ecx, &with_write_barrier);
1794
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001795 // Save new length.
1796 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1797
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001798 // Store the value.
1799 __ mov(FieldOperand(edi,
1800 eax,
1801 times_half_pointer_size,
1802 FixedArray::kHeaderSize - argc * kPointerSize),
1803 ecx);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001804
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001805 __ ret((argc + 1) * kPointerSize);
1806
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001807 __ bind(&check_double);
1808
1809
1810 // Check that the elements are in double mode.
1811 __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
1812 Immediate(factory()->fixed_double_array_map()));
1813 __ j(not_equal, &call_builtin);
1814
1815 // Get the array's length into eax and calculate new length.
1816 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
1817 STATIC_ASSERT(kSmiTagSize == 1);
1818 STATIC_ASSERT(kSmiTag == 0);
1819 __ add(eax, Immediate(Smi::FromInt(argc)));
1820
1821 // Get the elements' length into ecx.
1822 __ mov(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
1823
1824 // Check if we could survive without allocation.
1825 __ cmp(eax, ecx);
1826 __ j(greater, &call_builtin);
1827
1828 __ mov(ecx, Operand(esp, argc * kPointerSize));
1829 __ StoreNumberToDoubleElements(
1830 ecx, edi, eax, ecx, xmm0, &call_builtin, true, argc * kDoubleSize);
1831
1832 // Save new length.
1833 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1834 __ ret((argc + 1) * kPointerSize);
1835
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001836 __ bind(&with_write_barrier);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001837
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001838 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
1839
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001840 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001841 Label fast_object, not_fast_object;
1842 __ CheckFastObjectElements(ebx, &not_fast_object, Label::kNear);
1843 __ jmp(&fast_object);
1844 // In case of fast smi-only, convert to fast object, otherwise bail out.
1845 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001846 __ CheckFastSmiElements(ebx, &call_builtin);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001847 __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
1848 Immediate(factory()->heap_number_map()));
1849 __ j(equal, &call_builtin);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001850 // edi: elements array
1851 // edx: receiver
1852 // ebx: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001853 Label try_holey_map;
1854 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001855 FAST_ELEMENTS,
1856 ebx,
1857 edi,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001858 &try_holey_map);
1859
1860 ElementsTransitionGenerator::
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001861 GenerateMapChangeElementsTransition(masm(),
1862 DONT_TRACK_ALLOCATION_SITE,
1863 NULL);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001864 // Restore edi.
1865 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset));
1866 __ jmp(&fast_object);
1867
1868 __ bind(&try_holey_map);
1869 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1870 FAST_HOLEY_ELEMENTS,
1871 ebx,
1872 edi,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001873 &call_builtin);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001874 ElementsTransitionGenerator::
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001875 GenerateMapChangeElementsTransition(masm(),
1876 DONT_TRACK_ALLOCATION_SITE,
1877 NULL);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001878 // Restore edi.
1879 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset));
1880 __ bind(&fast_object);
1881 } else {
1882 __ CheckFastObjectElements(ebx, &call_builtin);
1883 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001884
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001885 // Save new length.
1886 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1887
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001888 // Store the value.
1889 __ lea(edx, FieldOperand(edi,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001890 eax, times_half_pointer_size,
1891 FixedArray::kHeaderSize - argc * kPointerSize));
1892 __ mov(Operand(edx, 0), ecx);
1893
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001894 __ RecordWrite(edi, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001895 OMIT_SMI_CHECK);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001896
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001897 __ ret((argc + 1) * kPointerSize);
1898
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001899 __ bind(&attempt_to_grow_elements);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001900 if (!FLAG_inline_new) {
1901 __ jmp(&call_builtin);
1902 }
1903
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001904 __ mov(ebx, Operand(esp, argc * kPointerSize));
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001905 // Growing elements that are SMI-only requires special handling in case
1906 // the new element is non-Smi. For now, delegate to the builtin.
1907 Label no_fast_elements_check;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001908 __ JumpIfSmi(ebx, &no_fast_elements_check);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001909 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
1910 __ CheckFastObjectElements(ecx, &call_builtin, Label::kFar);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001911 __ bind(&no_fast_elements_check);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001912
1913 // We could be lucky and the elements array could be at the top of
1914 // new-space. In this case we can just grow it in place by moving the
1915 // allocation pointer up.
1916
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001917 ExternalReference new_space_allocation_top =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001918 ExternalReference::new_space_allocation_top_address(isolate());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001919 ExternalReference new_space_allocation_limit =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001920 ExternalReference::new_space_allocation_limit_address(isolate());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001921
1922 const int kAllocationDelta = 4;
1923 // Load top.
1924 __ mov(ecx, Operand::StaticVariable(new_space_allocation_top));
1925
1926 // Check if it's the end of elements.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001927 __ lea(edx, FieldOperand(edi,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001928 eax, times_half_pointer_size,
1929 FixedArray::kHeaderSize - argc * kPointerSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001930 __ cmp(edx, ecx);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001931 __ j(not_equal, &call_builtin);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001932 __ add(ecx, Immediate(kAllocationDelta * kPointerSize));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001933 __ cmp(ecx, Operand::StaticVariable(new_space_allocation_limit));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001934 __ j(above, &call_builtin);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001935
1936 // We fit and could grow elements.
1937 __ mov(Operand::StaticVariable(new_space_allocation_top), ecx);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001938
1939 // Push the argument...
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001940 __ mov(Operand(edx, 0), ebx);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001941 // ... and fill the rest with holes.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001942 for (int i = 1; i < kAllocationDelta; i++) {
1943 __ mov(Operand(edx, i * kPointerSize),
lrn@chromium.org7516f052011-03-30 08:52:27 +00001944 Immediate(factory()->the_hole_value()));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001945 }
1946
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001947 // We know the elements array is in new space so we don't need the
1948 // remembered set, but we just pushed a value onto it so we may have to
1949 // tell the incremental marker to rescan the object that we just grew. We
1950 // don't need to worry about the holes because they are in old space and
1951 // already marked black.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001952 __ RecordWrite(edi, edx, ebx, kDontSaveFPRegs, OMIT_REMEMBERED_SET);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001953
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001954 // Restore receiver to edx as finish sequence assumes it's here.
1955 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1956
1957 // Increment element's and array's sizes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001958 __ add(FieldOperand(edi, FixedArray::kLengthOffset),
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001959 Immediate(Smi::FromInt(kAllocationDelta)));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001960
1961 // NOTE: This only happen in new-space, where we don't
1962 // care about the black-byte-count on pages. Otherwise we should
1963 // update that too if the object is black.
1964
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001965 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1966
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001967 __ ret((argc + 1) * kPointerSize);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001968 }
1969
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001970 __ bind(&call_builtin);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001971 __ TailCallExternalReference(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001972 ExternalReference(Builtins::c_ArrayPush, isolate()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001973 argc + 1,
1974 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001975 }
1976
1977 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001978 GenerateMissBranch();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001979
1980 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001981 return GetCode(type, name);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001982}
1983
1984
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001985Handle<Code> CallStubCompiler::CompileArrayPopCall(
1986 Handle<Object> object,
1987 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00001988 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001989 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001990 Handle<String> name,
1991 Code::StubType type) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001992 // ----------- S t a t e -------------
1993 // -- ecx : name
1994 // -- esp[0] : return address
1995 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1996 // -- ...
1997 // -- esp[(argc + 1) * 4] : receiver
1998 // -----------------------------------
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001999
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002000 // If object is not an array or is observed, bail out to regular call.
2001 if (!object->IsJSArray() ||
2002 !cell.is_null() ||
2003 Handle<JSArray>::cast(object)->map()->is_observed()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002004 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002005 }
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00002006
ager@chromium.orgac091b72010-05-05 07:34:42 +00002007 Label miss, return_undefined, call_builtin;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002008
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002009 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002010
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002011 // Get the receiver from the stack.
2012 const int argc = arguments().immediate();
2013 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
2014
2015 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002016 __ JumpIfSmi(edx, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002017 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2018 name, &miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002019
2020 // Get the elements array of the object.
2021 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset));
2022
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00002023 // Check that the elements are in fast mode and writable.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002024 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
lrn@chromium.org7516f052011-03-30 08:52:27 +00002025 Immediate(factory()->fixed_array_map()));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00002026 __ j(not_equal, &call_builtin);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002027
2028 // Get the array's length into ecx and calculate new length.
2029 __ mov(ecx, FieldOperand(edx, JSArray::kLengthOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002030 __ sub(ecx, Immediate(Smi::FromInt(1)));
ager@chromium.orgac091b72010-05-05 07:34:42 +00002031 __ j(negative, &return_undefined);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002032
2033 // Get the last element.
2034 STATIC_ASSERT(kSmiTagSize == 1);
2035 STATIC_ASSERT(kSmiTag == 0);
2036 __ mov(eax, FieldOperand(ebx,
2037 ecx, times_half_pointer_size,
2038 FixedArray::kHeaderSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002039 __ cmp(eax, Immediate(factory()->the_hole_value()));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002040 __ j(equal, &call_builtin);
2041
2042 // Set the array's length.
2043 __ mov(FieldOperand(edx, JSArray::kLengthOffset), ecx);
2044
2045 // Fill with the hole.
2046 __ mov(FieldOperand(ebx,
2047 ecx, times_half_pointer_size,
2048 FixedArray::kHeaderSize),
lrn@chromium.org7516f052011-03-30 08:52:27 +00002049 Immediate(factory()->the_hole_value()));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002050 __ ret((argc + 1) * kPointerSize);
2051
ager@chromium.orgac091b72010-05-05 07:34:42 +00002052 __ bind(&return_undefined);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002053 __ mov(eax, Immediate(factory()->undefined_value()));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002054 __ ret((argc + 1) * kPointerSize);
2055
2056 __ bind(&call_builtin);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002057 __ TailCallExternalReference(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002058 ExternalReference(Builtins::c_ArrayPop, isolate()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002059 argc + 1,
2060 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002061
2062 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002063 GenerateMissBranch();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002064
2065 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002066 return GetCode(type, name);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002067}
2068
2069
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002070Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
2071 Handle<Object> object,
2072 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002073 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002074 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002075 Handle<String> name,
2076 Code::StubType type) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002077 // ----------- S t a t e -------------
2078 // -- ecx : function name
2079 // -- esp[0] : return address
2080 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2081 // -- ...
2082 // -- esp[(argc + 1) * 4] : receiver
2083 // -----------------------------------
2084
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002085 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002086 if (!object->IsString() || !cell.is_null()) {
2087 return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002088 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002089
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002090 const int argc = arguments().immediate();
2091
2092 Label miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002093 Label name_miss;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002094 Label index_out_of_range;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002095 Label* index_out_of_range_label = &index_out_of_range;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002096
danno@chromium.org40cb8782011-05-25 07:58:50 +00002097 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002098 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002099 DEFAULT_STRING_STUB)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002100 index_out_of_range_label = &miss;
2101 }
2102
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002103 GenerateNameCheck(name, &name_miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002104
2105 // Check that the maps starting from the prototype haven't changed.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002106 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2107 Context::STRING_FUNCTION_INDEX,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002108 eax,
2109 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002110 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002111 CheckPrototypes(
2112 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2113 eax, holder, ebx, edx, edi, name, &miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002114
2115 Register receiver = ebx;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002116 Register index = edi;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002117 Register result = eax;
2118 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize));
2119 if (argc > 0) {
2120 __ mov(index, Operand(esp, (argc - 0) * kPointerSize));
2121 } else {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002122 __ Set(index, Immediate(factory()->undefined_value()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002123 }
2124
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002125 StringCharCodeAtGenerator generator(receiver,
2126 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002127 result,
2128 &miss, // When not a string.
2129 &miss, // When not a number.
2130 index_out_of_range_label,
2131 STRING_INDEX_IS_NUMBER);
2132 generator.GenerateFast(masm());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002133 __ ret((argc + 1) * kPointerSize);
2134
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002135 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002136 generator.GenerateSlow(masm(), call_helper);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002137
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002138 if (index_out_of_range.is_linked()) {
2139 __ bind(&index_out_of_range);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002140 __ Set(eax, Immediate(factory()->nan_value()));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002141 __ ret((argc + 1) * kPointerSize);
2142 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002143
2144 __ bind(&miss);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002145 // Restore function name in ecx.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002146 __ Set(ecx, Immediate(name));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002147 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002148 GenerateMissBranch();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002149
2150 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002151 return GetCode(type, name);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002152}
2153
2154
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002155Handle<Code> CallStubCompiler::CompileStringCharAtCall(
2156 Handle<Object> object,
2157 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002158 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002159 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002160 Handle<String> name,
2161 Code::StubType type) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002162 // ----------- S t a t e -------------
2163 // -- ecx : function name
2164 // -- esp[0] : return address
2165 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2166 // -- ...
2167 // -- esp[(argc + 1) * 4] : receiver
2168 // -----------------------------------
2169
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002170 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002171 if (!object->IsString() || !cell.is_null()) {
2172 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002173 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002174
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002175 const int argc = arguments().immediate();
2176
2177 Label miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002178 Label name_miss;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002179 Label index_out_of_range;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002180 Label* index_out_of_range_label = &index_out_of_range;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002181
danno@chromium.org40cb8782011-05-25 07:58:50 +00002182 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002183 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002184 DEFAULT_STRING_STUB)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002185 index_out_of_range_label = &miss;
2186 }
2187
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002188 GenerateNameCheck(name, &name_miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002189
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002190 // Check that the maps starting from the prototype haven't changed.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002191 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2192 Context::STRING_FUNCTION_INDEX,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002193 eax,
2194 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002195 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002196 CheckPrototypes(
2197 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2198 eax, holder, ebx, edx, edi, name, &miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002199
2200 Register receiver = eax;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002201 Register index = edi;
danno@chromium.orgc612e022011-11-10 11:38:15 +00002202 Register scratch = edx;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002203 Register result = eax;
2204 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize));
2205 if (argc > 0) {
2206 __ mov(index, Operand(esp, (argc - 0) * kPointerSize));
2207 } else {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002208 __ Set(index, Immediate(factory()->undefined_value()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002209 }
2210
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002211 StringCharAtGenerator generator(receiver,
2212 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00002213 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002214 result,
2215 &miss, // When not a string.
2216 &miss, // When not a number.
2217 index_out_of_range_label,
2218 STRING_INDEX_IS_NUMBER);
2219 generator.GenerateFast(masm());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002220 __ ret((argc + 1) * kPointerSize);
2221
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002222 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002223 generator.GenerateSlow(masm(), call_helper);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002224
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002225 if (index_out_of_range.is_linked()) {
2226 __ bind(&index_out_of_range);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002227 __ Set(eax, Immediate(factory()->empty_string()));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002228 __ ret((argc + 1) * kPointerSize);
2229 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002230
2231 __ bind(&miss);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002232 // Restore function name in ecx.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002233 __ Set(ecx, Immediate(name));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002234 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002235 GenerateMissBranch();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002236
2237 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002238 return GetCode(type, name);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002239}
2240
2241
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002242Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
2243 Handle<Object> object,
2244 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002245 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002246 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002247 Handle<String> name,
2248 Code::StubType type) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002249 // ----------- S t a t e -------------
2250 // -- ecx : function name
2251 // -- esp[0] : return address
2252 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2253 // -- ...
2254 // -- esp[(argc + 1) * 4] : receiver
2255 // -----------------------------------
2256
2257 const int argc = arguments().immediate();
2258
2259 // If the object is not a JSObject or we got an unexpected number of
2260 // arguments, bail out to the regular call.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002261 if (!object->IsJSObject() || argc != 1) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002262 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002263 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002264
2265 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002266 GenerateNameCheck(name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002267
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002268 if (cell.is_null()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002269 __ mov(edx, Operand(esp, 2 * kPointerSize));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002270 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002271 __ JumpIfSmi(edx, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002272 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2273 name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002274 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002275 ASSERT(cell->value() == *function);
2276 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2277 &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002278 GenerateLoadFunctionFromCell(cell, function, &miss);
2279 }
2280
2281 // Load the char code argument.
2282 Register code = ebx;
2283 __ mov(code, Operand(esp, 1 * kPointerSize));
2284
2285 // Check the code is a smi.
2286 Label slow;
2287 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002288 __ JumpIfNotSmi(code, &slow);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002289
2290 // Convert the smi code to uint16.
2291 __ and_(code, Immediate(Smi::FromInt(0xffff)));
2292
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002293 StringCharFromCodeGenerator generator(code, eax);
2294 generator.GenerateFast(masm());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002295 __ ret(2 * kPointerSize);
2296
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002297 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002298 generator.GenerateSlow(masm(), call_helper);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002299
2300 // Tail call the full function. We do not have to patch the receiver
2301 // because the function makes no use of it.
2302 __ bind(&slow);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002303 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002304 ? CALL_AS_FUNCTION
2305 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002306 ParameterCount expected(function);
2307 __ InvokeFunction(function, expected, arguments(),
2308 JUMP_FUNCTION, NullCallWrapper(), call_kind);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002309
2310 __ bind(&miss);
2311 // ecx: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002312 GenerateMissBranch();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002313
2314 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002315 return GetCode(type, name);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002316}
2317
2318
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002319Handle<Code> CallStubCompiler::CompileMathFloorCall(
2320 Handle<Object> object,
2321 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002322 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002323 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002324 Handle<String> name,
2325 Code::StubType type) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002326 // ----------- S t a t e -------------
2327 // -- ecx : name
2328 // -- esp[0] : return address
2329 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2330 // -- ...
2331 // -- esp[(argc + 1) * 4] : receiver
2332 // -----------------------------------
2333
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002334 if (!CpuFeatures::IsSupported(SSE2)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002335 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002336 }
2337
ulan@chromium.org750145a2013-03-07 15:14:13 +00002338 CpuFeatureScope use_sse2(masm(), SSE2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002339
2340 const int argc = arguments().immediate();
2341
2342 // If the object is not a JSObject or we got an unexpected number of
2343 // arguments, bail out to the regular call.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002344 if (!object->IsJSObject() || argc != 1) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002345 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002346 }
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002347
2348 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002349 GenerateNameCheck(name, &miss);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002350
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002351 if (cell.is_null()) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002352 __ mov(edx, Operand(esp, 2 * kPointerSize));
2353
2354 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002355 __ JumpIfSmi(edx, &miss);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002356
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002357 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2358 name, &miss);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002359 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002360 ASSERT(cell->value() == *function);
2361 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2362 &miss);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002363 GenerateLoadFunctionFromCell(cell, function, &miss);
2364 }
2365
2366 // Load the (only) argument into eax.
2367 __ mov(eax, Operand(esp, 1 * kPointerSize));
2368
2369 // Check if the argument is a smi.
2370 Label smi;
2371 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002372 __ JumpIfSmi(eax, &smi);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002373
2374 // Check if the argument is a heap number and load its value into xmm0.
2375 Label slow;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002376 __ CheckMap(eax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00002377 __ movsd(xmm0, FieldOperand(eax, HeapNumber::kValueOffset));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002378
2379 // Check if the argument is strictly positive. Note this also
2380 // discards NaN.
2381 __ xorpd(xmm1, xmm1);
2382 __ ucomisd(xmm0, xmm1);
2383 __ j(below_equal, &slow);
2384
2385 // Do a truncating conversion.
2386 __ cvttsd2si(eax, Operand(xmm0));
2387
2388 // Check if the result fits into a smi. Note this also checks for
2389 // 0x80000000 which signals a failed conversion.
2390 Label wont_fit_into_smi;
2391 __ test(eax, Immediate(0xc0000000));
2392 __ j(not_zero, &wont_fit_into_smi);
2393
2394 // Smi tag and return.
2395 __ SmiTag(eax);
2396 __ bind(&smi);
2397 __ ret(2 * kPointerSize);
2398
2399 // Check if the argument is < 2^kMantissaBits.
2400 Label already_round;
2401 __ bind(&wont_fit_into_smi);
2402 __ LoadPowerOf2(xmm1, ebx, HeapNumber::kMantissaBits);
2403 __ ucomisd(xmm0, xmm1);
2404 __ j(above_equal, &already_round);
2405
2406 // Save a copy of the argument.
2407 __ movaps(xmm2, xmm0);
2408
2409 // Compute (argument + 2^kMantissaBits) - 2^kMantissaBits.
2410 __ addsd(xmm0, xmm1);
2411 __ subsd(xmm0, xmm1);
2412
2413 // Compare the argument and the tentative result to get the right mask:
2414 // if xmm2 < xmm0:
2415 // xmm2 = 1...1
2416 // else:
2417 // xmm2 = 0...0
2418 __ cmpltsd(xmm2, xmm0);
2419
2420 // Subtract 1 if the argument was less than the tentative result.
2421 __ LoadPowerOf2(xmm1, ebx, 0);
2422 __ andpd(xmm1, xmm2);
2423 __ subsd(xmm0, xmm1);
2424
2425 // Return a new heap number.
2426 __ AllocateHeapNumber(eax, ebx, edx, &slow);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00002427 __ movsd(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002428 __ ret(2 * kPointerSize);
2429
2430 // Return the argument (when it's an already round heap number).
2431 __ bind(&already_round);
2432 __ mov(eax, Operand(esp, 1 * kPointerSize));
2433 __ ret(2 * kPointerSize);
2434
2435 // Tail call the full function. We do not have to patch the receiver
2436 // because the function makes no use of it.
2437 __ bind(&slow);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002438 ParameterCount expected(function);
2439 __ InvokeFunction(function, expected, arguments(),
2440 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002441
2442 __ bind(&miss);
2443 // ecx: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002444 GenerateMissBranch();
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002445
2446 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002447 return GetCode(type, name);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002448}
2449
2450
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002451Handle<Code> CallStubCompiler::CompileMathAbsCall(
2452 Handle<Object> object,
2453 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002454 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002455 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002456 Handle<String> name,
2457 Code::StubType type) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002458 // ----------- S t a t e -------------
2459 // -- ecx : name
2460 // -- esp[0] : return address
2461 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2462 // -- ...
2463 // -- esp[(argc + 1) * 4] : receiver
2464 // -----------------------------------
2465
2466 const int argc = arguments().immediate();
2467
2468 // If the object is not a JSObject or we got an unexpected number of
2469 // arguments, bail out to the regular call.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002470 if (!object->IsJSObject() || argc != 1) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002471 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002472 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002473
2474 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002475 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002476
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002477 if (cell.is_null()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002478 __ mov(edx, Operand(esp, 2 * kPointerSize));
2479
2480 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002481 __ JumpIfSmi(edx, &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002482
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002483 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2484 name, &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002485 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002486 ASSERT(cell->value() == *function);
2487 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2488 &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002489 GenerateLoadFunctionFromCell(cell, function, &miss);
2490 }
2491
2492 // Load the (only) argument into eax.
2493 __ mov(eax, Operand(esp, 1 * kPointerSize));
2494
2495 // Check if the argument is a smi.
2496 Label not_smi;
2497 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002498 __ JumpIfNotSmi(eax, &not_smi);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002499
danno@chromium.org59400602013-08-13 17:09:37 +00002500 // Branchless abs implementation, refer to below:
2501 // http://graphics.stanford.edu/~seander/bithacks.html#IntegerAbs
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002502 // Set ebx to 1...1 (== -1) if the argument is negative, or to 0...0
2503 // otherwise.
2504 __ mov(ebx, eax);
2505 __ sar(ebx, kBitsPerInt - 1);
2506
2507 // Do bitwise not or do nothing depending on ebx.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002508 __ xor_(eax, ebx);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002509
2510 // Add 1 or do nothing depending on ebx.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002511 __ sub(eax, ebx);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002512
2513 // If the result is still negative, go to the slow case.
2514 // This only happens for the most negative smi.
2515 Label slow;
2516 __ j(negative, &slow);
2517
2518 // Smi case done.
2519 __ ret(2 * kPointerSize);
2520
2521 // Check if the argument is a heap number and load its exponent and
2522 // sign into ebx.
2523 __ bind(&not_smi);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002524 __ CheckMap(eax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002525 __ mov(ebx, FieldOperand(eax, HeapNumber::kExponentOffset));
2526
2527 // Check the sign of the argument. If the argument is positive,
2528 // just return it.
2529 Label negative_sign;
2530 __ test(ebx, Immediate(HeapNumber::kSignMask));
2531 __ j(not_zero, &negative_sign);
2532 __ ret(2 * kPointerSize);
2533
2534 // If the argument is negative, clear the sign, and return a new
2535 // number.
2536 __ bind(&negative_sign);
2537 __ and_(ebx, ~HeapNumber::kSignMask);
2538 __ mov(ecx, FieldOperand(eax, HeapNumber::kMantissaOffset));
2539 __ AllocateHeapNumber(eax, edi, edx, &slow);
2540 __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), ebx);
2541 __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx);
2542 __ ret(2 * kPointerSize);
2543
2544 // Tail call the full function. We do not have to patch the receiver
2545 // because the function makes no use of it.
2546 __ bind(&slow);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002547 ParameterCount expected(function);
2548 __ InvokeFunction(function, expected, arguments(),
2549 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002550
2551 __ bind(&miss);
2552 // ecx: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002553 GenerateMissBranch();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002554
2555 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002556 return GetCode(type, name);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002557}
2558
2559
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002560Handle<Code> CallStubCompiler::CompileFastApiCall(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002561 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002562 Handle<Object> object,
2563 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002564 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002565 Handle<JSFunction> function,
2566 Handle<String> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002567 ASSERT(optimization.is_simple_api_call());
2568 // Bail out if object is a global object as we don't want to
2569 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002570 if (object->IsGlobalObject()) return Handle<Code>::null();
2571 if (!cell.is_null()) return Handle<Code>::null();
2572 if (!object->IsJSObject()) return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002573 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002574 Handle<JSObject>::cast(object), holder);
2575 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002576
2577 Label miss, miss_before_stack_reserved;
2578
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002579 GenerateNameCheck(name, &miss_before_stack_reserved);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002580
2581 // Get the receiver from the stack.
2582 const int argc = arguments().immediate();
2583 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
2584
2585 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002586 __ JumpIfSmi(edx, &miss_before_stack_reserved);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002587
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002588 Counters* counters = isolate()->counters();
2589 __ IncrementCounter(counters->call_const(), 1);
2590 __ IncrementCounter(counters->call_const_fast_api(), 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002591
2592 // Allocate space for v8::Arguments implicit values. Must be initialized
2593 // before calling any runtime function.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002594 __ sub(esp, Immediate(kFastApiCallArguments * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002595
2596 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002597 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
2598 name, depth, &miss);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002599
2600 // Move the return address on top of the stack.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002601 __ mov(eax, Operand(esp, kFastApiCallArguments * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002602 __ mov(Operand(esp, 0 * kPointerSize), eax);
2603
2604 // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains
2605 // duplicate of return address and will be overwritten.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002606 GenerateFastApiCall(masm(), optimization, argc, false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002607
2608 __ bind(&miss);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002609 __ add(esp, Immediate(kFastApiCallArguments * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002610
2611 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002612 GenerateMissBranch();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002613
2614 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002615 return GetCode(function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002616}
2617
2618
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002619void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) {
2620 Label success;
2621 // Check that the object is a boolean.
2622 __ cmp(object, factory()->true_value());
2623 __ j(equal, &success);
2624 __ cmp(object, factory()->false_value());
2625 __ j(not_equal, miss);
2626 __ bind(&success);
2627}
2628
2629
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002630void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
2631 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002632 Handle<Name> name,
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002633 CheckType check) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002634 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00002635 // -- ecx : name
2636 // -- esp[0] : return address
2637 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2638 // -- ...
2639 // -- esp[(argc + 1) * 4] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002640 // -----------------------------------
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002641 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002642 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002643
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002644 // Get the receiver from the stack.
2645 const int argc = arguments().immediate();
2646 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
2647
2648 // Check that the receiver isn't a smi.
2649 if (check != NUMBER_CHECK) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00002650 __ JumpIfSmi(edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002651 }
2652
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002653 // Make sure that it's okay not to patch the on stack receiver
2654 // unless we're doing a receiver map check.
2655 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002656 switch (check) {
2657 case RECEIVER_MAP_CHECK:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002658 __ IncrementCounter(isolate()->counters()->call_const(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00002659
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002660 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002661 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax,
2662 edi, name, &miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002663
2664 // Patch the receiver on the stack with the global proxy if
2665 // necessary.
2666 if (object->IsGlobalObject()) {
2667 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
2668 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
2669 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002670 break;
2671
2672 case STRING_CHECK:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002673 // Check that the object is a string.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002674 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, eax);
2675 __ j(above_equal, &miss);
2676 // Check that the maps starting from the prototype haven't changed.
2677 GenerateDirectLoadGlobalFunctionPrototype(
2678 masm(), Context::STRING_FUNCTION_INDEX, eax, &miss);
2679 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002680 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002681 eax, holder, ebx, edx, edi, name, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002682 break;
2683
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002684 case SYMBOL_CHECK:
2685 // Check that the object is a symbol.
2686 __ CmpObjectType(edx, SYMBOL_TYPE, eax);
2687 __ j(not_equal, &miss);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002688 // Check that the maps starting from the prototype haven't changed.
2689 GenerateDirectLoadGlobalFunctionPrototype(
2690 masm(), Context::SYMBOL_FUNCTION_INDEX, eax, &miss);
2691 CheckPrototypes(
2692 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2693 eax, holder, ebx, edx, edi, name, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002694 break;
2695
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002696 case NUMBER_CHECK: {
2697 Label fast;
2698 // Check that the object is a smi or a heap number.
2699 __ JumpIfSmi(edx, &fast);
2700 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, eax);
2701 __ j(not_equal, &miss);
2702 __ bind(&fast);
2703 // Check that the maps starting from the prototype haven't changed.
2704 GenerateDirectLoadGlobalFunctionPrototype(
2705 masm(), Context::NUMBER_FUNCTION_INDEX, eax, &miss);
2706 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002707 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002708 eax, holder, ebx, edx, edi, name, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002709 break;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002710 }
2711 case BOOLEAN_CHECK: {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002712 GenerateBooleanCheck(edx, &miss);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002713 // Check that the maps starting from the prototype haven't changed.
2714 GenerateDirectLoadGlobalFunctionPrototype(
2715 masm(), Context::BOOLEAN_FUNCTION_INDEX, eax, &miss);
2716 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002717 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002718 eax, holder, ebx, edx, edi, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002719 break;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002720 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002721 }
2722
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002723 Label success;
2724 __ jmp(&success);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002725
2726 // Handle call cache miss.
2727 __ bind(&miss);
2728 GenerateMissBranch();
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002729
2730 __ bind(&success);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002731}
2732
2733
2734void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002735 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002736 ? CALL_AS_FUNCTION
2737 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002738 ParameterCount expected(function);
2739 __ InvokeFunction(function, expected, arguments(),
2740 JUMP_FUNCTION, NullCallWrapper(), call_kind);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002741}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002742
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002743
2744Handle<Code> CallStubCompiler::CompileCallConstant(
2745 Handle<Object> object,
2746 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002747 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002748 CheckType check,
2749 Handle<JSFunction> function) {
2750
2751 if (HasCustomCallGenerator(function)) {
2752 Handle<Code> code = CompileCustomCall(object, holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002753 Handle<Cell>::null(),
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002754 function, Handle<String>::cast(name),
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002755 Code::CONSTANT);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002756 // A null handle means bail out to the regular compiler code below.
2757 if (!code.is_null()) return code;
2758 }
2759
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002760 CompileHandlerFrontend(object, holder, name, check);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002761 CompileHandlerBackend(function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002762
2763 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002764 return GetCode(function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002765}
2766
2767
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002768Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2769 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002770 Handle<Name> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002771 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00002772 // -- ecx : name
2773 // -- esp[0] : return address
2774 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2775 // -- ...
2776 // -- esp[(argc + 1) * 4] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002777 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002778 Label miss;
2779
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002780 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002781
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002782 // Get the number of arguments.
2783 const int argc = arguments().immediate();
2784
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002785 LookupResult lookup(isolate());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002786 LookupPostInterceptor(holder, name, &lookup);
2787
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002788 // Get the receiver from the stack.
2789 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002790
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002791 CallInterceptorCompiler compiler(this, arguments(), ecx, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002792 compiler.Compile(masm(), object, holder, name, &lookup, edx, ebx, edi, eax,
2793 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002794
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002795 // Restore receiver.
2796 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002797
2798 // Check that the function really is a function.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002799 __ JumpIfSmi(eax, &miss);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002800 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002801 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002802
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002803 // Patch the receiver on the stack with the global proxy if
2804 // necessary.
2805 if (object->IsGlobalObject()) {
2806 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
2807 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
2808 }
2809
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002810 // Invoke the function.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002811 __ mov(edi, eax);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002812 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002813 ? CALL_AS_FUNCTION
2814 : CALL_AS_METHOD;
2815 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION,
2816 NullCallWrapper(), call_kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002817
2818 // Handle load cache miss.
2819 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002820 GenerateMissBranch();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002821
2822 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002823 return GetCode(Code::INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002824}
2825
2826
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002827Handle<Code> CallStubCompiler::CompileCallGlobal(
2828 Handle<JSObject> object,
2829 Handle<GlobalObject> holder,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002830 Handle<PropertyCell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002831 Handle<JSFunction> function,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002832 Handle<Name> name) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002833 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00002834 // -- ecx : name
2835 // -- esp[0] : return address
2836 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
2837 // -- ...
2838 // -- esp[(argc + 1) * 4] : receiver
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002839 // -----------------------------------
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002840
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002841 if (HasCustomCallGenerator(function)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00002842 Handle<Code> code = CompileCustomCall(
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002843 object, holder, cell, function, Handle<String>::cast(name),
2844 Code::NORMAL);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002845 // A null handle means bail out to the regular compiler code below.
2846 if (!code.is_null()) return code;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002847 }
2848
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002849 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002850 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002851
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002852 // Get the number of arguments.
2853 const int argc = arguments().immediate();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002854 GenerateGlobalReceiverCheck(object, holder, name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002855 GenerateLoadFunctionFromCell(cell, function, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002856
2857 // Patch the receiver on the stack with the global proxy.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002858 if (object->IsGlobalObject()) {
2859 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
2860 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
2861 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002862
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002863 // Set up the context (function already in edi).
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002864 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
2865
2866 // Jump to the cached code (tail call).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002867 Counters* counters = isolate()->counters();
2868 __ IncrementCounter(counters->call_global_inline(), 1);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002869 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002870 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002871 ? CALL_AS_FUNCTION
2872 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002873 // We call indirectly through the code field in the function to
2874 // allow recompilation to take effect without changing any of the
2875 // call sites.
2876 __ InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset),
2877 expected, arguments(), JUMP_FUNCTION,
2878 NullCallWrapper(), call_kind);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002879
2880 // Handle call cache miss.
2881 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002882 __ IncrementCounter(counters->call_global_inline_miss(), 1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002883 GenerateMissBranch();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002884
2885 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002886 return GetCode(Code::NORMAL, name);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002887}
2888
2889
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002890Handle<Code> StoreStubCompiler::CompileStoreCallback(
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002891 Handle<JSObject> object,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002892 Handle<JSObject> holder,
danno@chromium.orgbee51992013-07-10 14:57:15 +00002893 Handle<Name> name,
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002894 Handle<ExecutableAccessorInfo> callback) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002895 HandlerFrontend(object, receiver(), holder, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002896
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002897 __ pop(scratch1()); // remove the return address
2898 __ push(receiver());
2899 __ Push(callback);
2900 __ Push(name);
2901 __ push(value());
2902 __ push(scratch1()); // restore return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002903
mads.s.ager31e71382008-08-13 09:32:07 +00002904 // Do tail-call to the runtime system.
2905 ExternalReference store_callback_property =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002906 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002907 __ TailCallExternalReference(store_callback_property, 4, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002908
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002909 // Return the generated code.
danno@chromium.orgbee51992013-07-10 14:57:15 +00002910 return GetCode(kind(), Code::CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002911}
2912
2913
dslomov@chromium.org639bac02013-09-09 11:58:54 +00002914Handle<Code> StoreStubCompiler::CompileStoreCallback(
2915 Handle<JSObject> object,
2916 Handle<JSObject> holder,
2917 Handle<Name> name,
2918 const CallOptimization& call_optimization) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002919 HandlerFrontend(object, receiver(), holder, name);
dslomov@chromium.org639bac02013-09-09 11:58:54 +00002920
2921 Register values[] = { value() };
2922 GenerateFastApiCall(
2923 masm(), call_optimization, receiver(), scratch1(), 1, values);
2924
2925 // Return the generated code.
2926 return GetCode(kind(), Code::CALLBACKS, name);
2927}
2928
2929
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002930#undef __
2931#define __ ACCESS_MASM(masm)
2932
2933
2934void StoreStubCompiler::GenerateStoreViaSetter(
2935 MacroAssembler* masm,
2936 Handle<JSFunction> setter) {
2937 // ----------- S t a t e -------------
2938 // -- eax : value
2939 // -- ecx : name
2940 // -- edx : receiver
2941 // -- esp[0] : return address
2942 // -----------------------------------
2943 {
2944 FrameScope scope(masm, StackFrame::INTERNAL);
2945
2946 // Save value register, so we can restore it later.
2947 __ push(eax);
2948
2949 if (!setter.is_null()) {
2950 // Call the JavaScript setter with receiver and value on the stack.
2951 __ push(edx);
2952 __ push(eax);
2953 ParameterCount actual(1);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002954 ParameterCount expected(setter);
2955 __ InvokeFunction(setter, expected, actual,
2956 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002957 } else {
2958 // If we generate a global code snippet for deoptimization only, remember
2959 // the place to continue after deoptimization.
2960 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2961 }
2962
2963 // We have to return the passed value, not the return value of the setter.
2964 __ pop(eax);
2965
2966 // Restore context register.
2967 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
2968 }
2969 __ ret(0);
2970}
2971
2972
2973#undef __
2974#define __ ACCESS_MASM(masm())
2975
2976
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002977Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002978 Handle<JSObject> object,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002979 Handle<Name> name) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002980 __ pop(scratch1()); // remove the return address
2981 __ push(receiver());
2982 __ push(this->name());
2983 __ push(value());
2984 __ push(Immediate(Smi::FromInt(strict_mode())));
2985 __ push(scratch1()); // restore return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002986
mads.s.ager31e71382008-08-13 09:32:07 +00002987 // Do tail-call to the runtime system.
2988 ExternalReference store_ic_property =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002989 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002990 __ TailCallExternalReference(store_ic_property, 4, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002991
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002992 // Return the generated code.
danno@chromium.orgbee51992013-07-10 14:57:15 +00002993 return GetCode(kind(), Code::INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002994}
2995
2996
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002997Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
2998 MapHandleList* receiver_maps,
2999 CodeHandleList* handler_stubs,
3000 MapHandleList* transitioned_maps) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003001 Label miss;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003002 __ JumpIfSmi(receiver(), &miss, Label::kNear);
3003 __ mov(scratch1(), FieldOperand(receiver(), HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003004 for (int i = 0; i < receiver_maps->length(); ++i) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003005 __ cmp(scratch1(), receiver_maps->at(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003006 if (transitioned_maps->at(i).is_null()) {
3007 __ j(equal, handler_stubs->at(i));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003008 } else {
3009 Label next_map;
3010 __ j(not_equal, &next_map, Label::kNear);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003011 __ mov(transition_map(), Immediate(transitioned_maps->at(i)));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003012 __ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003013 __ bind(&next_map);
3014 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003015 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003016 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003017 TailCallBuiltin(masm(), MissBuiltin(kind()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003018
3019 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003020 return GetICCode(
3021 kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003022}
3023
3024
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00003025Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00003026 Handle<Object> object,
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00003027 Handle<JSObject> last,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003028 Handle<Name> name,
verwaest@chromium.org057bd502013-11-06 12:03:29 +00003029 Handle<JSGlobalObject> global) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00003030 NonexistentHandlerFrontend(object, last, name, global);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00003031
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00003032 // Return undefined if maps of the full prototype chain are still the
3033 // same and no global property with this name contains a value.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003034 __ mov(eax, isolate()->factory()->undefined_value());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00003035 __ ret(0);
3036
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00003037 // Return the generated code.
ulan@chromium.org750145a2013-03-07 15:14:13 +00003038 return GetCode(kind(), Code::NONEXISTENT, name);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00003039}
3040
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003041
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00003042Register* LoadStubCompiler::registers() {
3043 // receiver, name, scratch1, scratch2, scratch3, scratch4.
3044 static Register registers[] = { edx, ecx, ebx, eax, edi, no_reg };
3045 return registers;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003046}
3047
3048
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00003049Register* KeyedLoadStubCompiler::registers() {
3050 // receiver, name, scratch1, scratch2, scratch3, scratch4.
3051 static Register registers[] = { edx, ecx, ebx, eax, edi, no_reg };
3052 return registers;
3053}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003054
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003055
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003056Register* StoreStubCompiler::registers() {
3057 // receiver, name, value, scratch1, scratch2, scratch3.
3058 static Register registers[] = { edx, ecx, eax, ebx, edi, no_reg };
3059 return registers;
3060}
3061
3062
3063Register* KeyedStoreStubCompiler::registers() {
3064 // receiver, name, value, scratch1, scratch2, scratch3.
3065 static Register registers[] = { edx, ecx, eax, ebx, edi, no_reg };
3066 return registers;
3067}
3068
3069
ulan@chromium.org750145a2013-03-07 15:14:13 +00003070void KeyedLoadStubCompiler::GenerateNameCheck(Handle<Name> name,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00003071 Register name_reg,
3072 Label* miss) {
3073 __ cmp(name_reg, Immediate(name));
3074 __ j(not_equal, miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003075}
3076
3077
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003078void KeyedStoreStubCompiler::GenerateNameCheck(Handle<Name> name,
3079 Register name_reg,
3080 Label* miss) {
3081 __ cmp(name_reg, Immediate(name));
3082 __ j(not_equal, miss);
3083}
3084
3085
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003086#undef __
3087#define __ ACCESS_MASM(masm)
3088
3089
3090void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00003091 Register receiver,
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003092 Handle<JSFunction> getter) {
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003093 {
3094 FrameScope scope(masm, StackFrame::INTERNAL);
3095
3096 if (!getter.is_null()) {
3097 // Call the JavaScript getter with the receiver on the stack.
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00003098 __ push(receiver);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003099 ParameterCount actual(0);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003100 ParameterCount expected(getter);
3101 __ InvokeFunction(getter, expected, actual,
3102 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003103 } else {
3104 // If we generate a global code snippet for deoptimization only, remember
3105 // the place to continue after deoptimization.
3106 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
3107 }
3108
3109 // Restore context register.
3110 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
3111 }
3112 __ ret(0);
3113}
3114
3115
3116#undef __
3117#define __ ACCESS_MASM(masm())
3118
3119
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003120Handle<Code> LoadStubCompiler::CompileLoadGlobal(
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00003121 Handle<Object> object,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003122 Handle<GlobalObject> global,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00003123 Handle<PropertyCell> cell,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003124 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003125 bool is_dont_delete) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00003126 Label miss;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003127
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00003128 HandlerFrontendHeader(object, receiver(), global, name, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003129 // Get the value from the cell.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003130 if (Serializer::enabled()) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003131 __ mov(eax, Immediate(cell));
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00003132 __ mov(eax, FieldOperand(eax, PropertyCell::kValueOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003133 } else {
danno@chromium.org41728482013-06-12 22:31:22 +00003134 __ mov(eax, Operand::ForCell(cell));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003135 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003136
3137 // Check for deleted property if property can actually be deleted.
3138 if (!is_dont_delete) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003139 __ cmp(eax, factory()->the_hole_value());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003140 __ j(equal, &miss);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003141 } else if (FLAG_debug_code) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003142 __ cmp(eax, factory()->the_hole_value());
danno@chromium.org59400602013-08-13 17:09:37 +00003143 __ Check(not_equal, kDontDeleteCellsCannotContainTheHole);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003144 }
3145
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00003146 HandlerFrontendFooter(name, &miss);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003147
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003148 Counters* counters = isolate()->counters();
3149 __ IncrementCounter(counters->named_load_global_stub(), 1);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003150 // The code above already loads the result into the return register.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003151 __ ret(0);
3152
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003153 // Return the generated code.
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00003154 return GetCode(kind(), Code::NORMAL, name);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003155}
3156
3157
danno@chromium.orgbee51992013-07-10 14:57:15 +00003158Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC(
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00003159 TypeHandleList* types,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003160 CodeHandleList* handlers,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003161 Handle<Name> name,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003162 Code::StubType type,
3163 IcCheckType check) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003164 Label miss;
3165
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003166 if (check == PROPERTY) {
3167 GenerateNameCheck(name, this->name(), &miss);
3168 }
3169
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00003170 Label number_case;
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00003171 Label* smi_target = IncludesNumberType(types) ? &number_case : &miss;
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00003172 __ JumpIfSmi(receiver(), smi_target);
3173
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003174 Register map_reg = scratch1();
3175 __ mov(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset));
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00003176 int receiver_count = types->length();
danno@chromium.orgf005df62013-04-30 16:36:45 +00003177 int number_of_handled_maps = 0;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003178 for (int current = 0; current < receiver_count; ++current) {
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00003179 Handle<Type> type = types->at(current);
3180 Handle<Map> map = IC::TypeToMap(*type, isolate());
danno@chromium.orgf005df62013-04-30 16:36:45 +00003181 if (!map->is_deprecated()) {
3182 number_of_handled_maps++;
3183 __ cmp(map_reg, map);
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00003184 if (type->Is(Type::Number())) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00003185 ASSERT(!number_case.is_unused());
3186 __ bind(&number_case);
3187 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00003188 __ j(equal, handlers->at(current));
3189 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003190 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00003191 ASSERT(number_of_handled_maps != 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003192
3193 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003194 TailCallBuiltin(masm(), MissBuiltin(kind()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003195
3196 // Return the generated code.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003197 InlineCacheState state =
danno@chromium.orgf005df62013-04-30 16:36:45 +00003198 number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC;
ulan@chromium.org750145a2013-03-07 15:14:13 +00003199 return GetICCode(kind(), type, name, state);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003200}
3201
3202
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003203#undef __
3204#define __ ACCESS_MASM(masm)
3205
3206
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003207void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3208 MacroAssembler* masm) {
3209 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003210 // -- ecx : key
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003211 // -- edx : receiver
3212 // -- esp[0] : return address
3213 // -----------------------------------
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00003214 Label slow, miss;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003215
3216 // This stub is meant to be tail-jumped to, the receiver must already
3217 // have been verified by the caller to not be a smi.
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00003218 __ JumpIfNotSmi(ecx, &miss);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003219 __ mov(ebx, ecx);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003220 __ SmiUntag(ebx);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003221 __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset));
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003222
3223 // Push receiver on the stack to free up a register for the dictionary
3224 // probing.
3225 __ push(edx);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003226 __ LoadFromNumberDictionary(&slow, eax, ecx, ebx, edx, edi, eax);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003227 // Pop receiver before returning.
3228 __ pop(edx);
3229 __ ret(0);
3230
3231 __ bind(&slow);
3232 __ pop(edx);
3233
3234 // ----------- S t a t e -------------
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003235 // -- ecx : key
3236 // -- edx : receiver
3237 // -- esp[0] : return address
3238 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003239 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003240
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00003241 __ bind(&miss);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003242 // ----------- S t a t e -------------
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003243 // -- ecx : key
3244 // -- edx : receiver
3245 // -- esp[0] : return address
3246 // -----------------------------------
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00003247 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003248}
3249
3250
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003251#undef __
3252
3253} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003254
3255#endif // V8_TARGET_ARCH_IA32