blob: 6ab3964b80f75b469e0004d32c0ee75d82e00278 [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,
machenbach@chromium.org37be4082013-11-26 13:50:38 +0000408 Handle<JSObject> holder_obj,
409 IC::UtilityId id) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000410 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
ager@chromium.org5c838252010-02-19 08:53:10 +0000411 __ CallExternalReference(
machenbach@chromium.org37be4082013-11-26 13:50:38 +0000412 ExternalReference(IC_Utility(id), 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
machenbach@chromium.org7ff76072013-11-21 09:47:43 +0000454static void GenerateFastApiCallBody(MacroAssembler* masm,
455 const CallOptimization& optimization,
456 int argc,
457 bool restore_context);
458
459
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000460// Generates call to API function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000461static void GenerateFastApiCall(MacroAssembler* masm,
462 const CallOptimization& optimization,
machenbach@chromium.org7ff76072013-11-21 09:47:43 +0000463 int argc) {
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +0000464 typedef FunctionCallbackArguments FCA;
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000465 // Save calling context.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000466 __ mov(Operand(esp, (1 + FCA::kContextSaveIndex) * kPointerSize), esi);
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000467
ager@chromium.org5c838252010-02-19 08:53:10 +0000468 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000469 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000470 __ LoadHeapObject(edi, function);
ager@chromium.org5c838252010-02-19 08:53:10 +0000471 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
472
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +0000473 // Construct the FunctionCallbackInfo.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000474 __ mov(Operand(esp, (1 + FCA::kCalleeIndex) * kPointerSize), edi);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000475 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000476 Handle<Object> call_data(api_call_info->data(), masm->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000477 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
478 __ mov(ecx, api_call_info);
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000479 __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kDataOffset));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000480 __ mov(Operand(esp, (1 + FCA::kDataIndex) * kPointerSize), ebx);
ager@chromium.org5c838252010-02-19 08:53:10 +0000481 } else {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000482 __ mov(Operand(esp, (1 + FCA::kDataIndex) * kPointerSize),
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +0000483 Immediate(call_data));
ager@chromium.org5c838252010-02-19 08:53:10 +0000484 }
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000485 __ mov(Operand(esp, (1 + FCA::kIsolateIndex) * kPointerSize),
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000486 Immediate(reinterpret_cast<int>(masm->isolate())));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000487 __ mov(Operand(esp, (1 + FCA::kReturnValueOffset) * kPointerSize),
hpayer@chromium.org4f626d12013-09-18 07:47:45 +0000488 masm->isolate()->factory()->undefined_value());
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000489 __ mov(Operand(esp, (1 + FCA::kReturnValueDefaultValueIndex) * kPointerSize),
490 masm->isolate()->factory()->undefined_value());
ager@chromium.org5c838252010-02-19 08:53:10 +0000491
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000492 // Prepare arguments.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000493 STATIC_ASSERT(kFastApiCallArguments == 7);
494 __ lea(eax, Operand(esp, 1 * kPointerSize));
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000495
machenbach@chromium.org7ff76072013-11-21 09:47:43 +0000496 GenerateFastApiCallBody(masm, optimization, argc, false);
497}
498
499
500// Generate call to api function.
501// This function uses push() to generate smaller, faster code than
502// the version above. It is an optimization that should will be removed
503// when api call ICs are generated in hydrogen.
504static void GenerateFastApiCall(MacroAssembler* masm,
505 const CallOptimization& optimization,
506 Register receiver,
507 Register scratch1,
508 Register scratch2,
509 Register scratch3,
510 int argc,
511 Register* values) {
512 ASSERT(optimization.is_simple_api_call());
513
514 // Copy return value.
515 __ pop(scratch1);
516
517 // receiver
518 __ push(receiver);
519
520 // Write the arguments to stack frame.
521 for (int i = 0; i < argc; i++) {
522 Register arg = values[argc-1-i];
523 ASSERT(!receiver.is(arg));
524 ASSERT(!scratch1.is(arg));
525 ASSERT(!scratch2.is(arg));
526 ASSERT(!scratch3.is(arg));
527 __ push(arg);
528 }
529
530 typedef FunctionCallbackArguments FCA;
531
532 STATIC_ASSERT(FCA::kHolderIndex == 0);
533 STATIC_ASSERT(FCA::kIsolateIndex == 1);
534 STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2);
535 STATIC_ASSERT(FCA::kReturnValueOffset == 3);
536 STATIC_ASSERT(FCA::kDataIndex == 4);
537 STATIC_ASSERT(FCA::kCalleeIndex == 5);
538 STATIC_ASSERT(FCA::kContextSaveIndex == 6);
539 STATIC_ASSERT(FCA::kArgsLength == 7);
540
541 // context save
542 __ push(esi);
543
544 // Get the function and setup the context.
545 Handle<JSFunction> function = optimization.constant_function();
546 __ LoadHeapObject(scratch2, function);
547 __ mov(esi, FieldOperand(scratch2, JSFunction::kContextOffset));
548 // callee
549 __ push(scratch2);
550
551 Isolate* isolate = masm->isolate();
552 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
553 Handle<Object> call_data(api_call_info->data(), isolate);
554 // Push data from ExecutableAccessorInfo.
555 if (isolate->heap()->InNewSpace(*call_data)) {
556 __ mov(scratch2, api_call_info);
557 __ mov(scratch3, FieldOperand(scratch2, CallHandlerInfo::kDataOffset));
558 __ push(scratch3);
559 } else {
560 __ push(Immediate(call_data));
561 }
562 // return value
563 __ push(Immediate(isolate->factory()->undefined_value()));
564 // return value default
565 __ push(Immediate(isolate->factory()->undefined_value()));
566 // isolate
567 __ push(Immediate(reinterpret_cast<int>(isolate)));
568 // holder
569 __ push(receiver);
570
571 // store receiver address for GenerateFastApiCallBody
572 ASSERT(!scratch1.is(eax));
573 __ mov(eax, esp);
574
575 // return address
576 __ push(scratch1);
577
578 GenerateFastApiCallBody(masm, optimization, argc, true);
579}
580
581
582static void GenerateFastApiCallBody(MacroAssembler* masm,
583 const CallOptimization& optimization,
584 int argc,
585 bool restore_context) {
586 // ----------- S t a t e -------------
587 // -- esp[0] : return address
588 // -- esp[4] - esp[28] : FunctionCallbackInfo, incl.
589 // : object passing the type check
590 // (set by CheckPrototypes)
591 // -- esp[32] : last argument
592 // -- ...
593 // -- esp[(argc + 7) * 4] : first argument
594 // -- esp[(argc + 8) * 4] : receiver
595 //
596 // -- eax : receiver address
597 // -----------------------------------
598 typedef FunctionCallbackArguments FCA;
599
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000600 // API function gets reference to the v8::Arguments. If CPU profiler
601 // is enabled wrapper function will be called and we need to pass
602 // address of the callback as additional parameter, always allocate
603 // space for it.
604 const int kApiArgc = 1 + 1;
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000605
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000606 // Allocate the v8::Arguments structure in the arguments' space since
607 // it's not controlled by GC.
608 const int kApiStackSpace = 4;
609
machenbach@chromium.org7ff76072013-11-21 09:47:43 +0000610 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
611
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000612 // Function address is a foreign pointer outside V8's heap.
613 Address function_address = v8::ToCData<Address>(api_call_info->callback());
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000614 __ PrepareCallApiFunction(kApiArgc + kApiStackSpace);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000615
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000616 // FunctionCallbackInfo::implicit_args_.
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000617 __ mov(ApiParameterOperand(2), eax);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000618 __ add(eax, Immediate((argc + kFastApiCallArguments - 1) * kPointerSize));
619 // FunctionCallbackInfo::values_.
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000620 __ mov(ApiParameterOperand(3), eax);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000621 // FunctionCallbackInfo::length_.
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000622 __ Set(ApiParameterOperand(4), Immediate(argc));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000623 // FunctionCallbackInfo::is_construct_call_.
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000624 __ Set(ApiParameterOperand(5), Immediate(0));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000625
626 // v8::InvocationCallback's argument.
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000627 __ lea(eax, ApiParameterOperand(2));
628 __ mov(ApiParameterOperand(0), eax);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000629
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000630 Address thunk_address = FUNCTION_ADDR(&InvokeFunctionCallback);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000631
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000632 Operand context_restore_operand(ebp,
633 (2 + FCA::kContextSaveIndex) * kPointerSize);
634 Operand return_value_operand(ebp,
635 (2 + FCA::kReturnValueOffset) * kPointerSize);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000636 __ CallApiFunctionAndReturn(function_address,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000637 thunk_address,
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000638 ApiParameterOperand(1),
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000639 argc + kFastApiCallArguments + 1,
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000640 return_value_operand,
641 restore_context ?
642 &context_restore_operand : NULL);
ager@chromium.org5c838252010-02-19 08:53:10 +0000643}
644
645
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000646class CallInterceptorCompiler BASE_EMBEDDED {
647 public:
machenbach@chromium.org8a58f642013-12-02 10:46:30 +0000648 CallInterceptorCompiler(CallStubCompiler* stub_compiler,
ager@chromium.org5c838252010-02-19 08:53:10 +0000649 const ParameterCount& arguments,
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +0000650 Register name)
ager@chromium.org5c838252010-02-19 08:53:10 +0000651 : stub_compiler_(stub_compiler),
652 arguments_(arguments),
machenbach@chromium.org8a58f642013-12-02 10:46:30 +0000653 name_(name) {}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000654
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000655 void Compile(MacroAssembler* masm,
656 Handle<JSObject> object,
657 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000658 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000659 LookupResult* lookup,
660 Register receiver,
661 Register scratch1,
662 Register scratch2,
663 Register scratch3,
664 Label* miss) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000665 ASSERT(holder->HasNamedInterceptor());
666 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
667
668 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000669 __ JumpIfSmi(receiver, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000670
671 CallOptimization optimization(lookup);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000672 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000673 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
674 holder, lookup, name, optimization, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000675 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000676 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
677 name, holder, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000678 }
679 }
680
681 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000682 void CompileCacheable(MacroAssembler* masm,
683 Handle<JSObject> object,
684 Register receiver,
685 Register scratch1,
686 Register scratch2,
687 Register scratch3,
688 Handle<JSObject> interceptor_holder,
689 LookupResult* lookup,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000690 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000691 const CallOptimization& optimization,
692 Label* miss_label) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000693 ASSERT(optimization.is_constant_call());
694 ASSERT(!lookup->holder()->IsGlobalObject());
695
696 int depth1 = kInvalidProtoDepth;
697 int depth2 = kInvalidProtoDepth;
698 bool can_do_fast_api_call = false;
699 if (optimization.is_simple_api_call() &&
700 !lookup->holder()->IsGlobalObject()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000701 depth1 = optimization.GetPrototypeDepthOfExpectedType(
702 object, interceptor_holder);
ager@chromium.org5c838252010-02-19 08:53:10 +0000703 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000704 depth2 = optimization.GetPrototypeDepthOfExpectedType(
705 interceptor_holder, Handle<JSObject>(lookup->holder()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000706 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000707 can_do_fast_api_call =
708 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000709 }
710
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000711 Counters* counters = masm->isolate()->counters();
712 __ IncrementCounter(counters->call_const_interceptor(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000713
714 if (can_do_fast_api_call) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000715 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000716 ReserveSpaceForFastApiCall(masm, scratch1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000717 }
718
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000719 // Check that the maps from receiver to interceptor's holder
720 // haven't changed and thus we can invoke interceptor.
ager@chromium.org5c838252010-02-19 08:53:10 +0000721 Label miss_cleanup;
722 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
723 Register holder =
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000724 stub_compiler_->CheckPrototypes(
725 IC::CurrentTypeOf(object, masm->isolate()), receiver,
726 interceptor_holder, scratch1, scratch2, scratch3,
727 name, depth1, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000728
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000729 // Invoke an interceptor and if it provides a value,
730 // branch to |regular_invoke|.
ager@chromium.org5c838252010-02-19 08:53:10 +0000731 Label regular_invoke;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000732 LoadWithInterceptor(masm, receiver, holder, interceptor_holder,
733 &regular_invoke);
ager@chromium.org5c838252010-02-19 08:53:10 +0000734
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000735 // Interceptor returned nothing for this property. Try to use cached
736 // constant function.
ager@chromium.org5c838252010-02-19 08:53:10 +0000737
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000738 // Check that the maps from interceptor's holder to constant function's
739 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000740 if (*interceptor_holder != lookup->holder()) {
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000741 stub_compiler_->CheckPrototypes(
jkummerow@chromium.org113035e2013-12-13 15:13:40 +0000742 IC::CurrentTypeOf(interceptor_holder, masm->isolate()), holder,
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000743 handle(lookup->holder()), scratch1, scratch2, scratch3,
744 name, depth2, miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000745 } else {
746 // CheckPrototypes has a side effect of fetching a 'holder'
747 // for API (object which is instanceof for the signature). It's
748 // safe to omit it here, as if present, it should be fetched
749 // by the previous CheckPrototypes.
750 ASSERT(depth2 == kInvalidProtoDepth);
751 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000752
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000753 // Invoke function.
ager@chromium.org5c838252010-02-19 08:53:10 +0000754 if (can_do_fast_api_call) {
machenbach@chromium.org7ff76072013-11-21 09:47:43 +0000755 GenerateFastApiCall(masm, optimization, arguments_.immediate());
ager@chromium.org5c838252010-02-19 08:53:10 +0000756 } else {
machenbach@chromium.org8a58f642013-12-02 10:46:30 +0000757 Handle<JSFunction> fun = optimization.constant_function();
jkummerow@chromium.org113035e2013-12-13 15:13:40 +0000758 stub_compiler_->GenerateJumpFunction(object, fun);
ager@chromium.org5c838252010-02-19 08:53:10 +0000759 }
760
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000761 // Deferred code for fast API call case---clean preallocated space.
ager@chromium.org5c838252010-02-19 08:53:10 +0000762 if (can_do_fast_api_call) {
763 __ bind(&miss_cleanup);
764 FreeSpaceForFastApiCall(masm, scratch1);
765 __ jmp(miss_label);
766 }
767
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000768 // Invoke a regular function.
ager@chromium.org5c838252010-02-19 08:53:10 +0000769 __ bind(&regular_invoke);
770 if (can_do_fast_api_call) {
771 FreeSpaceForFastApiCall(masm, scratch1);
772 }
773 }
774
775 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000776 Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +0000777 Register receiver,
778 Register scratch1,
779 Register scratch2,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000780 Register scratch3,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000781 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000782 Handle<JSObject> interceptor_holder,
ager@chromium.org5c838252010-02-19 08:53:10 +0000783 Label* miss_label) {
784 Register holder =
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000785 stub_compiler_->CheckPrototypes(
786 IC::CurrentTypeOf(object, masm->isolate()), receiver,
787 interceptor_holder, scratch1, scratch2, scratch3, name, miss_label);
ager@chromium.org5c838252010-02-19 08:53:10 +0000788
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000789 FrameScope scope(masm, StackFrame::INTERNAL);
ager@chromium.org5c838252010-02-19 08:53:10 +0000790 // Save the name_ register across the call.
791 __ push(name_);
792
machenbach@chromium.org37be4082013-11-26 13:50:38 +0000793 CompileCallLoadPropertyWithInterceptor(
794 masm, receiver, holder, name_, interceptor_holder,
795 IC::kLoadPropertyWithInterceptorForCall);
ager@chromium.org5c838252010-02-19 08:53:10 +0000796
797 // Restore the name_ register.
798 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000799
800 // Leave the internal frame.
ager@chromium.org5c838252010-02-19 08:53:10 +0000801 }
802
803 void LoadWithInterceptor(MacroAssembler* masm,
804 Register receiver,
805 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000806 Handle<JSObject> holder_obj,
ager@chromium.org5c838252010-02-19 08:53:10 +0000807 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000808 {
809 FrameScope scope(masm, StackFrame::INTERNAL);
jkummerow@chromium.org113035e2013-12-13 15:13:40 +0000810 __ push(receiver);
811 __ push(holder);
812 __ push(name_);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000813
machenbach@chromium.org37be4082013-11-26 13:50:38 +0000814 CompileCallLoadPropertyWithInterceptor(
815 masm, receiver, holder, name_, holder_obj,
816 IC::kLoadPropertyWithInterceptorOnly);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000817
jkummerow@chromium.org113035e2013-12-13 15:13:40 +0000818 __ pop(name_);
819 __ pop(holder);
820 __ pop(receiver);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000821 // Leave the internal frame.
822 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000823
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000824 __ cmp(eax, masm->isolate()->factory()->no_interceptor_result_sentinel());
ager@chromium.org5c838252010-02-19 08:53:10 +0000825 __ j(not_equal, interceptor_succeeded);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000826 }
827
machenbach@chromium.org8a58f642013-12-02 10:46:30 +0000828 CallStubCompiler* stub_compiler_;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000829 const ParameterCount& arguments_;
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000830 Register name_;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000831};
832
833
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +0000834void StoreStubCompiler::GenerateRestoreName(MacroAssembler* masm,
835 Label* label,
836 Handle<Name> name) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000837 if (!label->is_unused()) {
838 __ bind(label);
839 __ mov(this->name(), Immediate(name));
840 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000841}
842
843
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000844// Generate code to check that a global property cell is empty. Create
845// the property cell at compilation time if no cell exists for the
846// property.
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000847void StubCompiler::GenerateCheckPropertyCell(MacroAssembler* masm,
848 Handle<JSGlobalObject> global,
849 Handle<Name> name,
850 Register scratch,
851 Label* miss) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000852 Handle<PropertyCell> cell =
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000853 JSGlobalObject::EnsurePropertyCell(global, name);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000854 ASSERT(cell->value()->IsTheHole());
855 Handle<Oddball> the_hole = masm->isolate()->factory()->the_hole_value();
856 if (Serializer::enabled()) {
857 __ mov(scratch, Immediate(cell));
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000858 __ cmp(FieldOperand(scratch, PropertyCell::kValueOffset),
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000859 Immediate(the_hole));
860 } else {
danno@chromium.org41728482013-06-12 22:31:22 +0000861 __ cmp(Operand::ForCell(cell), Immediate(the_hole));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000862 }
863 __ j(not_equal, miss);
864}
865
866
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +0000867void StoreStubCompiler::GenerateNegativeHolderLookup(
danno@chromium.orgbee51992013-07-10 14:57:15 +0000868 MacroAssembler* masm,
869 Handle<JSObject> holder,
870 Register holder_reg,
871 Handle<Name> name,
872 Label* miss) {
873 if (holder->IsJSGlobalObject()) {
874 GenerateCheckPropertyCell(
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000875 masm, Handle<JSGlobalObject>::cast(holder), name, scratch1(), miss);
danno@chromium.orgbee51992013-07-10 14:57:15 +0000876 } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
877 GenerateDictionaryNegativeLookup(
878 masm, miss, holder_reg, name, scratch1(), scratch2());
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000879 }
danno@chromium.orgbee51992013-07-10 14:57:15 +0000880}
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000881
danno@chromium.orgbee51992013-07-10 14:57:15 +0000882
883// Receiver_reg is preserved on jumps to miss_label, but may be destroyed if
884// store is successful.
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +0000885void StoreStubCompiler::GenerateStoreTransition(MacroAssembler* masm,
886 Handle<JSObject> object,
887 LookupResult* lookup,
888 Handle<Map> transition,
889 Handle<Name> name,
890 Register receiver_reg,
891 Register storage_reg,
892 Register value_reg,
893 Register scratch1,
894 Register scratch2,
895 Register unused,
896 Label* miss_label,
897 Label* slow) {
danno@chromium.orgf005df62013-04-30 16:36:45 +0000898 int descriptor = transition->LastAdded();
899 DescriptorArray* descriptors = transition->instance_descriptors();
900 PropertyDetails details = descriptors->GetDetails(descriptor);
901 Representation representation = details.representation();
902 ASSERT(!representation.IsNone());
903
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000904 if (details.type() == CONSTANT) {
905 Handle<Object> constant(descriptors->GetValue(descriptor), masm->isolate());
906 __ CmpObject(value_reg, constant);
danno@chromium.orgbee51992013-07-10 14:57:15 +0000907 __ j(not_equal, miss_label);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000908 } else if (FLAG_track_fields && representation.IsSmi()) {
danno@chromium.orgbee51992013-07-10 14:57:15 +0000909 __ JumpIfNotSmi(value_reg, miss_label);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +0000910 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
danno@chromium.orgbee51992013-07-10 14:57:15 +0000911 __ JumpIfSmi(value_reg, miss_label);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000912 } else if (FLAG_track_double_fields && representation.IsDouble()) {
913 Label do_store, heap_number;
914 __ AllocateHeapNumber(storage_reg, scratch1, scratch2, slow);
915
916 __ JumpIfNotSmi(value_reg, &heap_number);
917 __ SmiUntag(value_reg);
918 if (CpuFeatures::IsSupported(SSE2)) {
919 CpuFeatureScope use_sse2(masm, SSE2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000920 __ Cvtsi2sd(xmm0, value_reg);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000921 } else {
922 __ push(value_reg);
923 __ fild_s(Operand(esp, 0));
924 __ pop(value_reg);
925 }
926 __ SmiTag(value_reg);
927 __ jmp(&do_store);
928
929 __ bind(&heap_number);
930 __ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(),
danno@chromium.orgbee51992013-07-10 14:57:15 +0000931 miss_label, DONT_DO_SMI_CHECK);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000932 if (CpuFeatures::IsSupported(SSE2)) {
933 CpuFeatureScope use_sse2(masm, SSE2);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000934 __ movsd(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000935 } else {
936 __ fld_d(FieldOperand(value_reg, HeapNumber::kValueOffset));
937 }
938
939 __ bind(&do_store);
940 if (CpuFeatures::IsSupported(SSE2)) {
941 CpuFeatureScope use_sse2(masm, SSE2);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000942 __ movsd(FieldOperand(storage_reg, HeapNumber::kValueOffset), xmm0);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000943 } else {
944 __ fstp_d(FieldOperand(storage_reg, HeapNumber::kValueOffset));
945 }
946 }
947
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000948 // Stub never generated for non-global objects that require access
949 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000950 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000951
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000952 // Perform map transition for the receiver if necessary.
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000953 if (details.type() == FIELD &&
954 object->map()->unused_property_fields() == 0) {
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000955 // The properties must be extended before we can store the value.
ager@chromium.org32912102009-01-16 10:38:43 +0000956 // We jump to a runtime call that extends the properties array.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000957 __ pop(scratch1); // Return address.
ager@chromium.org5c838252010-02-19 08:53:10 +0000958 __ push(receiver_reg);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000959 __ push(Immediate(transition));
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000960 __ push(value_reg);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000961 __ push(scratch1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000962 __ TailCallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000963 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
964 masm->isolate()),
965 3,
966 1);
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000967 return;
968 }
969
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000970 // Update the map of the object.
971 __ mov(scratch1, Immediate(transition));
972 __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1);
verwaest@chromium.org37141392012-05-31 13:27:02 +0000973
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000974 // Update the write barrier for the map field.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000975 __ RecordWriteField(receiver_reg,
976 HeapObject::kMapOffset,
977 scratch1,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000978 scratch2,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000979 kDontSaveFPRegs,
980 OMIT_REMEMBERED_SET,
981 OMIT_SMI_CHECK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000982
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000983 if (details.type() == CONSTANT) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000984 ASSERT(value_reg.is(eax));
985 __ ret(0);
986 return;
987 }
988
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000989 int index = transition->instance_descriptors()->GetFieldIndex(
990 transition->LastAdded());
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000991
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000992 // Adjust for the number of properties stored in the object. Even in the
993 // face of a transition we can use the old map here because the size of the
994 // object and the number of in-object properties is not going to change.
995 index -= object->map()->inobject_properties();
996
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000997 SmiCheck smi_check = representation.IsTagged()
998 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000999 // TODO(verwaest): Share this code as a code stub.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001000 if (index < 0) {
1001 // Set the property straight into the object.
1002 int offset = object->map()->instance_size() + (index * kPointerSize);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001003 if (FLAG_track_double_fields && representation.IsDouble()) {
1004 __ mov(FieldOperand(receiver_reg, offset), storage_reg);
1005 } else {
1006 __ mov(FieldOperand(receiver_reg, offset), value_reg);
1007 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001008
danno@chromium.orgf005df62013-04-30 16:36:45 +00001009 if (!FLAG_track_fields || !representation.IsSmi()) {
1010 // Update the write barrier for the array address.
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001011 if (!FLAG_track_double_fields || !representation.IsDouble()) {
danno@chromium.orgbee51992013-07-10 14:57:15 +00001012 __ mov(storage_reg, value_reg);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001013 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00001014 __ RecordWriteField(receiver_reg,
1015 offset,
danno@chromium.orgbee51992013-07-10 14:57:15 +00001016 storage_reg,
danno@chromium.orgf005df62013-04-30 16:36:45 +00001017 scratch1,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001018 kDontSaveFPRegs,
1019 EMIT_REMEMBERED_SET,
1020 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001021 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001022 } else {
1023 // Write to the properties array.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001024 int offset = index * kPointerSize + FixedArray::kHeaderSize;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001025 // Get the properties array (optimistically).
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001026 __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001027 if (FLAG_track_double_fields && representation.IsDouble()) {
1028 __ mov(FieldOperand(scratch1, offset), storage_reg);
1029 } else {
1030 __ mov(FieldOperand(scratch1, offset), value_reg);
1031 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001032
danno@chromium.orgf005df62013-04-30 16:36:45 +00001033 if (!FLAG_track_fields || !representation.IsSmi()) {
1034 // Update the write barrier for the array address.
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001035 if (!FLAG_track_double_fields || !representation.IsDouble()) {
danno@chromium.orgbee51992013-07-10 14:57:15 +00001036 __ mov(storage_reg, value_reg);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001037 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00001038 __ RecordWriteField(scratch1,
1039 offset,
danno@chromium.orgbee51992013-07-10 14:57:15 +00001040 storage_reg,
danno@chromium.orgf005df62013-04-30 16:36:45 +00001041 receiver_reg,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001042 kDontSaveFPRegs,
1043 EMIT_REMEMBERED_SET,
1044 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001045 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001046 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001047
1048 // Return the value (register eax).
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001049 ASSERT(value_reg.is(eax));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001050 __ ret(0);
1051}
1052
1053
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001054// Both name_reg and receiver_reg are preserved on jumps to miss_label,
1055// but may be destroyed if store is successful.
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001056void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
1057 Handle<JSObject> object,
1058 LookupResult* lookup,
1059 Register receiver_reg,
1060 Register name_reg,
1061 Register value_reg,
1062 Register scratch1,
1063 Register scratch2,
1064 Label* miss_label) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001065 // Stub never generated for non-global objects that require access
1066 // checks.
1067 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
1068
1069 int index = lookup->GetFieldIndex().field_index();
1070
1071 // Adjust for the number of properties stored in the object. Even in the
1072 // face of a transition we can use the old map here because the size of the
1073 // object and the number of in-object properties is not going to change.
1074 index -= object->map()->inobject_properties();
1075
danno@chromium.orgf005df62013-04-30 16:36:45 +00001076 Representation representation = lookup->representation();
1077 ASSERT(!representation.IsNone());
1078 if (FLAG_track_fields && representation.IsSmi()) {
1079 __ JumpIfNotSmi(value_reg, miss_label);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001080 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
1081 __ JumpIfSmi(value_reg, miss_label);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001082 } else if (FLAG_track_double_fields && representation.IsDouble()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001083 // Load the double storage.
1084 if (index < 0) {
1085 int offset = object->map()->instance_size() + (index * kPointerSize);
1086 __ mov(scratch1, FieldOperand(receiver_reg, offset));
1087 } else {
1088 __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
1089 int offset = index * kPointerSize + FixedArray::kHeaderSize;
1090 __ mov(scratch1, FieldOperand(scratch1, offset));
1091 }
1092
1093 // Store the value into the storage.
1094 Label do_store, heap_number;
1095 __ JumpIfNotSmi(value_reg, &heap_number);
1096 __ SmiUntag(value_reg);
1097 if (CpuFeatures::IsSupported(SSE2)) {
1098 CpuFeatureScope use_sse2(masm, SSE2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001099 __ Cvtsi2sd(xmm0, value_reg);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001100 } else {
1101 __ push(value_reg);
1102 __ fild_s(Operand(esp, 0));
1103 __ pop(value_reg);
1104 }
1105 __ SmiTag(value_reg);
1106 __ jmp(&do_store);
1107 __ bind(&heap_number);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001108 __ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(),
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001109 miss_label, DONT_DO_SMI_CHECK);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001110 if (CpuFeatures::IsSupported(SSE2)) {
1111 CpuFeatureScope use_sse2(masm, SSE2);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00001112 __ movsd(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001113 } else {
1114 __ fld_d(FieldOperand(value_reg, HeapNumber::kValueOffset));
1115 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00001116 __ bind(&do_store);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001117 if (CpuFeatures::IsSupported(SSE2)) {
1118 CpuFeatureScope use_sse2(masm, SSE2);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00001119 __ movsd(FieldOperand(scratch1, HeapNumber::kValueOffset), xmm0);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001120 } else {
1121 __ fstp_d(FieldOperand(scratch1, HeapNumber::kValueOffset));
1122 }
1123 // Return the value (register eax).
1124 ASSERT(value_reg.is(eax));
1125 __ ret(0);
1126 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +00001127 }
1128
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001129 ASSERT(!FLAG_track_double_fields || !representation.IsDouble());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001130 // TODO(verwaest): Share this code as a code stub.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001131 SmiCheck smi_check = representation.IsTagged()
1132 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001133 if (index < 0) {
1134 // Set the property straight into the object.
1135 int offset = object->map()->instance_size() + (index * kPointerSize);
1136 __ mov(FieldOperand(receiver_reg, offset), value_reg);
1137
danno@chromium.orgf005df62013-04-30 16:36:45 +00001138 if (!FLAG_track_fields || !representation.IsSmi()) {
1139 // Update the write barrier for the array address.
1140 // Pass the value being stored in the now unused name_reg.
1141 __ mov(name_reg, value_reg);
1142 __ RecordWriteField(receiver_reg,
1143 offset,
1144 name_reg,
1145 scratch1,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001146 kDontSaveFPRegs,
1147 EMIT_REMEMBERED_SET,
1148 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001149 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001150 } else {
1151 // Write to the properties array.
1152 int offset = index * kPointerSize + FixedArray::kHeaderSize;
1153 // Get the properties array (optimistically).
1154 __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001155 __ mov(FieldOperand(scratch1, offset), value_reg);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001156
danno@chromium.orgf005df62013-04-30 16:36:45 +00001157 if (!FLAG_track_fields || !representation.IsSmi()) {
1158 // Update the write barrier for the array address.
1159 // Pass the value being stored in the now unused name_reg.
1160 __ mov(name_reg, value_reg);
1161 __ RecordWriteField(scratch1,
1162 offset,
1163 name_reg,
1164 receiver_reg,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001165 kDontSaveFPRegs,
1166 EMIT_REMEMBERED_SET,
1167 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001168 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001169 }
1170
1171 // Return the value (register eax).
1172 ASSERT(value_reg.is(eax));
1173 __ ret(0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001174}
1175
1176
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001177void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001178 __ jmp(code, RelocInfo::CODE_TARGET);
1179}
1180
1181
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001182#undef __
1183#define __ ACCESS_MASM(masm())
1184
1185
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001186Register StubCompiler::CheckPrototypes(Handle<Type> type,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001187 Register object_reg,
1188 Handle<JSObject> holder,
1189 Register holder_reg,
1190 Register scratch1,
1191 Register scratch2,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001192 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001193 int save_at_depth,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001194 Label* miss,
1195 PrototypeCheckType check) {
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001196 Handle<Map> receiver_map(IC::TypeToMap(*type, isolate()));
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001197 // Make sure that the type feedback oracle harvests the receiver map.
1198 // TODO(svenpanne) Remove this hack when all ICs are reworked.
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001199 __ mov(scratch1, receiver_map);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001200
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001201 // Make sure there's no overlap between holder and object registers.
1202 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1203 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1204 && !scratch2.is(scratch1));
1205
1206 // Keep track of the current object in register reg.
1207 Register reg = object_reg;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001208 int depth = 0;
1209
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001210 const int kHolderIndex = FunctionCallbackArguments::kHolderIndex + 1;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001211 if (save_at_depth == depth) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001212 __ mov(Operand(esp, kHolderIndex * kPointerSize), reg);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001213 }
1214
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001215 Handle<JSObject> current = Handle<JSObject>::null();
1216 if (type->IsConstant()) current = Handle<JSObject>::cast(type->AsConstant());
1217 Handle<JSObject> prototype = Handle<JSObject>::null();
1218 Handle<Map> current_map = receiver_map;
1219 Handle<Map> holder_map(holder->map());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001220 // Traverse the prototype chain and check the maps in the prototype chain for
1221 // fast and global objects or do negative lookup for normal objects.
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001222 while (!current_map.is_identical_to(holder_map)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001223 ++depth;
1224
1225 // Only global objects and objects that do not require access
1226 // checks are allowed in stubs.
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001227 ASSERT(current_map->IsJSGlobalProxyMap() ||
1228 !current_map->is_access_check_needed());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001229
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001230 prototype = handle(JSObject::cast(current_map->prototype()));
1231 if (current_map->is_dictionary_map() &&
1232 !current_map->IsJSGlobalObjectMap() &&
1233 !current_map->IsJSGlobalProxyMap()) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001234 if (!name->IsUniqueName()) {
1235 ASSERT(name->IsString());
1236 name = factory()->InternalizeString(Handle<String>::cast(name));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001237 }
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001238 ASSERT(current.is_null() ||
1239 current->property_dictionary()->FindEntry(*name) ==
ulan@chromium.org750145a2013-03-07 15:14:13 +00001240 NameDictionary::kNotFound);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001241
1242 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1243 scratch1, scratch2);
1244
1245 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
1246 reg = holder_reg; // From now on the object will be in holder_reg.
1247 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
1248 } else {
1249 bool in_new_space = heap()->InNewSpace(*prototype);
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001250 if (depth != 1 || check == CHECK_ALL_MAPS) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001251 __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001252 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001253
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001254 // Check access rights to the global object. This has to happen after
1255 // the map check so that we know that the object is actually a global
1256 // object.
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001257 if (current_map->IsJSGlobalProxyMap()) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001258 __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss);
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001259 } else if (current_map->IsJSGlobalObjectMap()) {
1260 GenerateCheckPropertyCell(
1261 masm(), Handle<JSGlobalObject>::cast(current), name,
1262 scratch2, miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001263 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001264
1265 if (in_new_space) {
1266 // Save the map in scratch1 for later.
1267 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
1268 }
1269
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001270 reg = holder_reg; // From now on the object will be in holder_reg.
1271
1272 if (in_new_space) {
1273 // The prototype is in new space; we cannot store a reference to it
1274 // in the code. Load it from the map.
1275 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
1276 } else {
1277 // The prototype is in old space; load it directly.
1278 __ mov(reg, prototype);
1279 }
1280 }
1281
1282 if (save_at_depth == depth) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001283 __ mov(Operand(esp, kHolderIndex * kPointerSize), reg);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001284 }
1285
1286 // Go to the next object in the prototype chain.
1287 current = prototype;
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001288 current_map = handle(current->map());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001289 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001290
1291 // Log the check depth.
1292 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
1293
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001294 if (depth != 0 || check == CHECK_ALL_MAPS) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001295 // Check the holder map.
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001296 __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001297 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001298
1299 // Perform security check for access to the global object.
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001300 ASSERT(current_map->IsJSGlobalProxyMap() ||
1301 !current_map->is_access_check_needed());
1302 if (current_map->IsJSGlobalProxyMap()) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001303 __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001304 }
1305
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001306 // Return the register containing the holder.
1307 return reg;
1308}
1309
1310
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001311void LoadStubCompiler::HandlerFrontendFooter(Handle<Name> name, Label* miss) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001312 if (!miss->is_unused()) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001313 Label success;
1314 __ jmp(&success);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001315 __ bind(miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001316 TailCallBuiltin(masm(), MissBuiltin(kind()));
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001317 __ bind(&success);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001318 }
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001319}
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001320
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001321
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001322void StoreStubCompiler::HandlerFrontendFooter(Handle<Name> name, Label* miss) {
danno@chromium.orgbee51992013-07-10 14:57:15 +00001323 if (!miss->is_unused()) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001324 Label success;
1325 __ jmp(&success);
danno@chromium.orgbee51992013-07-10 14:57:15 +00001326 GenerateRestoreName(masm(), miss, name);
1327 TailCallBuiltin(masm(), MissBuiltin(kind()));
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001328 __ bind(&success);
danno@chromium.orgbee51992013-07-10 14:57:15 +00001329 }
1330}
1331
1332
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001333Register LoadStubCompiler::CallbackHandlerFrontend(
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001334 Handle<Type> type,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001335 Register object_reg,
1336 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001337 Handle<Name> name,
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00001338 Handle<Object> callback) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001339 Label miss;
1340
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00001341 Register reg = HandlerFrontendHeader(type, object_reg, holder, name, &miss);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001342
1343 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
1344 ASSERT(!reg.is(scratch2()));
1345 ASSERT(!reg.is(scratch3()));
1346 Register dictionary = scratch1();
1347 bool must_preserve_dictionary_reg = reg.is(dictionary);
1348
1349 // Load the properties dictionary.
1350 if (must_preserve_dictionary_reg) {
1351 __ push(dictionary);
1352 }
1353 __ mov(dictionary, FieldOperand(reg, JSObject::kPropertiesOffset));
1354
1355 // Probe the dictionary.
1356 Label probe_done, pop_and_miss;
ulan@chromium.org750145a2013-03-07 15:14:13 +00001357 NameDictionaryLookupStub::GeneratePositiveLookup(masm(),
1358 &pop_and_miss,
1359 &probe_done,
1360 dictionary,
1361 this->name(),
1362 scratch2(),
1363 scratch3());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001364 __ bind(&pop_and_miss);
1365 if (must_preserve_dictionary_reg) {
1366 __ pop(dictionary);
1367 }
1368 __ jmp(&miss);
1369 __ bind(&probe_done);
1370
1371 // If probing finds an entry in the dictionary, scratch2 contains the
1372 // index into the dictionary. Check that the value is the callback.
1373 Register index = scratch2();
1374 const int kElementsStartOffset =
ulan@chromium.org750145a2013-03-07 15:14:13 +00001375 NameDictionary::kHeaderSize +
1376 NameDictionary::kElementsStartIndex * kPointerSize;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001377 const int kValueOffset = kElementsStartOffset + kPointerSize;
1378 __ mov(scratch3(),
1379 Operand(dictionary, index, times_4, kValueOffset - kHeapObjectTag));
1380 if (must_preserve_dictionary_reg) {
1381 __ pop(dictionary);
1382 }
1383 __ cmp(scratch3(), callback);
1384 __ j(not_equal, &miss);
1385 }
1386
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001387 HandlerFrontendFooter(name, &miss);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001388 return reg;
1389}
1390
1391
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001392void LoadStubCompiler::GenerateLoadField(Register reg,
1393 Handle<JSObject> holder,
1394 PropertyIndex field,
1395 Representation representation) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001396 if (!reg.is(receiver())) __ mov(receiver(), reg);
1397 if (kind() == Code::LOAD_IC) {
1398 LoadFieldStub stub(field.is_inobject(holder),
1399 field.translate(holder),
1400 representation);
1401 GenerateTailCall(masm(), stub.GetCode(isolate()));
1402 } else {
1403 KeyedLoadFieldStub stub(field.is_inobject(holder),
1404 field.translate(holder),
1405 representation);
1406 GenerateTailCall(masm(), stub.GetCode(isolate()));
1407 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001408}
1409
1410
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001411void LoadStubCompiler::GenerateLoadCallback(
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00001412 const CallOptimization& call_optimization) {
dslomov@chromium.org639bac02013-09-09 11:58:54 +00001413 GenerateFastApiCall(
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00001414 masm(), call_optimization, receiver(), scratch1(),
1415 scratch2(), name(), 0, NULL);
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00001416}
1417
1418
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001419void LoadStubCompiler::GenerateLoadCallback(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001420 Register reg,
1421 Handle<ExecutableAccessorInfo> callback) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001422 // Insert additional parameters into the stack frame above return address.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001423 ASSERT(!scratch3().is(reg));
1424 __ pop(scratch3()); // Get return address to place it below.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001425
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001426 STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0);
1427 STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1);
1428 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2);
1429 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3);
1430 STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4);
1431 STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001432 __ push(receiver()); // receiver
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001433 // Push data from ExecutableAccessorInfo.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001434 if (isolate()->heap()->InNewSpace(callback->data())) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001435 ASSERT(!scratch2().is(reg));
1436 __ mov(scratch2(), Immediate(callback));
1437 __ push(FieldOperand(scratch2(), ExecutableAccessorInfo::kDataOffset));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001438 } else {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001439 __ push(Immediate(Handle<Object>(callback->data(), isolate())));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001440 }
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001441 __ push(Immediate(isolate()->factory()->undefined_value())); // ReturnValue
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001442 // ReturnValue default value
1443 __ push(Immediate(isolate()->factory()->undefined_value()));
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00001444 __ push(Immediate(reinterpret_cast<int>(isolate())));
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00001445 __ push(reg); // holder
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001446
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001447 // Save a pointer to where we pushed the arguments. This will be
1448 // passed as the const PropertyAccessorInfo& to the C++ callback.
1449 __ push(esp);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001450
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001451 __ push(name()); // name
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001452 __ mov(ebx, esp); // esp points to reference to name (handler).
1453
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001454 __ push(scratch3()); // Restore return address.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001455
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001456 // array for v8::Arguments::values_, handler for name and pointer
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001457 // to the values (it considered as smi in GC).
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001458 const int kStackSpace = PropertyCallbackArguments::kArgsLength + 2;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001459 // Allocate space for opional callback address parameter in case
1460 // CPU profiler is active.
1461 const int kApiArgc = 2 + 1;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001462
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001463 Address getter_address = v8::ToCData<Address>(callback->getter());
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001464 __ PrepareCallApiFunction(kApiArgc);
1465 __ mov(ApiParameterOperand(0), ebx); // name.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001466 __ add(ebx, Immediate(kPointerSize));
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001467 __ mov(ApiParameterOperand(1), ebx); // arguments pointer.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001468
kmillikin@chromium.org2d5475f2009-12-20 18:15:52 +00001469 // Emitting a stub call may try to allocate (if the code is not
1470 // already generated). Do not allow the assembler to perform a
1471 // garbage collection but instead return the allocation failure
1472 // object.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001473
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001474 Address thunk_address = FUNCTION_ADDR(&InvokeAccessorGetterCallback);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001475
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001476 __ CallApiFunctionAndReturn(getter_address,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001477 thunk_address,
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001478 ApiParameterOperand(2),
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001479 kStackSpace,
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001480 Operand(ebp, 7 * kPointerSize),
1481 NULL);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001482}
1483
1484
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001485void LoadStubCompiler::GenerateLoadConstant(Handle<Object> value) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001486 // Return the constant value.
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001487 __ LoadObject(eax, value);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001488 __ ret(0);
1489}
1490
1491
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001492void LoadStubCompiler::GenerateLoadInterceptor(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001493 Register holder_reg,
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001494 Handle<Object> object,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001495 Handle<JSObject> interceptor_holder,
1496 LookupResult* lookup,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001497 Handle<Name> name) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001498 ASSERT(interceptor_holder->HasNamedInterceptor());
1499 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1500
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001501 // So far the most popular follow ups for interceptor loads are FIELD
1502 // and CALLBACKS, so inline only them, other cases may be added
1503 // later.
1504 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001505 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001506 if (lookup->IsField()) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001507 compile_followup_inline = true;
1508 } else if (lookup->type() == CALLBACKS &&
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001509 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
1510 ExecutableAccessorInfo* callback =
1511 ExecutableAccessorInfo::cast(lookup->GetCallbackObject());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001512 compile_followup_inline = callback->getter() != NULL &&
1513 callback->IsCompatibleReceiver(*object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001514 }
1515 }
1516
1517 if (compile_followup_inline) {
1518 // Compile the interceptor call, followed by inline code to load the
1519 // property from further up the prototype chain if the call fails.
1520 // Check that the maps haven't changed.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001521 ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001522
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001523 // Preserve the receiver register explicitly whenever it is different from
1524 // the holder and it is needed should the interceptor return without any
1525 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1526 // the FIELD case might cause a miss during the prototype check.
1527 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001528 bool must_preserve_receiver_reg = !receiver().is(holder_reg) &&
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001529 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1530
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001531 // Save necessary data before invoking an interceptor.
1532 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001533 {
1534 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001535
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001536 if (must_preserve_receiver_reg) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001537 __ push(receiver());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001538 }
1539 __ push(holder_reg);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001540 __ push(this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001541
1542 // Invoke an interceptor. Note: map checks from receiver to
1543 // interceptor's holder has been compiled before (see a caller
1544 // of this method.)
machenbach@chromium.org37be4082013-11-26 13:50:38 +00001545 CompileCallLoadPropertyWithInterceptor(
1546 masm(), receiver(), holder_reg, this->name(), interceptor_holder,
1547 IC::kLoadPropertyWithInterceptorOnly);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001548
1549 // Check if interceptor provided a value for property. If it's
1550 // the case, return immediately.
1551 Label interceptor_failed;
1552 __ cmp(eax, factory()->no_interceptor_result_sentinel());
1553 __ j(equal, &interceptor_failed);
1554 frame_scope.GenerateLeaveFrame();
1555 __ ret(0);
1556
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001557 // Clobber registers when generating debug-code to provoke errors.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001558 __ bind(&interceptor_failed);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001559 if (FLAG_debug_code) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001560 __ mov(receiver(), Immediate(BitCast<int32_t>(kZapValue)));
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001561 __ mov(holder_reg, Immediate(BitCast<int32_t>(kZapValue)));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001562 __ mov(this->name(), Immediate(BitCast<int32_t>(kZapValue)));
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001563 }
1564
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001565 __ pop(this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001566 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001567 if (must_preserve_receiver_reg) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001568 __ pop(receiver());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001569 }
1570
1571 // Leave the internal frame.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001572 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001573
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001574 GenerateLoadPostInterceptor(holder_reg, interceptor_holder, name, lookup);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001575 } else { // !compile_followup_inline
1576 // Call the runtime system to load the interceptor.
1577 // Check that the maps haven't changed.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001578 __ pop(scratch2()); // save old return address
1579 PushInterceptorArguments(masm(), receiver(), holder_reg,
1580 this->name(), interceptor_holder);
1581 __ push(scratch2()); // restore old return address
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001582
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001583 ExternalReference ref =
1584 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001585 isolate());
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00001586 __ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength, 1);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001587 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001588}
1589
1590
ulan@chromium.org750145a2013-03-07 15:14:13 +00001591void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001592 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001593 __ cmp(ecx, Immediate(name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001594 __ j(not_equal, miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001595 }
1596}
1597
1598
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00001599void CallStubCompiler::GenerateFunctionCheck(Register function,
1600 Register scratch,
1601 Label* miss) {
1602 __ JumpIfSmi(function, miss);
1603 __ CmpObjectType(function, JS_FUNCTION_TYPE, scratch);
1604 __ j(not_equal, miss);
1605}
1606
1607
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001608void CallStubCompiler::GenerateLoadFunctionFromCell(
danno@chromium.org41728482013-06-12 22:31:22 +00001609 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001610 Handle<JSFunction> function,
1611 Label* miss) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001612 // Get the value from the cell.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001613 if (Serializer::enabled()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001614 __ mov(edi, Immediate(cell));
danno@chromium.org41728482013-06-12 22:31:22 +00001615 __ mov(edi, FieldOperand(edi, Cell::kValueOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001616 } else {
danno@chromium.org41728482013-06-12 22:31:22 +00001617 __ mov(edi, Operand::ForCell(cell));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001618 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001619
1620 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001621 if (isolate()->heap()->InNewSpace(*function)) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001622 // We can't embed a pointer to a function in new space so we have
1623 // to verify that the shared function info is unchanged. This has
1624 // the nice side effect that multiple closures based on the same
1625 // function can all use this call IC. Before we load through the
1626 // function, we have to verify that it still is a function.
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00001627 GenerateFunctionCheck(edi, ebx, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001628
1629 // Check the shared function info. Make sure it hasn't changed.
1630 __ cmp(FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset),
1631 Immediate(Handle<SharedFunctionInfo>(function->shared())));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001632 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001633 __ cmp(edi, Immediate(function));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001634 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001635 __ j(not_equal, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001636}
1637
1638
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001639void CallStubCompiler::GenerateMissBranch() {
1640 Handle<Code> code =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001641 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
danno@chromium.org40cb8782011-05-25 07:58:50 +00001642 kind_,
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00001643 extra_state());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001644 __ jmp(code, RelocInfo::CODE_TARGET);
1645}
1646
1647
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001648Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1649 Handle<JSObject> holder,
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00001650 PropertyIndex index,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001651 Handle<Name> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001652 Label miss;
1653
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00001654 Register reg = HandlerFrontendHeader(
1655 object, holder, name, RECEIVER_MAP_CHECK, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001656
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001657 GenerateFastPropertyLoad(
1658 masm(), edi, reg, index.is_inobject(holder),
1659 index.translate(holder), Representation::Tagged());
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00001660 GenerateJumpFunction(object, edi, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001661
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00001662 HandlerFrontendFooter(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001663
1664 // Return the generated code.
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00001665 return GetCode(Code::FAST, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001666}
1667
1668
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001669Handle<Code> CallStubCompiler::CompileArrayCodeCall(
1670 Handle<Object> object,
1671 Handle<JSObject> holder,
1672 Handle<Cell> cell,
1673 Handle<JSFunction> function,
1674 Handle<String> name,
1675 Code::StubType type) {
1676 Label miss;
1677
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00001678 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
1679 if (!cell.is_null()) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001680 ASSERT(cell->value() == *function);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001681 GenerateLoadFunctionFromCell(cell, function, &miss);
1682 }
1683
danno@chromium.orgbee51992013-07-10 14:57:15 +00001684 Handle<AllocationSite> site = isolate()->factory()->NewAllocationSite();
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001685 site->SetElementsKind(GetInitialFastElementsKind());
danno@chromium.orgbee51992013-07-10 14:57:15 +00001686 Handle<Cell> site_feedback_cell = isolate()->factory()->NewCell(site);
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00001687 const int argc = arguments().immediate();
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001688 __ mov(eax, Immediate(argc));
danno@chromium.orgbee51992013-07-10 14:57:15 +00001689 __ mov(ebx, site_feedback_cell);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001690 __ mov(edi, function);
1691
1692 ArrayConstructorStub stub(isolate());
1693 __ TailCallStub(&stub);
1694
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00001695 HandlerFrontendFooter(&miss);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001696
1697 // Return the generated code.
1698 return GetCode(type, name);
1699}
1700
1701
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001702Handle<Code> CallStubCompiler::CompileArrayPushCall(
1703 Handle<Object> object,
1704 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00001705 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001706 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001707 Handle<String> name,
1708 Code::StubType type) {
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00001709 // If object is not an array or is observed or sealed, bail out to regular
1710 // call.
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001711 if (!object->IsJSArray() ||
1712 !cell.is_null() ||
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00001713 Handle<JSArray>::cast(object)->map()->is_observed() ||
1714 !Handle<JSArray>::cast(object)->map()->is_extensible()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001715 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001716 }
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001717
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001718 Label miss;
1719
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00001720 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001721
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001722 const int argc = arguments().immediate();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001723 if (argc == 0) {
1724 // Noop, return the length.
1725 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
1726 __ ret((argc + 1) * kPointerSize);
1727 } else {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001728 Label call_builtin;
1729
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001730 if (argc == 1) { // Otherwise fall through to call builtin.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001731 Label attempt_to_grow_elements, with_write_barrier, check_double;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001732
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001733 // Get the elements array of the object.
1734 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset));
1735
1736 // Check that the elements are in fast mode and writable.
1737 __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
1738 Immediate(factory()->fixed_array_map()));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001739 __ j(not_equal, &check_double);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001740
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001741 // Get the array's length into eax and calculate new length.
1742 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
1743 STATIC_ASSERT(kSmiTagSize == 1);
1744 STATIC_ASSERT(kSmiTag == 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001745 __ add(eax, Immediate(Smi::FromInt(argc)));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001746
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001747 // Get the elements' length into ecx.
1748 __ mov(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001749
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001750 // Check if we could survive without allocation.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001751 __ cmp(eax, ecx);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001752 __ j(greater, &attempt_to_grow_elements);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001753
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001754 // Check if value is a smi.
1755 __ mov(ecx, Operand(esp, argc * kPointerSize));
1756 __ JumpIfNotSmi(ecx, &with_write_barrier);
1757
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001758 // Save new length.
1759 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1760
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001761 // Store the value.
1762 __ mov(FieldOperand(edi,
1763 eax,
1764 times_half_pointer_size,
1765 FixedArray::kHeaderSize - argc * kPointerSize),
1766 ecx);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001767
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001768 __ ret((argc + 1) * kPointerSize);
1769
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001770 __ bind(&check_double);
1771
1772
1773 // Check that the elements are in double mode.
1774 __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
1775 Immediate(factory()->fixed_double_array_map()));
1776 __ j(not_equal, &call_builtin);
1777
1778 // 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);
1782 __ add(eax, Immediate(Smi::FromInt(argc)));
1783
1784 // Get the elements' length into ecx.
1785 __ mov(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
1786
1787 // Check if we could survive without allocation.
1788 __ cmp(eax, ecx);
1789 __ j(greater, &call_builtin);
1790
1791 __ mov(ecx, Operand(esp, argc * kPointerSize));
1792 __ StoreNumberToDoubleElements(
1793 ecx, edi, eax, ecx, xmm0, &call_builtin, true, argc * kDoubleSize);
1794
1795 // Save new length.
1796 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1797 __ ret((argc + 1) * kPointerSize);
1798
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001799 __ bind(&with_write_barrier);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001800
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001801 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
1802
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001803 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001804 Label fast_object, not_fast_object;
1805 __ CheckFastObjectElements(ebx, &not_fast_object, Label::kNear);
1806 __ jmp(&fast_object);
1807 // In case of fast smi-only, convert to fast object, otherwise bail out.
1808 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001809 __ CheckFastSmiElements(ebx, &call_builtin);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001810 __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
1811 Immediate(factory()->heap_number_map()));
1812 __ j(equal, &call_builtin);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001813 // edi: elements array
1814 // edx: receiver
1815 // ebx: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001816 Label try_holey_map;
1817 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001818 FAST_ELEMENTS,
1819 ebx,
1820 edi,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001821 &try_holey_map);
1822
1823 ElementsTransitionGenerator::
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001824 GenerateMapChangeElementsTransition(masm(),
1825 DONT_TRACK_ALLOCATION_SITE,
1826 NULL);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001827 // Restore edi.
1828 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset));
1829 __ jmp(&fast_object);
1830
1831 __ bind(&try_holey_map);
1832 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1833 FAST_HOLEY_ELEMENTS,
1834 ebx,
1835 edi,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001836 &call_builtin);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001837 ElementsTransitionGenerator::
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001838 GenerateMapChangeElementsTransition(masm(),
1839 DONT_TRACK_ALLOCATION_SITE,
1840 NULL);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001841 // Restore edi.
1842 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset));
1843 __ bind(&fast_object);
1844 } else {
1845 __ CheckFastObjectElements(ebx, &call_builtin);
1846 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001847
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001848 // Save new length.
1849 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1850
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001851 // Store the value.
1852 __ lea(edx, FieldOperand(edi,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001853 eax, times_half_pointer_size,
1854 FixedArray::kHeaderSize - argc * kPointerSize));
1855 __ mov(Operand(edx, 0), ecx);
1856
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001857 __ RecordWrite(edi, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001858 OMIT_SMI_CHECK);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001859
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001860 __ ret((argc + 1) * kPointerSize);
1861
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001862 __ bind(&attempt_to_grow_elements);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001863 if (!FLAG_inline_new) {
1864 __ jmp(&call_builtin);
1865 }
1866
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001867 __ mov(ebx, Operand(esp, argc * kPointerSize));
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001868 // Growing elements that are SMI-only requires special handling in case
1869 // the new element is non-Smi. For now, delegate to the builtin.
1870 Label no_fast_elements_check;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001871 __ JumpIfSmi(ebx, &no_fast_elements_check);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001872 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
1873 __ CheckFastObjectElements(ecx, &call_builtin, Label::kFar);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001874 __ bind(&no_fast_elements_check);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001875
1876 // We could be lucky and the elements array could be at the top of
1877 // new-space. In this case we can just grow it in place by moving the
1878 // allocation pointer up.
1879
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001880 ExternalReference new_space_allocation_top =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001881 ExternalReference::new_space_allocation_top_address(isolate());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001882 ExternalReference new_space_allocation_limit =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001883 ExternalReference::new_space_allocation_limit_address(isolate());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001884
1885 const int kAllocationDelta = 4;
1886 // Load top.
1887 __ mov(ecx, Operand::StaticVariable(new_space_allocation_top));
1888
1889 // Check if it's the end of elements.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001890 __ lea(edx, FieldOperand(edi,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001891 eax, times_half_pointer_size,
1892 FixedArray::kHeaderSize - argc * kPointerSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001893 __ cmp(edx, ecx);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001894 __ j(not_equal, &call_builtin);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001895 __ add(ecx, Immediate(kAllocationDelta * kPointerSize));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001896 __ cmp(ecx, Operand::StaticVariable(new_space_allocation_limit));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001897 __ j(above, &call_builtin);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001898
1899 // We fit and could grow elements.
1900 __ mov(Operand::StaticVariable(new_space_allocation_top), ecx);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001901
1902 // Push the argument...
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001903 __ mov(Operand(edx, 0), ebx);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001904 // ... and fill the rest with holes.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001905 for (int i = 1; i < kAllocationDelta; i++) {
1906 __ mov(Operand(edx, i * kPointerSize),
lrn@chromium.org7516f052011-03-30 08:52:27 +00001907 Immediate(factory()->the_hole_value()));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001908 }
1909
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001910 // We know the elements array is in new space so we don't need the
1911 // remembered set, but we just pushed a value onto it so we may have to
1912 // tell the incremental marker to rescan the object that we just grew. We
1913 // don't need to worry about the holes because they are in old space and
1914 // already marked black.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001915 __ RecordWrite(edi, edx, ebx, kDontSaveFPRegs, OMIT_REMEMBERED_SET);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001916
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001917 // Restore receiver to edx as finish sequence assumes it's here.
1918 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1919
1920 // Increment element's and array's sizes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001921 __ add(FieldOperand(edi, FixedArray::kLengthOffset),
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001922 Immediate(Smi::FromInt(kAllocationDelta)));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001923
1924 // NOTE: This only happen in new-space, where we don't
1925 // care about the black-byte-count on pages. Otherwise we should
1926 // update that too if the object is black.
1927
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001928 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
1929
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001930 __ ret((argc + 1) * kPointerSize);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001931 }
1932
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001933 __ bind(&call_builtin);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001934 __ TailCallExternalReference(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001935 ExternalReference(Builtins::c_ArrayPush, isolate()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001936 argc + 1,
1937 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001938 }
1939
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00001940 HandlerFrontendFooter(&miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001941
1942 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001943 return GetCode(type, name);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001944}
1945
1946
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001947Handle<Code> CallStubCompiler::CompileArrayPopCall(
1948 Handle<Object> object,
1949 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00001950 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001951 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001952 Handle<String> name,
1953 Code::StubType type) {
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00001954 // If object is not an array or is observed or sealed, bail out to regular
1955 // call.
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001956 if (!object->IsJSArray() ||
1957 !cell.is_null() ||
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00001958 Handle<JSArray>::cast(object)->map()->is_observed() ||
1959 !Handle<JSArray>::cast(object)->map()->is_extensible()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001960 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001961 }
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001962
ager@chromium.orgac091b72010-05-05 07:34:42 +00001963 Label miss, return_undefined, call_builtin;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001964
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00001965 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001966
1967 // Get the elements array of the object.
1968 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset));
1969
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001970 // Check that the elements are in fast mode and writable.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001971 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
lrn@chromium.org7516f052011-03-30 08:52:27 +00001972 Immediate(factory()->fixed_array_map()));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001973 __ j(not_equal, &call_builtin);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001974
1975 // Get the array's length into ecx and calculate new length.
1976 __ mov(ecx, FieldOperand(edx, JSArray::kLengthOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001977 __ sub(ecx, Immediate(Smi::FromInt(1)));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001978 __ j(negative, &return_undefined);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001979
1980 // Get the last element.
1981 STATIC_ASSERT(kSmiTagSize == 1);
1982 STATIC_ASSERT(kSmiTag == 0);
1983 __ mov(eax, FieldOperand(ebx,
1984 ecx, times_half_pointer_size,
1985 FixedArray::kHeaderSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001986 __ cmp(eax, Immediate(factory()->the_hole_value()));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001987 __ j(equal, &call_builtin);
1988
1989 // Set the array's length.
1990 __ mov(FieldOperand(edx, JSArray::kLengthOffset), ecx);
1991
1992 // Fill with the hole.
1993 __ mov(FieldOperand(ebx,
1994 ecx, times_half_pointer_size,
1995 FixedArray::kHeaderSize),
lrn@chromium.org7516f052011-03-30 08:52:27 +00001996 Immediate(factory()->the_hole_value()));
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00001997 const int argc = arguments().immediate();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001998 __ ret((argc + 1) * kPointerSize);
1999
ager@chromium.orgac091b72010-05-05 07:34:42 +00002000 __ bind(&return_undefined);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002001 __ mov(eax, Immediate(factory()->undefined_value()));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002002 __ ret((argc + 1) * kPointerSize);
2003
2004 __ bind(&call_builtin);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002005 __ TailCallExternalReference(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002006 ExternalReference(Builtins::c_ArrayPop, isolate()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002007 argc + 1,
2008 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002009
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002010 HandlerFrontendFooter(&miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002011
2012 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002013 return GetCode(type, name);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002014}
2015
2016
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002017Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
2018 Handle<Object> object,
2019 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002020 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002021 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002022 Handle<String> name,
2023 Code::StubType type) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002024 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002025 if (!object->IsString() || !cell.is_null()) {
2026 return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002027 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002028
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002029 const int argc = arguments().immediate();
2030
2031 Label miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002032 Label name_miss;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002033 Label index_out_of_range;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002034 Label* index_out_of_range_label = &index_out_of_range;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002035
danno@chromium.org40cb8782011-05-25 07:58:50 +00002036 if (kind_ == Code::CALL_IC &&
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00002037 (CallICBase::StringStubState::decode(extra_state()) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002038 DEFAULT_STRING_STUB)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002039 index_out_of_range_label = &miss;
2040 }
2041
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002042 HandlerFrontendHeader(object, holder, name, STRING_CHECK, &name_miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002043
2044 Register receiver = ebx;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002045 Register index = edi;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002046 Register result = eax;
2047 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize));
2048 if (argc > 0) {
2049 __ mov(index, Operand(esp, (argc - 0) * kPointerSize));
2050 } else {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002051 __ Set(index, Immediate(factory()->undefined_value()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002052 }
2053
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002054 StringCharCodeAtGenerator generator(receiver,
2055 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002056 result,
2057 &miss, // When not a string.
2058 &miss, // When not a number.
2059 index_out_of_range_label,
2060 STRING_INDEX_IS_NUMBER);
2061 generator.GenerateFast(masm());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002062 __ ret((argc + 1) * kPointerSize);
2063
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002064 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002065 generator.GenerateSlow(masm(), call_helper);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002066
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002067 if (index_out_of_range.is_linked()) {
2068 __ bind(&index_out_of_range);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002069 __ Set(eax, Immediate(factory()->nan_value()));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002070 __ ret((argc + 1) * kPointerSize);
2071 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002072
2073 __ bind(&miss);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002074 // Restore function name in ecx.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002075 __ Set(ecx, Immediate(name));
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00002076 HandlerFrontendFooter(&name_miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002077
2078 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002079 return GetCode(type, name);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002080}
2081
2082
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002083Handle<Code> CallStubCompiler::CompileStringCharAtCall(
2084 Handle<Object> object,
2085 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002086 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002087 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002088 Handle<String> name,
2089 Code::StubType type) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002090 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002091 if (!object->IsString() || !cell.is_null()) {
2092 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002093 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002094
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002095 const int argc = arguments().immediate();
2096
2097 Label miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002098 Label name_miss;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002099 Label index_out_of_range;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002100 Label* index_out_of_range_label = &index_out_of_range;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002101
danno@chromium.org40cb8782011-05-25 07:58:50 +00002102 if (kind_ == Code::CALL_IC &&
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00002103 (CallICBase::StringStubState::decode(extra_state()) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002104 DEFAULT_STRING_STUB)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002105 index_out_of_range_label = &miss;
2106 }
2107
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002108 HandlerFrontendHeader(object, holder, name, STRING_CHECK, &name_miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002109
2110 Register receiver = eax;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002111 Register index = edi;
danno@chromium.orgc612e022011-11-10 11:38:15 +00002112 Register scratch = edx;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002113 Register result = eax;
2114 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize));
2115 if (argc > 0) {
2116 __ mov(index, Operand(esp, (argc - 0) * kPointerSize));
2117 } else {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002118 __ Set(index, Immediate(factory()->undefined_value()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002119 }
2120
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002121 StringCharAtGenerator generator(receiver,
2122 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00002123 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002124 result,
2125 &miss, // When not a string.
2126 &miss, // When not a number.
2127 index_out_of_range_label,
2128 STRING_INDEX_IS_NUMBER);
2129 generator.GenerateFast(masm());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002130 __ ret((argc + 1) * kPointerSize);
2131
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002132 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002133 generator.GenerateSlow(masm(), call_helper);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002134
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002135 if (index_out_of_range.is_linked()) {
2136 __ bind(&index_out_of_range);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002137 __ Set(eax, Immediate(factory()->empty_string()));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002138 __ ret((argc + 1) * kPointerSize);
2139 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002140
2141 __ bind(&miss);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002142 // Restore function name in ecx.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002143 __ Set(ecx, Immediate(name));
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00002144 HandlerFrontendFooter(&name_miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002145
2146 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002147 return GetCode(type, name);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002148}
2149
2150
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002151Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
2152 Handle<Object> object,
2153 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002154 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002155 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002156 Handle<String> name,
2157 Code::StubType type) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002158 const int argc = arguments().immediate();
2159
2160 // If the object is not a JSObject or we got an unexpected number of
2161 // arguments, bail out to the regular call.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002162 if (!object->IsJSObject() || argc != 1) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002163 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002164 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002165
2166 Label miss;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002167
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002168 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
2169 if (!cell.is_null()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002170 ASSERT(cell->value() == *function);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002171 GenerateLoadFunctionFromCell(cell, function, &miss);
2172 }
2173
2174 // Load the char code argument.
2175 Register code = ebx;
2176 __ mov(code, Operand(esp, 1 * kPointerSize));
2177
2178 // Check the code is a smi.
2179 Label slow;
2180 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002181 __ JumpIfNotSmi(code, &slow);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002182
2183 // Convert the smi code to uint16.
2184 __ and_(code, Immediate(Smi::FromInt(0xffff)));
2185
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002186 StringCharFromCodeGenerator generator(code, eax);
2187 generator.GenerateFast(masm());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002188 __ ret(2 * kPointerSize);
2189
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002190 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002191 generator.GenerateSlow(masm(), call_helper);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002192
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002193 __ bind(&slow);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00002194 // We do not have to patch the receiver because the function makes no use of
2195 // it.
2196 GenerateJumpFunctionIgnoreReceiver(function);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002197
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002198 HandlerFrontendFooter(&miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002199
2200 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002201 return GetCode(type, name);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002202}
2203
2204
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002205Handle<Code> CallStubCompiler::CompileMathFloorCall(
2206 Handle<Object> object,
2207 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002208 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002209 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002210 Handle<String> name,
2211 Code::StubType type) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002212 if (!CpuFeatures::IsSupported(SSE2)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002213 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002214 }
2215
ulan@chromium.org750145a2013-03-07 15:14:13 +00002216 CpuFeatureScope use_sse2(masm(), SSE2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002217
2218 const int argc = arguments().immediate();
2219
2220 // If the object is not a JSObject or we got an unexpected number of
2221 // arguments, bail out to the regular call.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002222 if (!object->IsJSObject() || argc != 1) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002223 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002224 }
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002225
2226 Label miss;
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002227
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002228 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
2229 if (!cell.is_null()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002230 ASSERT(cell->value() == *function);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002231 GenerateLoadFunctionFromCell(cell, function, &miss);
2232 }
2233
2234 // Load the (only) argument into eax.
2235 __ mov(eax, Operand(esp, 1 * kPointerSize));
2236
2237 // Check if the argument is a smi.
2238 Label smi;
2239 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002240 __ JumpIfSmi(eax, &smi);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002241
2242 // Check if the argument is a heap number and load its value into xmm0.
2243 Label slow;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002244 __ CheckMap(eax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00002245 __ movsd(xmm0, FieldOperand(eax, HeapNumber::kValueOffset));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002246
2247 // Check if the argument is strictly positive. Note this also
2248 // discards NaN.
2249 __ xorpd(xmm1, xmm1);
2250 __ ucomisd(xmm0, xmm1);
2251 __ j(below_equal, &slow);
2252
2253 // Do a truncating conversion.
2254 __ cvttsd2si(eax, Operand(xmm0));
2255
2256 // Check if the result fits into a smi. Note this also checks for
2257 // 0x80000000 which signals a failed conversion.
2258 Label wont_fit_into_smi;
2259 __ test(eax, Immediate(0xc0000000));
2260 __ j(not_zero, &wont_fit_into_smi);
2261
2262 // Smi tag and return.
2263 __ SmiTag(eax);
2264 __ bind(&smi);
2265 __ ret(2 * kPointerSize);
2266
2267 // Check if the argument is < 2^kMantissaBits.
2268 Label already_round;
2269 __ bind(&wont_fit_into_smi);
2270 __ LoadPowerOf2(xmm1, ebx, HeapNumber::kMantissaBits);
2271 __ ucomisd(xmm0, xmm1);
2272 __ j(above_equal, &already_round);
2273
2274 // Save a copy of the argument.
2275 __ movaps(xmm2, xmm0);
2276
2277 // Compute (argument + 2^kMantissaBits) - 2^kMantissaBits.
2278 __ addsd(xmm0, xmm1);
2279 __ subsd(xmm0, xmm1);
2280
2281 // Compare the argument and the tentative result to get the right mask:
2282 // if xmm2 < xmm0:
2283 // xmm2 = 1...1
2284 // else:
2285 // xmm2 = 0...0
2286 __ cmpltsd(xmm2, xmm0);
2287
2288 // Subtract 1 if the argument was less than the tentative result.
2289 __ LoadPowerOf2(xmm1, ebx, 0);
2290 __ andpd(xmm1, xmm2);
2291 __ subsd(xmm0, xmm1);
2292
2293 // Return a new heap number.
2294 __ AllocateHeapNumber(eax, ebx, edx, &slow);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00002295 __ movsd(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002296 __ ret(2 * kPointerSize);
2297
2298 // Return the argument (when it's an already round heap number).
2299 __ bind(&already_round);
2300 __ mov(eax, Operand(esp, 1 * kPointerSize));
2301 __ ret(2 * kPointerSize);
2302
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002303 __ bind(&slow);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00002304 // We do not have to patch the receiver because the function makes no use of
2305 // it.
2306 GenerateJumpFunctionIgnoreReceiver(function);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002307
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002308 HandlerFrontendFooter(&miss);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002309
2310 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002311 return GetCode(type, name);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002312}
2313
2314
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002315Handle<Code> CallStubCompiler::CompileMathAbsCall(
2316 Handle<Object> object,
2317 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002318 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002319 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002320 Handle<String> name,
2321 Code::StubType type) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002322 const int argc = arguments().immediate();
2323
2324 // If the object is not a JSObject or we got an unexpected number of
2325 // arguments, bail out to the regular call.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002326 if (!object->IsJSObject() || argc != 1) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002327 return Handle<Code>::null();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002328 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002329
2330 Label miss;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002331
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002332 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
2333 if (!cell.is_null()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002334 ASSERT(cell->value() == *function);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002335 GenerateLoadFunctionFromCell(cell, function, &miss);
2336 }
2337
2338 // Load the (only) argument into eax.
2339 __ mov(eax, Operand(esp, 1 * kPointerSize));
2340
2341 // Check if the argument is a smi.
2342 Label not_smi;
2343 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002344 __ JumpIfNotSmi(eax, &not_smi);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002345
danno@chromium.org59400602013-08-13 17:09:37 +00002346 // Branchless abs implementation, refer to below:
2347 // http://graphics.stanford.edu/~seander/bithacks.html#IntegerAbs
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002348 // Set ebx to 1...1 (== -1) if the argument is negative, or to 0...0
2349 // otherwise.
2350 __ mov(ebx, eax);
2351 __ sar(ebx, kBitsPerInt - 1);
2352
2353 // Do bitwise not or do nothing depending on ebx.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002354 __ xor_(eax, ebx);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002355
2356 // Add 1 or do nothing depending on ebx.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002357 __ sub(eax, ebx);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002358
2359 // If the result is still negative, go to the slow case.
2360 // This only happens for the most negative smi.
2361 Label slow;
2362 __ j(negative, &slow);
2363
2364 // Smi case done.
2365 __ ret(2 * kPointerSize);
2366
2367 // Check if the argument is a heap number and load its exponent and
2368 // sign into ebx.
2369 __ bind(&not_smi);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002370 __ CheckMap(eax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002371 __ mov(ebx, FieldOperand(eax, HeapNumber::kExponentOffset));
2372
2373 // Check the sign of the argument. If the argument is positive,
2374 // just return it.
2375 Label negative_sign;
2376 __ test(ebx, Immediate(HeapNumber::kSignMask));
2377 __ j(not_zero, &negative_sign);
2378 __ ret(2 * kPointerSize);
2379
2380 // If the argument is negative, clear the sign, and return a new
2381 // number.
2382 __ bind(&negative_sign);
2383 __ and_(ebx, ~HeapNumber::kSignMask);
2384 __ mov(ecx, FieldOperand(eax, HeapNumber::kMantissaOffset));
2385 __ AllocateHeapNumber(eax, edi, edx, &slow);
2386 __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), ebx);
2387 __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx);
2388 __ ret(2 * kPointerSize);
2389
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002390 __ bind(&slow);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00002391 // We do not have to patch the receiver because the function makes no use of
2392 // it.
2393 GenerateJumpFunctionIgnoreReceiver(function);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002394
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002395 HandlerFrontendFooter(&miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002396
2397 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002398 return GetCode(type, name);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002399}
2400
2401
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002402Handle<Code> CallStubCompiler::CompileFastApiCall(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002403 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002404 Handle<Object> object,
2405 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002406 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002407 Handle<JSFunction> function,
2408 Handle<String> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002409 ASSERT(optimization.is_simple_api_call());
2410 // Bail out if object is a global object as we don't want to
2411 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002412 if (object->IsGlobalObject()) return Handle<Code>::null();
2413 if (!cell.is_null()) return Handle<Code>::null();
2414 if (!object->IsJSObject()) return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002415 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002416 Handle<JSObject>::cast(object), holder);
2417 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002418
2419 Label miss, miss_before_stack_reserved;
2420
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002421 GenerateNameCheck(name, &miss_before_stack_reserved);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002422
2423 // Get the receiver from the stack.
2424 const int argc = arguments().immediate();
2425 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
2426
2427 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002428 __ JumpIfSmi(edx, &miss_before_stack_reserved);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002429
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002430 Counters* counters = isolate()->counters();
2431 __ IncrementCounter(counters->call_const(), 1);
2432 __ IncrementCounter(counters->call_const_fast_api(), 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002433
2434 // Allocate space for v8::Arguments implicit values. Must be initialized
2435 // before calling any runtime function.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002436 __ sub(esp, Immediate(kFastApiCallArguments * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002437
2438 // Check that the maps haven't changed and find a Holder as a side effect.
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00002439 CheckPrototypes(IC::CurrentTypeOf(object, isolate()), edx, holder,
2440 ebx, eax, edi, name, depth, &miss);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002441
2442 // Move the return address on top of the stack.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002443 __ mov(eax, Operand(esp, kFastApiCallArguments * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002444 __ mov(Operand(esp, 0 * kPointerSize), eax);
2445
2446 // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains
2447 // duplicate of return address and will be overwritten.
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00002448 GenerateFastApiCall(masm(), optimization, argc);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002449
2450 __ bind(&miss);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002451 __ add(esp, Immediate(kFastApiCallArguments * kPointerSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002452
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00002453 HandlerFrontendFooter(&miss_before_stack_reserved);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002454
2455 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002456 return GetCode(function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002457}
2458
2459
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002460void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) {
2461 Label success;
2462 // Check that the object is a boolean.
2463 __ cmp(object, factory()->true_value());
2464 __ j(equal, &success);
2465 __ cmp(object, factory()->false_value());
2466 __ j(not_equal, miss);
2467 __ bind(&success);
2468}
2469
2470
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002471void CallStubCompiler::PatchGlobalProxy(Handle<Object> object) {
2472 if (object->IsGlobalObject()) {
2473 const int argc = arguments().immediate();
2474 const int receiver_offset = (argc + 1) * kPointerSize;
2475 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
2476 __ mov(Operand(esp, receiver_offset), edx);
2477 }
2478}
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002479
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002480
2481Register CallStubCompiler::HandlerFrontendHeader(Handle<Object> object,
2482 Handle<JSObject> holder,
2483 Handle<Name> name,
2484 CheckType check,
2485 Label* miss) {
2486 GenerateNameCheck(name, miss);
2487
2488 Register reg = edx;
2489
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002490 const int argc = arguments().immediate();
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002491 const int receiver_offset = (argc + 1) * kPointerSize;
2492 __ mov(reg, Operand(esp, receiver_offset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002493
2494 // Check that the receiver isn't a smi.
2495 if (check != NUMBER_CHECK) {
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002496 __ JumpIfSmi(reg, miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002497 }
2498
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002499 // Make sure that it's okay not to patch the on stack receiver
2500 // unless we're doing a receiver map check.
2501 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002502 switch (check) {
2503 case RECEIVER_MAP_CHECK:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002504 __ IncrementCounter(isolate()->counters()->call_const(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00002505
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002506 // Check that the maps haven't changed.
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002507 reg = CheckPrototypes(IC::CurrentTypeOf(object, isolate()), reg, holder,
2508 ebx, eax, edi, name, miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002509
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002510 break;
2511
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00002512 case STRING_CHECK: {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002513 // Check that the object is a string.
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002514 __ CmpObjectType(reg, FIRST_NONSTRING_TYPE, eax);
2515 __ j(above_equal, miss);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002516 // Check that the maps starting from the prototype haven't changed.
2517 GenerateDirectLoadGlobalFunctionPrototype(
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002518 masm(), Context::STRING_FUNCTION_INDEX, eax, miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002519 break;
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00002520 }
2521 case SYMBOL_CHECK: {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002522 // Check that the object is a symbol.
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002523 __ CmpObjectType(reg, SYMBOL_TYPE, eax);
2524 __ j(not_equal, miss);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002525 // Check that the maps starting from the prototype haven't changed.
2526 GenerateDirectLoadGlobalFunctionPrototype(
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002527 masm(), Context::SYMBOL_FUNCTION_INDEX, eax, miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002528 break;
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00002529 }
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002530 case NUMBER_CHECK: {
2531 Label fast;
2532 // Check that the object is a smi or a heap number.
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002533 __ JumpIfSmi(reg, &fast);
2534 __ CmpObjectType(reg, HEAP_NUMBER_TYPE, eax);
2535 __ j(not_equal, miss);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002536 __ bind(&fast);
2537 // Check that the maps starting from the prototype haven't changed.
2538 GenerateDirectLoadGlobalFunctionPrototype(
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002539 masm(), Context::NUMBER_FUNCTION_INDEX, eax, miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002540 break;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002541 }
2542 case BOOLEAN_CHECK: {
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002543 GenerateBooleanCheck(reg, miss);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002544 // Check that the maps starting from the prototype haven't changed.
2545 GenerateDirectLoadGlobalFunctionPrototype(
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002546 masm(), Context::BOOLEAN_FUNCTION_INDEX, eax, miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002547 break;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002548 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002549 }
2550
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002551 if (check != RECEIVER_MAP_CHECK) {
2552 Handle<Object> prototype(object->GetPrototype(isolate()), isolate());
2553 reg = CheckPrototypes(
2554 IC::CurrentTypeOf(prototype, isolate()),
2555 eax, holder, ebx, edx, edi, name, miss);
2556 }
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002557
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002558 return reg;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002559}
2560
2561
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00002562void CallStubCompiler::GenerateJumpFunction(Handle<Object> object,
2563 Register function,
2564 Label* miss) {
2565 // Check that the function really is a function.
2566 GenerateFunctionCheck(function, ebx, miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002567
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00002568 if (!function.is(edi)) __ mov(edi, function);
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002569 PatchGlobalProxy(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002570
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00002571 // Invoke the function.
2572 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION,
2573 NullCallWrapper(), call_kind());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002574}
2575
2576
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002577Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2578 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002579 Handle<Name> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002580 Label miss;
2581
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002582 GenerateNameCheck(name, &miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002583
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002584 // Get the number of arguments.
2585 const int argc = arguments().immediate();
2586
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002587 LookupResult lookup(isolate());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002588 LookupPostInterceptor(holder, name, &lookup);
2589
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002590 // Get the receiver from the stack.
2591 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002592
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +00002593 CallInterceptorCompiler compiler(this, arguments(), ecx);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002594 compiler.Compile(masm(), object, holder, name, &lookup, edx, ebx, edi, eax,
2595 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002596
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002597 // Restore receiver.
2598 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002599
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00002600 GenerateJumpFunction(object, eax, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002601
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00002602 HandlerFrontendFooter(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002603
2604 // Return the generated code.
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00002605 return GetCode(Code::FAST, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002606}
2607
2608
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002609Handle<Code> CallStubCompiler::CompileCallGlobal(
2610 Handle<JSObject> object,
2611 Handle<GlobalObject> holder,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002612 Handle<PropertyCell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002613 Handle<JSFunction> function,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002614 Handle<Name> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002615 if (HasCustomCallGenerator(function)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00002616 Handle<Code> code = CompileCustomCall(
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002617 object, holder, cell, function, Handle<String>::cast(name),
2618 Code::NORMAL);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002619 // A null handle means bail out to the regular compiler code below.
2620 if (!code.is_null()) return code;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002621 }
2622
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002623 Label miss;
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002624 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00002625 // Potentially loads a closure that matches the shared function info of the
2626 // function, rather than function.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002627 GenerateLoadFunctionFromCell(cell, function, &miss);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00002628 GenerateJumpFunction(object, edi, function);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002629
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002630 HandlerFrontendFooter(&miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002631
2632 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002633 return GetCode(Code::NORMAL, name);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002634}
2635
2636
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002637Handle<Code> StoreStubCompiler::CompileStoreCallback(
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002638 Handle<JSObject> object,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002639 Handle<JSObject> holder,
danno@chromium.orgbee51992013-07-10 14:57:15 +00002640 Handle<Name> name,
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002641 Handle<ExecutableAccessorInfo> callback) {
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00002642 HandlerFrontend(IC::CurrentTypeOf(object, isolate()),
2643 receiver(), holder, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002644
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002645 __ pop(scratch1()); // remove the return address
2646 __ push(receiver());
2647 __ Push(callback);
2648 __ Push(name);
2649 __ push(value());
2650 __ push(scratch1()); // restore return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002651
mads.s.ager31e71382008-08-13 09:32:07 +00002652 // Do tail-call to the runtime system.
2653 ExternalReference store_callback_property =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002654 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002655 __ TailCallExternalReference(store_callback_property, 4, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002656
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002657 // Return the generated code.
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00002658 return GetCode(kind(), Code::FAST, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002659}
2660
2661
dslomov@chromium.org639bac02013-09-09 11:58:54 +00002662Handle<Code> StoreStubCompiler::CompileStoreCallback(
2663 Handle<JSObject> object,
2664 Handle<JSObject> holder,
2665 Handle<Name> name,
2666 const CallOptimization& call_optimization) {
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00002667 HandlerFrontend(IC::CurrentTypeOf(object, isolate()),
2668 receiver(), holder, name);
dslomov@chromium.org639bac02013-09-09 11:58:54 +00002669
2670 Register values[] = { value() };
2671 GenerateFastApiCall(
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00002672 masm(), call_optimization, receiver(), scratch1(),
2673 scratch2(), this->name(), 1, values);
dslomov@chromium.org639bac02013-09-09 11:58:54 +00002674
2675 // Return the generated code.
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00002676 return GetCode(kind(), Code::FAST, name);
dslomov@chromium.org639bac02013-09-09 11:58:54 +00002677}
2678
2679
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002680#undef __
2681#define __ ACCESS_MASM(masm)
2682
2683
2684void StoreStubCompiler::GenerateStoreViaSetter(
2685 MacroAssembler* masm,
2686 Handle<JSFunction> setter) {
2687 // ----------- S t a t e -------------
2688 // -- eax : value
2689 // -- ecx : name
2690 // -- edx : receiver
2691 // -- esp[0] : return address
2692 // -----------------------------------
2693 {
2694 FrameScope scope(masm, StackFrame::INTERNAL);
2695
2696 // Save value register, so we can restore it later.
2697 __ push(eax);
2698
2699 if (!setter.is_null()) {
2700 // Call the JavaScript setter with receiver and value on the stack.
2701 __ push(edx);
2702 __ push(eax);
2703 ParameterCount actual(1);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002704 ParameterCount expected(setter);
2705 __ InvokeFunction(setter, expected, actual,
2706 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002707 } else {
2708 // If we generate a global code snippet for deoptimization only, remember
2709 // the place to continue after deoptimization.
2710 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2711 }
2712
2713 // We have to return the passed value, not the return value of the setter.
2714 __ pop(eax);
2715
2716 // Restore context register.
2717 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
2718 }
2719 __ ret(0);
2720}
2721
2722
2723#undef __
2724#define __ ACCESS_MASM(masm())
2725
2726
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002727Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002728 Handle<JSObject> object,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002729 Handle<Name> name) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002730 __ pop(scratch1()); // remove the return address
2731 __ push(receiver());
2732 __ push(this->name());
2733 __ push(value());
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002734 __ push(scratch1()); // restore return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002735
mads.s.ager31e71382008-08-13 09:32:07 +00002736 // Do tail-call to the runtime system.
2737 ExternalReference store_ic_property =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002738 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00002739 __ TailCallExternalReference(store_ic_property, 3, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002740
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002741 // Return the generated code.
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00002742 return GetCode(kind(), Code::FAST, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002743}
2744
2745
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002746Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
2747 MapHandleList* receiver_maps,
2748 CodeHandleList* handler_stubs,
2749 MapHandleList* transitioned_maps) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002750 Label miss;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002751 __ JumpIfSmi(receiver(), &miss, Label::kNear);
2752 __ mov(scratch1(), FieldOperand(receiver(), HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002753 for (int i = 0; i < receiver_maps->length(); ++i) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002754 __ cmp(scratch1(), receiver_maps->at(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002755 if (transitioned_maps->at(i).is_null()) {
2756 __ j(equal, handler_stubs->at(i));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002757 } else {
2758 Label next_map;
2759 __ j(not_equal, &next_map, Label::kNear);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002760 __ mov(transition_map(), Immediate(transitioned_maps->at(i)));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002761 __ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002762 __ bind(&next_map);
2763 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002764 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002765 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002766 TailCallBuiltin(masm(), MissBuiltin(kind()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002767
2768 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002769 return GetICCode(
2770 kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002771}
2772
2773
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00002774Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<Type> type,
2775 Handle<JSObject> last,
2776 Handle<Name> name) {
2777 NonexistentHandlerFrontend(type, last, name);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002778
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002779 // Return undefined if maps of the full prototype chain are still the
2780 // same and no global property with this name contains a value.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002781 __ mov(eax, isolate()->factory()->undefined_value());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002782 __ ret(0);
2783
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002784 // Return the generated code.
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00002785 return GetCode(kind(), Code::FAST, name);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002786}
2787
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002788
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002789Register* LoadStubCompiler::registers() {
2790 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2791 static Register registers[] = { edx, ecx, ebx, eax, edi, no_reg };
2792 return registers;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002793}
2794
2795
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002796Register* KeyedLoadStubCompiler::registers() {
2797 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2798 static Register registers[] = { edx, ecx, ebx, eax, edi, no_reg };
2799 return registers;
2800}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002801
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002802
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002803Register* StoreStubCompiler::registers() {
2804 // receiver, name, value, scratch1, scratch2, scratch3.
2805 static Register registers[] = { edx, ecx, eax, ebx, edi, no_reg };
2806 return registers;
2807}
2808
2809
2810Register* KeyedStoreStubCompiler::registers() {
2811 // receiver, name, value, scratch1, scratch2, scratch3.
2812 static Register registers[] = { edx, ecx, eax, ebx, edi, no_reg };
2813 return registers;
2814}
2815
2816
ulan@chromium.org750145a2013-03-07 15:14:13 +00002817void KeyedLoadStubCompiler::GenerateNameCheck(Handle<Name> name,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002818 Register name_reg,
2819 Label* miss) {
2820 __ cmp(name_reg, Immediate(name));
2821 __ j(not_equal, miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002822}
2823
2824
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002825void KeyedStoreStubCompiler::GenerateNameCheck(Handle<Name> name,
2826 Register name_reg,
2827 Label* miss) {
2828 __ cmp(name_reg, Immediate(name));
2829 __ j(not_equal, miss);
2830}
2831
2832
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002833#undef __
2834#define __ ACCESS_MASM(masm)
2835
2836
2837void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00002838 Register receiver,
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002839 Handle<JSFunction> getter) {
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002840 {
2841 FrameScope scope(masm, StackFrame::INTERNAL);
2842
2843 if (!getter.is_null()) {
2844 // Call the JavaScript getter with the receiver on the stack.
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00002845 __ push(receiver);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002846 ParameterCount actual(0);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002847 ParameterCount expected(getter);
2848 __ InvokeFunction(getter, expected, actual,
2849 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002850 } else {
2851 // If we generate a global code snippet for deoptimization only, remember
2852 // the place to continue after deoptimization.
2853 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
2854 }
2855
2856 // Restore context register.
2857 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
2858 }
2859 __ ret(0);
2860}
2861
2862
2863#undef __
2864#define __ ACCESS_MASM(masm())
2865
2866
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002867Handle<Code> LoadStubCompiler::CompileLoadGlobal(
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00002868 Handle<Type> type,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002869 Handle<GlobalObject> global,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002870 Handle<PropertyCell> cell,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002871 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002872 bool is_dont_delete) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002873 Label miss;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002874
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00002875 HandlerFrontendHeader(type, receiver(), global, name, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002876 // Get the value from the cell.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002877 if (Serializer::enabled()) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002878 __ mov(eax, Immediate(cell));
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002879 __ mov(eax, FieldOperand(eax, PropertyCell::kValueOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002880 } else {
danno@chromium.org41728482013-06-12 22:31:22 +00002881 __ mov(eax, Operand::ForCell(cell));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002882 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002883
2884 // Check for deleted property if property can actually be deleted.
2885 if (!is_dont_delete) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002886 __ cmp(eax, factory()->the_hole_value());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002887 __ j(equal, &miss);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002888 } else if (FLAG_debug_code) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002889 __ cmp(eax, factory()->the_hole_value());
danno@chromium.org59400602013-08-13 17:09:37 +00002890 __ Check(not_equal, kDontDeleteCellsCannotContainTheHole);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002891 }
2892
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002893 HandlerFrontendFooter(name, &miss);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002894
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002895 Counters* counters = isolate()->counters();
2896 __ IncrementCounter(counters->named_load_global_stub(), 1);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002897 // The code above already loads the result into the return register.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002898 __ ret(0);
2899
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002900 // Return the generated code.
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00002901 return GetCode(kind(), Code::NORMAL, name);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002902}
2903
2904
danno@chromium.orgbee51992013-07-10 14:57:15 +00002905Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC(
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00002906 TypeHandleList* types,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002907 CodeHandleList* handlers,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002908 Handle<Name> name,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002909 Code::StubType type,
2910 IcCheckType check) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002911 Label miss;
2912
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002913 if (check == PROPERTY) {
2914 GenerateNameCheck(name, this->name(), &miss);
2915 }
2916
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002917 Label number_case;
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00002918 Label* smi_target = IncludesNumberType(types) ? &number_case : &miss;
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002919 __ JumpIfSmi(receiver(), smi_target);
2920
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002921 Register map_reg = scratch1();
2922 __ mov(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset));
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00002923 int receiver_count = types->length();
danno@chromium.orgf005df62013-04-30 16:36:45 +00002924 int number_of_handled_maps = 0;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002925 for (int current = 0; current < receiver_count; ++current) {
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00002926 Handle<Type> type = types->at(current);
2927 Handle<Map> map = IC::TypeToMap(*type, isolate());
danno@chromium.orgf005df62013-04-30 16:36:45 +00002928 if (!map->is_deprecated()) {
2929 number_of_handled_maps++;
2930 __ cmp(map_reg, map);
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00002931 if (type->Is(Type::Number())) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002932 ASSERT(!number_case.is_unused());
2933 __ bind(&number_case);
2934 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00002935 __ j(equal, handlers->at(current));
2936 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002937 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00002938 ASSERT(number_of_handled_maps != 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002939
2940 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002941 TailCallBuiltin(masm(), MissBuiltin(kind()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002942
2943 // Return the generated code.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002944 InlineCacheState state =
danno@chromium.orgf005df62013-04-30 16:36:45 +00002945 number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC;
ulan@chromium.org750145a2013-03-07 15:14:13 +00002946 return GetICCode(kind(), type, name, state);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002947}
2948
2949
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002950#undef __
2951#define __ ACCESS_MASM(masm)
2952
2953
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002954void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
2955 MacroAssembler* masm) {
2956 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002957 // -- ecx : key
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002958 // -- edx : receiver
2959 // -- esp[0] : return address
2960 // -----------------------------------
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00002961 Label slow, miss;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002962
2963 // This stub is meant to be tail-jumped to, the receiver must already
2964 // have been verified by the caller to not be a smi.
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00002965 __ JumpIfNotSmi(ecx, &miss);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002966 __ mov(ebx, ecx);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002967 __ SmiUntag(ebx);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002968 __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset));
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002969
2970 // Push receiver on the stack to free up a register for the dictionary
2971 // probing.
2972 __ push(edx);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002973 __ LoadFromNumberDictionary(&slow, eax, ecx, ebx, edx, edi, eax);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002974 // Pop receiver before returning.
2975 __ pop(edx);
2976 __ ret(0);
2977
2978 __ bind(&slow);
2979 __ pop(edx);
2980
2981 // ----------- S t a t e -------------
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002982 // -- ecx : key
2983 // -- edx : receiver
2984 // -- esp[0] : return address
2985 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002986 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002987
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00002988 __ bind(&miss);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002989 // ----------- S t a t e -------------
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002990 // -- ecx : key
2991 // -- edx : receiver
2992 // -- esp[0] : return address
2993 // -----------------------------------
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00002994 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002995}
2996
2997
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002998#undef __
2999
3000} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003001
3002#endif // V8_TARGET_ARCH_IA32