blob: 6e422422ea6529984c4725e94b8ae15699d1620b [file] [log] [blame]
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001// Copyright 2012 the V8 project authors. All rights reserved.
ager@chromium.org5c838252010-02-19 08:53:10 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000030#if defined(V8_TARGET_ARCH_MIPS)
31
ager@chromium.org5c838252010-02-19 08:53:10 +000032#include "ic-inl.h"
karlklose@chromium.org83a47282011-05-11 11:54:09 +000033#include "codegen.h"
ager@chromium.org5c838252010-02-19 08:53:10 +000034#include "stub-cache.h"
35
36namespace v8 {
37namespace internal {
38
39#define __ ACCESS_MASM(masm)
40
41
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000042static void ProbeTable(Isolate* isolate,
43 MacroAssembler* masm,
44 Code::Flags flags,
45 StubCache::Table table,
fschneider@chromium.org35814e52012-03-01 15:43:35 +000046 Register receiver,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000047 Register name,
fschneider@chromium.org35814e52012-03-01 15:43:35 +000048 // Number of the cache entry, not scaled.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000049 Register offset,
50 Register scratch,
fschneider@chromium.org35814e52012-03-01 15:43:35 +000051 Register scratch2,
52 Register offset_scratch) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000053 ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
54 ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
fschneider@chromium.org35814e52012-03-01 15:43:35 +000055 ExternalReference map_offset(isolate->stub_cache()->map_reference(table));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000056
57 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());
fschneider@chromium.org35814e52012-03-01 15:43:35 +000059 uint32_t map_off_addr = reinterpret_cast<uint32_t>(map_offset.address());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000060
61 // 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));
fschneider@chromium.org35814e52012-03-01 15:43:35 +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));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000068
69 Label miss;
fschneider@chromium.org35814e52012-03-01 15:43:35 +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 __ sll(offset_scratch, offset, 1);
75 __ Addu(offset_scratch, offset_scratch, offset);
76
77 // Calculate the base address of the entry.
78 __ li(base_addr, Operand(key_offset));
79 __ sll(at, offset_scratch, kPointerSizeLog2);
80 __ Addu(base_addr, base_addr, at);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000081
82 // Check that the key in the entry matches the name.
fschneider@chromium.org35814e52012-03-01 15:43:35 +000083 __ lw(at, MemOperand(base_addr, 0));
84 __ Branch(&miss, ne, name, Operand(at));
85
86 // Check the map matches.
87 __ lw(at, MemOperand(base_addr, map_off_addr - key_off_addr));
88 __ lw(scratch2, FieldMemOperand(receiver, HeapObject::kMapOffset));
89 __ Branch(&miss, ne, at, Operand(scratch2));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000090
91 // Get the code entry from the cache.
fschneider@chromium.org35814e52012-03-01 15:43:35 +000092 Register code = scratch2;
93 scratch2 = no_reg;
94 __ lw(code, MemOperand(base_addr, value_off_addr - key_off_addr));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000095
96 // Check that the flags match what we're looking for.
fschneider@chromium.org35814e52012-03-01 15:43:35 +000097 Register flags_reg = base_addr;
98 base_addr = no_reg;
99 __ lw(flags_reg, FieldMemOperand(code, Code::kFlagsOffset));
100 __ And(flags_reg, flags_reg, Operand(~Code::kFlagsNotUsedInLookup));
101 __ Branch(&miss, ne, flags_reg, Operand(flags));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000102
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000103#ifdef DEBUG
104 if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
105 __ jmp(&miss);
106 } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
107 __ jmp(&miss);
108 }
109#endif
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000110
111 // Jump to the first instruction in the code stub.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000112 __ Addu(at, code, Operand(Code::kHeaderSize - kHeapObjectTag));
113 __ Jump(at);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000114
115 // Miss: fall through.
116 __ bind(&miss);
117}
118
119
120// Helper function used to check that the dictionary doesn't contain
121// the property. This function may return false negatives, so miss_label
122// must always call a backup property check that is complete.
123// This function is safe to call if the receiver has fast properties.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000124// Name must be unique and receiver must be a heap object.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000125static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
126 Label* miss_label,
127 Register receiver,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000128 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000129 Register scratch0,
130 Register scratch1) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000131 ASSERT(name->IsUniqueName());
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 __ lw(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
144 __ lbu(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
145 __ And(scratch0, scratch0, Operand(kInterceptorOrAccessCheckNeededMask));
146 __ Branch(miss_label, ne, scratch0, Operand(zero_reg));
147
148 // Check that receiver is a JSObject.
149 __ lbu(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
150 __ Branch(miss_label, lt, scratch0, Operand(FIRST_SPEC_OBJECT_TYPE));
151
152 // Load properties array.
153 Register properties = scratch0;
154 __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
155 // Check that the properties array is a dictionary.
156 __ lw(map, FieldMemOperand(properties, HeapObject::kMapOffset));
157 Register tmp = properties;
158 __ LoadRoot(tmp, Heap::kHashTableMapRootIndex);
159 __ Branch(miss_label, ne, map, Operand(tmp));
160
161 // Restore the temporarily used register.
162 __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
163
164
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000165 NameDictionaryLookupStub::GenerateNegativeLookup(masm,
166 miss_label,
167 &done,
168 receiver,
169 properties,
170 name,
171 scratch1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000172 __ bind(&done);
173 __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
174}
175
176
ager@chromium.org5c838252010-02-19 08:53:10 +0000177void StubCache::GenerateProbe(MacroAssembler* masm,
178 Code::Flags flags,
179 Register receiver,
180 Register name,
181 Register scratch,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000182 Register extra,
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000183 Register extra2,
184 Register extra3) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000185 Isolate* isolate = masm->isolate();
186 Label miss;
187
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000188 // Make sure that code is valid. The multiplying code relies on the
189 // entry size being 12.
190 ASSERT(sizeof(Entry) == 12);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000191
192 // Make sure the flags does not name a specific type.
193 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
194
195 // Make sure that there are no register conflicts.
196 ASSERT(!scratch.is(receiver));
197 ASSERT(!scratch.is(name));
198 ASSERT(!extra.is(receiver));
199 ASSERT(!extra.is(name));
200 ASSERT(!extra.is(scratch));
201 ASSERT(!extra2.is(receiver));
202 ASSERT(!extra2.is(name));
203 ASSERT(!extra2.is(scratch));
204 ASSERT(!extra2.is(extra));
205
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000206 // Check register validity.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000207 ASSERT(!scratch.is(no_reg));
208 ASSERT(!extra.is(no_reg));
209 ASSERT(!extra2.is(no_reg));
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000210 ASSERT(!extra3.is(no_reg));
211
212 Counters* counters = masm->isolate()->counters();
213 __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1,
214 extra2, extra3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000215
216 // Check that the receiver isn't a smi.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000217 __ JumpIfSmi(receiver, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000218
219 // Get the map of the receiver and compute the hash.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000220 __ lw(scratch, FieldMemOperand(name, Name::kHashFieldOffset));
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000221 __ lw(at, FieldMemOperand(receiver, HeapObject::kMapOffset));
222 __ Addu(scratch, scratch, at);
223 uint32_t mask = kPrimaryTableSize - 1;
224 // We shift out the last two bits because they are not part of the hash and
225 // they are always 01 for maps.
226 __ srl(scratch, scratch, kHeapObjectTagSize);
227 __ Xor(scratch, scratch, Operand((flags >> kHeapObjectTagSize) & mask));
228 __ And(scratch, scratch, Operand(mask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000229
230 // Probe the primary table.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000231 ProbeTable(isolate,
232 masm,
233 flags,
234 kPrimary,
235 receiver,
236 name,
237 scratch,
238 extra,
239 extra2,
240 extra3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000241
242 // Primary miss: Compute hash for secondary probe.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000243 __ srl(at, name, kHeapObjectTagSize);
244 __ Subu(scratch, scratch, at);
245 uint32_t mask2 = kSecondaryTableSize - 1;
246 __ Addu(scratch, scratch, Operand((flags >> kHeapObjectTagSize) & mask2));
247 __ And(scratch, scratch, Operand(mask2));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000248
249 // Probe the secondary table.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000250 ProbeTable(isolate,
251 masm,
252 flags,
253 kSecondary,
254 receiver,
255 name,
256 scratch,
257 extra,
258 extra2,
259 extra3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000260
261 // Cache miss: Fall-through and let caller handle the miss by
262 // entering the runtime system.
263 __ bind(&miss);
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000264 __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1,
265 extra2, extra3);
ager@chromium.org5c838252010-02-19 08:53:10 +0000266}
267
268
269void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
270 int index,
271 Register prototype) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000272 // Load the global or builtins object from the current context.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000273 __ lw(prototype,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000274 MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
275 // Load the native context from the global or builtins object.
276 __ lw(prototype,
277 FieldMemOperand(prototype, GlobalObject::kNativeContextOffset));
278 // Load the function from the native context.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000279 __ lw(prototype, MemOperand(prototype, Context::SlotOffset(index)));
280 // Load the initial map. The global functions all have initial maps.
281 __ lw(prototype,
282 FieldMemOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
283 // Load the prototype from the initial map.
284 __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000285}
286
287
lrn@chromium.org7516f052011-03-30 08:52:27 +0000288void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000289 MacroAssembler* masm,
290 int index,
291 Register prototype,
292 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000293 Isolate* isolate = masm->isolate();
294 // Check we're still in the same context.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000295 __ lw(prototype,
296 MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000297 ASSERT(!prototype.is(at));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000298 __ li(at, isolate->global_object());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000299 __ Branch(miss, ne, prototype, Operand(at));
300 // Get the global function with the given index.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000301 Handle<JSFunction> function(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000302 JSFunction::cast(isolate->native_context()->get(index)));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000303 // Load its initial map. The global functions all have initial maps.
304 __ li(prototype, Handle<Map>(function->initial_map()));
305 // Load the prototype from the initial map.
306 __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000307}
308
309
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000310void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
311 Register dst,
312 Register src,
313 bool inobject,
314 int index,
315 Representation representation) {
316 ASSERT(!FLAG_track_double_fields || !representation.IsDouble());
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000317 int offset = index * kPointerSize;
318 if (!inobject) {
319 // Calculate the offset into the properties array.
320 offset = offset + FixedArray::kHeaderSize;
321 __ lw(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
322 src = dst;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000323 }
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000324 __ lw(dst, FieldMemOperand(src, offset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000325}
326
327
328void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
329 Register receiver,
330 Register scratch,
331 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000332 // Check that the receiver isn't a smi.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000333 __ JumpIfSmi(receiver, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000334
335 // Check that the object is a JS array.
336 __ GetObjectType(receiver, scratch, scratch);
337 __ Branch(miss_label, ne, scratch, Operand(JS_ARRAY_TYPE));
338
339 // Load length directly from the JS array.
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000340 __ Ret(USE_DELAY_SLOT);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000341 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000342}
343
344
345// Generate code to check if an object is a string. If the object is a
346// heap object, its map's instance type is left in the scratch1 register.
347// If this is not needed, scratch1 and scratch2 may be the same register.
348static void GenerateStringCheck(MacroAssembler* masm,
349 Register receiver,
350 Register scratch1,
351 Register scratch2,
352 Label* smi,
353 Label* non_string_object) {
354 // Check that the receiver isn't a smi.
355 __ JumpIfSmi(receiver, smi, t0);
356
357 // Check that the object is a string.
358 __ lw(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
359 __ lbu(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
360 __ And(scratch2, scratch1, Operand(kIsNotStringMask));
361 // The cast is to resolve the overload for the argument of 0x0.
362 __ Branch(non_string_object,
363 ne,
364 scratch2,
365 Operand(static_cast<int32_t>(kStringTag)));
ager@chromium.org5c838252010-02-19 08:53:10 +0000366}
367
368
lrn@chromium.org7516f052011-03-30 08:52:27 +0000369// Generate code to load the length from a string object and return the length.
370// If the receiver object is not a string or a wrapped string object the
371// execution continues at the miss label. The register containing the
372// receiver is potentially clobbered.
373void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
374 Register receiver,
375 Register scratch1,
376 Register scratch2,
377 Label* miss,
378 bool support_wrappers) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000379 Label check_wrapper;
380
381 // Check if the object is a string leaving the instance type in the
382 // scratch1 register.
383 GenerateStringCheck(masm, receiver, scratch1, scratch2, miss,
384 support_wrappers ? &check_wrapper : miss);
385
386 // Load length directly from the string.
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000387 __ Ret(USE_DELAY_SLOT);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000388 __ lw(v0, FieldMemOperand(receiver, String::kLengthOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000389
390 if (support_wrappers) {
391 // Check if the object is a JSValue wrapper.
392 __ bind(&check_wrapper);
393 __ Branch(miss, ne, scratch1, Operand(JS_VALUE_TYPE));
394
395 // Unwrap the value and check if the wrapped value is a string.
396 __ lw(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
397 GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000398 __ Ret(USE_DELAY_SLOT);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000399 __ lw(v0, FieldMemOperand(scratch1, String::kLengthOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000400 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000401}
402
403
ager@chromium.org5c838252010-02-19 08:53:10 +0000404void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
405 Register receiver,
406 Register scratch1,
407 Register scratch2,
408 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000409 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000410 __ Ret(USE_DELAY_SLOT);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000411 __ mov(v0, scratch1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000412}
413
414
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000415// Generate code to check that a global property cell is empty. Create
416// the property cell at compilation time if no cell exists for the
417// property.
418static void GenerateCheckPropertyCell(MacroAssembler* masm,
419 Handle<GlobalObject> global,
420 Handle<Name> name,
421 Register scratch,
422 Label* miss) {
danno@chromium.orgf95d4b92013-06-13 14:40:17 +0000423 Handle<Cell> cell = GlobalObject::EnsurePropertyCell(global, name);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000424 ASSERT(cell->value()->IsTheHole());
425 __ li(scratch, Operand(cell));
danno@chromium.orgf95d4b92013-06-13 14:40:17 +0000426 __ lw(scratch, FieldMemOperand(scratch, Cell::kValueOffset));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000427 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
428 __ Branch(miss, ne, scratch, Operand(at));
429}
430
431
432// Generate StoreTransition code, value is passed in a0 register.
ager@chromium.org5c838252010-02-19 08:53:10 +0000433// After executing generated code, the receiver_reg and name_reg
434// may be clobbered.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000435void StubCompiler::GenerateStoreTransition(MacroAssembler* masm,
436 Handle<JSObject> object,
437 LookupResult* lookup,
438 Handle<Map> transition,
439 Handle<Name> name,
440 Register receiver_reg,
441 Register name_reg,
442 Register value_reg,
443 Register scratch1,
444 Register scratch2,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000445 Register scratch3,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000446 Label* miss_label,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000447 Label* miss_restore_name,
448 Label* slow) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000449 // a0 : value.
450 Label exit;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000451
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000452 // Check that the map of the object hasn't changed.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000453 __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000454 DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000455
456 // Perform global security token check if needed.
457 if (object->IsJSGlobalProxy()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000458 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
459 }
460
danno@chromium.orgf005df62013-04-30 16:36:45 +0000461 int descriptor = transition->LastAdded();
462 DescriptorArray* descriptors = transition->instance_descriptors();
463 PropertyDetails details = descriptors->GetDetails(descriptor);
464 Representation representation = details.representation();
465 ASSERT(!representation.IsNone());
466
467 // Ensure no transitions to deprecated maps are followed.
468 __ CheckMapDeprecated(transition, scratch1, miss_label);
469
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000470 // Check that we are allowed to write this.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000471 if (object->GetPrototype()->IsJSObject()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000472 JSObject* holder;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000473 // holder == object indicates that no property was found.
474 if (lookup->holder() != *object) {
475 holder = lookup->holder();
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000476 } else {
477 // Find the top object.
478 holder = *object;
479 do {
480 holder = JSObject::cast(holder->GetPrototype());
481 } while (holder->GetPrototype()->IsJSObject());
482 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000483 Register holder_reg = CheckPrototypes(
484 object, receiver_reg, Handle<JSObject>(holder), name_reg,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000485 scratch1, scratch2, name, miss_restore_name, SKIP_RECEIVER);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000486 // If no property was found, and the holder (the last object in the
487 // prototype chain) is in slow mode, we need to do a negative lookup on the
488 // holder.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000489 if (lookup->holder() == *object) {
490 if (holder->IsJSGlobalObject()) {
491 GenerateCheckPropertyCell(
492 masm,
493 Handle<GlobalObject>(GlobalObject::cast(holder)),
494 name,
495 scratch1,
496 miss_restore_name);
497 } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
498 GenerateDictionaryNegativeLookup(
499 masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
500 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000501 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000502 }
503
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000504 Register storage_reg = name_reg;
505
danno@chromium.orgfe578672013-06-15 14:38:35 +0000506 if (FLAG_track_fields && representation.IsSmi()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000507 __ JumpIfNotSmi(value_reg, miss_restore_name);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +0000508 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
509 __ JumpIfSmi(value_reg, miss_restore_name);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000510 } else if (FLAG_track_double_fields && representation.IsDouble()) {
511 Label do_store, heap_number;
512 __ LoadRoot(scratch3, Heap::kHeapNumberMapRootIndex);
513 __ AllocateHeapNumber(storage_reg, scratch1, scratch2, scratch3, slow);
514
515 __ JumpIfNotSmi(value_reg, &heap_number);
516 __ SmiUntag(scratch1, value_reg);
517 __ mtc1(scratch1, f6);
518 __ cvt_d_w(f4, f6);
519 __ jmp(&do_store);
520
521 __ bind(&heap_number);
522 __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex,
523 miss_restore_name, DONT_DO_SMI_CHECK);
524 __ ldc1(f4, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
525
526 __ bind(&do_store);
527 __ sdc1(f4, FieldMemOperand(storage_reg, HeapNumber::kValueOffset));
528 }
529
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000530 // Stub never generated for non-global objects that require access
531 // checks.
532 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
533
534 // Perform map transition for the receiver if necessary.
danno@chromium.orgfe578672013-06-15 14:38:35 +0000535 if (object->map()->unused_property_fields() == 0) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000536 // The properties must be extended before we can store the value.
537 // We jump to a runtime call that extends the properties array.
538 __ push(receiver_reg);
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000539 __ li(a2, Operand(transition));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000540 __ Push(a2, a0);
541 __ TailCallExternalReference(
542 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
543 masm->isolate()),
544 3, 1);
545 return;
546 }
547
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000548 // Update the map of the object.
549 __ li(scratch1, Operand(transition));
550 __ sw(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
verwaest@chromium.org37141392012-05-31 13:27:02 +0000551
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000552 // Update the write barrier for the map field and pass the now unused
553 // name_reg as scratch register.
554 __ RecordWriteField(receiver_reg,
555 HeapObject::kMapOffset,
556 scratch1,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000557 scratch2,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000558 kRAHasNotBeenSaved,
559 kDontSaveFPRegs,
560 OMIT_REMEMBERED_SET,
561 OMIT_SMI_CHECK);
562
563 int index = transition->instance_descriptors()->GetFieldIndex(
564 transition->LastAdded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000565
566 // Adjust for the number of properties stored in the object. Even in the
567 // face of a transition we can use the old map here because the size of the
568 // object and the number of in-object properties is not going to change.
569 index -= object->map()->inobject_properties();
570
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000571 // TODO(verwaest): Share this code as a code stub.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000572 SmiCheck smi_check = representation.IsTagged()
573 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000574 if (index < 0) {
575 // Set the property straight into the object.
576 int offset = object->map()->instance_size() + (index * kPointerSize);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000577 if (FLAG_track_double_fields && representation.IsDouble()) {
578 __ sw(storage_reg, FieldMemOperand(receiver_reg, offset));
579 } else {
580 __ sw(value_reg, FieldMemOperand(receiver_reg, offset));
581 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000582
danno@chromium.orgf005df62013-04-30 16:36:45 +0000583 if (!FLAG_track_fields || !representation.IsSmi()) {
584 // Skip updating write barrier if storing a smi.
585 __ JumpIfSmi(value_reg, &exit);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000586
danno@chromium.orgf005df62013-04-30 16:36:45 +0000587 // Update the write barrier for the array address.
588 // Pass the now unused name_reg as a scratch register.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000589 if (!FLAG_track_double_fields || !representation.IsDouble()) {
590 __ mov(name_reg, value_reg);
591 } else {
592 ASSERT(storage_reg.is(name_reg));
593 }
danno@chromium.orgf005df62013-04-30 16:36:45 +0000594 __ RecordWriteField(receiver_reg,
595 offset,
596 name_reg,
597 scratch1,
598 kRAHasNotBeenSaved,
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 } else {
604 // Write to the properties array.
605 int offset = index * kPointerSize + FixedArray::kHeaderSize;
606 // Get the properties array
607 __ lw(scratch1,
608 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000609 if (FLAG_track_double_fields && representation.IsDouble()) {
610 __ sw(storage_reg, FieldMemOperand(scratch1, offset));
611 } else {
612 __ sw(value_reg, FieldMemOperand(scratch1, offset));
613 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000614
danno@chromium.orgf005df62013-04-30 16:36:45 +0000615 if (!FLAG_track_fields || !representation.IsSmi()) {
616 // Skip updating write barrier if storing a smi.
617 __ JumpIfSmi(value_reg, &exit);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000618
danno@chromium.orgf005df62013-04-30 16:36:45 +0000619 // Update the write barrier for the array address.
620 // Ok to clobber receiver_reg and name_reg, since we return.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000621 if (!FLAG_track_double_fields || !representation.IsDouble()) {
622 __ mov(name_reg, value_reg);
623 } else {
624 ASSERT(storage_reg.is(name_reg));
625 }
danno@chromium.orgf005df62013-04-30 16:36:45 +0000626 __ RecordWriteField(scratch1,
627 offset,
628 name_reg,
629 receiver_reg,
630 kRAHasNotBeenSaved,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000631 kDontSaveFPRegs,
632 EMIT_REMEMBERED_SET,
633 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000634 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000635 }
636
637 // Return the value (register v0).
638 ASSERT(value_reg.is(a0));
639 __ bind(&exit);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000640 __ Ret(USE_DELAY_SLOT);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000641 __ mov(v0, a0);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000642}
643
644
645// Generate StoreField code, value is passed in a0 register.
646// When leaving generated code after success, the receiver_reg and name_reg
647// may be clobbered. Upon branch to miss_label, the receiver and name
648// registers have their original values.
649void StubCompiler::GenerateStoreField(MacroAssembler* masm,
650 Handle<JSObject> object,
651 LookupResult* lookup,
652 Register receiver_reg,
653 Register name_reg,
654 Register value_reg,
655 Register scratch1,
656 Register scratch2,
657 Label* miss_label) {
658 // a0 : value
659 Label exit;
660
661 // Check that the map of the object hasn't changed.
662 __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000663 DO_SMI_CHECK);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000664
665 // Perform global security token check if needed.
666 if (object->IsJSGlobalProxy()) {
667 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
668 }
669
670 // Stub never generated for non-global objects that require access
671 // checks.
672 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
673
674 int index = lookup->GetFieldIndex().field_index();
675
676 // Adjust for the number of properties stored in the object. Even in the
677 // face of a transition we can use the old map here because the size of the
678 // object and the number of in-object properties is not going to change.
679 index -= object->map()->inobject_properties();
680
danno@chromium.orgf005df62013-04-30 16:36:45 +0000681 Representation representation = lookup->representation();
682 ASSERT(!representation.IsNone());
683 if (FLAG_track_fields && representation.IsSmi()) {
684 __ JumpIfNotSmi(value_reg, miss_label);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +0000685 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
686 __ JumpIfSmi(value_reg, miss_label);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000687 } else if (FLAG_track_double_fields && representation.IsDouble()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000688 // Load the double storage.
689 if (index < 0) {
690 int offset = object->map()->instance_size() + (index * kPointerSize);
691 __ lw(scratch1, FieldMemOperand(receiver_reg, offset));
692 } else {
693 __ lw(scratch1,
694 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
695 int offset = index * kPointerSize + FixedArray::kHeaderSize;
696 __ lw(scratch1, FieldMemOperand(scratch1, offset));
697 }
698
699 // Store the value into the storage.
700 Label do_store, heap_number;
701 __ JumpIfNotSmi(value_reg, &heap_number);
702 __ SmiUntag(scratch2, value_reg);
703 __ mtc1(scratch2, f6);
704 __ cvt_d_w(f4, f6);
705 __ jmp(&do_store);
706
707 __ bind(&heap_number);
708 __ CheckMap(value_reg, scratch2, Heap::kHeapNumberMapRootIndex,
danno@chromium.orgf005df62013-04-30 16:36:45 +0000709 miss_label, DONT_DO_SMI_CHECK);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000710 __ ldc1(f4, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
711
danno@chromium.orgf005df62013-04-30 16:36:45 +0000712 __ bind(&do_store);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000713 __ sdc1(f4, FieldMemOperand(scratch1, HeapNumber::kValueOffset));
714 // Return the value (register v0).
715 ASSERT(value_reg.is(a0));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000716 __ Ret(USE_DELAY_SLOT);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000717 __ mov(v0, a0);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000718 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +0000719 }
720
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000721 // TODO(verwaest): Share this code as a code stub.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000722 SmiCheck smi_check = representation.IsTagged()
723 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000724 if (index < 0) {
725 // Set the property straight into the object.
726 int offset = object->map()->instance_size() + (index * kPointerSize);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000727 __ sw(value_reg, FieldMemOperand(receiver_reg, offset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000728
danno@chromium.orgf005df62013-04-30 16:36:45 +0000729 if (!FLAG_track_fields || !representation.IsSmi()) {
730 // Skip updating write barrier if storing a smi.
731 __ JumpIfSmi(value_reg, &exit);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000732
danno@chromium.orgf005df62013-04-30 16:36:45 +0000733 // Update the write barrier for the array address.
734 // Pass the now unused name_reg as a scratch register.
735 __ mov(name_reg, value_reg);
736 __ RecordWriteField(receiver_reg,
737 offset,
738 name_reg,
739 scratch1,
740 kRAHasNotBeenSaved,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000741 kDontSaveFPRegs,
742 EMIT_REMEMBERED_SET,
743 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000744 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000745 } else {
746 // Write to the properties array.
747 int offset = index * kPointerSize + FixedArray::kHeaderSize;
748 // Get the properties array.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000749 __ lw(scratch1,
750 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000751 __ sw(value_reg, FieldMemOperand(scratch1, offset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000752
danno@chromium.orgf005df62013-04-30 16:36:45 +0000753 if (!FLAG_track_fields || !representation.IsSmi()) {
754 // Skip updating write barrier if storing a smi.
755 __ JumpIfSmi(value_reg, &exit);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000756
danno@chromium.orgf005df62013-04-30 16:36:45 +0000757 // Update the write barrier for the array address.
758 // Ok to clobber receiver_reg and name_reg, since we return.
759 __ mov(name_reg, value_reg);
760 __ RecordWriteField(scratch1,
761 offset,
762 name_reg,
763 receiver_reg,
764 kRAHasNotBeenSaved,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000765 kDontSaveFPRegs,
766 EMIT_REMEMBERED_SET,
767 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000768 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000769 }
770
771 // Return the value (register v0).
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000772 ASSERT(value_reg.is(a0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000773 __ bind(&exit);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000774 __ Ret(USE_DELAY_SLOT);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000775 __ mov(v0, a0);
ager@chromium.org5c838252010-02-19 08:53:10 +0000776}
777
778
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000779void BaseStoreStubCompiler::GenerateRestoreName(MacroAssembler* masm,
780 Label* label,
781 Handle<Name> name) {
782 if (!label->is_unused()) {
783 __ bind(label);
784 __ li(this->name(), Operand(name));
785 }
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000786}
787
788
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000789static void GenerateCallFunction(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000790 Handle<Object> object,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000791 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000792 Label* miss,
793 Code::ExtraICState extra_ic_state) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000794 // ----------- S t a t e -------------
795 // -- a0: receiver
796 // -- a1: function to call
797 // -----------------------------------
798 // Check that the function really is a function.
799 __ JumpIfSmi(a1, miss);
800 __ GetObjectType(a1, a3, a3);
801 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
802
803 // Patch the receiver on the stack with the global proxy if
804 // necessary.
805 if (object->IsGlobalObject()) {
806 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
807 __ sw(a3, MemOperand(sp, arguments.immediate() * kPointerSize));
808 }
809
810 // Invoke the function.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000811 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
812 ? CALL_AS_FUNCTION
813 : CALL_AS_METHOD;
814 __ InvokeFunction(a1, arguments, JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000815}
816
817
818static void PushInterceptorArguments(MacroAssembler* masm,
819 Register receiver,
820 Register holder,
821 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000822 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000823 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000824 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
825 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000826 Register scratch = name;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000827 __ li(scratch, Operand(interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000828 __ Push(scratch, receiver, holder);
829 __ lw(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
830 __ push(scratch);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000831 __ li(scratch, Operand(ExternalReference::isolate_address(masm->isolate())));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000832 __ push(scratch);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000833}
834
835
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000836static void CompileCallLoadPropertyWithInterceptor(
837 MacroAssembler* masm,
838 Register receiver,
839 Register holder,
840 Register name,
841 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000842 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
843
844 ExternalReference ref =
845 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
846 masm->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000847 __ PrepareCEntryArgs(6);
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000848 __ PrepareCEntryFunction(ref);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000849
850 CEntryStub stub(1);
851 __ CallStub(&stub);
852}
853
854
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000855static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000856
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000857// Reserves space for the extra arguments to API function in the
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000858// caller's frame.
859//
860// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
861static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
862 Register scratch) {
863 ASSERT(Smi::FromInt(0) == 0);
864 for (int i = 0; i < kFastApiCallArguments; i++) {
865 __ push(zero_reg);
866 }
867}
868
869
870// Undoes the effects of ReserveSpaceForFastApiCall.
871static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
872 __ Drop(kFastApiCallArguments);
873}
874
875
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000876static void GenerateFastApiDirectCall(MacroAssembler* masm,
877 const CallOptimization& optimization,
878 int argc) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000879 // ----------- S t a t e -------------
880 // -- sp[0] : holder (set by CheckPrototypes)
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000881 // -- sp[4] : callee JS function
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000882 // -- sp[8] : call data
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000883 // -- sp[12] : isolate
palfia@homejinni.com79d0bf72013-06-10 19:35:04 +0000884 // -- sp[16] : ReturnValue default value
885 // -- sp[20] : ReturnValue
886 // -- sp[24] : last JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000887 // -- ...
palfia@homejinni.com79d0bf72013-06-10 19:35:04 +0000888 // -- sp[(argc + 5) * 4] : first JS argument
889 // -- sp[(argc + 6) * 4] : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000890 // -----------------------------------
891 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000892 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000893 __ LoadHeapObject(t1, function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000894 __ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset));
895
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000896 // Pass the additional arguments.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000897 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000898 Handle<Object> call_data(api_call_info->data(), masm->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000899 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
900 __ li(a0, api_call_info);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000901 __ lw(t2, FieldMemOperand(a0, CallHandlerInfo::kDataOffset));
902 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000903 __ li(t2, call_data);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000904 }
905
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000906 __ li(t3, Operand(ExternalReference::isolate_address(masm->isolate())));
palfia@homejinni.com79d0bf72013-06-10 19:35:04 +0000907 // Store JS function, call data, isolate ReturnValue default and ReturnValue.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000908 __ sw(t1, MemOperand(sp, 1 * kPointerSize));
909 __ sw(t2, MemOperand(sp, 2 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000910 __ sw(t3, MemOperand(sp, 3 * kPointerSize));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000911 __ LoadRoot(t1, Heap::kUndefinedValueRootIndex);
912 __ sw(t1, MemOperand(sp, 4 * kPointerSize));
palfia@homejinni.com79d0bf72013-06-10 19:35:04 +0000913 __ sw(t1, MemOperand(sp, 5 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000914
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000915 // Prepare arguments.
palfia@homejinni.com79d0bf72013-06-10 19:35:04 +0000916 __ Addu(a2, sp, Operand(5 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000917
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000918 // Allocate the v8::Arguments structure in the arguments' space since
919 // it's not controlled by GC.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000920 const int kApiStackSpace = 4;
921
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000922 FrameScope frame_scope(masm, StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000923 __ EnterExitFrame(false, kApiStackSpace);
924
925 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
926 // struct from the function (which is currently the case). This means we pass
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +0000927 // the first argument in a1 instead of a0, if returns_handle is true.
928 // CallApiFunctionAndReturn will set up a0.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000929
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000930 Address function_address = v8::ToCData<Address>(api_call_info->callback());
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000931 bool returns_handle =
932 !CallbackTable::ReturnsVoid(masm->isolate(), function_address);
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +0000933
934 Register first_arg = returns_handle ? a1 : a0;
935
936 // first_arg = v8::Arguments&
937 // Arguments is built at sp + 1 (sp is a reserved spot for ra).
938 __ Addu(first_arg, sp, kPointerSize);
939
940 // v8::Arguments::implicit_args_
941 __ sw(a2, MemOperand(first_arg, 0 * kPointerSize));
942 // v8::Arguments::values_
943 __ Addu(t0, a2, Operand(argc * kPointerSize));
944 __ sw(t0, MemOperand(first_arg, 1 * kPointerSize));
945 // v8::Arguments::length_ = argc
946 __ li(t0, Operand(argc));
947 __ sw(t0, MemOperand(first_arg, 2 * kPointerSize));
948 // v8::Arguments::is_construct_call = 0
949 __ sw(zero_reg, MemOperand(first_arg, 3 * kPointerSize));
950
951 const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000952 ApiFunction fun(function_address);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000953 ExternalReference::Type type =
954 returns_handle ?
955 ExternalReference::DIRECT_API_CALL :
956 ExternalReference::DIRECT_API_CALL_NEW;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000957 ExternalReference ref =
958 ExternalReference(&fun,
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000959 type,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000960 masm->isolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000961 AllowExternalCallThatCantCauseGC scope(masm);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000962 __ CallApiFunctionAndReturn(ref,
963 kStackUnwindSpace,
964 returns_handle,
965 kFastApiCallArguments + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000966}
967
lrn@chromium.org7516f052011-03-30 08:52:27 +0000968class CallInterceptorCompiler BASE_EMBEDDED {
969 public:
970 CallInterceptorCompiler(StubCompiler* stub_compiler,
971 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000972 Register name,
973 Code::ExtraICState extra_ic_state)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000974 : stub_compiler_(stub_compiler),
975 arguments_(arguments),
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000976 name_(name),
977 extra_ic_state_(extra_ic_state) {}
lrn@chromium.org7516f052011-03-30 08:52:27 +0000978
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000979 void Compile(MacroAssembler* masm,
980 Handle<JSObject> object,
981 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000982 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000983 LookupResult* lookup,
984 Register receiver,
985 Register scratch1,
986 Register scratch2,
987 Register scratch3,
988 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000989 ASSERT(holder->HasNamedInterceptor());
990 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
991
992 // Check that the receiver isn't a smi.
993 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000994 CallOptimization optimization(lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000995 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000996 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
997 holder, lookup, name, optimization, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000998 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000999 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
1000 name, holder, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001001 }
1002 }
1003
1004 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001005 void CompileCacheable(MacroAssembler* masm,
1006 Handle<JSObject> object,
1007 Register receiver,
1008 Register scratch1,
1009 Register scratch2,
1010 Register scratch3,
1011 Handle<JSObject> interceptor_holder,
1012 LookupResult* lookup,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001013 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001014 const CallOptimization& optimization,
1015 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001016 ASSERT(optimization.is_constant_call());
1017 ASSERT(!lookup->holder()->IsGlobalObject());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001018 Counters* counters = masm->isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001019 int depth1 = kInvalidProtoDepth;
1020 int depth2 = kInvalidProtoDepth;
1021 bool can_do_fast_api_call = false;
1022 if (optimization.is_simple_api_call() &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001023 !lookup->holder()->IsGlobalObject()) {
1024 depth1 = optimization.GetPrototypeDepthOfExpectedType(
1025 object, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001026 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001027 depth2 = optimization.GetPrototypeDepthOfExpectedType(
1028 interceptor_holder, Handle<JSObject>(lookup->holder()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001029 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001030 can_do_fast_api_call =
1031 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001032 }
1033
1034 __ IncrementCounter(counters->call_const_interceptor(), 1,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001035 scratch1, scratch2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001036
1037 if (can_do_fast_api_call) {
1038 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
1039 scratch1, scratch2);
1040 ReserveSpaceForFastApiCall(masm, scratch1);
1041 }
1042
1043 // Check that the maps from receiver to interceptor's holder
1044 // haven't changed and thus we can invoke interceptor.
1045 Label miss_cleanup;
1046 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
1047 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001048 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
1049 scratch1, scratch2, scratch3,
1050 name, depth1, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001051
1052 // Invoke an interceptor and if it provides a value,
1053 // branch to |regular_invoke|.
1054 Label regular_invoke;
1055 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
1056 &regular_invoke);
1057
1058 // Interceptor returned nothing for this property. Try to use cached
1059 // constant function.
1060
1061 // Check that the maps from interceptor's holder to constant function's
1062 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001063 if (*interceptor_holder != lookup->holder()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001064 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001065 Handle<JSObject>(lookup->holder()),
1066 scratch1, scratch2, scratch3,
1067 name, depth2, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001068 } else {
1069 // CheckPrototypes has a side effect of fetching a 'holder'
1070 // for API (object which is instanceof for the signature). It's
1071 // safe to omit it here, as if present, it should be fetched
1072 // by the previous CheckPrototypes.
1073 ASSERT(depth2 == kInvalidProtoDepth);
1074 }
1075
1076 // Invoke function.
1077 if (can_do_fast_api_call) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001078 GenerateFastApiDirectCall(masm, optimization, arguments_.immediate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001079 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001080 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
1081 ? CALL_AS_FUNCTION
1082 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001083 Handle<JSFunction> function = optimization.constant_function();
1084 ParameterCount expected(function);
1085 __ InvokeFunction(function, expected, arguments_,
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001086 JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001087 }
1088
1089 // Deferred code for fast API call case---clean preallocated space.
1090 if (can_do_fast_api_call) {
1091 __ bind(&miss_cleanup);
1092 FreeSpaceForFastApiCall(masm);
1093 __ Branch(miss_label);
1094 }
1095
1096 // Invoke a regular function.
1097 __ bind(&regular_invoke);
1098 if (can_do_fast_api_call) {
1099 FreeSpaceForFastApiCall(masm);
1100 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00001101 }
1102
1103 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001104 Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001105 Register receiver,
1106 Register scratch1,
1107 Register scratch2,
1108 Register scratch3,
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001109 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001110 Handle<JSObject> interceptor_holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001111 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001112 Register holder =
1113 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001114 scratch1, scratch2, scratch3,
1115 name, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001116
1117 // Call a runtime function to load the interceptor property.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001118 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001119 // Save the name_ register across the call.
1120 __ push(name_);
1121
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001122 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001123
1124 __ CallExternalReference(
1125 ExternalReference(
1126 IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
1127 masm->isolate()),
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001128 6);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001129 // Restore the name_ register.
1130 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001131 // Leave the internal frame.
lrn@chromium.org7516f052011-03-30 08:52:27 +00001132 }
1133
1134 void LoadWithInterceptor(MacroAssembler* masm,
1135 Register receiver,
1136 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001137 Handle<JSObject> holder_obj,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001138 Register scratch,
1139 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001140 {
1141 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001142
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001143 __ Push(holder, name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001144 CompileCallLoadPropertyWithInterceptor(masm,
1145 receiver,
1146 holder,
1147 name_,
1148 holder_obj);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001149 __ pop(name_); // Restore the name.
1150 __ pop(receiver); // Restore the holder.
1151 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001152 // If interceptor returns no-result sentinel, call the constant function.
1153 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
1154 __ Branch(interceptor_succeeded, ne, v0, Operand(scratch));
lrn@chromium.org7516f052011-03-30 08:52:27 +00001155 }
1156
1157 StubCompiler* stub_compiler_;
1158 const ParameterCount& arguments_;
1159 Register name_;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001160 Code::ExtraICState extra_ic_state_;
lrn@chromium.org7516f052011-03-30 08:52:27 +00001161};
1162
1163
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001164// Calls GenerateCheckPropertyCell for each global object in the prototype chain
1165// from object to (but not including) holder.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001166static void GenerateCheckPropertyCells(MacroAssembler* masm,
1167 Handle<JSObject> object,
1168 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001169 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001170 Register scratch,
1171 Label* miss) {
1172 Handle<JSObject> current = object;
1173 while (!current.is_identical_to(holder)) {
1174 if (current->IsGlobalObject()) {
1175 GenerateCheckPropertyCell(masm,
1176 Handle<GlobalObject>::cast(current),
1177 name,
1178 scratch,
1179 miss);
1180 }
1181 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
1182 }
1183}
1184
1185
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001186// Convert and store int passed in register ival to IEEE 754 single precision
1187// floating point value at memory location (dst + 4 * wordoffset)
1188// If FPU is available use it for conversion.
1189static void StoreIntAsFloat(MacroAssembler* masm,
1190 Register dst,
1191 Register wordoffset,
1192 Register ival,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001193 Register scratch1) {
1194 __ mtc1(ival, f0);
1195 __ cvt_s_w(f0, f0);
1196 __ sll(scratch1, wordoffset, 2);
1197 __ addu(scratch1, dst, scratch1);
1198 __ swc1(f0, MemOperand(scratch1, 0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001199}
1200
1201
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001202void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001203 __ Jump(code, RelocInfo::CODE_TARGET);
1204}
1205
1206
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001207#undef __
1208#define __ ACCESS_MASM(masm())
1209
1210
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001211Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
1212 Register object_reg,
1213 Handle<JSObject> holder,
1214 Register holder_reg,
1215 Register scratch1,
1216 Register scratch2,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001217 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001218 int save_at_depth,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001219 Label* miss,
1220 PrototypeCheckType check) {
1221 Handle<JSObject> first = object;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001222 // Make sure there's no overlap between holder and object registers.
1223 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1224 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1225 && !scratch2.is(scratch1));
1226
1227 // Keep track of the current object in register reg.
1228 Register reg = object_reg;
1229 int depth = 0;
1230
1231 if (save_at_depth == depth) {
1232 __ sw(reg, MemOperand(sp));
1233 }
1234
1235 // Check the maps in the prototype chain.
1236 // Traverse the prototype chain from the object and do map checks.
1237 Handle<JSObject> current = object;
1238 while (!current.is_identical_to(holder)) {
1239 ++depth;
1240
1241 // Only global objects and objects that do not require access
1242 // checks are allowed in stubs.
1243 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1244
1245 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
1246 if (!current->HasFastProperties() &&
1247 !current->IsJSGlobalObject() &&
1248 !current->IsJSGlobalProxy()) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001249 if (!name->IsUniqueName()) {
1250 ASSERT(name->IsString());
1251 name = factory()->InternalizeString(Handle<String>::cast(name));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001252 }
1253 ASSERT(current->property_dictionary()->FindEntry(*name) ==
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001254 NameDictionary::kNotFound);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001255
1256 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1257 scratch1, scratch2);
1258
1259 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1260 reg = holder_reg; // From now on the object will be in holder_reg.
1261 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1262 } else {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001263 Register map_reg = scratch1;
1264 if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) {
1265 Handle<Map> current_map(current->map());
1266 // CheckMap implicitly loads the map of |reg| into |map_reg|.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001267 __ CheckMap(reg, map_reg, current_map, miss, DONT_DO_SMI_CHECK);
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001268 } else {
1269 __ lw(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
1270 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001271 // Check access rights to the global object. This has to happen after
1272 // the map check so that we know that the object is actually a global
1273 // object.
1274 if (current->IsJSGlobalProxy()) {
1275 __ CheckAccessGlobalProxy(reg, scratch2, miss);
1276 }
1277 reg = holder_reg; // From now on the object will be in holder_reg.
1278
1279 if (heap()->InNewSpace(*prototype)) {
1280 // The prototype is in new space; we cannot store a reference to it
1281 // in the code. Load it from the map.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001282 __ lw(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001283 } else {
1284 // The prototype is in old space; load it directly.
1285 __ li(reg, Operand(prototype));
1286 }
1287 }
1288
1289 if (save_at_depth == depth) {
1290 __ sw(reg, MemOperand(sp));
1291 }
1292
1293 // Go to the next object in the prototype chain.
1294 current = prototype;
1295 }
1296
1297 // Log the check depth.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001298 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001299
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001300 if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) {
1301 // Check the holder map.
1302 __ CheckMap(reg, scratch1, Handle<Map>(holder->map()), miss,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001303 DONT_DO_SMI_CHECK);
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001304 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001305
1306 // Perform security check for access to the global object.
1307 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1308 if (holder->IsJSGlobalProxy()) {
1309 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1310 }
1311
1312 // If we've skipped any global objects, it's not enough to verify that
1313 // their maps haven't changed. We also need to check that the property
1314 // cell for the property is still empty.
1315 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1316
1317 // Return the register containing the holder.
1318 return reg;
1319}
1320
1321
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001322void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success,
1323 Label* miss) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001324 if (!miss->is_unused()) {
1325 __ Branch(success);
1326 __ bind(miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001327 TailCallBuiltin(masm(), MissBuiltin(kind()));
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001328 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001329}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001330
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001331
1332Register BaseLoadStubCompiler::CallbackHandlerFrontend(
1333 Handle<JSObject> object,
1334 Register object_reg,
1335 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001336 Handle<Name> name,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001337 Label* success,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001338 Handle<ExecutableAccessorInfo> callback) {
1339 Label miss;
1340
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001341 Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001342
1343 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
1344 ASSERT(!reg.is(scratch2()));
1345 ASSERT(!reg.is(scratch3()));
1346 ASSERT(!reg.is(scratch4()));
1347
1348 // Load the properties dictionary.
1349 Register dictionary = scratch4();
1350 __ lw(dictionary, FieldMemOperand(reg, JSObject::kPropertiesOffset));
1351
1352 // Probe the dictionary.
1353 Label probe_done;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001354 NameDictionaryLookupStub::GeneratePositiveLookup(masm(),
1355 &miss,
1356 &probe_done,
1357 dictionary,
1358 this->name(),
1359 scratch2(),
1360 scratch3());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001361 __ bind(&probe_done);
1362
1363 // If probing finds an entry in the dictionary, scratch3 contains the
1364 // pointer into the dictionary. Check that the value is the callback.
1365 Register pointer = scratch3();
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001366 const int kElementsStartOffset = NameDictionary::kHeaderSize +
1367 NameDictionary::kElementsStartIndex * kPointerSize;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001368 const int kValueOffset = kElementsStartOffset + kPointerSize;
1369 __ lw(scratch2(), FieldMemOperand(pointer, kValueOffset));
1370 __ Branch(&miss, ne, scratch2(), Operand(callback));
1371 }
1372
1373 HandlerFrontendFooter(success, &miss);
1374 return reg;
1375}
1376
1377
1378void BaseLoadStubCompiler::NonexistentHandlerFrontend(
1379 Handle<JSObject> object,
1380 Handle<JSObject> last,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001381 Handle<Name> name,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001382 Label* success,
1383 Handle<GlobalObject> global) {
1384 Label miss;
1385
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001386 HandlerFrontendHeader(object, receiver(), last, name, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001387
1388 // If the last object in the prototype chain is a global object,
1389 // check that the global property cell is empty.
1390 if (!global.is_null()) {
1391 GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
1392 }
1393
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001394 HandlerFrontendFooter(success, &miss);
1395}
1396
1397
1398void BaseLoadStubCompiler::GenerateLoadField(Register reg,
1399 Handle<JSObject> holder,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001400 PropertyIndex field,
1401 Representation representation) {
1402 if (!reg.is(receiver())) __ mov(receiver(), reg);
1403 if (kind() == Code::LOAD_IC) {
1404 LoadFieldStub stub(field.is_inobject(holder),
1405 field.translate(holder),
1406 representation);
1407 GenerateTailCall(masm(), stub.GetCode(isolate()));
1408 } else {
1409 KeyedLoadFieldStub stub(field.is_inobject(holder),
1410 field.translate(holder),
1411 representation);
1412 GenerateTailCall(masm(), stub.GetCode(isolate()));
1413 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001414}
1415
1416
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001417void BaseLoadStubCompiler::GenerateLoadConstant(Handle<JSFunction> value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001418 // Return the constant value.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001419 __ LoadHeapObject(v0, value);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001420 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001421}
1422
1423
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001424void BaseLoadStubCompiler::GenerateLoadCallback(
1425 Register reg,
1426 Handle<ExecutableAccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001427 // Build AccessorInfo::args_ list on the stack and push property name below
1428 // the exit frame to make GC aware of them and store pointers to them.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001429 __ push(receiver());
1430 __ mov(scratch2(), sp); // scratch2 = AccessorInfo::args_
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001431 if (heap()->InNewSpace(callback->data())) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001432 __ li(scratch3(), callback);
1433 __ lw(scratch3(), FieldMemOperand(scratch3(),
1434 ExecutableAccessorInfo::kDataOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001435 } else {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001436 __ li(scratch3(), Handle<Object>(callback->data(), isolate()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001437 }
palfia@homejinni.com79d0bf72013-06-10 19:35:04 +00001438 __ Subu(sp, sp, 6 * kPointerSize);
1439 __ sw(reg, MemOperand(sp, 5 * kPointerSize));
1440 __ sw(scratch3(), MemOperand(sp, 4 * kPointerSize));
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00001441 __ LoadRoot(scratch3(), Heap::kUndefinedValueRootIndex);
palfia@homejinni.com79d0bf72013-06-10 19:35:04 +00001442 __ sw(scratch3(), MemOperand(sp, 3 * kPointerSize));
1443 __ sw(scratch3(), MemOperand(sp, 2 * kPointerSize));
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00001444 __ li(scratch4(),
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001445 Operand(ExternalReference::isolate_address(isolate())));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001446 __ sw(scratch4(), MemOperand(sp, 1 * kPointerSize));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001447 __ sw(name(), MemOperand(sp, 0 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001448
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00001449 Address getter_address = v8::ToCData<Address>(callback->getter());
1450 bool returns_handle =
1451 !CallbackTable::ReturnsVoid(isolate(), getter_address);
1452
1453 Register first_arg = returns_handle ? a1 : a0;
1454 Register second_arg = returns_handle ? a2 : a1;
1455
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001456 __ mov(a2, scratch2()); // Saved in case scratch2 == a1.
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00001457 __ mov(first_arg, sp); // (first argument - see note below) = Handle<Name>
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001458
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001459 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
1460 // struct from the function (which is currently the case). This means we pass
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00001461 // the arguments in a1-a2 instead of a0-a1, if returns_handle is true.
1462 // CallApiFunctionAndReturn will set up a0.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001463
1464 const int kApiStackSpace = 1;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001465 FrameScope frame_scope(masm(), StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001466 __ EnterExitFrame(false, kApiStackSpace);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001467
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001468 // Create AccessorInfo instance on the stack above the exit frame with
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001469 // scratch2 (internal::Object** args_) as the data.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001470 __ sw(a2, MemOperand(sp, kPointerSize));
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00001471 // (second argument - see note above) = AccessorInfo&
1472 __ Addu(second_arg, sp, kPointerSize);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001473
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001474 const int kStackUnwindSpace = kFastApiCallArguments + 1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001475 ApiFunction fun(getter_address);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001476 ExternalReference::Type type =
1477 returns_handle ?
1478 ExternalReference::DIRECT_GETTER_CALL :
1479 ExternalReference::DIRECT_GETTER_CALL_NEW;
svenpanne@chromium.org42bcd8e2013-06-14 14:05:05 +00001480
danno@chromium.orgfe578672013-06-15 14:38:35 +00001481 ExternalReference ref = ExternalReference(&fun, type, isolate());
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001482 __ CallApiFunctionAndReturn(ref,
1483 kStackUnwindSpace,
1484 returns_handle,
palfia@homejinni.com79d0bf72013-06-10 19:35:04 +00001485 5);
ager@chromium.org5c838252010-02-19 08:53:10 +00001486}
1487
1488
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001489void BaseLoadStubCompiler::GenerateLoadInterceptor(
1490 Register holder_reg,
1491 Handle<JSObject> object,
1492 Handle<JSObject> interceptor_holder,
1493 LookupResult* lookup,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001494 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001495 ASSERT(interceptor_holder->HasNamedInterceptor());
1496 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1497
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001498 // So far the most popular follow ups for interceptor loads are FIELD
1499 // and CALLBACKS, so inline only them, other cases may be added
1500 // later.
1501 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001502 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001503 if (lookup->IsField()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001504 compile_followup_inline = true;
1505 } else if (lookup->type() == CALLBACKS &&
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001506 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
1507 ExecutableAccessorInfo* callback =
1508 ExecutableAccessorInfo::cast(lookup->GetCallbackObject());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001509 compile_followup_inline = callback->getter() != NULL &&
1510 callback->IsCompatibleReceiver(*object);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001511 }
1512 }
1513
1514 if (compile_followup_inline) {
1515 // Compile the interceptor call, followed by inline code to load the
1516 // property from further up the prototype chain if the call fails.
1517 // Check that the maps haven't changed.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001518 ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001519
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001520 // Preserve the receiver register explicitly whenever it is different from
1521 // the holder and it is needed should the interceptor return without any
1522 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1523 // the FIELD case might cause a miss during the prototype check.
1524 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001525 bool must_preserve_receiver_reg = !receiver().is(holder_reg) &&
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001526 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1527
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001528 // Save necessary data before invoking an interceptor.
1529 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001530 {
1531 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001532 if (must_preserve_receiver_reg) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001533 __ Push(receiver(), holder_reg, this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001534 } else {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001535 __ Push(holder_reg, this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001536 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001537 // Invoke an interceptor. Note: map checks from receiver to
1538 // interceptor's holder has been compiled before (see a caller
1539 // of this method).
1540 CompileCallLoadPropertyWithInterceptor(masm(),
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001541 receiver(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001542 holder_reg,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001543 this->name(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001544 interceptor_holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001545 // Check if interceptor provided a value for property. If it's
1546 // the case, return immediately.
1547 Label interceptor_failed;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001548 __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
1549 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001550 frame_scope.GenerateLeaveFrame();
1551 __ Ret();
1552
1553 __ bind(&interceptor_failed);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001554 __ pop(this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001555 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001556 if (must_preserve_receiver_reg) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001557 __ pop(receiver());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001558 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001559 // Leave the internal frame.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001560 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001561 GenerateLoadPostInterceptor(holder_reg, interceptor_holder, name, lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001562 } else { // !compile_followup_inline
1563 // Call the runtime system to load the interceptor.
1564 // Check that the maps haven't changed.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001565 PushInterceptorArguments(masm(), receiver(), holder_reg,
1566 this->name(), interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001567
1568 ExternalReference ref = ExternalReference(
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001569 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001570 __ TailCallExternalReference(ref, 6, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001571 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001572}
1573
1574
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001575void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001576 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001577 __ Branch(miss, ne, a2, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001578 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001579}
1580
1581
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001582void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1583 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001584 Handle<Name> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001585 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001586 ASSERT(holder->IsGlobalObject());
1587
1588 // Get the number of arguments.
1589 const int argc = arguments().immediate();
1590
1591 // Get the receiver from the stack.
1592 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1593
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001594 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001595 __ JumpIfSmi(a0, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001596 CheckPrototypes(object, a0, holder, a3, a1, t0, name, miss);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001597}
1598
1599
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001600void CallStubCompiler::GenerateLoadFunctionFromCell(
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00001601 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001602 Handle<JSFunction> function,
1603 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001604 // Get the value from the cell.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001605 __ li(a3, Operand(cell));
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00001606 __ lw(a1, FieldMemOperand(a3, Cell::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001607
1608 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001609 if (heap()->InNewSpace(*function)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001610 // We can't embed a pointer to a function in new space so we have
1611 // to verify that the shared function info is unchanged. This has
1612 // the nice side effect that multiple closures based on the same
1613 // function can all use this call IC. Before we load through the
1614 // function, we have to verify that it still is a function.
1615 __ JumpIfSmi(a1, miss);
1616 __ GetObjectType(a1, a3, a3);
1617 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
1618
1619 // Check the shared function info. Make sure it hasn't changed.
1620 __ li(a3, Handle<SharedFunctionInfo>(function->shared()));
1621 __ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
1622 __ Branch(miss, ne, t0, Operand(a3));
1623 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001624 __ Branch(miss, ne, a1, Operand(function));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001625 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001626}
1627
1628
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001629void CallStubCompiler::GenerateMissBranch() {
1630 Handle<Code> code =
danno@chromium.org40cb8782011-05-25 07:58:50 +00001631 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1632 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001633 extra_state_);
1634 __ Jump(code, RelocInfo::CODE_TARGET);
1635}
1636
1637
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001638Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1639 Handle<JSObject> holder,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001640 PropertyIndex index,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001641 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001642 // ----------- S t a t e -------------
1643 // -- a2 : name
1644 // -- ra : return address
1645 // -----------------------------------
1646 Label miss;
1647
1648 GenerateNameCheck(name, &miss);
1649
1650 const int argc = arguments().immediate();
1651
1652 // Get the receiver of the function from the stack into a0.
1653 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1654 // Check that the receiver isn't a smi.
1655 __ JumpIfSmi(a0, &miss, t0);
1656
1657 // Do the right check and compute the holder register.
1658 Register reg = CheckPrototypes(object, a0, holder, a1, a3, t0, name, &miss);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001659 GenerateFastPropertyLoad(masm(), a1, reg, index.is_inobject(holder),
1660 index.translate(holder), Representation::Tagged());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001661
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001662 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001663
1664 // Handle call cache miss.
1665 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001666 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001667
1668 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001669 return GetCode(Code::FIELD, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001670}
1671
1672
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001673Handle<Code> CallStubCompiler::CompileArrayPushCall(
1674 Handle<Object> object,
1675 Handle<JSObject> holder,
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00001676 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001677 Handle<JSFunction> function,
1678 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001679 // ----------- S t a t e -------------
1680 // -- a2 : name
1681 // -- ra : return address
1682 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1683 // -- ...
1684 // -- sp[argc * 4] : receiver
1685 // -----------------------------------
1686
1687 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001688 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001689
1690 Label miss;
1691
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001692 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001693
1694 Register receiver = a1;
1695
1696 // Get the receiver from the stack.
1697 const int argc = arguments().immediate();
1698 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1699
1700 // Check that the receiver isn't a smi.
1701 __ JumpIfSmi(receiver, &miss);
1702
1703 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001704 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, a3, v0, t0,
1705 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001706
1707 if (argc == 0) {
1708 // Nothing to do, just return the length.
1709 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001710 __ DropAndRet(argc + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001711 } else {
1712 Label call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001713 if (argc == 1) { // Otherwise fall through to call the builtin.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001714 Label attempt_to_grow_elements, with_write_barrier, check_double;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001715
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001716 Register elements = t2;
1717 Register end_elements = t1;
1718 // Get the elements array of the object.
1719 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1720
1721 // Check that the elements are in fast mode and writable.
1722 __ CheckMap(elements,
1723 v0,
1724 Heap::kFixedArrayMapRootIndex,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001725 &check_double,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001726 DONT_DO_SMI_CHECK);
1727
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001728 // Get the array's length into v0 and calculate new length.
1729 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1730 STATIC_ASSERT(kSmiTagSize == 1);
1731 STATIC_ASSERT(kSmiTag == 0);
1732 __ Addu(v0, v0, Operand(Smi::FromInt(argc)));
1733
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001734 // Get the elements' length.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001735 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1736
1737 // Check if we could survive without allocation.
1738 __ Branch(&attempt_to_grow_elements, gt, v0, Operand(t0));
1739
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001740 // Check if value is a smi.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001741 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1742 __ JumpIfNotSmi(t0, &with_write_barrier);
1743
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001744 // Save new length.
1745 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1746
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001747 // Store the value.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001748 // We may need a register containing the address end_elements below,
1749 // so write back the value in end_elements.
1750 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1751 __ Addu(end_elements, elements, end_elements);
1752 const int kEndElementsOffset =
1753 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001754 __ Addu(end_elements, end_elements, kEndElementsOffset);
1755 __ sw(t0, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001756
1757 // Check for a smi.
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001758 __ DropAndRet(argc + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001759
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001760 __ bind(&check_double);
1761
1762 // Check that the elements are in fast mode and writable.
1763 __ CheckMap(elements,
1764 a0,
1765 Heap::kFixedDoubleArrayMapRootIndex,
1766 &call_builtin,
1767 DONT_DO_SMI_CHECK);
1768
1769 // Get the array's length into r0 and calculate new length.
1770 __ lw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1771 STATIC_ASSERT(kSmiTagSize == 1);
1772 STATIC_ASSERT(kSmiTag == 0);
1773 __ Addu(a0, a0, Operand(Smi::FromInt(argc)));
1774
1775 // Get the elements' length.
1776 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1777
1778 // Check if we could survive without allocation.
1779 __ Branch(&call_builtin, gt, a0, Operand(t0));
1780
1781 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1782 __ StoreNumberToDoubleElements(
1783 t0, a0, elements, a3, t1, a2, t5,
1784 &call_builtin, argc * kDoubleSize);
1785
1786 // Save new length.
1787 __ sw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1788
1789 // Check for a smi.
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001790 __ DropAndRet(argc + 1);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001791
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001792 __ bind(&with_write_barrier);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001793
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001794 __ lw(a3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1795
1796 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
1797 Label fast_object, not_fast_object;
1798 __ CheckFastObjectElements(a3, t3, &not_fast_object);
1799 __ jmp(&fast_object);
1800 // In case of fast smi-only, convert to fast object, otherwise bail out.
1801 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001802 __ CheckFastSmiElements(a3, t3, &call_builtin);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001803
1804 __ lw(t3, FieldMemOperand(t0, HeapObject::kMapOffset));
1805 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
1806 __ Branch(&call_builtin, eq, t3, Operand(at));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001807 // edx: receiver
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001808 // a3: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001809 Label try_holey_map;
1810 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001811 FAST_ELEMENTS,
1812 a3,
1813 t3,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001814 &try_holey_map);
1815 __ mov(a2, receiver);
1816 ElementsTransitionGenerator::
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001817 GenerateMapChangeElementsTransition(masm(),
1818 DONT_TRACK_ALLOCATION_SITE,
1819 NULL);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001820 __ jmp(&fast_object);
1821
1822 __ bind(&try_holey_map);
1823 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1824 FAST_HOLEY_ELEMENTS,
1825 a3,
1826 t3,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001827 &call_builtin);
1828 __ mov(a2, receiver);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001829 ElementsTransitionGenerator::
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001830 GenerateMapChangeElementsTransition(masm(),
1831 DONT_TRACK_ALLOCATION_SITE,
1832 NULL);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001833 __ bind(&fast_object);
1834 } else {
1835 __ CheckFastObjectElements(a3, a3, &call_builtin);
1836 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001837
1838 // Save new length.
1839 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1840
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001841 // Store the value.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001842 // We may need a register containing the address end_elements below,
1843 // so write back the value in end_elements.
1844 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1845 __ Addu(end_elements, elements, end_elements);
1846 __ Addu(end_elements, end_elements, kEndElementsOffset);
1847 __ sw(t0, MemOperand(end_elements));
1848
1849 __ RecordWrite(elements,
1850 end_elements,
1851 t0,
1852 kRAHasNotBeenSaved,
1853 kDontSaveFPRegs,
1854 EMIT_REMEMBERED_SET,
1855 OMIT_SMI_CHECK);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001856 __ DropAndRet(argc + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001857
1858 __ bind(&attempt_to_grow_elements);
1859 // v0: array's length + 1.
1860 // t0: elements' length.
1861
1862 if (!FLAG_inline_new) {
1863 __ Branch(&call_builtin);
1864 }
1865
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001866 __ lw(a2, MemOperand(sp, (argc - 1) * kPointerSize));
1867 // Growing elements that are SMI-only requires special handling in case
1868 // the new element is non-Smi. For now, delegate to the builtin.
1869 Label no_fast_elements_check;
1870 __ JumpIfSmi(a2, &no_fast_elements_check);
1871 __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1872 __ CheckFastObjectElements(t3, t3, &call_builtin);
1873 __ bind(&no_fast_elements_check);
1874
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001875 ExternalReference new_space_allocation_top =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001876 ExternalReference::new_space_allocation_top_address(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001877 ExternalReference new_space_allocation_limit =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001878 ExternalReference::new_space_allocation_limit_address(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001879
1880 const int kAllocationDelta = 4;
1881 // Load top and check if it is the end of elements.
1882 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1883 __ Addu(end_elements, elements, end_elements);
1884 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset));
1885 __ li(t3, Operand(new_space_allocation_top));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001886 __ lw(a3, MemOperand(t3));
1887 __ Branch(&call_builtin, ne, end_elements, Operand(a3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001888
1889 __ li(t5, Operand(new_space_allocation_limit));
1890 __ lw(t5, MemOperand(t5));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001891 __ Addu(a3, a3, Operand(kAllocationDelta * kPointerSize));
1892 __ Branch(&call_builtin, hi, a3, Operand(t5));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001893
1894 // We fit and could grow elements.
1895 // Update new_space_allocation_top.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001896 __ sw(a3, MemOperand(t3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001897 // Push the argument.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001898 __ sw(a2, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001899 // Fill the rest with holes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001900 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001901 for (int i = 1; i < kAllocationDelta; i++) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001902 __ sw(a3, MemOperand(end_elements, i * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001903 }
1904
1905 // Update elements' and array's sizes.
1906 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1907 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta)));
1908 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1909
1910 // Elements are in new space, so write barrier is not required.
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001911 __ DropAndRet(argc + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001912 }
1913 __ bind(&call_builtin);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001914 __ TailCallExternalReference(
1915 ExternalReference(Builtins::c_ArrayPush, isolate()), argc + 1, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001916 }
1917
1918 // Handle call cache miss.
1919 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001920 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001921
1922 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001923 return GetCode(function);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001924}
1925
1926
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001927Handle<Code> CallStubCompiler::CompileArrayPopCall(
1928 Handle<Object> object,
1929 Handle<JSObject> holder,
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00001930 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001931 Handle<JSFunction> function,
1932 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001933 // ----------- S t a t e -------------
1934 // -- a2 : name
1935 // -- ra : return address
1936 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1937 // -- ...
1938 // -- sp[argc * 4] : receiver
1939 // -----------------------------------
1940
1941 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001942 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001943
1944 Label miss, return_undefined, call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001945 Register receiver = a1;
1946 Register elements = a3;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001947 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001948
1949 // Get the receiver from the stack.
1950 const int argc = arguments().immediate();
1951 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001952 // Check that the receiver isn't a smi.
1953 __ JumpIfSmi(receiver, &miss);
1954
1955 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001956 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, elements,
1957 t0, v0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001958
1959 // Get the elements array of the object.
1960 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1961
1962 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001963 __ CheckMap(elements,
1964 v0,
1965 Heap::kFixedArrayMapRootIndex,
1966 &call_builtin,
1967 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001968
1969 // Get the array's length into t0 and calculate new length.
1970 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1971 __ Subu(t0, t0, Operand(Smi::FromInt(1)));
1972 __ Branch(&return_undefined, lt, t0, Operand(zero_reg));
1973
1974 // Get the last element.
1975 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1976 STATIC_ASSERT(kSmiTagSize == 1);
1977 STATIC_ASSERT(kSmiTag == 0);
1978 // We can't address the last element in one operation. Compute the more
1979 // expensive shift first, and use an offset later on.
1980 __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize);
1981 __ Addu(elements, elements, t1);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001982 __ lw(v0, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001983 __ Branch(&call_builtin, eq, v0, Operand(t2));
1984
1985 // Set the array's length.
1986 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1987
1988 // Fill with the hole.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001989 __ sw(t2, FieldMemOperand(elements, FixedArray::kHeaderSize));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001990 __ DropAndRet(argc + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001991
1992 __ bind(&return_undefined);
1993 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001994 __ DropAndRet(argc + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001995
1996 __ bind(&call_builtin);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001997 __ TailCallExternalReference(
1998 ExternalReference(Builtins::c_ArrayPop, isolate()), argc + 1, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001999
2000 // Handle call cache miss.
2001 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002002 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002003
2004 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002005 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002006}
2007
2008
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002009Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
2010 Handle<Object> object,
2011 Handle<JSObject> holder,
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002012 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002013 Handle<JSFunction> function,
2014 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002015 // ----------- S t a t e -------------
2016 // -- a2 : function name
2017 // -- ra : return address
2018 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2019 // -- ...
2020 // -- sp[argc * 4] : receiver
2021 // -----------------------------------
2022
2023 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002024 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002025
2026 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002027 Label miss;
2028 Label name_miss;
2029 Label index_out_of_range;
2030
2031 Label* index_out_of_range_label = &index_out_of_range;
2032
danno@chromium.org40cb8782011-05-25 07:58:50 +00002033 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002034 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002035 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002036 index_out_of_range_label = &miss;
2037 }
2038
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002039 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002040
2041 // Check that the maps starting from the prototype haven't changed.
2042 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2043 Context::STRING_FUNCTION_INDEX,
2044 v0,
2045 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002046 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002047 CheckPrototypes(
2048 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2049 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002050
2051 Register receiver = a1;
2052 Register index = t1;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002053 Register result = v0;
2054 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
2055 if (argc > 0) {
2056 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
2057 } else {
2058 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
2059 }
2060
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002061 StringCharCodeAtGenerator generator(receiver,
2062 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002063 result,
2064 &miss, // When not a string.
2065 &miss, // When not a number.
2066 index_out_of_range_label,
2067 STRING_INDEX_IS_NUMBER);
2068 generator.GenerateFast(masm());
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00002069 __ DropAndRet(argc + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002070
2071 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002072 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002073
2074 if (index_out_of_range.is_linked()) {
2075 __ bind(&index_out_of_range);
2076 __ LoadRoot(v0, Heap::kNanValueRootIndex);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00002077 __ DropAndRet(argc + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002078 }
2079
2080 __ bind(&miss);
2081 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002082 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002083 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002084 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002085
2086 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002087 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002088}
2089
2090
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002091Handle<Code> CallStubCompiler::CompileStringCharAtCall(
2092 Handle<Object> object,
2093 Handle<JSObject> holder,
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002094 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002095 Handle<JSFunction> function,
2096 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002097 // ----------- S t a t e -------------
2098 // -- a2 : function name
2099 // -- ra : return address
2100 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2101 // -- ...
2102 // -- sp[argc * 4] : receiver
2103 // -----------------------------------
2104
2105 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002106 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002107
2108 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002109 Label miss;
2110 Label name_miss;
2111 Label index_out_of_range;
2112 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00002113 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002114 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002115 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002116 index_out_of_range_label = &miss;
2117 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002118 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002119
2120 // Check that the maps starting from the prototype haven't changed.
2121 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2122 Context::STRING_FUNCTION_INDEX,
2123 v0,
2124 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002125 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002126 CheckPrototypes(
2127 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2128 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002129
2130 Register receiver = v0;
2131 Register index = t1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00002132 Register scratch = a3;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002133 Register result = v0;
2134 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
2135 if (argc > 0) {
2136 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
2137 } else {
2138 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
2139 }
2140
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002141 StringCharAtGenerator generator(receiver,
2142 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00002143 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002144 result,
2145 &miss, // When not a string.
2146 &miss, // When not a number.
2147 index_out_of_range_label,
2148 STRING_INDEX_IS_NUMBER);
2149 generator.GenerateFast(masm());
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00002150 __ DropAndRet(argc + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002151
2152 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002153 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002154
2155 if (index_out_of_range.is_linked()) {
2156 __ bind(&index_out_of_range);
ulan@chromium.org750145a2013-03-07 15:14:13 +00002157 __ LoadRoot(v0, Heap::kempty_stringRootIndex);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00002158 __ DropAndRet(argc + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002159 }
2160
2161 __ bind(&miss);
2162 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002163 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002164 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002165 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002166
2167 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002168 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002169}
2170
2171
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002172Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
2173 Handle<Object> object,
2174 Handle<JSObject> holder,
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002175 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002176 Handle<JSFunction> function,
2177 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002178 // ----------- S t a t e -------------
2179 // -- a2 : function name
2180 // -- ra : return address
2181 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2182 // -- ...
2183 // -- sp[argc * 4] : receiver
2184 // -----------------------------------
2185
2186 const int argc = arguments().immediate();
2187
2188 // If the object is not a JSObject or we got an unexpected number of
2189 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002190 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002191
2192 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002193 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002194
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002195 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002196 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
2197
2198 STATIC_ASSERT(kSmiTag == 0);
2199 __ JumpIfSmi(a1, &miss);
2200
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002201 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2202 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002203 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002204 ASSERT(cell->value() == *function);
2205 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2206 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002207 GenerateLoadFunctionFromCell(cell, function, &miss);
2208 }
2209
2210 // Load the char code argument.
2211 Register code = a1;
2212 __ lw(code, MemOperand(sp, 0 * kPointerSize));
2213
2214 // Check the code is a smi.
2215 Label slow;
2216 STATIC_ASSERT(kSmiTag == 0);
2217 __ JumpIfNotSmi(code, &slow);
2218
2219 // Convert the smi code to uint16.
2220 __ And(code, code, Operand(Smi::FromInt(0xffff)));
2221
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002222 StringCharFromCodeGenerator generator(code, v0);
2223 generator.GenerateFast(masm());
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00002224 __ DropAndRet(argc + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002225
2226 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002227 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002228
2229 // Tail call the full function. We do not have to patch the receiver
2230 // because the function makes no use of it.
2231 __ bind(&slow);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002232 ParameterCount expected(function);
2233 __ InvokeFunction(function, expected, arguments(),
2234 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002235
2236 __ bind(&miss);
2237 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002238 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002239
2240 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002241 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002242}
2243
2244
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002245Handle<Code> CallStubCompiler::CompileMathFloorCall(
2246 Handle<Object> object,
2247 Handle<JSObject> holder,
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002248 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002249 Handle<JSFunction> function,
2250 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002251 // ----------- S t a t e -------------
2252 // -- a2 : function name
2253 // -- ra : return address
2254 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2255 // -- ...
2256 // -- sp[argc * 4] : receiver
2257 // -----------------------------------
2258
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002259
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002260 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002261 // If the object is not a JSObject or we got an unexpected number of
2262 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002263 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002264
2265 Label miss, slow;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002266 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002267
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002268 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002269 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002270 STATIC_ASSERT(kSmiTag == 0);
2271 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002272 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2273 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002274 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002275 ASSERT(cell->value() == *function);
2276 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2277 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002278 GenerateLoadFunctionFromCell(cell, function, &miss);
2279 }
2280
2281 // Load the (only) argument into v0.
2282 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2283
2284 // If the argument is a smi, just return.
2285 STATIC_ASSERT(kSmiTag == 0);
2286 __ And(t0, v0, Operand(kSmiTagMask));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00002287 __ DropAndRet(argc + 1, eq, t0, Operand(zero_reg));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002288
danno@chromium.org40cb8782011-05-25 07:58:50 +00002289 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002290
2291 Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return;
2292
2293 // If fpu is enabled, we use the floor instruction.
2294
2295 // Load the HeapNumber value.
2296 __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2297
2298 // Backup FCSR.
2299 __ cfc1(a3, FCSR);
2300 // Clearing FCSR clears the exception mask with no side-effects.
2301 __ ctc1(zero_reg, FCSR);
2302 // Convert the argument to an integer.
2303 __ floor_w_d(f0, f0);
2304
2305 // Start checking for special cases.
2306 // Get the argument exponent and clear the sign bit.
2307 __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize));
2308 __ And(t2, t1, Operand(~HeapNumber::kSignMask));
2309 __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord);
2310
2311 // Retrieve FCSR and check for fpu errors.
2312 __ cfc1(t5, FCSR);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002313 __ And(t5, t5, Operand(kFCSRExceptionFlagMask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002314 __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));
2315
2316 // Check for NaN, Infinity, and -Infinity.
2317 // They are invariant through a Math.Floor call, so just
2318 // return the original argument.
2319 __ Subu(t3, t2, Operand(HeapNumber::kExponentMask
2320 >> HeapNumber::kMantissaBitsInTopWord));
2321 __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg));
2322 // We had an overflow or underflow in the conversion. Check if we
2323 // have a big exponent.
2324 // If greater or equal, the argument is already round and in v0.
2325 __ Branch(&restore_fcsr_and_return, ge, t3,
2326 Operand(HeapNumber::kMantissaBits));
2327 __ Branch(&wont_fit_smi);
2328
2329 __ bind(&no_fpu_error);
2330 // Move the result back to v0.
2331 __ mfc1(v0, f0);
2332 // Check if the result fits into a smi.
2333 __ Addu(a1, v0, Operand(0x40000000));
2334 __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg));
2335 // Tag the result.
2336 STATIC_ASSERT(kSmiTag == 0);
2337 __ sll(v0, v0, kSmiTagSize);
2338
2339 // Check for -0.
2340 __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg));
2341 // t1 already holds the HeapNumber exponent.
2342 __ And(t0, t1, Operand(HeapNumber::kSignMask));
2343 // If our HeapNumber is negative it was -0, so load its address and return.
2344 // Else v0 is loaded with 0, so we can also just return.
2345 __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg));
2346 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2347
2348 __ bind(&restore_fcsr_and_return);
2349 // Restore FCSR and return.
2350 __ ctc1(a3, FCSR);
2351
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00002352 __ DropAndRet(argc + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002353
2354 __ bind(&wont_fit_smi);
2355 // Restore FCSR and fall to slow case.
2356 __ ctc1(a3, FCSR);
2357
2358 __ bind(&slow);
2359 // Tail call the full function. We do not have to patch the receiver
2360 // because the function makes no use of it.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002361 ParameterCount expected(function);
2362 __ InvokeFunction(function, expected, arguments(),
2363 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002364
2365 __ bind(&miss);
2366 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002367 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002368
2369 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002370 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002371}
2372
2373
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002374Handle<Code> CallStubCompiler::CompileMathAbsCall(
2375 Handle<Object> object,
2376 Handle<JSObject> holder,
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002377 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002378 Handle<JSFunction> function,
2379 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002380 // ----------- S t a t e -------------
2381 // -- a2 : function name
2382 // -- ra : return address
2383 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2384 // -- ...
2385 // -- sp[argc * 4] : receiver
2386 // -----------------------------------
2387
2388 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002389 // If the object is not a JSObject or we got an unexpected number of
2390 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002391 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002392
2393 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002394
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002395 GenerateNameCheck(name, &miss);
2396 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002397 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002398 STATIC_ASSERT(kSmiTag == 0);
2399 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002400 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2401 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002402 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002403 ASSERT(cell->value() == *function);
2404 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2405 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002406 GenerateLoadFunctionFromCell(cell, function, &miss);
2407 }
2408
2409 // Load the (only) argument into v0.
2410 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2411
2412 // Check if the argument is a smi.
2413 Label not_smi;
2414 STATIC_ASSERT(kSmiTag == 0);
2415 __ JumpIfNotSmi(v0, &not_smi);
2416
2417 // Do bitwise not or do nothing depending on the sign of the
2418 // argument.
2419 __ sra(t0, v0, kBitsPerInt - 1);
2420 __ Xor(a1, v0, t0);
2421
2422 // Add 1 or do nothing depending on the sign of the argument.
2423 __ Subu(v0, a1, t0);
2424
2425 // If the result is still negative, go to the slow case.
2426 // This only happens for the most negative smi.
2427 Label slow;
2428 __ Branch(&slow, lt, v0, Operand(zero_reg));
2429
2430 // Smi case done.
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00002431 __ DropAndRet(argc + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002432
2433 // Check if the argument is a heap number and load its exponent and
2434 // sign.
2435 __ bind(&not_smi);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002436 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002437 __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2438
2439 // Check the sign of the argument. If the argument is positive,
2440 // just return it.
2441 Label negative_sign;
2442 __ And(t0, a1, Operand(HeapNumber::kSignMask));
2443 __ Branch(&negative_sign, ne, t0, Operand(zero_reg));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00002444 __ DropAndRet(argc + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002445
2446 // If the argument is negative, clear the sign, and return a new
2447 // number.
2448 __ bind(&negative_sign);
2449 __ Xor(a1, a1, Operand(HeapNumber::kSignMask));
2450 __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2451 __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
2452 __ AllocateHeapNumber(v0, t0, t1, t2, &slow);
2453 __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2454 __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00002455 __ DropAndRet(argc + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002456
2457 // Tail call the full function. We do not have to patch the receiver
2458 // because the function makes no use of it.
2459 __ bind(&slow);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002460 ParameterCount expected(function);
2461 __ InvokeFunction(function, expected, arguments(),
2462 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002463
2464 __ bind(&miss);
2465 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002466 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002467
2468 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002469 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002470}
2471
2472
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002473Handle<Code> CallStubCompiler::CompileFastApiCall(
lrn@chromium.org7516f052011-03-30 08:52:27 +00002474 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002475 Handle<Object> object,
2476 Handle<JSObject> holder,
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002477 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002478 Handle<JSFunction> function,
2479 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002480
danno@chromium.org40cb8782011-05-25 07:58:50 +00002481 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002482
2483 ASSERT(optimization.is_simple_api_call());
2484 // Bail out if object is a global object as we don't want to
2485 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002486 if (object->IsGlobalObject()) return Handle<Code>::null();
2487 if (!cell.is_null()) return Handle<Code>::null();
2488 if (!object->IsJSObject()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002489 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002490 Handle<JSObject>::cast(object), holder);
2491 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002492
2493 Label miss, miss_before_stack_reserved;
2494
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002495 GenerateNameCheck(name, &miss_before_stack_reserved);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002496
2497 // Get the receiver from the stack.
2498 const int argc = arguments().immediate();
2499 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2500
2501 // Check that the receiver isn't a smi.
2502 __ JumpIfSmi(a1, &miss_before_stack_reserved);
2503
2504 __ IncrementCounter(counters->call_const(), 1, a0, a3);
2505 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2506
2507 ReserveSpaceForFastApiCall(masm(), a0);
2508
2509 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002510 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002511 depth, &miss);
2512
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002513 GenerateFastApiDirectCall(masm(), optimization, argc);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002514
2515 __ bind(&miss);
2516 FreeSpaceForFastApiCall(masm());
2517
2518 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002519 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002520
2521 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002522 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002523}
2524
2525
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002526void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
2527 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002528 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002529 CheckType check,
2530 Label* success) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002531 // ----------- S t a t e -------------
2532 // -- a2 : name
2533 // -- ra : return address
2534 // -----------------------------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002535 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002536 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002537
2538 // Get the receiver from the stack.
2539 const int argc = arguments().immediate();
2540 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2541
2542 // Check that the receiver isn't a smi.
2543 if (check != NUMBER_CHECK) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002544 __ JumpIfSmi(a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002545 }
2546
2547 // Make sure that it's okay not to patch the on stack receiver
2548 // unless we're doing a receiver map check.
2549 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002550 switch (check) {
2551 case RECEIVER_MAP_CHECK:
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002552 __ IncrementCounter(isolate()->counters()->call_const(), 1, a0, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002553
2554 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002555 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2556 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002557
2558 // Patch the receiver on the stack with the global proxy if
2559 // necessary.
2560 if (object->IsGlobalObject()) {
2561 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2562 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2563 }
2564 break;
2565
2566 case STRING_CHECK:
ulan@chromium.org750145a2013-03-07 15:14:13 +00002567 // Check that the object is a string.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002568 __ GetObjectType(a1, a3, a3);
2569 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2570 // Check that the maps starting from the prototype haven't changed.
2571 GenerateDirectLoadGlobalFunctionPrototype(
2572 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
2573 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002574 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002575 a0, holder, a3, a1, t0, name, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002576 break;
2577
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002578 case SYMBOL_CHECK:
2579 // Check that the object is a symbol.
2580 __ GetObjectType(a1, a1, a3);
2581 __ Branch(&miss, ne, a3, Operand(SYMBOL_TYPE));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002582 // Check that the maps starting from the prototype haven't changed.
2583 GenerateDirectLoadGlobalFunctionPrototype(
2584 masm(), Context::SYMBOL_FUNCTION_INDEX, a0, &miss);
2585 CheckPrototypes(
2586 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2587 a0, holder, a3, a1, t0, name, &miss);
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002588 break;
2589
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002590 case NUMBER_CHECK: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002591 Label fast;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002592 // Check that the object is a smi or a heap number.
2593 __ JumpIfSmi(a1, &fast);
2594 __ GetObjectType(a1, a0, a0);
2595 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
2596 __ bind(&fast);
2597 // Check that the maps starting from the prototype haven't changed.
2598 GenerateDirectLoadGlobalFunctionPrototype(
2599 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
2600 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002601 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002602 a0, holder, a3, a1, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002603 break;
2604 }
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002605 case BOOLEAN_CHECK: {
2606 Label fast;
2607 // Check that the object is a boolean.
2608 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
2609 __ Branch(&fast, eq, a1, Operand(t0));
2610 __ LoadRoot(t0, Heap::kFalseValueRootIndex);
2611 __ Branch(&miss, ne, a1, Operand(t0));
2612 __ bind(&fast);
2613 // Check that the maps starting from the prototype haven't changed.
2614 GenerateDirectLoadGlobalFunctionPrototype(
2615 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
2616 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002617 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002618 a0, holder, a3, a1, t0, name, &miss);
2619 break;
2620 }
2621 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002622
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002623 __ jmp(success);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002624
2625 // Handle call cache miss.
2626 __ bind(&miss);
2627
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002628 GenerateMissBranch();
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002629}
2630
2631
2632void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) {
2633 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
2634 ? CALL_AS_FUNCTION
2635 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002636 ParameterCount expected(function);
2637 __ InvokeFunction(function, expected, arguments(),
2638 JUMP_FUNCTION, NullCallWrapper(), call_kind);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002639}
2640
2641
2642Handle<Code> CallStubCompiler::CompileCallConstant(
2643 Handle<Object> object,
2644 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002645 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002646 CheckType check,
2647 Handle<JSFunction> function) {
2648 if (HasCustomCallGenerator(function)) {
2649 Handle<Code> code = CompileCustomCall(object, holder,
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002650 Handle<Cell>::null(),
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002651 function, Handle<String>::cast(name));
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002652 // A null handle means bail out to the regular compiler code below.
2653 if (!code.is_null()) return code;
2654 }
2655
2656 Label success;
2657
2658 CompileHandlerFrontend(object, holder, name, check, &success);
2659 __ bind(&success);
2660 CompileHandlerBackend(function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002661
2662 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002663 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002664}
2665
2666
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002667Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2668 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002669 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002670 // ----------- S t a t e -------------
2671 // -- a2 : name
2672 // -- ra : return address
2673 // -----------------------------------
2674
2675 Label miss;
2676
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002677 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002678
2679 // Get the number of arguments.
2680 const int argc = arguments().immediate();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002681 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002682 LookupPostInterceptor(holder, name, &lookup);
2683
2684 // Get the receiver from the stack.
2685 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2686
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002687 CallInterceptorCompiler compiler(this, arguments(), a2, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002688 compiler.Compile(masm(), object, holder, name, &lookup, a1, a3, t0, a0,
2689 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002690
2691 // Move returned value, the function to call, to a1.
2692 __ mov(a1, v0);
2693 // Restore receiver.
2694 __ lw(a0, MemOperand(sp, argc * kPointerSize));
2695
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002696 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002697
2698 // Handle call cache miss.
2699 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002700 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002701
2702 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002703 return GetCode(Code::INTERCEPTOR, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002704}
2705
2706
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002707Handle<Code> CallStubCompiler::CompileCallGlobal(
2708 Handle<JSObject> object,
2709 Handle<GlobalObject> holder,
2710 Handle<JSGlobalPropertyCell> cell,
2711 Handle<JSFunction> function,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002712 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002713 // ----------- S t a t e -------------
2714 // -- a2 : name
2715 // -- ra : return address
2716 // -----------------------------------
2717
2718 if (HasCustomCallGenerator(function)) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002719 Handle<Code> code = CompileCustomCall(
2720 object, holder, cell, function, Handle<String>::cast(name));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002721 // A null handle means bail out to the regular compiler code below.
2722 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002723 }
2724
2725 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002726 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002727
2728 // Get the number of arguments.
2729 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002730 GenerateGlobalReceiverCheck(object, holder, name, &miss);
2731 GenerateLoadFunctionFromCell(cell, function, &miss);
2732
2733 // Patch the receiver on the stack with the global proxy if
2734 // necessary.
2735 if (object->IsGlobalObject()) {
2736 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
2737 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2738 }
2739
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002740 // Set up the context (function already in r1).
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002741 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
2742
2743 // Jump to the cached code (tail call).
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002744 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002745 __ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002746 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002747 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002748 ? CALL_AS_FUNCTION
2749 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002750 // We call indirectly through the code field in the function to
2751 // allow recompilation to take effect without changing any of the
2752 // call sites.
2753 __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
2754 __ InvokeCode(a3, expected, arguments(), JUMP_FUNCTION,
2755 NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002756
2757 // Handle call cache miss.
2758 __ bind(&miss);
2759 __ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002760 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002761
2762 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002763 return GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002764}
2765
2766
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002767Handle<Code> StoreStubCompiler::CompileStoreCallback(
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002768 Handle<Name> name,
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002769 Handle<JSObject> object,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002770 Handle<JSObject> holder,
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002771 Handle<ExecutableAccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002772 Label miss;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002773 // Check that the maps haven't changed.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002774 __ JumpIfSmi(receiver(), &miss);
2775 CheckPrototypes(object, receiver(), holder,
2776 scratch1(), scratch2(), scratch3(), name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002777
2778 // Stub never generated for non-global objects that require access
2779 // checks.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002780 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002781
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002782 __ push(receiver()); // Receiver.
2783 __ li(at, Operand(callback)); // Callback info.
2784 __ Push(at, this->name(), value());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002785
2786 // Do tail-call to the runtime system.
2787 ExternalReference store_callback_property =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002788 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002789 __ TailCallExternalReference(store_callback_property, 4, 1);
2790
2791 // Handle store cache miss.
2792 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002793 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002794
2795 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002796 return GetICCode(kind(), Code::CALLBACKS, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002797}
2798
2799
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002800#undef __
2801#define __ ACCESS_MASM(masm)
2802
2803
2804void StoreStubCompiler::GenerateStoreViaSetter(
2805 MacroAssembler* masm,
2806 Handle<JSFunction> setter) {
2807 // ----------- S t a t e -------------
2808 // -- a0 : value
2809 // -- a1 : receiver
2810 // -- a2 : name
2811 // -- ra : return address
2812 // -----------------------------------
2813 {
2814 FrameScope scope(masm, StackFrame::INTERNAL);
2815
2816 // Save value register, so we can restore it later.
2817 __ push(a0);
2818
2819 if (!setter.is_null()) {
2820 // Call the JavaScript setter with receiver and value on the stack.
2821 __ push(a1);
2822 __ push(a0);
2823 ParameterCount actual(1);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002824 ParameterCount expected(setter);
2825 __ InvokeFunction(setter, expected, actual,
2826 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002827 } else {
2828 // If we generate a global code snippet for deoptimization only, remember
2829 // the place to continue after deoptimization.
2830 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2831 }
2832
2833 // We have to return the passed value, not the return value of the setter.
2834 __ pop(v0);
2835
2836 // Restore context register.
2837 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2838 }
2839 __ Ret();
2840}
2841
2842
2843#undef __
2844#define __ ACCESS_MASM(masm())
2845
2846
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002847Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002848 Handle<JSObject> object,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002849 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002850 Label miss;
2851
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002852 // Check that the map of the object hasn't changed.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002853 __ CheckMap(receiver(), scratch1(), Handle<Map>(object->map()), &miss,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002854 DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002855
2856 // Perform global security token check if needed.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002857 if (object->IsJSGlobalProxy()) {
2858 __ CheckAccessGlobalProxy(receiver(), scratch1(), &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002859 }
2860
2861 // Stub is never generated for non-global objects that require access
2862 // checks.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002863 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002864
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002865 __ Push(receiver(), this->name(), value());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002866
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002867 __ li(scratch1(), Operand(Smi::FromInt(strict_mode())));
2868 __ push(scratch1()); // strict mode
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002869
2870 // Do tail-call to the runtime system.
2871 ExternalReference store_ic_property =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002872 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002873 __ TailCallExternalReference(store_ic_property, 4, 1);
2874
2875 // Handle store cache miss.
2876 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002877 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002878
2879 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002880 return GetICCode(kind(), Code::INTERCEPTOR, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002881}
2882
2883
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002884Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2885 Handle<GlobalObject> object,
2886 Handle<JSGlobalPropertyCell> cell,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002887 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002888 Label miss;
2889
2890 // Check that the map of the global has not changed.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002891 __ lw(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset));
2892 __ Branch(&miss, ne, scratch1(), Operand(Handle<Map>(object->map())));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002893
2894 // Check that the value in the cell is not the hole. If it is, this
2895 // cell could have been deleted and reintroducing the global needs
2896 // to update the property details in the property dictionary of the
2897 // global object. We bail out to the runtime system to do that.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002898 __ li(scratch1(), Operand(cell));
2899 __ LoadRoot(scratch2(), Heap::kTheHoleValueRootIndex);
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002900 __ lw(scratch3(), FieldMemOperand(scratch1(), Cell::kValueOffset));
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002901 __ Branch(&miss, eq, scratch3(), Operand(scratch2()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002902
2903 // Store the value in the cell.
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002904 __ sw(value(), FieldMemOperand(scratch1(), Cell::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002905 __ mov(v0, a0); // Stored value must be returned in v0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002906 // Cells are always rescanned, so no write barrier here.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002907
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002908 Counters* counters = isolate()->counters();
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002909 __ IncrementCounter(
2910 counters->named_store_global_inline(), 1, scratch1(), scratch2());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002911 __ Ret();
2912
2913 // Handle store cache miss.
2914 __ bind(&miss);
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002915 __ IncrementCounter(
2916 counters->named_store_global_inline_miss(), 1, scratch1(), scratch2());
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002917 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002918
2919 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002920 return GetICCode(kind(), Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002921}
2922
2923
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002924Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
2925 Handle<JSObject> object,
2926 Handle<JSObject> last,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002927 Handle<Name> name,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002928 Handle<GlobalObject> global) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002929 Label success;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002930
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002931 NonexistentHandlerFrontend(object, last, name, &success, global);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002932
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002933 __ bind(&success);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002934 // Return undefined if maps of the full prototype chain is still the same.
2935 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2936 __ Ret();
2937
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002938 // Return the generated code.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002939 return GetCode(kind(), Code::NONEXISTENT, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002940}
2941
2942
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002943Register* LoadStubCompiler::registers() {
2944 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2945 static Register registers[] = { a0, a2, a3, a1, t0, t1 };
2946 return registers;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002947}
2948
2949
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002950Register* KeyedLoadStubCompiler::registers() {
2951 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2952 static Register registers[] = { a1, a0, a2, a3, t0, t1 };
2953 return registers;
2954}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002955
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002956
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002957Register* StoreStubCompiler::registers() {
2958 // receiver, name, value, scratch1, scratch2, scratch3.
2959 static Register registers[] = { a1, a2, a0, a3, t0, t1 };
2960 return registers;
2961}
2962
2963
2964Register* KeyedStoreStubCompiler::registers() {
2965 // receiver, name, value, scratch1, scratch2, scratch3.
2966 static Register registers[] = { a2, a1, a0, a3, t0, t1 };
2967 return registers;
2968}
2969
2970
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002971void KeyedLoadStubCompiler::GenerateNameCheck(Handle<Name> name,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002972 Register name_reg,
2973 Label* miss) {
2974 __ Branch(miss, ne, name_reg, Operand(name));
lrn@chromium.org7516f052011-03-30 08:52:27 +00002975}
2976
2977
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002978void KeyedStoreStubCompiler::GenerateNameCheck(Handle<Name> name,
2979 Register name_reg,
2980 Label* miss) {
2981 __ Branch(miss, ne, name_reg, Operand(name));
2982}
2983
2984
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002985#undef __
2986#define __ ACCESS_MASM(masm)
2987
2988
2989void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
2990 Handle<JSFunction> getter) {
2991 // ----------- S t a t e -------------
2992 // -- a0 : receiver
2993 // -- a2 : name
2994 // -- ra : return address
2995 // -----------------------------------
2996 {
2997 FrameScope scope(masm, StackFrame::INTERNAL);
2998
2999 if (!getter.is_null()) {
3000 // Call the JavaScript getter with the receiver on the stack.
3001 __ push(a0);
3002 ParameterCount actual(0);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003003 ParameterCount expected(getter);
3004 __ InvokeFunction(getter, expected, actual,
3005 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003006 } else {
3007 // If we generate a global code snippet for deoptimization only, remember
3008 // the place to continue after deoptimization.
3009 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
3010 }
3011
3012 // Restore context register.
3013 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
3014 }
3015 __ Ret();
3016}
3017
3018
3019#undef __
3020#define __ ACCESS_MASM(masm())
3021
3022
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003023Handle<Code> LoadStubCompiler::CompileLoadGlobal(
3024 Handle<JSObject> object,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003025 Handle<GlobalObject> global,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003026 Handle<JSGlobalPropertyCell> cell,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003027 Handle<Name> name,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003028 bool is_dont_delete) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003029 Label success, miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003030
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003031 __ CheckMap(
3032 receiver(), scratch1(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
3033 HandlerFrontendHeader(
3034 object, receiver(), Handle<JSObject>::cast(global), name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003035
3036 // Get the value from the cell.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003037 __ li(a3, Operand(cell));
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00003038 __ lw(t0, FieldMemOperand(a3, Cell::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003039
3040 // Check for deleted property if property can actually be deleted.
3041 if (!is_dont_delete) {
3042 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
3043 __ Branch(&miss, eq, t0, Operand(at));
3044 }
3045
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003046 HandlerFrontendFooter(&success, &miss);
3047 __ bind(&success);
3048
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003049 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003050 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00003051 __ Ret(USE_DELAY_SLOT);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003052 __ mov(v0, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003053
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003054 // Return the generated code.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003055 return GetICCode(kind(), Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003056}
3057
3058
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003059Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003060 MapHandleList* receiver_maps,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003061 CodeHandleList* handlers,
3062 Handle<Name> name,
3063 Code::StubType type,
3064 IcCheckType check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003065 Label miss;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003066
3067 if (check == PROPERTY) {
3068 GenerateNameCheck(name, this->name(), &miss);
3069 }
3070
3071 __ JumpIfSmi(receiver(), &miss);
3072 Register map_reg = scratch1();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003073
danno@chromium.org40cb8782011-05-25 07:58:50 +00003074 int receiver_count = receiver_maps->length();
danno@chromium.orgf005df62013-04-30 16:36:45 +00003075 int number_of_handled_maps = 0;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003076 __ lw(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003077 for (int current = 0; current < receiver_count; ++current) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00003078 Handle<Map> map = receiver_maps->at(current);
3079 if (!map->is_deprecated()) {
3080 number_of_handled_maps++;
3081 __ Jump(handlers->at(current), RelocInfo::CODE_TARGET,
3082 eq, map_reg, Operand(receiver_maps->at(current)));
3083 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003084 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00003085 ASSERT(number_of_handled_maps != 0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003086
3087 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003088 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003089
3090 // Return the generated code.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003091 InlineCacheState state =
danno@chromium.orgf005df62013-04-30 16:36:45 +00003092 number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003093 return GetICCode(kind(), type, name, state);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003094}
3095
3096
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003097Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
3098 MapHandleList* receiver_maps,
3099 CodeHandleList* handler_stubs,
3100 MapHandleList* transitioned_maps) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003101 Label miss;
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003102 __ JumpIfSmi(receiver(), &miss);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003103
3104 int receiver_count = receiver_maps->length();
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003105 __ lw(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003106 for (int i = 0; i < receiver_count; ++i) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003107 if (transitioned_maps->at(i).is_null()) {
3108 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq,
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003109 scratch1(), Operand(receiver_maps->at(i)));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003110 } else {
3111 Label next_map;
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003112 __ Branch(&next_map, ne, scratch1(), Operand(receiver_maps->at(i)));
3113 __ li(transition_map(), Operand(transitioned_maps->at(i)));
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003114 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003115 __ bind(&next_map);
3116 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003117 }
3118
3119 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003120 TailCallBuiltin(masm(), MissBuiltin(kind()));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003121
3122 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003123 return GetICCode(
3124 kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003125}
3126
3127
danno@chromium.org40cb8782011-05-25 07:58:50 +00003128#undef __
3129#define __ ACCESS_MASM(masm)
3130
3131
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003132void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3133 MacroAssembler* masm) {
3134 // ---------- S t a t e --------------
3135 // -- ra : return address
3136 // -- a0 : key
3137 // -- a1 : receiver
3138 // -----------------------------------
3139 Label slow, miss_force_generic;
3140
3141 Register key = a0;
3142 Register receiver = a1;
3143
3144 __ JumpIfNotSmi(key, &miss_force_generic);
3145 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
3146 __ sra(a2, a0, kSmiTagSize);
3147 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
3148 __ Ret();
3149
3150 // Slow case, key and receiver still in a0 and a1.
3151 __ bind(&slow);
3152 __ IncrementCounter(
3153 masm->isolate()->counters()->keyed_load_external_array_slow(),
3154 1, a2, a3);
3155 // Entry registers are intact.
3156 // ---------- S t a t e --------------
3157 // -- ra : return address
3158 // -- a0 : key
3159 // -- a1 : receiver
3160 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003161 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003162
3163 // Miss case, call the runtime.
3164 __ bind(&miss_force_generic);
3165
3166 // ---------- S t a t e --------------
3167 // -- ra : return address
3168 // -- a0 : key
3169 // -- a1 : receiver
3170 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003171 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_MissForceGeneric);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003172}
3173
3174
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003175static void GenerateSmiKeyCheck(MacroAssembler* masm,
3176 Register key,
3177 Register scratch0,
3178 Register scratch1,
3179 FPURegister double_scratch0,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003180 FPURegister double_scratch1,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003181 Label* fail) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003182 Label key_ok;
3183 // Check for smi or a smi inside a heap number. We convert the heap
3184 // number and check if the conversion is exact and fits into the smi
3185 // range.
3186 __ JumpIfSmi(key, &key_ok);
3187 __ CheckMap(key,
3188 scratch0,
3189 Heap::kHeapNumberMapRootIndex,
3190 fail,
3191 DONT_DO_SMI_CHECK);
3192 __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
3193 __ EmitFPUTruncate(kRoundToZero,
3194 scratch0,
3195 double_scratch0,
3196 at,
3197 double_scratch1,
3198 scratch1,
3199 kCheckForInexactConversion);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003200
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003201 __ Branch(fail, ne, scratch1, Operand(zero_reg));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003202
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003203 __ SmiTagCheckOverflow(key, scratch0, scratch1);
3204 __ BranchOnOverflow(fail, scratch1);
3205 __ bind(&key_ok);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003206}
3207
3208
danno@chromium.org40cb8782011-05-25 07:58:50 +00003209void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3210 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003211 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003212 // ---------- S t a t e --------------
3213 // -- a0 : value
3214 // -- a1 : key
3215 // -- a2 : receiver
3216 // -- ra : return address
3217 // -----------------------------------
3218
danno@chromium.org40cb8782011-05-25 07:58:50 +00003219 Label slow, check_heap_number, miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003220
3221 // Register usage.
3222 Register value = a0;
3223 Register key = a1;
3224 Register receiver = a2;
3225 // a3 mostly holds the elements array or the destination external array.
3226
danno@chromium.org40cb8782011-05-25 07:58:50 +00003227 // This stub is meant to be tail-jumped to, the receiver must already
3228 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003229
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003230 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003231 GenerateSmiKeyCheck(masm, key, t0, t1, f2, f4, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003232
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003233 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3234
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003235 // Check that the index is in range.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003236 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3237 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003238 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003239
3240 // Handle both smis and HeapNumbers in the fast path. Go to the
3241 // runtime for all other kinds of values.
3242 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003243
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003244 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003245 // Double to pixel conversion is only implemented in the runtime for now.
3246 __ JumpIfNotSmi(value, &slow);
3247 } else {
3248 __ JumpIfNotSmi(value, &check_heap_number);
3249 }
3250 __ SmiUntag(t1, value);
3251 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3252
3253 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003254 // t1: value (integer).
3255
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003256 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003257 case EXTERNAL_PIXEL_ELEMENTS: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003258 // Clamp the value to [0..255].
3259 // v0 is used as a scratch register here.
3260 Label done;
3261 __ li(v0, Operand(255));
3262 // Normal branch: nop in delay slot.
3263 __ Branch(&done, gt, t1, Operand(v0));
3264 // Use delay slot in this branch.
3265 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg));
3266 __ mov(v0, zero_reg); // In delay slot.
3267 __ mov(v0, t1); // Value is in range 0..255.
3268 __ bind(&done);
3269 __ mov(t1, v0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003270
3271 __ srl(t8, key, 1);
3272 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003273 __ sb(t1, MemOperand(t8, 0));
3274 }
3275 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003276 case EXTERNAL_BYTE_ELEMENTS:
3277 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003278 __ srl(t8, key, 1);
3279 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003280 __ sb(t1, MemOperand(t8, 0));
3281 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003282 case EXTERNAL_SHORT_ELEMENTS:
3283 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003284 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003285 __ sh(t1, MemOperand(t8, 0));
3286 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003287 case EXTERNAL_INT_ELEMENTS:
3288 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003289 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003290 __ addu(t8, a3, t8);
3291 __ sw(t1, MemOperand(t8, 0));
3292 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003293 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003294 // Perform int-to-float conversion and store to memory.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003295 __ SmiUntag(t0, key);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003296 StoreIntAsFloat(masm, a3, t0, t1, t2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003297 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003298 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003299 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003300 __ addu(a3, a3, t8);
3301 // a3: effective address of the double element
3302 FloatingPointHelper::Destination destination;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003303 destination = FloatingPointHelper::kFPURegisters;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003304 FloatingPointHelper::ConvertIntToDouble(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003305 masm, t1, destination,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003306 f0, t2, t3, // These are: double_dst, dst_mantissa, dst_exponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003307 t0, f2); // These are: scratch2, single_scratch.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003308 __ sdc1(f0, MemOperand(a3, 0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003309 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003310 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003311 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003312 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003313 case FAST_HOLEY_ELEMENTS:
3314 case FAST_HOLEY_SMI_ELEMENTS:
3315 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003316 case DICTIONARY_ELEMENTS:
3317 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003318 UNREACHABLE();
3319 break;
3320 }
3321
3322 // Entry registers are intact, a0 holds the value which is the return value.
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00003323 __ Ret(USE_DELAY_SLOT);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003324 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003325
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003326 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003327 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003328 __ bind(&check_heap_number);
3329 __ GetObjectType(value, t1, t2);
3330 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE));
3331
3332 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3333
3334 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003335
3336 // The WebGL specification leaves the behavior of storing NaN and
3337 // +/-Infinity into integer arrays basically undefined. For more
3338 // reproducible behavior, convert these to zero.
3339
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003340
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003341 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003342
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003343 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
3344 __ cvt_s_d(f0, f0);
3345 __ sll(t8, key, 1);
3346 __ addu(t8, a3, t8);
3347 __ swc1(f0, MemOperand(t8, 0));
3348 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
3349 __ sll(t8, key, 2);
3350 __ addu(t8, a3, t8);
3351 __ sdc1(f0, MemOperand(t8, 0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003352 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003353 __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003354
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003355 switch (elements_kind) {
3356 case EXTERNAL_BYTE_ELEMENTS:
3357 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3358 __ srl(t8, key, 1);
3359 __ addu(t8, a3, t8);
3360 __ sb(t3, MemOperand(t8, 0));
3361 break;
3362 case EXTERNAL_SHORT_ELEMENTS:
3363 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3364 __ addu(t8, a3, key);
3365 __ sh(t3, MemOperand(t8, 0));
3366 break;
3367 case EXTERNAL_INT_ELEMENTS:
3368 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3369 __ sll(t8, key, 1);
3370 __ addu(t8, a3, t8);
3371 __ sw(t3, MemOperand(t8, 0));
3372 break;
3373 case EXTERNAL_PIXEL_ELEMENTS:
3374 case EXTERNAL_FLOAT_ELEMENTS:
3375 case EXTERNAL_DOUBLE_ELEMENTS:
3376 case FAST_ELEMENTS:
3377 case FAST_SMI_ELEMENTS:
3378 case FAST_DOUBLE_ELEMENTS:
3379 case FAST_HOLEY_ELEMENTS:
3380 case FAST_HOLEY_SMI_ELEMENTS:
3381 case FAST_HOLEY_DOUBLE_ELEMENTS:
3382 case DICTIONARY_ELEMENTS:
3383 case NON_STRICT_ARGUMENTS_ELEMENTS:
3384 UNREACHABLE();
3385 break;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003386 }
3387 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003388
3389 // Entry registers are intact, a0 holds the value
3390 // which is the return value.
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00003391 __ Ret(USE_DELAY_SLOT);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003392 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003393 }
3394
danno@chromium.org40cb8782011-05-25 07:58:50 +00003395 // Slow case, key and receiver still in a0 and a1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003396 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003397 __ IncrementCounter(
3398 masm->isolate()->counters()->keyed_load_external_array_slow(),
3399 1, a2, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003400 // Entry registers are intact.
3401 // ---------- S t a t e --------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003402 // -- ra : return address
danno@chromium.org40cb8782011-05-25 07:58:50 +00003403 // -- a0 : key
3404 // -- a1 : receiver
3405 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003406 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003407
3408 // Miss case, call the runtime.
3409 __ bind(&miss_force_generic);
3410
3411 // ---------- S t a t e --------------
3412 // -- ra : return address
3413 // -- a0 : key
3414 // -- a1 : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003415 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003416 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003417}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003418
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003419
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003420void KeyedStoreStubCompiler::GenerateStoreFastElement(
3421 MacroAssembler* masm,
3422 bool is_js_array,
yangguo@chromium.org56454712012-02-16 15:33:53 +00003423 ElementsKind elements_kind,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003424 KeyedAccessStoreMode store_mode) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003425 // ----------- S t a t e -------------
3426 // -- a0 : value
3427 // -- a1 : key
3428 // -- a2 : receiver
3429 // -- ra : return address
3430 // -- a3 : scratch
3431 // -- a4 : scratch (elements)
3432 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00003433 Label miss_force_generic, transition_elements_kind, grow, slow;
3434 Label finish_store, check_capacity;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003435
3436 Register value_reg = a0;
3437 Register key_reg = a1;
3438 Register receiver_reg = a2;
yangguo@chromium.org56454712012-02-16 15:33:53 +00003439 Register scratch = t0;
3440 Register elements_reg = a3;
3441 Register length_reg = t1;
3442 Register scratch2 = t2;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003443
3444 // This stub is meant to be tail-jumped to, the receiver must already
3445 // have been verified by the caller to not be a smi.
3446
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003447 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003448 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003449
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003450 if (IsFastSmiElementsKind(elements_kind)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003451 __ JumpIfNotSmi(value_reg, &transition_elements_kind);
3452 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003453
3454 // Check that the key is within bounds.
yangguo@chromium.org56454712012-02-16 15:33:53 +00003455 __ lw(elements_reg,
3456 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003457 if (is_js_array) {
3458 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3459 } else {
3460 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3461 }
3462 // Compare smis.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003463 if (is_js_array && IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003464 __ Branch(&grow, hs, key_reg, Operand(scratch));
3465 } else {
3466 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
3467 }
3468
3469 // Make sure elements is a fast element array, not 'cow'.
3470 __ CheckMap(elements_reg,
3471 scratch,
3472 Heap::kFixedArrayMapRootIndex,
3473 &miss_force_generic,
3474 DONT_DO_SMI_CHECK);
3475
3476 __ bind(&finish_store);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003477
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003478 if (IsFastSmiElementsKind(elements_kind)) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003479 __ Addu(scratch,
3480 elements_reg,
3481 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3482 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
3483 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
3484 __ Addu(scratch, scratch, scratch2);
3485 __ sw(value_reg, MemOperand(scratch));
3486 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003487 ASSERT(IsFastObjectElementsKind(elements_kind));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003488 __ Addu(scratch,
3489 elements_reg,
3490 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3491 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
3492 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
3493 __ Addu(scratch, scratch, scratch2);
3494 __ sw(value_reg, MemOperand(scratch));
3495 __ mov(receiver_reg, value_reg);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003496 __ RecordWrite(elements_reg, // Object.
3497 scratch, // Address.
3498 receiver_reg, // Value.
3499 kRAHasNotBeenSaved,
3500 kDontSaveFPRegs);
3501 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003502 // value_reg (a0) is preserved.
3503 // Done.
3504 __ Ret();
3505
3506 __ bind(&miss_force_generic);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003507 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003508
3509 __ bind(&transition_elements_kind);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003510 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003511
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003512 if (is_js_array && IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003513 // Grow the array by a single element if possible.
3514 __ bind(&grow);
3515
3516 // Make sure the array is only growing by a single element, anything else
3517 // must be handled by the runtime.
3518 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch));
3519
3520 // Check for the empty array, and preallocate a small backing store if
3521 // possible.
3522 __ lw(length_reg,
3523 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3524 __ lw(elements_reg,
3525 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3526 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
3527 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
3528
3529 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003530 __ Allocate(size, elements_reg, scratch, scratch2, &slow, TAG_OBJECT);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003531
3532 __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex);
3533 __ sw(scratch, FieldMemOperand(elements_reg, JSObject::kMapOffset));
3534 __ li(scratch, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
3535 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3536 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
3537 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
3538 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::SizeFor(i)));
3539 }
3540
3541 // Store the element at index zero.
3542 __ sw(value_reg, FieldMemOperand(elements_reg, FixedArray::SizeFor(0)));
3543
3544 // Install the new backing store in the JSArray.
3545 __ sw(elements_reg,
3546 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3547 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
3548 scratch, kRAHasNotBeenSaved, kDontSaveFPRegs,
3549 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3550
3551 // Increment the length of the array.
3552 __ li(length_reg, Operand(Smi::FromInt(1)));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00003553 __ Ret(USE_DELAY_SLOT);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003554 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
yangguo@chromium.org56454712012-02-16 15:33:53 +00003555
3556 __ bind(&check_capacity);
3557 // Check for cow elements, in general they are not handled by this stub
3558 __ CheckMap(elements_reg,
3559 scratch,
3560 Heap::kFixedCOWArrayMapRootIndex,
3561 &miss_force_generic,
3562 DONT_DO_SMI_CHECK);
3563
3564 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3565 __ Branch(&slow, hs, length_reg, Operand(scratch));
3566
3567 // Grow the array and finish the store.
3568 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
3569 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3570 __ jmp(&finish_store);
3571
3572 __ bind(&slow);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003573 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003574 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003575}
3576
3577
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003578void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
3579 MacroAssembler* masm,
yangguo@chromium.org56454712012-02-16 15:33:53 +00003580 bool is_js_array,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003581 KeyedAccessStoreMode store_mode) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003582 // ----------- S t a t e -------------
3583 // -- a0 : value
3584 // -- a1 : key
3585 // -- a2 : receiver
3586 // -- ra : return address
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003587 // -- a3 : scratch (elements backing store)
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003588 // -- t0 : scratch (elements_reg)
3589 // -- t1 : scratch (mantissa_reg)
3590 // -- t2 : scratch (exponent_reg)
3591 // -- t3 : scratch4
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003592 // -- t4 : scratch
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003593 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00003594 Label miss_force_generic, transition_elements_kind, grow, slow;
3595 Label finish_store, check_capacity;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003596
3597 Register value_reg = a0;
3598 Register key_reg = a1;
3599 Register receiver_reg = a2;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003600 Register elements_reg = a3;
3601 Register scratch1 = t0;
3602 Register scratch2 = t1;
3603 Register scratch3 = t2;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003604 Register scratch4 = t3;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003605 Register scratch5 = t4;
yangguo@chromium.org56454712012-02-16 15:33:53 +00003606 Register length_reg = t3;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003607
3608 // This stub is meant to be tail-jumped to, the receiver must already
3609 // have been verified by the caller to not be a smi.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003610
3611 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003612 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003613
3614 __ lw(elements_reg,
3615 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3616
3617 // Check that the key is within bounds.
3618 if (is_js_array) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003619 __ lw(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003620 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003621 __ lw(scratch1,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003622 FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3623 }
3624 // Compare smis, unsigned compare catches both negative and out-of-bound
3625 // indexes.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003626 if (IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003627 __ Branch(&grow, hs, key_reg, Operand(scratch1));
3628 } else {
3629 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch1));
3630 }
3631
3632 __ bind(&finish_store);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003633
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003634 __ StoreNumberToDoubleElements(value_reg,
3635 key_reg,
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00003636 // All registers after this are overwritten.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003637 elements_reg,
3638 scratch1,
3639 scratch2,
3640 scratch3,
3641 scratch4,
3642 &transition_elements_kind);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003643
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003644 __ Ret(USE_DELAY_SLOT);
3645 __ mov(v0, value_reg); // In delay slot.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003646
3647 // Handle store cache miss, replacing the ic with the generic stub.
3648 __ bind(&miss_force_generic);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003649 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003650
3651 __ bind(&transition_elements_kind);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003652 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003653
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003654 if (is_js_array && IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003655 // Grow the array by a single element if possible.
3656 __ bind(&grow);
3657
3658 // Make sure the array is only growing by a single element, anything else
3659 // must be handled by the runtime.
3660 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch1));
3661
3662 // Transition on values that can't be stored in a FixedDoubleArray.
3663 Label value_is_smi;
3664 __ JumpIfSmi(value_reg, &value_is_smi);
3665 __ lw(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
3666 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
3667 __ Branch(&transition_elements_kind, ne, scratch1, Operand(at));
3668 __ bind(&value_is_smi);
3669
3670 // Check for the empty array, and preallocate a small backing store if
3671 // possible.
3672 __ lw(length_reg,
3673 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3674 __ lw(elements_reg,
3675 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3676 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
3677 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
3678
3679 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003680 __ Allocate(size, elements_reg, scratch1, scratch2, &slow, TAG_OBJECT);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003681
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003682 // Initialize the new FixedDoubleArray.
yangguo@chromium.org56454712012-02-16 15:33:53 +00003683 __ LoadRoot(scratch1, Heap::kFixedDoubleArrayMapRootIndex);
3684 __ sw(scratch1, FieldMemOperand(elements_reg, JSObject::kMapOffset));
3685 __ li(scratch1, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
3686 __ sw(scratch1,
3687 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
3688
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003689 __ mov(scratch1, elements_reg);
3690 __ StoreNumberToDoubleElements(value_reg,
3691 key_reg,
3692 // All registers after this are overwritten.
3693 scratch1,
3694 scratch2,
3695 scratch3,
3696 scratch4,
3697 scratch5,
3698 &transition_elements_kind);
3699
3700 __ li(scratch1, Operand(kHoleNanLower32));
3701 __ li(scratch2, Operand(kHoleNanUpper32));
3702 for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) {
3703 int offset = FixedDoubleArray::OffsetOfElementAt(i);
3704 __ sw(scratch1, FieldMemOperand(elements_reg, offset));
3705 __ sw(scratch2, FieldMemOperand(elements_reg, offset + kPointerSize));
3706 }
3707
yangguo@chromium.org56454712012-02-16 15:33:53 +00003708 // Install the new backing store in the JSArray.
3709 __ sw(elements_reg,
3710 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3711 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
3712 scratch1, kRAHasNotBeenSaved, kDontSaveFPRegs,
3713 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3714
3715 // Increment the length of the array.
3716 __ li(length_reg, Operand(Smi::FromInt(1)));
3717 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00003718 __ Ret(USE_DELAY_SLOT);
danno@chromium.org00379b82012-05-04 09:16:29 +00003719 __ lw(elements_reg,
3720 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
yangguo@chromium.org56454712012-02-16 15:33:53 +00003721
3722 __ bind(&check_capacity);
3723 // Make sure that the backing store can hold additional elements.
3724 __ lw(scratch1,
3725 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
3726 __ Branch(&slow, hs, length_reg, Operand(scratch1));
3727
3728 // Grow the array and finish the store.
3729 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
3730 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3731 __ jmp(&finish_store);
3732
3733 __ bind(&slow);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003734 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003735 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003736}
3737
3738
ager@chromium.org5c838252010-02-19 08:53:10 +00003739#undef __
3740
3741} } // namespace v8::internal
3742
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003743#endif // V8_TARGET_ARCH_MIPS