blob: 88e220e2ba62e25e880d12a2ae6e4087826ab961 [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_ARM
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,
ulan@chromium.org812308e2012-02-29 15:58:45 +000046 Register receiver,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000047 Register name,
ulan@chromium.org812308e2012-02-29 15:58:45 +000048 // Number of the cache entry, not scaled.
fschneider@chromium.orge03fb642010-11-01 12:34:09 +000049 Register offset,
50 Register scratch,
ulan@chromium.org812308e2012-02-29 15:58:45 +000051 Register scratch2,
52 Register offset_scratch) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000053 ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
54 ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
ulan@chromium.org812308e2012-02-29 15:58:45 +000055 ExternalReference map_offset(isolate->stub_cache()->map_reference(table));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000056
fschneider@chromium.orge03fb642010-11-01 12:34:09 +000057 uint32_t key_off_addr = reinterpret_cast<uint32_t>(key_offset.address());
58 uint32_t value_off_addr = reinterpret_cast<uint32_t>(value_offset.address());
ulan@chromium.org812308e2012-02-29 15:58:45 +000059 uint32_t map_off_addr = reinterpret_cast<uint32_t>(map_offset.address());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000060
fschneider@chromium.orge03fb642010-11-01 12:34:09 +000061 // Check the relative positions of the address fields.
62 ASSERT(value_off_addr > key_off_addr);
63 ASSERT((value_off_addr - key_off_addr) % 4 == 0);
64 ASSERT((value_off_addr - key_off_addr) < (256 * 4));
ulan@chromium.org812308e2012-02-29 15:58:45 +000065 ASSERT(map_off_addr > key_off_addr);
66 ASSERT((map_off_addr - key_off_addr) % 4 == 0);
67 ASSERT((map_off_addr - key_off_addr) < (256 * 4));
fschneider@chromium.orge03fb642010-11-01 12:34:09 +000068
69 Label miss;
ulan@chromium.org812308e2012-02-29 15:58:45 +000070 Register base_addr = scratch;
71 scratch = no_reg;
72
73 // Multiply by 3 because there are 3 fields per entry (name, code, map).
74 __ add(offset_scratch, offset, Operand(offset, LSL, 1));
75
76 // Calculate the base address of the entry.
77 __ mov(base_addr, Operand(key_offset));
78 __ add(base_addr, base_addr, Operand(offset_scratch, LSL, kPointerSizeLog2));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000079
80 // Check that the key in the entry matches the name.
ulan@chromium.org812308e2012-02-29 15:58:45 +000081 __ ldr(ip, MemOperand(base_addr, 0));
fschneider@chromium.org013f3e12010-04-26 13:27:52 +000082 __ cmp(name, ip);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000083 __ b(ne, &miss);
84
ulan@chromium.org812308e2012-02-29 15:58:45 +000085 // Check the map matches.
86 __ ldr(ip, MemOperand(base_addr, map_off_addr - key_off_addr));
87 __ ldr(scratch2, FieldMemOperand(receiver, HeapObject::kMapOffset));
88 __ cmp(ip, scratch2);
89 __ b(ne, &miss);
90
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000091 // Get the code entry from the cache.
ulan@chromium.org812308e2012-02-29 15:58:45 +000092 Register code = scratch2;
93 scratch2 = no_reg;
94 __ ldr(code, MemOperand(base_addr, value_off_addr - key_off_addr));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000095
96 // Check that the flags match what we're looking for.
ulan@chromium.org812308e2012-02-29 15:58:45 +000097 Register flags_reg = base_addr;
98 base_addr = no_reg;
99 __ ldr(flags_reg, FieldMemOperand(code, Code::kFlagsOffset));
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +0000100 // It's a nice optimization if this constant is encodable in the bic insn.
101
102 uint32_t mask = Code::kFlagsNotUsedInLookup;
103 ASSERT(__ ImmediateFitsAddrMode1Instruction(mask));
ulan@chromium.org812308e2012-02-29 15:58:45 +0000104 __ bic(flags_reg, flags_reg, Operand(mask));
svenpanne@chromium.org876cca82013-03-18 14:43:20 +0000105 __ cmp(flags_reg, Operand(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000106 __ b(ne, &miss);
107
ulan@chromium.org812308e2012-02-29 15:58:45 +0000108#ifdef DEBUG
109 if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
110 __ jmp(&miss);
111 } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
112 __ jmp(&miss);
113 }
114#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000115
116 // Jump to the first instruction in the code stub.
ulan@chromium.org812308e2012-02-29 15:58:45 +0000117 __ add(pc, code, Operand(Code::kHeaderSize - kHeapObjectTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000118
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000119 // Miss: fall through.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000120 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000121}
122
123
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000124void StubCompiler::GenerateDictionaryNegativeLookup(MacroAssembler* masm,
125 Label* miss_label,
126 Register receiver,
127 Handle<Name> name,
128 Register scratch0,
129 Register scratch1) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000130 ASSERT(name->IsUniqueName());
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000131 ASSERT(!receiver.is(scratch0));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000132 Counters* counters = masm->isolate()->counters();
133 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
134 __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
135
136 Label done;
137
138 const int kInterceptorOrAccessCheckNeededMask =
139 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
140
141 // Bail out if the receiver has a named interceptor or requires access checks.
142 Register map = scratch1;
143 __ ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
144 __ ldrb(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
145 __ tst(scratch0, Operand(kInterceptorOrAccessCheckNeededMask));
146 __ b(ne, miss_label);
147
148 // Check that receiver is a JSObject.
149 __ ldrb(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
150 __ cmp(scratch0, Operand(FIRST_SPEC_OBJECT_TYPE));
151 __ b(lt, miss_label);
152
153 // Load properties array.
154 Register properties = scratch0;
155 __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
156 // Check that the properties array is a dictionary.
157 __ ldr(map, FieldMemOperand(properties, HeapObject::kMapOffset));
158 Register tmp = properties;
159 __ LoadRoot(tmp, Heap::kHashTableMapRootIndex);
160 __ cmp(map, tmp);
161 __ b(ne, miss_label);
162
163 // Restore the temporarily used register.
164 __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
165
166
ulan@chromium.org750145a2013-03-07 15:14:13 +0000167 NameDictionaryLookupStub::GenerateNegativeLookup(masm,
168 miss_label,
169 &done,
170 receiver,
171 properties,
172 name,
173 scratch1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000174 __ bind(&done);
175 __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
176}
177
178
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000179void StubCache::GenerateProbe(MacroAssembler* masm,
180 Code::Flags flags,
181 Register receiver,
182 Register name,
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000183 Register scratch,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000184 Register extra,
ulan@chromium.org812308e2012-02-29 15:58:45 +0000185 Register extra2,
186 Register extra3) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000187 Isolate* isolate = masm->isolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000188 Label miss;
189
ulan@chromium.org812308e2012-02-29 15:58:45 +0000190 // Make sure that code is valid. The multiplying code relies on the
191 // entry size being 12.
192 ASSERT(sizeof(Entry) == 12);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000193
194 // Make sure the flags does not name a specific type.
195 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
196
197 // Make sure that there are no register conflicts.
198 ASSERT(!scratch.is(receiver));
199 ASSERT(!scratch.is(name));
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000200 ASSERT(!extra.is(receiver));
201 ASSERT(!extra.is(name));
202 ASSERT(!extra.is(scratch));
203 ASSERT(!extra2.is(receiver));
204 ASSERT(!extra2.is(name));
205 ASSERT(!extra2.is(scratch));
206 ASSERT(!extra2.is(extra));
207
208 // Check scratch, extra and extra2 registers are valid.
209 ASSERT(!scratch.is(no_reg));
210 ASSERT(!extra.is(no_reg));
211 ASSERT(!extra2.is(no_reg));
ulan@chromium.org812308e2012-02-29 15:58:45 +0000212 ASSERT(!extra3.is(no_reg));
213
214 Counters* counters = masm->isolate()->counters();
215 __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1,
216 extra2, extra3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000217
218 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000219 __ JumpIfSmi(receiver, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000220
221 // Get the map of the receiver and compute the hash.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000222 __ ldr(scratch, FieldMemOperand(name, Name::kHashFieldOffset));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000223 __ ldr(ip, FieldMemOperand(receiver, HeapObject::kMapOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000224 __ add(scratch, scratch, Operand(ip));
ulan@chromium.org812308e2012-02-29 15:58:45 +0000225 uint32_t mask = kPrimaryTableSize - 1;
226 // We shift out the last two bits because they are not part of the hash and
227 // they are always 01 for maps.
228 __ mov(scratch, Operand(scratch, LSR, kHeapObjectTagSize));
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +0000229 // Mask down the eor argument to the minimum to keep the immediate
230 // ARM-encodable.
ulan@chromium.org812308e2012-02-29 15:58:45 +0000231 __ eor(scratch, scratch, Operand((flags >> kHeapObjectTagSize) & mask));
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000232 // Prefer and_ to ubfx here because ubfx takes 2 cycles.
233 __ and_(scratch, scratch, Operand(mask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000234
235 // Probe the primary table.
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +0000236 ProbeTable(isolate,
237 masm,
238 flags,
239 kPrimary,
ulan@chromium.org812308e2012-02-29 15:58:45 +0000240 receiver,
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +0000241 name,
242 scratch,
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +0000243 extra,
ulan@chromium.org812308e2012-02-29 15:58:45 +0000244 extra2,
245 extra3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000246
247 // Primary miss: Compute hash for secondary probe.
ulan@chromium.org812308e2012-02-29 15:58:45 +0000248 __ sub(scratch, scratch, Operand(name, LSR, kHeapObjectTagSize));
249 uint32_t mask2 = kSecondaryTableSize - 1;
250 __ add(scratch, scratch, Operand((flags >> kHeapObjectTagSize) & mask2));
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000251 __ and_(scratch, scratch, Operand(mask2));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000252
253 // Probe the secondary table.
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +0000254 ProbeTable(isolate,
255 masm,
256 flags,
257 kSecondary,
ulan@chromium.org812308e2012-02-29 15:58:45 +0000258 receiver,
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +0000259 name,
260 scratch,
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +0000261 extra,
ulan@chromium.org812308e2012-02-29 15:58:45 +0000262 extra2,
263 extra3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000264
265 // Cache miss: Fall-through and let caller handle the miss by
266 // entering the runtime system.
267 __ bind(&miss);
ulan@chromium.org812308e2012-02-29 15:58:45 +0000268 __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1,
269 extra2, extra3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000270}
271
272
273void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
274 int index,
275 Register prototype) {
276 // Load the global or builtins object from the current context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000277 __ ldr(prototype,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000278 MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
279 // Load the native context from the global or builtins object.
280 __ ldr(prototype,
281 FieldMemOperand(prototype, GlobalObject::kNativeContextOffset));
282 // Load the function from the native context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000283 __ ldr(prototype, MemOperand(prototype, Context::SlotOffset(index)));
284 // Load the initial map. The global functions all have initial maps.
285 __ ldr(prototype,
286 FieldMemOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
287 // Load the prototype from the initial map.
288 __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
289}
290
291
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000292void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000293 MacroAssembler* masm,
294 int index,
295 Register prototype,
296 Label* miss) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000297 Isolate* isolate = masm->isolate();
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000298 // Check we're still in the same context.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000299 __ ldr(prototype,
300 MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
301 __ Move(ip, isolate->global_object());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000302 __ cmp(prototype, ip);
303 __ b(ne, miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000304 // Get the global function with the given index.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000305 Handle<JSFunction> function(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000306 JSFunction::cast(isolate->native_context()->get(index)));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000307 // Load its initial map. The global functions all have initial maps.
308 __ Move(prototype, Handle<Map>(function->initial_map()));
309 // Load the prototype from the initial map.
310 __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
311}
312
313
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000314void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
315 Register dst,
316 Register src,
317 bool inobject,
318 int index,
319 Representation representation) {
320 ASSERT(!FLAG_track_double_fields || !representation.IsDouble());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000321 int offset = index * kPointerSize;
322 if (!inobject) {
323 // Calculate the offset into the properties array.
324 offset = offset + FixedArray::kHeaderSize;
325 __ ldr(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
326 src = dst;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000327 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000328 __ ldr(dst, FieldMemOperand(src, offset));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000329}
330
331
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000332void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
333 Register receiver,
334 Register scratch,
335 Label* miss_label) {
336 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000337 __ JumpIfSmi(receiver, miss_label);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000338
339 // Check that the object is a JS array.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000340 __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000341 __ b(ne, miss_label);
342
343 // Load length directly from the JS array.
344 __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
345 __ Ret();
346}
347
348
ager@chromium.org5c838252010-02-19 08:53:10 +0000349// Generate code to check if an object is a string. If the object is a
350// heap object, its map's instance type is left in the scratch1 register.
351// If this is not needed, scratch1 and scratch2 may be the same register.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000352static void GenerateStringCheck(MacroAssembler* masm,
353 Register receiver,
354 Register scratch1,
355 Register scratch2,
356 Label* smi,
357 Label* non_string_object) {
358 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000359 __ JumpIfSmi(receiver, smi);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000360
361 // Check that the object is a string.
362 __ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
363 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
364 __ and_(scratch2, scratch1, Operand(kIsNotStringMask));
365 // The cast is to resolve the overload for the argument of 0x0.
366 __ cmp(scratch2, Operand(static_cast<int32_t>(kStringTag)));
367 __ b(ne, non_string_object);
368}
369
370
ager@chromium.org32912102009-01-16 10:38:43 +0000371// Generate code to load the length from a string object and return the length.
372// If the receiver object is not a string or a wrapped string object the
373// execution continues at the miss label. The register containing the
374// receiver is potentially clobbered.
ager@chromium.org5c838252010-02-19 08:53:10 +0000375void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
376 Register receiver,
377 Register scratch1,
378 Register scratch2,
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000379 Label* miss) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000380 Label check_wrapper;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000381
382 // Check if the object is a string leaving the instance type in the
383 // scratch1 register.
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000384 GenerateStringCheck(masm, receiver, scratch1, scratch2, miss, &check_wrapper);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000385
386 // Load length directly from the string.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000387 __ ldr(r0, FieldMemOperand(receiver, String::kLengthOffset));
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000388 __ Ret();
389
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000390 // Check if the object is a JSValue wrapper.
391 __ bind(&check_wrapper);
392 __ cmp(scratch1, Operand(JS_VALUE_TYPE));
393 __ b(ne, miss);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000394
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000395 // Unwrap the value and check if the wrapped value is a string.
396 __ ldr(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
397 GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
398 __ ldr(r0, FieldMemOperand(scratch1, String::kLengthOffset));
399 __ Ret();
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000400}
401
402
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000403void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
404 Register receiver,
405 Register scratch1,
406 Register scratch2,
407 Label* miss_label) {
408 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
409 __ mov(r0, scratch1);
410 __ Ret();
411}
412
413
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000414// Generate code to check that a global property cell is empty. Create
415// the property cell at compilation time if no cell exists for the
416// property.
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000417void StubCompiler::GenerateCheckPropertyCell(MacroAssembler* masm,
418 Handle<JSGlobalObject> global,
419 Handle<Name> name,
420 Register scratch,
421 Label* miss) {
422 Handle<Cell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000423 ASSERT(cell->value()->IsTheHole());
424 __ mov(scratch, Operand(cell));
danno@chromium.org41728482013-06-12 22:31:22 +0000425 __ ldr(scratch, FieldMemOperand(scratch, Cell::kValueOffset));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000426 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
427 __ cmp(scratch, ip);
428 __ b(ne, miss);
429}
430
431
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +0000432void StoreStubCompiler::GenerateNegativeHolderLookup(
danno@chromium.orgbee51992013-07-10 14:57:15 +0000433 MacroAssembler* masm,
434 Handle<JSObject> holder,
435 Register holder_reg,
436 Handle<Name> name,
437 Label* miss) {
438 if (holder->IsJSGlobalObject()) {
439 GenerateCheckPropertyCell(
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000440 masm, Handle<JSGlobalObject>::cast(holder), name, scratch1(), miss);
danno@chromium.orgbee51992013-07-10 14:57:15 +0000441 } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
442 GenerateDictionaryNegativeLookup(
443 masm, miss, holder_reg, name, scratch1(), scratch2());
444 }
445}
446
447
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000448// Generate StoreTransition code, value is passed in r0 register.
ager@chromium.org5c838252010-02-19 08:53:10 +0000449// When leaving generated code after success, the receiver_reg and name_reg
450// may be clobbered. Upon branch to miss_label, the receiver and name
451// registers have their original values.
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +0000452void StoreStubCompiler::GenerateStoreTransition(MacroAssembler* masm,
453 Handle<JSObject> object,
454 LookupResult* lookup,
455 Handle<Map> transition,
456 Handle<Name> name,
457 Register receiver_reg,
458 Register storage_reg,
459 Register value_reg,
460 Register scratch1,
461 Register scratch2,
462 Register scratch3,
463 Label* miss_label,
464 Label* slow) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000465 // r0 : value
466 Label exit;
467
danno@chromium.orgf005df62013-04-30 16:36:45 +0000468 int descriptor = transition->LastAdded();
469 DescriptorArray* descriptors = transition->instance_descriptors();
470 PropertyDetails details = descriptors->GetDetails(descriptor);
471 Representation representation = details.representation();
472 ASSERT(!representation.IsNone());
473
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000474 if (details.type() == CONSTANT) {
475 Handle<Object> constant(descriptors->GetValue(descriptor), masm->isolate());
bmeurer@chromium.orge94b5ff2013-10-25 09:22:31 +0000476 __ Move(scratch1, constant);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000477 __ cmp(value_reg, scratch1);
danno@chromium.orgbee51992013-07-10 14:57:15 +0000478 __ b(ne, miss_label);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000479 } else if (FLAG_track_fields && representation.IsSmi()) {
danno@chromium.orgbee51992013-07-10 14:57:15 +0000480 __ JumpIfNotSmi(value_reg, miss_label);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +0000481 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
danno@chromium.orgbee51992013-07-10 14:57:15 +0000482 __ JumpIfSmi(value_reg, miss_label);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000483 } else if (FLAG_track_double_fields && representation.IsDouble()) {
484 Label do_store, heap_number;
485 __ LoadRoot(scratch3, Heap::kHeapNumberMapRootIndex);
486 __ AllocateHeapNumber(storage_reg, scratch1, scratch2, scratch3, slow);
487
488 __ JumpIfNotSmi(value_reg, &heap_number);
489 __ SmiUntag(scratch1, value_reg);
490 __ vmov(s0, scratch1);
491 __ vcvt_f64_s32(d0, s0);
492 __ jmp(&do_store);
493
494 __ bind(&heap_number);
495 __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex,
danno@chromium.orgbee51992013-07-10 14:57:15 +0000496 miss_label, DONT_DO_SMI_CHECK);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000497 __ vldr(d0, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
498
499 __ bind(&do_store);
500 __ vstr(d0, FieldMemOperand(storage_reg, HeapNumber::kValueOffset));
501 }
502
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000503 // Stub never generated for non-global objects that require access
504 // checks.
505 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
506
507 // Perform map transition for the receiver if necessary.
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000508 if (details.type() == FIELD &&
509 object->map()->unused_property_fields() == 0) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000510 // The properties must be extended before we can store the value.
ager@chromium.org32912102009-01-16 10:38:43 +0000511 // We jump to a runtime call that extends the properties array.
ager@chromium.org5c838252010-02-19 08:53:10 +0000512 __ push(receiver_reg);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000513 __ mov(r2, Operand(transition));
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000514 __ Push(r2, r0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000515 __ TailCallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000516 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
517 masm->isolate()),
518 3,
519 1);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000520 return;
521 }
522
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000523 // Update the map of the object.
524 __ mov(scratch1, Operand(transition));
525 __ str(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
verwaest@chromium.org37141392012-05-31 13:27:02 +0000526
danno@chromium.orgbee51992013-07-10 14:57:15 +0000527 // Update the write barrier for the map field.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000528 __ RecordWriteField(receiver_reg,
529 HeapObject::kMapOffset,
530 scratch1,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000531 scratch2,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000532 kLRHasNotBeenSaved,
533 kDontSaveFPRegs,
534 OMIT_REMEMBERED_SET,
535 OMIT_SMI_CHECK);
536
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000537 if (details.type() == CONSTANT) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000538 ASSERT(value_reg.is(r0));
539 __ Ret();
540 return;
541 }
542
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000543 int index = transition->instance_descriptors()->GetFieldIndex(
544 transition->LastAdded());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000545
546 // Adjust for the number of properties stored in the object. Even in the
547 // face of a transition we can use the old map here because the size of the
548 // object and the number of in-object properties is not going to change.
549 index -= object->map()->inobject_properties();
550
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000551 // TODO(verwaest): Share this code as a code stub.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000552 SmiCheck smi_check = representation.IsTagged()
553 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000554 if (index < 0) {
555 // Set the property straight into the object.
556 int offset = object->map()->instance_size() + (index * kPointerSize);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000557 if (FLAG_track_double_fields && representation.IsDouble()) {
558 __ str(storage_reg, FieldMemOperand(receiver_reg, offset));
559 } else {
560 __ str(value_reg, FieldMemOperand(receiver_reg, offset));
561 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000562
danno@chromium.orgf005df62013-04-30 16:36:45 +0000563 if (!FLAG_track_fields || !representation.IsSmi()) {
danno@chromium.orgf005df62013-04-30 16:36:45 +0000564 // Update the write barrier for the array address.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000565 if (!FLAG_track_double_fields || !representation.IsDouble()) {
danno@chromium.orgbee51992013-07-10 14:57:15 +0000566 __ mov(storage_reg, value_reg);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000567 }
danno@chromium.orgf005df62013-04-30 16:36:45 +0000568 __ RecordWriteField(receiver_reg,
569 offset,
danno@chromium.orgbee51992013-07-10 14:57:15 +0000570 storage_reg,
danno@chromium.orgf005df62013-04-30 16:36:45 +0000571 scratch1,
572 kLRHasNotBeenSaved,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000573 kDontSaveFPRegs,
574 EMIT_REMEMBERED_SET,
575 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000576 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000577 } else {
578 // Write to the properties array.
579 int offset = index * kPointerSize + FixedArray::kHeaderSize;
580 // Get the properties array
581 __ ldr(scratch1,
582 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000583 if (FLAG_track_double_fields && representation.IsDouble()) {
584 __ str(storage_reg, FieldMemOperand(scratch1, offset));
585 } else {
586 __ str(value_reg, FieldMemOperand(scratch1, offset));
587 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000588
danno@chromium.orgf005df62013-04-30 16:36:45 +0000589 if (!FLAG_track_fields || !representation.IsSmi()) {
danno@chromium.orgf005df62013-04-30 16:36:45 +0000590 // Update the write barrier for the array address.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000591 if (!FLAG_track_double_fields || !representation.IsDouble()) {
danno@chromium.orgbee51992013-07-10 14:57:15 +0000592 __ mov(storage_reg, value_reg);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000593 }
danno@chromium.orgf005df62013-04-30 16:36:45 +0000594 __ RecordWriteField(scratch1,
595 offset,
danno@chromium.orgbee51992013-07-10 14:57:15 +0000596 storage_reg,
danno@chromium.orgf005df62013-04-30 16:36:45 +0000597 receiver_reg,
598 kLRHasNotBeenSaved,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000599 kDontSaveFPRegs,
600 EMIT_REMEMBERED_SET,
601 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000602 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000603 }
604
605 // Return the value (register r0).
606 ASSERT(value_reg.is(r0));
607 __ bind(&exit);
608 __ Ret();
609}
610
611
612// Generate StoreField code, value is passed in r0 register.
613// When leaving generated code after success, the receiver_reg and name_reg
614// may be clobbered. Upon branch to miss_label, the receiver and name
615// registers have their original values.
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +0000616void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
617 Handle<JSObject> object,
618 LookupResult* lookup,
619 Register receiver_reg,
620 Register name_reg,
621 Register value_reg,
622 Register scratch1,
623 Register scratch2,
624 Label* miss_label) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000625 // r0 : value
626 Label exit;
627
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000628 // Stub never generated for non-global objects that require access
629 // checks.
630 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
631
632 int index = lookup->GetFieldIndex().field_index();
633
634 // Adjust for the number of properties stored in the object. Even in the
635 // face of a transition we can use the old map here because the size of the
636 // object and the number of in-object properties is not going to change.
637 index -= object->map()->inobject_properties();
638
danno@chromium.orgf005df62013-04-30 16:36:45 +0000639 Representation representation = lookup->representation();
640 ASSERT(!representation.IsNone());
641 if (FLAG_track_fields && representation.IsSmi()) {
642 __ JumpIfNotSmi(value_reg, miss_label);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +0000643 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
644 __ JumpIfSmi(value_reg, miss_label);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000645 } else if (FLAG_track_double_fields && representation.IsDouble()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000646 // Load the double storage.
647 if (index < 0) {
648 int offset = object->map()->instance_size() + (index * kPointerSize);
649 __ ldr(scratch1, FieldMemOperand(receiver_reg, offset));
650 } else {
651 __ ldr(scratch1,
652 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
653 int offset = index * kPointerSize + FixedArray::kHeaderSize;
654 __ ldr(scratch1, FieldMemOperand(scratch1, offset));
655 }
656
657 // Store the value into the storage.
658 Label do_store, heap_number;
659 __ JumpIfNotSmi(value_reg, &heap_number);
660 __ SmiUntag(scratch2, value_reg);
661 __ vmov(s0, scratch2);
662 __ vcvt_f64_s32(d0, s0);
663 __ jmp(&do_store);
664
665 __ bind(&heap_number);
666 __ CheckMap(value_reg, scratch2, Heap::kHeapNumberMapRootIndex,
danno@chromium.orgf005df62013-04-30 16:36:45 +0000667 miss_label, DONT_DO_SMI_CHECK);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000668 __ vldr(d0, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
669
danno@chromium.orgf005df62013-04-30 16:36:45 +0000670 __ bind(&do_store);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000671 __ vstr(d0, FieldMemOperand(scratch1, HeapNumber::kValueOffset));
672 // Return the value (register r0).
673 ASSERT(value_reg.is(r0));
674 __ Ret();
675 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +0000676 }
677
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000678 // TODO(verwaest): Share this code as a code stub.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000679 SmiCheck smi_check = representation.IsTagged()
680 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000681 if (index < 0) {
682 // Set the property straight into the object.
683 int offset = object->map()->instance_size() + (index * kPointerSize);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000684 __ str(value_reg, FieldMemOperand(receiver_reg, offset));
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000685
danno@chromium.orgf005df62013-04-30 16:36:45 +0000686 if (!FLAG_track_fields || !representation.IsSmi()) {
687 // Skip updating write barrier if storing a smi.
688 __ JumpIfSmi(value_reg, &exit);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000689
danno@chromium.orgf005df62013-04-30 16:36:45 +0000690 // Update the write barrier for the array address.
691 // Pass the now unused name_reg as a scratch register.
692 __ mov(name_reg, value_reg);
693 __ RecordWriteField(receiver_reg,
694 offset,
695 name_reg,
696 scratch1,
697 kLRHasNotBeenSaved,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000698 kDontSaveFPRegs,
699 EMIT_REMEMBERED_SET,
700 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000701 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000702 } else {
703 // Write to the properties array.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000704 int offset = index * kPointerSize + FixedArray::kHeaderSize;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000705 // Get the properties array
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000706 __ ldr(scratch1,
707 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000708 __ str(value_reg, FieldMemOperand(scratch1, offset));
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000709
danno@chromium.orgf005df62013-04-30 16:36:45 +0000710 if (!FLAG_track_fields || !representation.IsSmi()) {
711 // Skip updating write barrier if storing a smi.
712 __ JumpIfSmi(value_reg, &exit);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000713
danno@chromium.orgf005df62013-04-30 16:36:45 +0000714 // Update the write barrier for the array address.
715 // Ok to clobber receiver_reg and name_reg, since we return.
716 __ mov(name_reg, value_reg);
717 __ RecordWriteField(scratch1,
718 offset,
719 name_reg,
720 receiver_reg,
721 kLRHasNotBeenSaved,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000722 kDontSaveFPRegs,
723 EMIT_REMEMBERED_SET,
724 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000725 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000726 }
727
728 // Return the value (register r0).
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000729 ASSERT(value_reg.is(r0));
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000730 __ bind(&exit);
731 __ Ret();
732}
733
734
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +0000735void StoreStubCompiler::GenerateRestoreName(MacroAssembler* masm,
736 Label* label,
737 Handle<Name> name) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000738 if (!label->is_unused()) {
739 __ bind(label);
740 __ mov(this->name(), Operand(name));
741 }
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000742}
743
744
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000745static void GenerateCallFunction(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000746 Handle<Object> object,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000747 const ParameterCount& arguments,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000748 Label* miss,
749 Code::ExtraICState extra_ic_state) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000750 // ----------- S t a t e -------------
751 // -- r0: receiver
752 // -- r1: function to call
753 // -----------------------------------
754
755 // Check that the function really is a function.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000756 __ JumpIfSmi(r1, miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000757 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000758 __ b(ne, miss);
759
760 // Patch the receiver on the stack with the global proxy if
761 // necessary.
762 if (object->IsGlobalObject()) {
763 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
764 __ str(r3, MemOperand(sp, arguments.immediate() * kPointerSize));
765 }
766
767 // Invoke the function.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000768 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
769 ? CALL_AS_FUNCTION
770 : CALL_AS_METHOD;
771 __ InvokeFunction(r1, arguments, JUMP_FUNCTION, NullCallWrapper(), call_kind);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000772}
773
774
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000775static void PushInterceptorArguments(MacroAssembler* masm,
776 Register receiver,
777 Register holder,
778 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000779 Handle<JSObject> holder_obj) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000780 STATIC_ASSERT(StubCache::kInterceptorArgsNameIndex == 0);
781 STATIC_ASSERT(StubCache::kInterceptorArgsInfoIndex == 1);
782 STATIC_ASSERT(StubCache::kInterceptorArgsThisIndex == 2);
783 STATIC_ASSERT(StubCache::kInterceptorArgsHolderIndex == 3);
784 STATIC_ASSERT(StubCache::kInterceptorArgsLength == 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000785 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000786 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
787 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000788 Register scratch = name;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000789 __ mov(scratch, Operand(interceptor));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000790 __ push(scratch);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000791 __ push(receiver);
792 __ push(holder);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000793}
794
795
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000796static void CompileCallLoadPropertyWithInterceptor(
797 MacroAssembler* masm,
798 Register receiver,
799 Register holder,
800 Register name,
801 Handle<JSObject> holder_obj) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000802 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
803
804 ExternalReference ref =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000805 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
806 masm->isolate());
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000807 __ mov(r0, Operand(StubCache::kInterceptorArgsLength));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000808 __ mov(r1, Operand(ref));
809
810 CEntryStub stub(1);
811 __ CallStub(&stub);
812}
813
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000814
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000815static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000816
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000817// Reserves space for the extra arguments to API function in the
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000818// caller's frame.
819//
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000820// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000821static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
822 Register scratch) {
823 __ mov(scratch, Operand(Smi::FromInt(0)));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000824 for (int i = 0; i < kFastApiCallArguments; i++) {
825 __ push(scratch);
826 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000827}
828
829
830// Undoes the effects of ReserveSpaceForFastApiCall.
831static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000832 __ Drop(kFastApiCallArguments);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000833}
834
835
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000836static void GenerateFastApiDirectCall(MacroAssembler* masm,
837 const CallOptimization& optimization,
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000838 int argc,
839 bool restore_context) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000840 // ----------- S t a t e -------------
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +0000841 // -- sp[0] - sp[24] : FunctionCallbackInfo, incl.
842 // : holder (set by CheckPrototypes)
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000843 // -- sp[28] : last JS argument
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000844 // -- ...
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000845 // -- sp[(argc + 6) * 4] : first JS argument
846 // -- sp[(argc + 7) * 4] : receiver
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000847 // -----------------------------------
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +0000848 typedef FunctionCallbackArguments FCA;
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000849 // Save calling context.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000850 __ str(cp, MemOperand(sp, FCA::kContextSaveIndex * kPointerSize));
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000851 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000852 Handle<JSFunction> function = optimization.constant_function();
bmeurer@chromium.orge94b5ff2013-10-25 09:22:31 +0000853 __ Move(r5, function);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000854 __ ldr(cp, FieldMemOperand(r5, JSFunction::kContextOffset));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000855 __ str(r5, MemOperand(sp, FCA::kCalleeIndex * kPointerSize));
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000856
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +0000857 // Construct the FunctionCallbackInfo.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000858 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000859 Handle<Object> call_data(api_call_info->data(), masm->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000860 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
861 __ Move(r0, api_call_info);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000862 __ ldr(r6, FieldMemOperand(r0, CallHandlerInfo::kDataOffset));
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000863 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000864 __ Move(r6, call_data);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000865 }
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000866 // Store call data.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000867 __ str(r6, MemOperand(sp, FCA::kDataIndex * kPointerSize));
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000868 // Store isolate.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +0000869 __ mov(r5, Operand(ExternalReference::isolate_address(masm->isolate())));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000870 __ str(r5, MemOperand(sp, FCA::kIsolateIndex * kPointerSize));
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000871 // Store ReturnValue default and ReturnValue.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000872 __ LoadRoot(r5, Heap::kUndefinedValueRootIndex);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000873 __ str(r5, MemOperand(sp, FCA::kReturnValueOffset * kPointerSize));
874 __ str(r5, MemOperand(sp, FCA::kReturnValueDefaultValueIndex * kPointerSize));
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000875
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000876 // Prepare arguments.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000877 __ mov(r2, sp);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000878
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000879 // Allocate the v8::Arguments structure in the arguments' space since
880 // it's not controlled by GC.
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000881 const int kApiStackSpace = 4;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000882
883 FrameScope frame_scope(masm, StackFrame::MANUAL);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000884 __ EnterExitFrame(false, kApiStackSpace);
885
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000886 // r0 = FunctionCallbackInfo&
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000887 // Arguments is after the return address.
888 __ add(r0, sp, Operand(1 * kPointerSize));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000889 // FunctionCallbackInfo::implicit_args_
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000890 __ str(r2, MemOperand(r0, 0 * kPointerSize));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000891 // FunctionCallbackInfo::values_
892 __ add(ip, r2, Operand((kFastApiCallArguments - 1 + argc) * kPointerSize));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000893 __ str(ip, MemOperand(r0, 1 * kPointerSize));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000894 // FunctionCallbackInfo::length_ = argc
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000895 __ mov(ip, Operand(argc));
896 __ str(ip, MemOperand(r0, 2 * kPointerSize));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000897 // FunctionCallbackInfo::is_construct_call = 0
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000898 __ mov(ip, Operand::Zero());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000899 __ str(ip, MemOperand(r0, 3 * kPointerSize));
900
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000901 const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000902 Address function_address = v8::ToCData<Address>(api_call_info->callback());
903 ApiFunction fun(function_address);
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000904 ExternalReference::Type type = ExternalReference::DIRECT_API_CALL;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000905 ExternalReference ref = ExternalReference(&fun,
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000906 type,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000907 masm->isolate());
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000908 Address thunk_address = FUNCTION_ADDR(&InvokeFunctionCallback);
909 ExternalReference::Type thunk_type = ExternalReference::PROFILING_API_CALL;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000910 ApiFunction thunk_fun(thunk_address);
911 ExternalReference thunk_ref = ExternalReference(&thunk_fun, thunk_type,
912 masm->isolate());
913
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000914 AllowExternalCallThatCantCauseGC scope(masm);
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000915 MemOperand context_restore_operand(
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000916 fp, (2 + FCA::kContextSaveIndex) * kPointerSize);
917 MemOperand return_value_operand(fp,
918 (2 + FCA::kReturnValueOffset) * kPointerSize);
919
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000920 __ CallApiFunctionAndReturn(ref,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000921 function_address,
922 thunk_ref,
923 r1,
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000924 kStackUnwindSpace,
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000925 return_value_operand,
926 restore_context ?
927 &context_restore_operand : NULL);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000928}
929
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000930
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000931// Generate call to api function.
932static void GenerateFastApiCall(MacroAssembler* masm,
933 const CallOptimization& optimization,
934 Register receiver,
935 Register scratch,
936 int argc,
937 Register* values) {
938 ASSERT(optimization.is_simple_api_call());
939 ASSERT(!receiver.is(scratch));
940
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000941 typedef FunctionCallbackArguments FCA;
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000942 const int stack_space = kFastApiCallArguments + argc + 1;
943 // Assign stack space for the call arguments.
944 __ sub(sp, sp, Operand(stack_space * kPointerSize));
945 // Write holder to stack frame.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000946 __ str(receiver, MemOperand(sp, FCA::kHolderIndex * kPointerSize));
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000947 // Write receiver to stack frame.
948 int index = stack_space - 1;
949 __ str(receiver, MemOperand(sp, index * kPointerSize));
950 // Write the arguments to stack frame.
951 for (int i = 0; i < argc; i++) {
952 ASSERT(!receiver.is(values[i]));
953 ASSERT(!scratch.is(values[i]));
954 __ str(receiver, MemOperand(sp, index-- * kPointerSize));
955 }
956
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000957 GenerateFastApiDirectCall(masm, optimization, argc, true);
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000958}
959
960
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000961class CallInterceptorCompiler BASE_EMBEDDED {
962 public:
963 CallInterceptorCompiler(StubCompiler* stub_compiler,
964 const ParameterCount& arguments,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000965 Register name,
966 Code::ExtraICState extra_ic_state)
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000967 : stub_compiler_(stub_compiler),
968 arguments_(arguments),
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000969 name_(name),
970 extra_ic_state_(extra_ic_state) {}
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000971
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000972 void Compile(MacroAssembler* masm,
973 Handle<JSObject> object,
974 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000975 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000976 LookupResult* lookup,
977 Register receiver,
978 Register scratch1,
979 Register scratch2,
980 Register scratch3,
981 Label* miss) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000982 ASSERT(holder->HasNamedInterceptor());
983 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
984
985 // Check that the receiver isn't a smi.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000986 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000987 CallOptimization optimization(lookup);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000988 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000989 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
990 holder, lookup, name, optimization, miss);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000991 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000992 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
993 name, holder, miss);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000994 }
995 }
996
997 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000998 void CompileCacheable(MacroAssembler* masm,
999 Handle<JSObject> object,
1000 Register receiver,
1001 Register scratch1,
1002 Register scratch2,
1003 Register scratch3,
1004 Handle<JSObject> interceptor_holder,
1005 LookupResult* lookup,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001006 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001007 const CallOptimization& optimization,
1008 Label* miss_label) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001009 ASSERT(optimization.is_constant_call());
1010 ASSERT(!lookup->holder()->IsGlobalObject());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001011 Counters* counters = masm->isolate()->counters();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001012 int depth1 = kInvalidProtoDepth;
1013 int depth2 = kInvalidProtoDepth;
1014 bool can_do_fast_api_call = false;
1015 if (optimization.is_simple_api_call() &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001016 !lookup->holder()->IsGlobalObject()) {
1017 depth1 = optimization.GetPrototypeDepthOfExpectedType(
1018 object, interceptor_holder);
1019 if (depth1 == kInvalidProtoDepth) {
1020 depth2 = optimization.GetPrototypeDepthOfExpectedType(
1021 interceptor_holder, Handle<JSObject>(lookup->holder()));
1022 }
1023 can_do_fast_api_call =
1024 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001025 }
1026
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001027 __ IncrementCounter(counters->call_const_interceptor(), 1,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001028 scratch1, scratch2);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001029
1030 if (can_do_fast_api_call) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001031 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001032 scratch1, scratch2);
1033 ReserveSpaceForFastApiCall(masm, scratch1);
1034 }
1035
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001036 // Check that the maps from receiver to interceptor's holder
1037 // haven't changed and thus we can invoke interceptor.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001038 Label miss_cleanup;
1039 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
1040 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001041 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
1042 scratch1, scratch2, scratch3,
1043 name, depth1, miss);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001044
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001045 // Invoke an interceptor and if it provides a value,
1046 // branch to |regular_invoke|.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001047 Label regular_invoke;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001048 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001049 &regular_invoke);
1050
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001051 // Interceptor returned nothing for this property. Try to use cached
1052 // constant function.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001053
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001054 // Check that the maps from interceptor's holder to constant function's
1055 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001056 if (*interceptor_holder != lookup->holder()) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001057 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001058 Handle<JSObject>(lookup->holder()),
1059 scratch1, scratch2, scratch3,
1060 name, depth2, miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001061 } else {
1062 // CheckPrototypes has a side effect of fetching a 'holder'
1063 // for API (object which is instanceof for the signature). It's
1064 // safe to omit it here, as if present, it should be fetched
1065 // by the previous CheckPrototypes.
1066 ASSERT(depth2 == kInvalidProtoDepth);
1067 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001068
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001069 // Invoke function.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001070 if (can_do_fast_api_call) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001071 GenerateFastApiDirectCall(
1072 masm, optimization, arguments_.immediate(), false);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001073 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001074 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
1075 ? CALL_AS_FUNCTION
1076 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001077 Handle<JSFunction> function = optimization.constant_function();
1078 ParameterCount expected(function);
1079 __ InvokeFunction(function, expected, arguments_,
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001080 JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001081 }
1082
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001083 // Deferred code for fast API call case---clean preallocated space.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001084 if (can_do_fast_api_call) {
1085 __ bind(&miss_cleanup);
1086 FreeSpaceForFastApiCall(masm);
1087 __ b(miss_label);
1088 }
1089
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001090 // Invoke a regular function.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001091 __ bind(&regular_invoke);
1092 if (can_do_fast_api_call) {
1093 FreeSpaceForFastApiCall(masm);
1094 }
1095 }
1096
1097 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001098 Handle<JSObject> object,
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001099 Register receiver,
1100 Register scratch1,
1101 Register scratch2,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001102 Register scratch3,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001103 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001104 Handle<JSObject> interceptor_holder,
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001105 Label* miss_label) {
1106 Register holder =
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001107 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001108 scratch1, scratch2, scratch3,
1109 name, miss_label);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001110
1111 // Call a runtime function to load the interceptor property.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001112 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001113 // Save the name_ register across the call.
1114 __ push(name_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001115 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001116 __ CallExternalReference(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001117 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
1118 masm->isolate()),
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00001119 StubCache::kInterceptorArgsLength);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001120 // Restore the name_ register.
1121 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001122 // Leave the internal frame.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001123 }
1124
1125 void LoadWithInterceptor(MacroAssembler* masm,
1126 Register receiver,
1127 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001128 Handle<JSObject> holder_obj,
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001129 Register scratch,
1130 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001131 {
1132 FrameScope scope(masm, StackFrame::INTERNAL);
1133 __ Push(holder, name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001134 CompileCallLoadPropertyWithInterceptor(masm,
1135 receiver,
1136 holder,
1137 name_,
1138 holder_obj);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001139 __ pop(name_); // Restore the name.
1140 __ pop(receiver); // Restore the holder.
1141 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001142 // If interceptor returns no-result sentinel, call the constant function.
1143 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
1144 __ cmp(r0, scratch);
1145 __ b(ne, interceptor_succeeded);
1146 }
1147
1148 StubCompiler* stub_compiler_;
1149 const ParameterCount& arguments_;
1150 Register name_;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001151 Code::ExtraICState extra_ic_state_;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001152};
1153
1154
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001155void StubCompiler::GenerateCheckPropertyCells(MacroAssembler* masm,
1156 Handle<JSObject> object,
1157 Handle<JSObject> holder,
1158 Handle<Name> name,
1159 Register scratch,
1160 Label* miss) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001161 Handle<JSObject> current = object;
1162 while (!current.is_identical_to(holder)) {
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001163 if (current->IsJSGlobalObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001164 GenerateCheckPropertyCell(masm,
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001165 Handle<JSGlobalObject>::cast(current),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001166 name,
1167 scratch,
1168 miss);
1169 }
1170 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
1171 }
1172}
1173
1174
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001175void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001176 __ Jump(code, RelocInfo::CODE_TARGET);
1177}
1178
1179
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001180#undef __
1181#define __ ACCESS_MASM(masm())
1182
1183
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001184Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
1185 Register object_reg,
1186 Handle<JSObject> holder,
1187 Register holder_reg,
1188 Register scratch1,
1189 Register scratch2,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001190 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001191 int save_at_depth,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001192 Label* miss,
1193 PrototypeCheckType check) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001194 // Make sure that the type feedback oracle harvests the receiver map.
1195 // TODO(svenpanne) Remove this hack when all ICs are reworked.
1196 __ mov(scratch1, Operand(Handle<Map>(object->map())));
1197
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001198 Handle<JSObject> first = object;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001199 // Make sure there's no overlap between holder and object registers.
1200 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1201 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1202 && !scratch2.is(scratch1));
1203
1204 // Keep track of the current object in register reg.
1205 Register reg = object_reg;
1206 int depth = 0;
1207
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001208 typedef FunctionCallbackArguments FCA;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001209 if (save_at_depth == depth) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001210 __ str(reg, MemOperand(sp, FCA::kHolderIndex * kPointerSize));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001211 }
1212
1213 // Check the maps in the prototype chain.
1214 // Traverse the prototype chain from the object and do map checks.
1215 Handle<JSObject> current = object;
1216 while (!current.is_identical_to(holder)) {
1217 ++depth;
1218
1219 // Only global objects and objects that do not require access
1220 // checks are allowed in stubs.
1221 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1222
1223 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
1224 if (!current->HasFastProperties() &&
1225 !current->IsJSGlobalObject() &&
1226 !current->IsJSGlobalProxy()) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001227 if (!name->IsUniqueName()) {
1228 ASSERT(name->IsString());
1229 name = factory()->InternalizeString(Handle<String>::cast(name));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001230 }
1231 ASSERT(current->property_dictionary()->FindEntry(*name) ==
ulan@chromium.org750145a2013-03-07 15:14:13 +00001232 NameDictionary::kNotFound);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001233
1234 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1235 scratch1, scratch2);
1236
1237 __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1238 reg = holder_reg; // From now on the object will be in holder_reg.
1239 __ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1240 } else {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001241 Register map_reg = scratch1;
1242 if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) {
1243 Handle<Map> current_map(current->map());
1244 // CheckMap implicitly loads the map of |reg| into |map_reg|.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001245 __ CheckMap(reg, map_reg, current_map, miss, DONT_DO_SMI_CHECK);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001246 } else {
1247 __ ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
1248 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001249
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001250 // Check access rights to the global object. This has to happen after
1251 // the map check so that we know that the object is actually a global
1252 // object.
1253 if (current->IsJSGlobalProxy()) {
1254 __ CheckAccessGlobalProxy(reg, scratch2, miss);
1255 }
1256 reg = holder_reg; // From now on the object will be in holder_reg.
1257
1258 if (heap()->InNewSpace(*prototype)) {
1259 // The prototype is in new space; we cannot store a reference to it
1260 // in the code. Load it from the map.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001261 __ ldr(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001262 } else {
1263 // The prototype is in old space; load it directly.
1264 __ mov(reg, Operand(prototype));
1265 }
1266 }
1267
1268 if (save_at_depth == depth) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001269 __ str(reg, MemOperand(sp, FCA::kHolderIndex * kPointerSize));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001270 }
1271
1272 // Go to the next object in the prototype chain.
1273 current = prototype;
1274 }
1275
1276 // Log the check depth.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001277 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001278
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001279 if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) {
1280 // Check the holder map.
1281 __ CheckMap(reg, scratch1, Handle<Map>(holder->map()), miss,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001282 DONT_DO_SMI_CHECK);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001283 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001284
1285 // Perform security check for access to the global object.
1286 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1287 if (holder->IsJSGlobalProxy()) {
1288 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1289 }
1290
1291 // If we've skipped any global objects, it's not enough to verify that
1292 // their maps haven't changed. We also need to check that the property
1293 // cell for the property is still empty.
1294 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1295
1296 // Return the register containing the holder.
1297 return reg;
1298}
1299
1300
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001301void LoadStubCompiler::HandlerFrontendFooter(Handle<Name> name, Label* miss) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001302 if (!miss->is_unused()) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001303 Label success;
1304 __ b(&success);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001305 __ bind(miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001306 TailCallBuiltin(masm(), MissBuiltin(kind()));
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001307 __ bind(&success);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001308 }
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001309}
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001310
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001311
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001312void StoreStubCompiler::HandlerFrontendFooter(Handle<Name> name, Label* miss) {
danno@chromium.orgbee51992013-07-10 14:57:15 +00001313 if (!miss->is_unused()) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001314 Label success;
1315 __ b(&success);
danno@chromium.orgbee51992013-07-10 14:57:15 +00001316 GenerateRestoreName(masm(), miss, name);
1317 TailCallBuiltin(masm(), MissBuiltin(kind()));
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001318 __ bind(&success);
danno@chromium.orgbee51992013-07-10 14:57:15 +00001319 }
1320}
1321
1322
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001323Register LoadStubCompiler::CallbackHandlerFrontend(
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001324 Handle<Object> object,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001325 Register object_reg,
1326 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001327 Handle<Name> name,
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00001328 Handle<Object> callback) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001329 Label miss;
1330
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001331 Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001332
1333 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
1334 ASSERT(!reg.is(scratch2()));
1335 ASSERT(!reg.is(scratch3()));
1336 ASSERT(!reg.is(scratch4()));
1337
1338 // Load the properties dictionary.
1339 Register dictionary = scratch4();
1340 __ ldr(dictionary, FieldMemOperand(reg, JSObject::kPropertiesOffset));
1341
1342 // Probe the dictionary.
1343 Label probe_done;
ulan@chromium.org750145a2013-03-07 15:14:13 +00001344 NameDictionaryLookupStub::GeneratePositiveLookup(masm(),
1345 &miss,
1346 &probe_done,
1347 dictionary,
1348 this->name(),
1349 scratch2(),
1350 scratch3());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001351 __ bind(&probe_done);
1352
1353 // If probing finds an entry in the dictionary, scratch3 contains the
1354 // pointer into the dictionary. Check that the value is the callback.
1355 Register pointer = scratch3();
ulan@chromium.org750145a2013-03-07 15:14:13 +00001356 const int kElementsStartOffset = NameDictionary::kHeaderSize +
1357 NameDictionary::kElementsStartIndex * kPointerSize;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001358 const int kValueOffset = kElementsStartOffset + kPointerSize;
1359 __ ldr(scratch2(), FieldMemOperand(pointer, kValueOffset));
1360 __ cmp(scratch2(), Operand(callback));
1361 __ b(ne, &miss);
1362 }
1363
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001364 HandlerFrontendFooter(name, &miss);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001365 return reg;
1366}
1367
1368
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001369void LoadStubCompiler::GenerateLoadField(Register reg,
1370 Handle<JSObject> holder,
1371 PropertyIndex field,
1372 Representation representation) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001373 if (!reg.is(receiver())) __ mov(receiver(), reg);
1374 if (kind() == Code::LOAD_IC) {
1375 LoadFieldStub stub(field.is_inobject(holder),
1376 field.translate(holder),
1377 representation);
1378 GenerateTailCall(masm(), stub.GetCode(isolate()));
1379 } else {
1380 KeyedLoadFieldStub stub(field.is_inobject(holder),
1381 field.translate(holder),
1382 representation);
1383 GenerateTailCall(masm(), stub.GetCode(isolate()));
1384 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001385}
1386
1387
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001388void LoadStubCompiler::GenerateLoadConstant(Handle<Object> value) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001389 // Return the constant value.
bmeurer@chromium.orge94b5ff2013-10-25 09:22:31 +00001390 __ Move(r0, value);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001391 __ Ret();
1392}
1393
1394
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001395void LoadStubCompiler::GenerateLoadCallback(
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00001396 const CallOptimization& call_optimization) {
dslomov@chromium.org639bac02013-09-09 11:58:54 +00001397 GenerateFastApiCall(
1398 masm(), call_optimization, receiver(), scratch3(), 0, NULL);
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00001399}
1400
1401
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001402void LoadStubCompiler::GenerateLoadCallback(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001403 Register reg,
1404 Handle<ExecutableAccessorInfo> callback) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001405 // Build AccessorInfo::args_ list on the stack and push property name below
1406 // the exit frame to make GC aware of them and store pointers to them.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001407 STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0);
1408 STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1);
1409 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2);
1410 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3);
1411 STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4);
1412 STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5);
1413 STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 6);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00001414 ASSERT(!scratch2().is(reg));
1415 ASSERT(!scratch3().is(reg));
1416 ASSERT(!scratch4().is(reg));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001417 __ push(receiver());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001418 if (heap()->InNewSpace(callback->data())) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001419 __ Move(scratch3(), callback);
1420 __ ldr(scratch3(), FieldMemOperand(scratch3(),
1421 ExecutableAccessorInfo::kDataOffset));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001422 } else {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001423 __ Move(scratch3(), Handle<Object>(callback->data(), isolate()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001424 }
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00001425 __ push(scratch3());
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00001426 __ LoadRoot(scratch3(), Heap::kUndefinedValueRootIndex);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001427 __ mov(scratch4(), scratch3());
1428 __ Push(scratch3(), scratch4());
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00001429 __ mov(scratch4(),
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001430 Operand(ExternalReference::isolate_address(isolate())));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001431 __ Push(scratch4(), reg);
1432 __ mov(scratch2(), sp); // scratch2 = PropertyAccessorInfo::args_
1433 __ push(name());
ulan@chromium.org750145a2013-03-07 15:14:13 +00001434 __ mov(r0, sp); // r0 = Handle<Name>
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001435
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001436 const int kApiStackSpace = 1;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001437 FrameScope frame_scope(masm(), StackFrame::MANUAL);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001438 __ EnterExitFrame(false, kApiStackSpace);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001439
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001440 // Create PropertyAccessorInfo instance on the stack above the exit frame with
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001441 // scratch2 (internal::Object** args_) as the data.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001442 __ str(scratch2(), MemOperand(sp, 1 * kPointerSize));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001443 __ add(r1, sp, Operand(1 * kPointerSize)); // r1 = AccessorInfo&
1444
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001445 const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001446 Address getter_address = v8::ToCData<Address>(callback->getter());
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001447
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001448 ApiFunction fun(getter_address);
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001449 ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
danno@chromium.orgfe578672013-06-15 14:38:35 +00001450 ExternalReference ref = ExternalReference(&fun, type, isolate());
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001451
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001452 Address thunk_address = FUNCTION_ADDR(&InvokeAccessorGetterCallback);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001453 ExternalReference::Type thunk_type =
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001454 ExternalReference::PROFILING_GETTER_CALL;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001455 ApiFunction thunk_fun(thunk_address);
1456 ExternalReference thunk_ref = ExternalReference(&thunk_fun, thunk_type,
1457 isolate());
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001458 __ CallApiFunctionAndReturn(ref,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001459 getter_address,
1460 thunk_ref,
1461 r2,
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001462 kStackUnwindSpace,
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001463 MemOperand(fp, 6 * kPointerSize),
1464 NULL);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001465}
1466
1467
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001468void LoadStubCompiler::GenerateLoadInterceptor(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001469 Register holder_reg,
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001470 Handle<Object> object,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001471 Handle<JSObject> interceptor_holder,
1472 LookupResult* lookup,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001473 Handle<Name> name) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001474 ASSERT(interceptor_holder->HasNamedInterceptor());
1475 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1476
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001477 // So far the most popular follow ups for interceptor loads are FIELD
1478 // and CALLBACKS, so inline only them, other cases may be added
1479 // later.
1480 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001481 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001482 if (lookup->IsField()) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001483 compile_followup_inline = true;
1484 } else if (lookup->type() == CALLBACKS &&
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001485 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
1486 ExecutableAccessorInfo* callback =
1487 ExecutableAccessorInfo::cast(lookup->GetCallbackObject());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001488 compile_followup_inline = callback->getter() != NULL &&
1489 callback->IsCompatibleReceiver(*object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001490 }
1491 }
1492
1493 if (compile_followup_inline) {
1494 // Compile the interceptor call, followed by inline code to load the
1495 // property from further up the prototype chain if the call fails.
1496 // Check that the maps haven't changed.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001497 ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001498
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001499 // Preserve the receiver register explicitly whenever it is different from
1500 // the holder and it is needed should the interceptor return without any
1501 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1502 // the FIELD case might cause a miss during the prototype check.
1503 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001504 bool must_preserve_receiver_reg = !receiver().is(holder_reg) &&
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001505 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1506
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001507 // Save necessary data before invoking an interceptor.
1508 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001509 {
1510 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001511 if (must_preserve_receiver_reg) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001512 __ Push(receiver(), holder_reg, this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001513 } else {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001514 __ Push(holder_reg, this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001515 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001516 // Invoke an interceptor. Note: map checks from receiver to
1517 // interceptor's holder has been compiled before (see a caller
1518 // of this method.)
1519 CompileCallLoadPropertyWithInterceptor(masm(),
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001520 receiver(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001521 holder_reg,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001522 this->name(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001523 interceptor_holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001524 // Check if interceptor provided a value for property. If it's
1525 // the case, return immediately.
1526 Label interceptor_failed;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001527 __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
1528 __ cmp(r0, scratch1());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001529 __ b(eq, &interceptor_failed);
1530 frame_scope.GenerateLeaveFrame();
1531 __ Ret();
1532
1533 __ bind(&interceptor_failed);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001534 __ pop(this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001535 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001536 if (must_preserve_receiver_reg) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001537 __ pop(receiver());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001538 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001539 // Leave the internal frame.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001540 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001541
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001542 GenerateLoadPostInterceptor(holder_reg, interceptor_holder, name, lookup);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001543 } else { // !compile_followup_inline
1544 // Call the runtime system to load the interceptor.
1545 // Check that the maps haven't changed.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001546 PushInterceptorArguments(masm(), receiver(), holder_reg,
1547 this->name(), interceptor_holder);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001548
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001549 ExternalReference ref =
1550 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad),
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001551 isolate());
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00001552 __ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength, 1);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001553 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001554}
1555
1556
ulan@chromium.org750145a2013-03-07 15:14:13 +00001557void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001558 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001559 __ cmp(r2, Operand(name));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001560 __ b(ne, miss);
1561 }
1562}
1563
1564
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001565void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1566 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001567 Handle<Name> name,
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001568 Label* miss) {
1569 ASSERT(holder->IsGlobalObject());
1570
1571 // Get the number of arguments.
1572 const int argc = arguments().immediate();
1573
1574 // Get the receiver from the stack.
1575 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
1576
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001577 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001578 __ JumpIfSmi(r0, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001579 CheckPrototypes(object, r0, holder, r3, r1, r4, name, miss);
1580}
1581
1582
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001583void CallStubCompiler::GenerateLoadFunctionFromCell(
danno@chromium.org41728482013-06-12 22:31:22 +00001584 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001585 Handle<JSFunction> function,
1586 Label* miss) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001587 // Get the value from the cell.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001588 __ mov(r3, Operand(cell));
danno@chromium.org41728482013-06-12 22:31:22 +00001589 __ ldr(r1, FieldMemOperand(r3, Cell::kValueOffset));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001590
1591 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001592 if (heap()->InNewSpace(*function)) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001593 // We can't embed a pointer to a function in new space so we have
1594 // to verify that the shared function info is unchanged. This has
1595 // the nice side effect that multiple closures based on the same
1596 // function can all use this call IC. Before we load through the
1597 // function, we have to verify that it still is a function.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001598 __ JumpIfSmi(r1, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001599 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
1600 __ b(ne, miss);
1601
1602 // Check the shared function info. Make sure it hasn't changed.
1603 __ Move(r3, Handle<SharedFunctionInfo>(function->shared()));
1604 __ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
1605 __ cmp(r4, r3);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001606 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001607 __ cmp(r1, Operand(function));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001608 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001609 __ b(ne, miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001610}
1611
1612
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001613void CallStubCompiler::GenerateMissBranch() {
1614 Handle<Code> code =
danno@chromium.org40cb8782011-05-25 07:58:50 +00001615 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1616 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001617 extra_state_);
1618 __ Jump(code, RelocInfo::CODE_TARGET);
1619}
1620
1621
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001622Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1623 Handle<JSObject> holder,
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00001624 PropertyIndex index,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001625 Handle<Name> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001626 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00001627 // -- r2 : name
1628 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001629 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001630 Label miss;
1631
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001632 GenerateNameCheck(name, &miss);
1633
mads.s.ager31e71382008-08-13 09:32:07 +00001634 const int argc = arguments().immediate();
1635
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001636 // Get the receiver of the function from the stack into r0.
1637 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001638 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001639 __ JumpIfSmi(r0, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001640
1641 // Do the right check and compute the holder register.
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001642 Register reg = CheckPrototypes(object, r0, holder, r1, r3, r4, name, &miss);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001643 GenerateFastPropertyLoad(masm(), r1, reg, index.is_inobject(holder),
1644 index.translate(holder), Representation::Tagged());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001645
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001646 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001647
1648 // Handle call cache miss.
1649 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001650 GenerateMissBranch();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001651
1652 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001653 return GetCode(Code::FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001654}
1655
1656
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001657Handle<Code> CallStubCompiler::CompileArrayCodeCall(
1658 Handle<Object> object,
1659 Handle<JSObject> holder,
1660 Handle<Cell> cell,
1661 Handle<JSFunction> function,
1662 Handle<String> name,
1663 Code::StubType type) {
1664 Label miss;
1665
1666 // Check that function is still array
1667 const int argc = arguments().immediate();
1668 GenerateNameCheck(name, &miss);
1669 Register receiver = r1;
1670
1671 if (cell.is_null()) {
1672 __ ldr(receiver, MemOperand(sp, argc * kPointerSize));
1673
1674 // Check that the receiver isn't a smi.
1675 __ JumpIfSmi(receiver, &miss);
1676
1677 // Check that the maps haven't changed.
1678 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, r3, r0,
1679 r4, name, &miss);
1680 } else {
1681 ASSERT(cell->value() == *function);
1682 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
1683 &miss);
1684 GenerateLoadFunctionFromCell(cell, function, &miss);
1685 }
1686
danno@chromium.orgbee51992013-07-10 14:57:15 +00001687 Handle<AllocationSite> site = isolate()->factory()->NewAllocationSite();
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001688 site->SetElementsKind(GetInitialFastElementsKind());
danno@chromium.orgbee51992013-07-10 14:57:15 +00001689 Handle<Cell> site_feedback_cell = isolate()->factory()->NewCell(site);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001690 __ mov(r0, Operand(argc));
danno@chromium.orgbee51992013-07-10 14:57:15 +00001691 __ mov(r2, Operand(site_feedback_cell));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001692 __ mov(r1, Operand(function));
1693
1694 ArrayConstructorStub stub(isolate());
1695 __ TailCallStub(&stub);
1696
1697 __ bind(&miss);
1698 GenerateMissBranch();
1699
1700 // Return the generated code.
1701 return GetCode(type, name);
1702}
1703
1704
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001705Handle<Code> CallStubCompiler::CompileArrayPushCall(
1706 Handle<Object> object,
1707 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00001708 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001709 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001710 Handle<String> name,
1711 Code::StubType type) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001712 // ----------- S t a t e -------------
1713 // -- r2 : name
1714 // -- lr : return address
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001715 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1716 // -- ...
1717 // -- sp[argc * 4] : receiver
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001718 // -----------------------------------
1719
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001720 // If object is not an array or is observed, bail out to regular call.
1721 if (!object->IsJSArray() ||
1722 !cell.is_null() ||
1723 Handle<JSArray>::cast(object)->map()->is_observed()) {
1724 return Handle<Code>::null();
1725 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001726
1727 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001728 GenerateNameCheck(name, &miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001729
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001730 Register receiver = r1;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001731 // Get the receiver from the stack
1732 const int argc = arguments().immediate();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001733 __ ldr(receiver, MemOperand(sp, argc * kPointerSize));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001734
1735 // Check that the receiver isn't a smi.
ager@chromium.org378b34e2011-01-28 08:04:38 +00001736 __ JumpIfSmi(receiver, &miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001737
1738 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001739 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, r3, r0, r4,
1740 name, &miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001741
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001742 if (argc == 0) {
1743 // Nothing to do, just return the length.
1744 __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1745 __ Drop(argc + 1);
1746 __ Ret();
1747 } else {
1748 Label call_builtin;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001749
1750 if (argc == 1) { // Otherwise fall through to call the builtin.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001751 Label attempt_to_grow_elements, with_write_barrier, check_double;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001752
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001753 Register elements = r6;
1754 Register end_elements = r5;
1755 // Get the elements array of the object.
1756 __ ldr(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1757
1758 // Check that the elements are in fast mode and writable.
1759 __ CheckMap(elements,
1760 r0,
1761 Heap::kFixedArrayMapRootIndex,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001762 &check_double,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001763 DONT_DO_SMI_CHECK);
1764
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001765 // Get the array's length into r0 and calculate new length.
1766 __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001767 __ add(r0, r0, Operand(Smi::FromInt(argc)));
1768
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001769 // Get the elements' length.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001770 __ ldr(r4, FieldMemOperand(elements, FixedArray::kLengthOffset));
1771
1772 // Check if we could survive without allocation.
1773 __ cmp(r0, r4);
1774 __ b(gt, &attempt_to_grow_elements);
1775
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001776 // Check if value is a smi.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001777 __ ldr(r4, MemOperand(sp, (argc - 1) * kPointerSize));
1778 __ JumpIfNotSmi(r4, &with_write_barrier);
1779
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001780 // Save new length.
1781 __ str(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1782
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001783 // Store the value.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001784 // We may need a register containing the address end_elements below,
1785 // so write back the value in end_elements.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001786 __ add(end_elements, elements, Operand::PointerOffsetFromSmiKey(r0));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001787 const int kEndElementsOffset =
1788 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
1789 __ str(r4, MemOperand(end_elements, kEndElementsOffset, PreIndex));
1790
1791 // Check for a smi.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001792 __ Drop(argc + 1);
1793 __ Ret();
1794
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001795 __ bind(&check_double);
1796
1797 // Check that the elements are in fast mode and writable.
1798 __ CheckMap(elements,
1799 r0,
1800 Heap::kFixedDoubleArrayMapRootIndex,
1801 &call_builtin,
1802 DONT_DO_SMI_CHECK);
1803
1804 // Get the array's length into r0 and calculate new length.
1805 __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001806 __ add(r0, r0, Operand(Smi::FromInt(argc)));
1807
1808 // Get the elements' length.
1809 __ ldr(r4, FieldMemOperand(elements, FixedArray::kLengthOffset));
1810
1811 // Check if we could survive without allocation.
1812 __ cmp(r0, r4);
1813 __ b(gt, &call_builtin);
1814
1815 __ ldr(r4, MemOperand(sp, (argc - 1) * kPointerSize));
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001816 __ StoreNumberToDoubleElements(r4, r0, elements, r5, d0,
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001817 &call_builtin, argc * kDoubleSize);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001818
1819 // Save new length.
1820 __ str(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1821
1822 // Check for a smi.
1823 __ Drop(argc + 1);
1824 __ Ret();
1825
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001826 __ bind(&with_write_barrier);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001827
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001828 __ ldr(r3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1829
1830 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
1831 Label fast_object, not_fast_object;
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00001832 __ CheckFastObjectElements(r3, r9, &not_fast_object);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001833 __ jmp(&fast_object);
1834 // In case of fast smi-only, convert to fast object, otherwise bail out.
1835 __ bind(&not_fast_object);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00001836 __ CheckFastSmiElements(r3, r9, &call_builtin);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001837
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00001838 __ ldr(r9, FieldMemOperand(r4, HeapObject::kMapOffset));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001839 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00001840 __ cmp(r9, ip);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001841 __ b(eq, &call_builtin);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001842 // edx: receiver
1843 // r3: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001844 Label try_holey_map;
1845 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001846 FAST_ELEMENTS,
1847 r3,
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00001848 r9,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001849 &try_holey_map);
1850 __ mov(r2, receiver);
1851 ElementsTransitionGenerator::
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001852 GenerateMapChangeElementsTransition(masm(),
1853 DONT_TRACK_ALLOCATION_SITE,
1854 NULL);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001855 __ jmp(&fast_object);
1856
1857 __ bind(&try_holey_map);
1858 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1859 FAST_HOLEY_ELEMENTS,
1860 r3,
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00001861 r9,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001862 &call_builtin);
1863 __ mov(r2, receiver);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001864 ElementsTransitionGenerator::
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001865 GenerateMapChangeElementsTransition(masm(),
1866 DONT_TRACK_ALLOCATION_SITE,
1867 NULL);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001868 __ bind(&fast_object);
1869 } else {
1870 __ CheckFastObjectElements(r3, r3, &call_builtin);
1871 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001872
1873 // Save new length.
1874 __ str(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1875
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001876 // Store the value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001877 // We may need a register containing the address end_elements below,
1878 // so write back the value in end_elements.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001879 __ add(end_elements, elements, Operand::PointerOffsetFromSmiKey(r0));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001880 __ str(r4, MemOperand(end_elements, kEndElementsOffset, PreIndex));
1881
1882 __ RecordWrite(elements,
1883 end_elements,
1884 r4,
1885 kLRHasNotBeenSaved,
1886 kDontSaveFPRegs,
1887 EMIT_REMEMBERED_SET,
1888 OMIT_SMI_CHECK);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001889 __ Drop(argc + 1);
1890 __ Ret();
1891
1892 __ bind(&attempt_to_grow_elements);
1893 // r0: array's length + 1.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001894
1895 if (!FLAG_inline_new) {
1896 __ b(&call_builtin);
1897 }
1898
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001899 __ ldr(r2, MemOperand(sp, (argc - 1) * kPointerSize));
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001900 // Growing elements that are SMI-only requires special handling in case
1901 // the new element is non-Smi. For now, delegate to the builtin.
1902 Label no_fast_elements_check;
1903 __ JumpIfSmi(r2, &no_fast_elements_check);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00001904 __ ldr(r9, FieldMemOperand(receiver, HeapObject::kMapOffset));
1905 __ CheckFastObjectElements(r9, r9, &call_builtin);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001906 __ bind(&no_fast_elements_check);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001907
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001908 ExternalReference new_space_allocation_top =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001909 ExternalReference::new_space_allocation_top_address(isolate());
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001910 ExternalReference new_space_allocation_limit =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001911 ExternalReference::new_space_allocation_limit_address(isolate());
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001912
1913 const int kAllocationDelta = 4;
1914 // Load top and check if it is the end of elements.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001915 __ add(end_elements, elements, Operand::PointerOffsetFromSmiKey(r0));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001916 __ add(end_elements, end_elements, Operand(kEndElementsOffset));
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00001917 __ mov(r4, Operand(new_space_allocation_top));
1918 __ ldr(r3, MemOperand(r4));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001919 __ cmp(end_elements, r3);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001920 __ b(ne, &call_builtin);
1921
1922 __ mov(r9, Operand(new_space_allocation_limit));
1923 __ ldr(r9, MemOperand(r9));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001924 __ add(r3, r3, Operand(kAllocationDelta * kPointerSize));
1925 __ cmp(r3, r9);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001926 __ b(hi, &call_builtin);
1927
1928 // We fit and could grow elements.
1929 // Update new_space_allocation_top.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00001930 __ str(r3, MemOperand(r4));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001931 // Push the argument.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001932 __ str(r2, MemOperand(end_elements));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001933 // Fill the rest with holes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001934 __ LoadRoot(r3, Heap::kTheHoleValueRootIndex);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001935 for (int i = 1; i < kAllocationDelta; i++) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001936 __ str(r3, MemOperand(end_elements, i * kPointerSize));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001937 }
1938
1939 // Update elements' and array's sizes.
1940 __ str(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00001941 __ ldr(r4, FieldMemOperand(elements, FixedArray::kLengthOffset));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001942 __ add(r4, r4, Operand(Smi::FromInt(kAllocationDelta)));
1943 __ str(r4, FieldMemOperand(elements, FixedArray::kLengthOffset));
1944
1945 // Elements are in new space, so write barrier is not required.
1946 __ Drop(argc + 1);
1947 __ Ret();
1948 }
1949 __ bind(&call_builtin);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001950 __ TailCallExternalReference(
1951 ExternalReference(Builtins::c_ArrayPush, isolate()), argc + 1, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001952 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001953
1954 // Handle call cache miss.
1955 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001956 GenerateMissBranch();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001957
1958 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001959 return GetCode(type, name);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001960}
1961
1962
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001963Handle<Code> CallStubCompiler::CompileArrayPopCall(
1964 Handle<Object> object,
1965 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00001966 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001967 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001968 Handle<String> name,
1969 Code::StubType type) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001970 // ----------- S t a t e -------------
1971 // -- r2 : name
1972 // -- lr : return address
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001973 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1974 // -- ...
1975 // -- sp[argc * 4] : receiver
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001976 // -----------------------------------
1977
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001978 // If object is not an array or is observed, bail out to regular call.
1979 if (!object->IsJSArray() ||
1980 !cell.is_null() ||
1981 Handle<JSArray>::cast(object)->map()->is_observed()) {
1982 return Handle<Code>::null();
1983 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001984
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001985 Label miss, return_undefined, call_builtin;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001986 Register receiver = r1;
1987 Register elements = r3;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001988 GenerateNameCheck(name, &miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001989
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001990 // Get the receiver from the stack
1991 const int argc = arguments().immediate();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001992 __ ldr(receiver, MemOperand(sp, argc * kPointerSize));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001993 // Check that the receiver isn't a smi.
ager@chromium.org378b34e2011-01-28 08:04:38 +00001994 __ JumpIfSmi(receiver, &miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001995
1996 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001997 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, elements,
1998 r4, r0, name, &miss);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001999
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00002000 // Get the elements array of the object.
2001 __ ldr(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
2002
2003 // Check that the elements are in fast mode and writable.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002004 __ CheckMap(elements,
2005 r0,
2006 Heap::kFixedArrayMapRootIndex,
2007 &call_builtin,
2008 DONT_DO_SMI_CHECK);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00002009
2010 // Get the array's length into r4 and calculate new length.
2011 __ ldr(r4, FieldMemOperand(receiver, JSArray::kLengthOffset));
2012 __ sub(r4, r4, Operand(Smi::FromInt(1)), SetCC);
2013 __ b(lt, &return_undefined);
2014
2015 // Get the last element.
2016 __ LoadRoot(r6, Heap::kTheHoleValueRootIndex);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00002017 // We can't address the last element in one operation. Compute the more
2018 // expensive shift first, and use an offset later on.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002019 __ add(elements, elements, Operand::PointerOffsetFromSmiKey(r4));
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00002020 __ ldr(r0, FieldMemOperand(elements, FixedArray::kHeaderSize));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00002021 __ cmp(r0, r6);
2022 __ b(eq, &call_builtin);
2023
2024 // Set the array's length.
2025 __ str(r4, FieldMemOperand(receiver, JSArray::kLengthOffset));
2026
2027 // Fill with the hole.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00002028 __ str(r6, FieldMemOperand(elements, FixedArray::kHeaderSize));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00002029 __ Drop(argc + 1);
2030 __ Ret();
2031
2032 __ bind(&return_undefined);
2033 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
2034 __ Drop(argc + 1);
2035 __ Ret();
2036
2037 __ bind(&call_builtin);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002038 __ TailCallExternalReference(
2039 ExternalReference(Builtins::c_ArrayPop, isolate()), argc + 1, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002040
2041 // Handle call cache miss.
2042 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002043 GenerateMissBranch();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002044
2045 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002046 return GetCode(type, name);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002047}
2048
2049
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002050Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
2051 Handle<Object> object,
2052 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002053 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002054 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002055 Handle<String> name,
2056 Code::StubType type) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00002057 // ----------- S t a t e -------------
2058 // -- r2 : function name
2059 // -- lr : return address
2060 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2061 // -- ...
2062 // -- sp[argc * 4] : receiver
2063 // -----------------------------------
2064
2065 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002066 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002067
2068 const int argc = arguments().immediate();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002069 Label miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002070 Label name_miss;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002071 Label index_out_of_range;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002072 Label* index_out_of_range_label = &index_out_of_range;
2073
danno@chromium.org40cb8782011-05-25 07:58:50 +00002074 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002075 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002076 DEFAULT_STRING_STUB)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002077 index_out_of_range_label = &miss;
2078 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002079 GenerateNameCheck(name, &name_miss);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002080
2081 // Check that the maps starting from the prototype haven't changed.
2082 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2083 Context::STRING_FUNCTION_INDEX,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002084 r0,
2085 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002086 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002087 CheckPrototypes(
2088 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2089 r0, holder, r1, r3, r4, name, &miss);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002090
2091 Register receiver = r1;
2092 Register index = r4;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002093 Register result = r0;
2094 __ ldr(receiver, MemOperand(sp, argc * kPointerSize));
2095 if (argc > 0) {
2096 __ ldr(index, MemOperand(sp, (argc - 1) * kPointerSize));
2097 } else {
2098 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
2099 }
2100
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002101 StringCharCodeAtGenerator generator(receiver,
2102 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002103 result,
2104 &miss, // When not a string.
2105 &miss, // When not a number.
2106 index_out_of_range_label,
2107 STRING_INDEX_IS_NUMBER);
2108 generator.GenerateFast(masm());
ricow@chromium.org65fae842010-08-25 15:26:24 +00002109 __ Drop(argc + 1);
2110 __ Ret();
2111
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002112 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002113 generator.GenerateSlow(masm(), call_helper);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002114
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002115 if (index_out_of_range.is_linked()) {
2116 __ bind(&index_out_of_range);
2117 __ LoadRoot(r0, Heap::kNanValueRootIndex);
2118 __ Drop(argc + 1);
2119 __ Ret();
2120 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00002121
2122 __ bind(&miss);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002123 // Restore function name in r2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002124 __ Move(r2, name);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002125 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002126 GenerateMissBranch();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002127
2128 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002129 return GetCode(type, name);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002130}
2131
2132
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002133Handle<Code> CallStubCompiler::CompileStringCharAtCall(
2134 Handle<Object> object,
2135 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002136 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002137 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002138 Handle<String> name,
2139 Code::StubType type) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00002140 // ----------- S t a t e -------------
2141 // -- r2 : function name
2142 // -- lr : return address
2143 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2144 // -- ...
2145 // -- sp[argc * 4] : receiver
2146 // -----------------------------------
2147
2148 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002149 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002150
2151 const int argc = arguments().immediate();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002152 Label miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002153 Label name_miss;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002154 Label index_out_of_range;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002155 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00002156 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002157 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002158 DEFAULT_STRING_STUB)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002159 index_out_of_range_label = &miss;
2160 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002161 GenerateNameCheck(name, &name_miss);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002162
2163 // Check that the maps starting from the prototype haven't changed.
2164 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2165 Context::STRING_FUNCTION_INDEX,
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002166 r0,
2167 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002168 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002169 CheckPrototypes(
2170 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2171 r0, holder, r1, r3, r4, name, &miss);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002172
2173 Register receiver = r0;
2174 Register index = r4;
danno@chromium.orgc612e022011-11-10 11:38:15 +00002175 Register scratch = r3;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002176 Register result = r0;
2177 __ ldr(receiver, MemOperand(sp, argc * kPointerSize));
2178 if (argc > 0) {
2179 __ ldr(index, MemOperand(sp, (argc - 1) * kPointerSize));
2180 } else {
2181 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
2182 }
2183
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002184 StringCharAtGenerator generator(receiver,
2185 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00002186 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002187 result,
2188 &miss, // When not a string.
2189 &miss, // When not a number.
2190 index_out_of_range_label,
2191 STRING_INDEX_IS_NUMBER);
2192 generator.GenerateFast(masm());
ricow@chromium.org65fae842010-08-25 15:26:24 +00002193 __ Drop(argc + 1);
2194 __ Ret();
2195
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002196 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002197 generator.GenerateSlow(masm(), call_helper);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002198
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002199 if (index_out_of_range.is_linked()) {
2200 __ bind(&index_out_of_range);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002201 __ LoadRoot(r0, Heap::kempty_stringRootIndex);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002202 __ Drop(argc + 1);
2203 __ Ret();
2204 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00002205
2206 __ bind(&miss);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002207 // Restore function name in r2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002208 __ Move(r2, name);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002209 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002210 GenerateMissBranch();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002211
2212 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002213 return GetCode(type, name);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002214}
2215
2216
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002217Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
2218 Handle<Object> object,
2219 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002220 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002221 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002222 Handle<String> name,
2223 Code::StubType type) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002224 // ----------- S t a t e -------------
2225 // -- r2 : function name
2226 // -- lr : return address
2227 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2228 // -- ...
2229 // -- sp[argc * 4] : receiver
2230 // -----------------------------------
2231
2232 const int argc = arguments().immediate();
2233
2234 // If the object is not a JSObject or we got an unexpected number of
2235 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002236 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002237
2238 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002239 GenerateNameCheck(name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002240
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002241 if (cell.is_null()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002242 __ ldr(r1, MemOperand(sp, 1 * kPointerSize));
2243
whesse@chromium.org7b260152011-06-20 15:33:18 +00002244 __ JumpIfSmi(r1, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002245
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002246 CheckPrototypes(Handle<JSObject>::cast(object), r1, holder, r0, r3, r4,
2247 name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002248 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002249 ASSERT(cell->value() == *function);
2250 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2251 &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002252 GenerateLoadFunctionFromCell(cell, function, &miss);
2253 }
2254
2255 // Load the char code argument.
2256 Register code = r1;
2257 __ ldr(code, MemOperand(sp, 0 * kPointerSize));
2258
2259 // Check the code is a smi.
2260 Label slow;
whesse@chromium.org7b260152011-06-20 15:33:18 +00002261 __ JumpIfNotSmi(code, &slow);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002262
2263 // Convert the smi code to uint16.
2264 __ and_(code, code, Operand(Smi::FromInt(0xffff)));
2265
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002266 StringCharFromCodeGenerator generator(code, r0);
2267 generator.GenerateFast(masm());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002268 __ Drop(argc + 1);
2269 __ Ret();
2270
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002271 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002272 generator.GenerateSlow(masm(), call_helper);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002273
2274 // Tail call the full function. We do not have to patch the receiver
2275 // because the function makes no use of it.
2276 __ bind(&slow);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002277 ParameterCount expected(function);
2278 __ InvokeFunction(function, expected, arguments(),
2279 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002280
2281 __ bind(&miss);
2282 // r2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002283 GenerateMissBranch();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002284
2285 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002286 return GetCode(type, name);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002287}
2288
2289
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002290Handle<Code> CallStubCompiler::CompileMathFloorCall(
2291 Handle<Object> object,
2292 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002293 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002294 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002295 Handle<String> name,
2296 Code::StubType type) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002297 // ----------- S t a t e -------------
2298 // -- r2 : function name
2299 // -- lr : return address
2300 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2301 // -- ...
2302 // -- sp[argc * 4] : receiver
2303 // -----------------------------------
2304
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002305 const int argc = arguments().immediate();
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002306 // If the object is not a JSObject or we got an unexpected number of
2307 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002308 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002309
2310 Label miss, slow;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002311 GenerateNameCheck(name, &miss);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002312
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002313 if (cell.is_null()) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002314 __ ldr(r1, MemOperand(sp, 1 * kPointerSize));
ager@chromium.org378b34e2011-01-28 08:04:38 +00002315 __ JumpIfSmi(r1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002316 CheckPrototypes(Handle<JSObject>::cast(object), r1, holder, r0, r3, r4,
2317 name, &miss);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002318 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002319 ASSERT(cell->value() == *function);
2320 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2321 &miss);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002322 GenerateLoadFunctionFromCell(cell, function, &miss);
2323 }
2324
2325 // Load the (only) argument into r0.
2326 __ ldr(r0, MemOperand(sp, 0 * kPointerSize));
2327
2328 // If the argument is a smi, just return.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002329 __ SmiTst(r0);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002330 __ Drop(argc + 1, eq);
2331 __ Ret(eq);
2332
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002333 __ CheckMap(r0, r1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002334
ulan@chromium.org750145a2013-03-07 15:14:13 +00002335 Label smi_check, just_return;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002336
2337 // Load the HeapNumber value.
2338 // We will need access to the value in the core registers, so we load it
2339 // with ldrd and move it to the fpu. It also spares a sub instruction for
2340 // updating the HeapNumber value address, as vldr expects a multiple
2341 // of 4 offset.
2342 __ Ldrd(r4, r5, FieldMemOperand(r0, HeapNumber::kValueOffset));
2343 __ vmov(d1, r4, r5);
2344
ulan@chromium.org750145a2013-03-07 15:14:13 +00002345 // Check for NaN, Infinities and -0.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002346 // They are invariant through a Math.Floor call, so just
2347 // return the original argument.
ulan@chromium.org750145a2013-03-07 15:14:13 +00002348 __ Sbfx(r3, r5, HeapNumber::kExponentShift, HeapNumber::kExponentBits);
2349 __ cmp(r3, Operand(-1));
2350 __ b(eq, &just_return);
2351 __ eor(r3, r5, Operand(0x80000000u));
2352 __ orr(r3, r3, r4, SetCC);
2353 __ b(eq, &just_return);
2354 // Test for values that can be exactly represented as a
2355 // signed 32-bit integer.
2356 __ TryDoubleToInt32Exact(r0, d1, d2);
2357 // If exact, check smi
2358 __ b(eq, &smi_check);
2359 __ cmp(r5, Operand(0));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002360
ulan@chromium.org750145a2013-03-07 15:14:13 +00002361 // If input is in ]+0, +inf[, the cmp has cleared overflow and negative
2362 // (V=0 and N=0), the two following instructions won't execute and
2363 // we fall through smi_check to check if the result can fit into a smi.
2364
2365 // If input is in ]-inf, -0[, sub one and, go to slow if we have
2366 // an overflow. Else we fall through smi check.
2367 // Hint: if x is a negative, non integer number,
2368 // floor(x) <=> round_to_zero(x) - 1.
2369 __ sub(r0, r0, Operand(1), SetCC, mi);
2370 __ b(vs, &slow);
2371
2372 __ bind(&smi_check);
2373 // Check if the result can fit into an smi. If we had an overflow,
2374 // the result is either 0x80000000 or 0x7FFFFFFF and won't fit into an smi.
ulan@chromium.org750145a2013-03-07 15:14:13 +00002375 // If result doesn't fit into an smi, branch to slow.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002376 __ SmiTag(r0, SetCC);
2377 __ b(vs, &slow);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002378
ulan@chromium.org750145a2013-03-07 15:14:13 +00002379 __ bind(&just_return);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002380 __ Drop(argc + 1);
2381 __ Ret();
2382
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002383 __ bind(&slow);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002384 // Tail call the full function. We do not have to patch the receiver
2385 // because the function makes no use of it.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002386 ParameterCount expected(function);
2387 __ InvokeFunction(function, expected, arguments(),
2388 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002389
2390 __ bind(&miss);
2391 // r2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002392 GenerateMissBranch();
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002393
2394 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002395 return GetCode(type, name);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002396}
2397
2398
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002399Handle<Code> CallStubCompiler::CompileMathAbsCall(
2400 Handle<Object> object,
2401 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002402 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002403 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002404 Handle<String> name,
2405 Code::StubType type) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002406 // ----------- S t a t e -------------
2407 // -- r2 : function name
2408 // -- lr : return address
2409 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2410 // -- ...
2411 // -- sp[argc * 4] : receiver
2412 // -----------------------------------
2413
2414 const int argc = arguments().immediate();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002415 // If the object is not a JSObject or we got an unexpected number of
2416 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002417 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002418
2419 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002420 GenerateNameCheck(name, &miss);
2421 if (cell.is_null()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002422 __ ldr(r1, MemOperand(sp, 1 * kPointerSize));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002423 __ JumpIfSmi(r1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002424 CheckPrototypes(Handle<JSObject>::cast(object), r1, holder, r0, r3, r4,
2425 name, &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002426 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002427 ASSERT(cell->value() == *function);
2428 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2429 &miss);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002430 GenerateLoadFunctionFromCell(cell, function, &miss);
2431 }
2432
2433 // Load the (only) argument into r0.
2434 __ ldr(r0, MemOperand(sp, 0 * kPointerSize));
2435
2436 // Check if the argument is a smi.
2437 Label not_smi;
ager@chromium.org378b34e2011-01-28 08:04:38 +00002438 __ JumpIfNotSmi(r0, &not_smi);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002439
2440 // Do bitwise not or do nothing depending on the sign of the
2441 // argument.
2442 __ eor(r1, r0, Operand(r0, ASR, kBitsPerInt - 1));
2443
2444 // Add 1 or do nothing depending on the sign of the argument.
2445 __ sub(r0, r1, Operand(r0, ASR, kBitsPerInt - 1), SetCC);
2446
2447 // If the result is still negative, go to the slow case.
2448 // This only happens for the most negative smi.
2449 Label slow;
2450 __ b(mi, &slow);
2451
2452 // Smi case done.
2453 __ Drop(argc + 1);
2454 __ Ret();
2455
2456 // Check if the argument is a heap number and load its exponent and
2457 // sign.
2458 __ bind(&not_smi);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002459 __ CheckMap(r0, r1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002460 __ ldr(r1, FieldMemOperand(r0, HeapNumber::kExponentOffset));
2461
2462 // Check the sign of the argument. If the argument is positive,
2463 // just return it.
2464 Label negative_sign;
2465 __ tst(r1, Operand(HeapNumber::kSignMask));
2466 __ b(ne, &negative_sign);
2467 __ Drop(argc + 1);
2468 __ Ret();
2469
2470 // If the argument is negative, clear the sign, and return a new
2471 // number.
2472 __ bind(&negative_sign);
2473 __ eor(r1, r1, Operand(HeapNumber::kSignMask));
2474 __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
2475 __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
2476 __ AllocateHeapNumber(r0, r4, r5, r6, &slow);
2477 __ str(r1, FieldMemOperand(r0, HeapNumber::kExponentOffset));
2478 __ str(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
2479 __ Drop(argc + 1);
2480 __ Ret();
2481
2482 // Tail call the full function. We do not have to patch the receiver
2483 // because the function makes no use of it.
2484 __ bind(&slow);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002485 ParameterCount expected(function);
2486 __ InvokeFunction(function, expected, arguments(),
2487 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002488
2489 __ bind(&miss);
2490 // r2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002491 GenerateMissBranch();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002492
2493 // Return the generated code.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002494 return GetCode(type, name);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002495}
2496
2497
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002498Handle<Code> CallStubCompiler::CompileFastApiCall(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002499 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002500 Handle<Object> object,
2501 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002502 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002503 Handle<JSFunction> function,
2504 Handle<String> name) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002505 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002506
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002507 ASSERT(optimization.is_simple_api_call());
2508 // Bail out if object is a global object as we don't want to
2509 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002510 if (object->IsGlobalObject()) return Handle<Code>::null();
2511 if (!cell.is_null()) return Handle<Code>::null();
2512 if (!object->IsJSObject()) return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002513 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002514 Handle<JSObject>::cast(object), holder);
2515 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002516
2517 Label miss, miss_before_stack_reserved;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002518 GenerateNameCheck(name, &miss_before_stack_reserved);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002519
2520 // Get the receiver from the stack.
2521 const int argc = arguments().immediate();
2522 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
2523
2524 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002525 __ JumpIfSmi(r1, &miss_before_stack_reserved);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002526
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002527 __ IncrementCounter(counters->call_const(), 1, r0, r3);
2528 __ IncrementCounter(counters->call_const_fast_api(), 1, r0, r3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002529
2530 ReserveSpaceForFastApiCall(masm(), r0);
2531
2532 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002533 CheckPrototypes(Handle<JSObject>::cast(object), r1, holder, r0, r3, r4, name,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002534 depth, &miss);
2535
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002536 GenerateFastApiDirectCall(masm(), optimization, argc, false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002537
2538 __ bind(&miss);
2539 FreeSpaceForFastApiCall(masm());
2540
2541 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002542 GenerateMissBranch();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002543
2544 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002545 return GetCode(function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002546}
2547
2548
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002549void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) {
2550 Label success;
2551 // Check that the object is a boolean.
2552 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
2553 __ cmp(object, ip);
2554 __ b(eq, &success);
2555 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
2556 __ cmp(object, ip);
2557 __ b(ne, miss);
2558 __ bind(&success);
2559}
2560
2561
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002562void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
2563 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002564 Handle<Name> name,
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002565 CheckType check) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002566 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00002567 // -- r2 : name
2568 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002569 // -----------------------------------
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002570 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002571 GenerateNameCheck(name, &miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002572
mads.s.ager31e71382008-08-13 09:32:07 +00002573 // Get the receiver from the stack
2574 const int argc = arguments().immediate();
2575 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
2576
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002577 // Check that the receiver isn't a smi.
2578 if (check != NUMBER_CHECK) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00002579 __ JumpIfSmi(r1, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002580 }
2581
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002582 // Make sure that it's okay not to patch the on stack receiver
2583 // unless we're doing a receiver map check.
2584 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002585 switch (check) {
2586 case RECEIVER_MAP_CHECK:
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002587 __ IncrementCounter(isolate()->counters()->call_const(), 1, r0, r3);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002588
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002589 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002590 CheckPrototypes(Handle<JSObject>::cast(object), r1, holder, r0, r3, r4,
2591 name, &miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002592
2593 // Patch the receiver on the stack with the global proxy if
2594 // necessary.
2595 if (object->IsGlobalObject()) {
2596 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
2597 __ str(r3, MemOperand(sp, argc * kPointerSize));
2598 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002599 break;
2600
2601 case STRING_CHECK:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002602 // Check that the object is a string.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002603 __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE);
2604 __ b(ge, &miss);
2605 // Check that the maps starting from the prototype haven't changed.
2606 GenerateDirectLoadGlobalFunctionPrototype(
2607 masm(), Context::STRING_FUNCTION_INDEX, r0, &miss);
2608 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002609 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002610 r0, holder, r3, r1, r4, name, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002611 break;
2612
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002613 case SYMBOL_CHECK:
2614 // Check that the object is a symbol.
2615 __ CompareObjectType(r1, r1, r3, SYMBOL_TYPE);
2616 __ b(ne, &miss);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002617 // Check that the maps starting from the prototype haven't changed.
2618 GenerateDirectLoadGlobalFunctionPrototype(
2619 masm(), Context::SYMBOL_FUNCTION_INDEX, r0, &miss);
2620 CheckPrototypes(
2621 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2622 r0, holder, r3, r1, r4, name, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002623 break;
2624
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002625 case NUMBER_CHECK: {
2626 Label fast;
2627 // Check that the object is a smi or a heap number.
2628 __ JumpIfSmi(r1, &fast);
2629 __ CompareObjectType(r1, r0, r0, HEAP_NUMBER_TYPE);
2630 __ b(ne, &miss);
2631 __ bind(&fast);
2632 // Check that the maps starting from the prototype haven't changed.
2633 GenerateDirectLoadGlobalFunctionPrototype(
2634 masm(), Context::NUMBER_FUNCTION_INDEX, r0, &miss);
2635 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002636 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002637 r0, holder, r3, r1, r4, name, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002638 break;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002639 }
2640 case BOOLEAN_CHECK: {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002641 GenerateBooleanCheck(r1, &miss);
2642
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002643 // Check that the maps starting from the prototype haven't changed.
2644 GenerateDirectLoadGlobalFunctionPrototype(
2645 masm(), Context::BOOLEAN_FUNCTION_INDEX, r0, &miss);
2646 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002647 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002648 r0, holder, r3, r1, r4, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002649 break;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002650 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002651 }
2652
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002653 Label success;
2654 __ b(&success);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002655
2656 // Handle call cache miss.
2657 __ bind(&miss);
2658 GenerateMissBranch();
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002659
2660 __ bind(&success);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002661}
2662
2663
2664void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002665 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002666 ? CALL_AS_FUNCTION
2667 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002668 ParameterCount expected(function);
2669 __ InvokeFunction(function, expected, arguments(),
2670 JUMP_FUNCTION, NullCallWrapper(), call_kind);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002671}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002672
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002673
2674Handle<Code> CallStubCompiler::CompileCallConstant(
2675 Handle<Object> object,
2676 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002677 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002678 CheckType check,
2679 Handle<JSFunction> function) {
2680 if (HasCustomCallGenerator(function)) {
2681 Handle<Code> code = CompileCustomCall(object, holder,
danno@chromium.org41728482013-06-12 22:31:22 +00002682 Handle<Cell>::null(),
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002683 function, Handle<String>::cast(name),
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002684 Code::CONSTANT);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002685 // A null handle means bail out to the regular compiler code below.
2686 if (!code.is_null()) return code;
2687 }
2688
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002689 CompileHandlerFrontend(object, holder, name, check);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002690 CompileHandlerBackend(function);
2691
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002692 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002693 return GetCode(function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002694}
2695
2696
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002697Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2698 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002699 Handle<Name> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002700 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00002701 // -- r2 : name
2702 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002703 // -----------------------------------
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002704 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002705 GenerateNameCheck(name, &miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002706
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002707 // Get the number of arguments.
2708 const int argc = arguments().immediate();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002709 LookupResult lookup(isolate());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002710 LookupPostInterceptor(holder, name, &lookup);
2711
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002712 // Get the receiver from the stack.
2713 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002714
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002715 CallInterceptorCompiler compiler(this, arguments(), r2, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002716 compiler.Compile(masm(), object, holder, name, &lookup, r1, r3, r4, r0,
2717 &miss);
ager@chromium.org5c838252010-02-19 08:53:10 +00002718
2719 // Move returned value, the function to call, to r1.
2720 __ mov(r1, r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002721 // Restore receiver.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002722 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002723
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002724 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002725
2726 // Handle call cache miss.
2727 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002728 GenerateMissBranch();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002729
2730 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002731 return GetCode(Code::INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002732}
2733
2734
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002735Handle<Code> CallStubCompiler::CompileCallGlobal(
2736 Handle<JSObject> object,
2737 Handle<GlobalObject> holder,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002738 Handle<PropertyCell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002739 Handle<JSFunction> function,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002740 Handle<Name> name) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002741 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00002742 // -- r2 : name
2743 // -- lr : return address
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002744 // -----------------------------------
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002745 if (HasCustomCallGenerator(function)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00002746 Handle<Code> code = CompileCustomCall(
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002747 object, holder, cell, function, Handle<String>::cast(name),
2748 Code::NORMAL);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002749 // A null handle means bail out to the regular compiler code below.
2750 if (!code.is_null()) return code;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002751 }
2752
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002753 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002754 GenerateNameCheck(name, &miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002755
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002756 // Get the number of arguments.
2757 const int argc = arguments().immediate();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002758 GenerateGlobalReceiverCheck(object, holder, name, &miss);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002759 GenerateLoadFunctionFromCell(cell, function, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002760
2761 // Patch the receiver on the stack with the global proxy if
2762 // necessary.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002763 if (object->IsGlobalObject()) {
2764 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
2765 __ str(r3, MemOperand(sp, argc * kPointerSize));
2766 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002767
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002768 // Set up the context (function already in r1).
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002769 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
2770
2771 // Jump to the cached code (tail call).
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002772 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002773 __ IncrementCounter(counters->call_global_inline(), 1, r3, r4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002774 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002775 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002776 ? CALL_AS_FUNCTION
2777 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002778 // We call indirectly through the code field in the function to
2779 // allow recompilation to take effect without changing any of the
2780 // call sites.
2781 __ ldr(r3, FieldMemOperand(r1, JSFunction::kCodeEntryOffset));
2782 __ InvokeCode(r3, expected, arguments(), JUMP_FUNCTION,
2783 NullCallWrapper(), call_kind);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002784
2785 // Handle call cache miss.
2786 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002787 __ IncrementCounter(counters->call_global_inline_miss(), 1, r1, r3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002788 GenerateMissBranch();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002789
2790 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002791 return GetCode(Code::NORMAL, name);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002792}
2793
2794
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002795Handle<Code> StoreStubCompiler::CompileStoreCallback(
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002796 Handle<JSObject> object,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002797 Handle<JSObject> holder,
danno@chromium.orgbee51992013-07-10 14:57:15 +00002798 Handle<Name> name,
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002799 Handle<ExecutableAccessorInfo> callback) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002800 HandlerFrontend(object, receiver(), holder, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002801
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002802 // Stub never generated for non-global objects that require access checks.
2803 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002804
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002805 __ push(receiver()); // receiver
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002806 __ mov(ip, Operand(callback)); // callback info
danno@chromium.orgbee51992013-07-10 14:57:15 +00002807 __ push(ip);
2808 __ mov(ip, Operand(name));
2809 __ Push(ip, value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002810
mads.s.ager31e71382008-08-13 09:32:07 +00002811 // Do tail-call to the runtime system.
2812 ExternalReference store_callback_property =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002813 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002814 __ TailCallExternalReference(store_callback_property, 4, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002815
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002816 // Return the generated code.
danno@chromium.orgbee51992013-07-10 14:57:15 +00002817 return GetCode(kind(), Code::CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002818}
2819
2820
dslomov@chromium.org639bac02013-09-09 11:58:54 +00002821Handle<Code> StoreStubCompiler::CompileStoreCallback(
2822 Handle<JSObject> object,
2823 Handle<JSObject> holder,
2824 Handle<Name> name,
2825 const CallOptimization& call_optimization) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002826 HandlerFrontend(object, receiver(), holder, name);
dslomov@chromium.org639bac02013-09-09 11:58:54 +00002827
2828 Register values[] = { value() };
2829 GenerateFastApiCall(
2830 masm(), call_optimization, receiver(), scratch3(), 1, values);
2831
2832 // Return the generated code.
2833 return GetCode(kind(), Code::CALLBACKS, name);
2834}
2835
2836
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002837#undef __
2838#define __ ACCESS_MASM(masm)
2839
2840
2841void StoreStubCompiler::GenerateStoreViaSetter(
2842 MacroAssembler* masm,
2843 Handle<JSFunction> setter) {
2844 // ----------- S t a t e -------------
2845 // -- r0 : value
2846 // -- r1 : receiver
2847 // -- r2 : name
2848 // -- lr : return address
2849 // -----------------------------------
2850 {
2851 FrameScope scope(masm, StackFrame::INTERNAL);
2852
2853 // Save value register, so we can restore it later.
2854 __ push(r0);
2855
2856 if (!setter.is_null()) {
2857 // Call the JavaScript setter with receiver and value on the stack.
2858 __ Push(r1, r0);
2859 ParameterCount actual(1);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002860 ParameterCount expected(setter);
2861 __ InvokeFunction(setter, expected, actual,
2862 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002863 } else {
2864 // If we generate a global code snippet for deoptimization only, remember
2865 // the place to continue after deoptimization.
2866 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2867 }
2868
2869 // We have to return the passed value, not the return value of the setter.
2870 __ pop(r0);
2871
2872 // Restore context register.
2873 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2874 }
2875 __ Ret();
2876}
2877
2878
2879#undef __
2880#define __ ACCESS_MASM(masm())
2881
2882
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002883Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002884 Handle<JSObject> object,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002885 Handle<Name> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002886 Label miss;
2887
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002888 // Check that the map of the object hasn't changed.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002889 __ CheckMap(receiver(), scratch1(), Handle<Map>(object->map()), &miss,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002890 DO_SMI_CHECK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002891
2892 // Perform global security token check if needed.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002893 if (object->IsJSGlobalProxy()) {
2894 __ CheckAccessGlobalProxy(receiver(), scratch1(), &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002895 }
2896
ager@chromium.org5c838252010-02-19 08:53:10 +00002897 // Stub is never generated for non-global objects that require access
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002898 // checks.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002899 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002900
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002901 __ Push(receiver(), this->name(), value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002902
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002903 __ mov(scratch1(), Operand(Smi::FromInt(strict_mode())));
2904 __ push(scratch1()); // strict mode
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002905
mads.s.ager31e71382008-08-13 09:32:07 +00002906 // Do tail-call to the runtime system.
2907 ExternalReference store_ic_property =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002908 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002909 __ TailCallExternalReference(store_ic_property, 4, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002910
2911 // Handle store cache miss.
2912 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002913 TailCallBuiltin(masm(), MissBuiltin(kind()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002914
2915 // Return the generated code.
jkummerow@chromium.orgfe74d5d2013-09-06 11:12:30 +00002916 return GetCode(kind(), Code::INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002917}
2918
2919
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00002920Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002921 Handle<Object> object,
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00002922 Handle<JSObject> last,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002923 Handle<Name> name,
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002924 Handle<JSGlobalObject> global) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002925 NonexistentHandlerFrontend(object, last, name, global);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002926
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002927 // Return undefined if maps of the full prototype chain are still the
2928 // same and no global property with this name contains a value.
2929 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
2930 __ Ret();
2931
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002932 // Return the generated code.
ulan@chromium.org750145a2013-03-07 15:14:13 +00002933 return GetCode(kind(), Code::NONEXISTENT, name);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002934}
2935
2936
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002937Register* LoadStubCompiler::registers() {
2938 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2939 static Register registers[] = { r0, r2, r3, r1, r4, r5 };
2940 return registers;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002941}
2942
2943
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002944Register* KeyedLoadStubCompiler::registers() {
2945 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2946 static Register registers[] = { r1, r0, r2, r3, r4, r5 };
2947 return registers;
2948}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002949
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002950
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002951Register* StoreStubCompiler::registers() {
2952 // receiver, name, value, scratch1, scratch2, scratch3.
2953 static Register registers[] = { r1, r2, r0, r3, r4, r5 };
2954 return registers;
2955}
2956
2957
2958Register* KeyedStoreStubCompiler::registers() {
2959 // receiver, name, value, scratch1, scratch2, scratch3.
2960 static Register registers[] = { r2, r1, r0, r3, r4, r5 };
2961 return registers;
2962}
2963
2964
ulan@chromium.org750145a2013-03-07 15:14:13 +00002965void KeyedLoadStubCompiler::GenerateNameCheck(Handle<Name> name,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002966 Register name_reg,
2967 Label* miss) {
2968 __ cmp(name_reg, Operand(name));
2969 __ b(ne, miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002970}
2971
2972
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002973void KeyedStoreStubCompiler::GenerateNameCheck(Handle<Name> name,
2974 Register name_reg,
2975 Label* miss) {
2976 __ cmp(name_reg, Operand(name));
2977 __ b(ne, miss);
2978}
2979
2980
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002981#undef __
2982#define __ ACCESS_MASM(masm)
2983
2984
2985void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00002986 Register receiver,
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002987 Handle<JSFunction> getter) {
2988 // ----------- S t a t e -------------
2989 // -- r0 : receiver
2990 // -- r2 : name
2991 // -- lr : return address
2992 // -----------------------------------
2993 {
2994 FrameScope scope(masm, StackFrame::INTERNAL);
2995
2996 if (!getter.is_null()) {
2997 // Call the JavaScript getter with the receiver on the stack.
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00002998 __ push(receiver);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002999 ParameterCount actual(0);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003000 ParameterCount expected(getter);
3001 __ InvokeFunction(getter, expected, actual,
3002 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003003 } else {
3004 // If we generate a global code snippet for deoptimization only, remember
3005 // the place to continue after deoptimization.
3006 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
3007 }
3008
3009 // Restore context register.
3010 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
3011 }
3012 __ Ret();
3013}
3014
3015
3016#undef __
3017#define __ ACCESS_MASM(masm())
3018
3019
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003020Handle<Code> LoadStubCompiler::CompileLoadGlobal(
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00003021 Handle<Object> object,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003022 Handle<GlobalObject> global,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00003023 Handle<PropertyCell> cell,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003024 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003025 bool is_dont_delete) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00003026 Label miss;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003027
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00003028 HandlerFrontendHeader(object, receiver(), global, name, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003029
3030 // Get the value from the cell.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003031 __ mov(r3, Operand(cell));
danno@chromium.org41728482013-06-12 22:31:22 +00003032 __ ldr(r4, FieldMemOperand(r3, Cell::kValueOffset));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003033
3034 // Check for deleted property if property can actually be deleted.
3035 if (!is_dont_delete) {
ager@chromium.orgab99eea2009-08-25 07:05:41 +00003036 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00003037 __ cmp(r4, ip);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003038 __ b(eq, &miss);
3039 }
3040
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00003041 HandlerFrontendFooter(name, &miss);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003042
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003043 Counters* counters = isolate()->counters();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003044 __ IncrementCounter(counters->named_load_global_stub(), 1, r1, r3);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003045 __ mov(r0, r4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003046 __ Ret();
3047
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003048 // Return the generated code.
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00003049 return GetCode(kind(), Code::NORMAL, name);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003050}
3051
3052
danno@chromium.orgbee51992013-07-10 14:57:15 +00003053Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC(
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003054 MapHandleList* receiver_maps,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003055 CodeHandleList* handlers,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003056 Handle<Name> name,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003057 Code::StubType type,
3058 IcCheckType check) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003059 Label miss;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003060
3061 if (check == PROPERTY) {
3062 GenerateNameCheck(name, this->name(), &miss);
3063 }
3064
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00003065 Label number_case;
3066 Label* smi_target = HasHeapNumberMap(receiver_maps) ? &number_case : &miss;
3067 __ JumpIfSmi(receiver(), smi_target);
3068
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003069 Register map_reg = scratch1();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003070
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003071 int receiver_count = receiver_maps->length();
danno@chromium.orgf005df62013-04-30 16:36:45 +00003072 int number_of_handled_maps = 0;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003073 __ ldr(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset));
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00003074 Handle<Map> heap_number_map = isolate()->factory()->heap_number_map();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003075 for (int current = 0; current < receiver_count; ++current) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00003076 Handle<Map> map = receiver_maps->at(current);
3077 if (!map->is_deprecated()) {
3078 number_of_handled_maps++;
3079 __ mov(ip, Operand(receiver_maps->at(current)));
3080 __ cmp(map_reg, ip);
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00003081 if (map.is_identical_to(heap_number_map)) {
3082 ASSERT(!number_case.is_unused());
3083 __ bind(&number_case);
3084 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00003085 __ Jump(handlers->at(current), RelocInfo::CODE_TARGET, eq);
3086 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003087 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00003088 ASSERT(number_of_handled_maps != 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003089
3090 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003091 TailCallBuiltin(masm(), MissBuiltin(kind()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003092
3093 // Return the generated code.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003094 InlineCacheState state =
danno@chromium.orgf005df62013-04-30 16:36:45 +00003095 number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC;
ulan@chromium.org750145a2013-03-07 15:14:13 +00003096 return GetICCode(kind(), type, name, state);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003097}
3098
3099
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003100Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
3101 MapHandleList* receiver_maps,
3102 CodeHandleList* handler_stubs,
3103 MapHandleList* transitioned_maps) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003104 Label miss;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003105 __ JumpIfSmi(receiver(), &miss);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003106
3107 int receiver_count = receiver_maps->length();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003108 __ ldr(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003109 for (int i = 0; i < receiver_count; ++i) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003110 __ mov(ip, Operand(receiver_maps->at(i)));
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003111 __ cmp(scratch1(), ip);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003112 if (transitioned_maps->at(i).is_null()) {
3113 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003114 } else {
3115 Label next_map;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003116 __ b(ne, &next_map);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003117 __ mov(transition_map(), Operand(transitioned_maps->at(i)));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003118 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, al);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003119 __ bind(&next_map);
3120 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003121 }
3122
3123 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003124 TailCallBuiltin(masm(), MissBuiltin(kind()));
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003125
3126 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003127 return GetICCode(
3128 kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003129}
3130
3131
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003132#undef __
3133#define __ ACCESS_MASM(masm)
3134
3135
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003136void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3137 MacroAssembler* masm) {
3138 // ---------- S t a t e --------------
3139 // -- lr : return address
3140 // -- r0 : key
3141 // -- r1 : receiver
3142 // -----------------------------------
3143 Label slow, miss_force_generic;
3144
3145 Register key = r0;
3146 Register receiver = r1;
3147
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00003148 __ UntagAndJumpIfNotSmi(r2, key, &miss_force_generic);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003149 __ ldr(r4, FieldMemOperand(receiver, JSObject::kElementsOffset));
3150 __ LoadFromNumberDictionary(&slow, r4, key, r0, r2, r3, r5);
3151 __ Ret();
3152
3153 __ bind(&slow);
3154 __ IncrementCounter(
3155 masm->isolate()->counters()->keyed_load_external_array_slow(),
3156 1, r2, r3);
3157
3158 // ---------- S t a t e --------------
3159 // -- lr : return address
3160 // -- r0 : key
3161 // -- r1 : receiver
3162 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003163 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003164
3165 // Miss case, call the runtime.
3166 __ bind(&miss_force_generic);
3167
3168 // ---------- S t a t e --------------
3169 // -- lr : return address
3170 // -- r0 : key
3171 // -- r1 : receiver
3172 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003173 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_MissForceGeneric);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003174}
3175
3176
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003177#undef __
3178
3179} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003180
3181#endif // V8_TARGET_ARCH_ARM