blob: 51df45224abdb33a3d2e1d7cf4d758cf06b6e2d9 [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
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000506 if (details.type() == CONSTANT_FUNCTION) {
507 Handle<HeapObject> constant(
508 HeapObject::cast(descriptors->GetValue(descriptor)));
509 __ LoadHeapObject(scratch1, constant);
510 __ Branch(miss_restore_name, ne, value_reg, Operand(scratch1));
511 } else if (FLAG_track_fields && representation.IsSmi()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000512 __ JumpIfNotSmi(value_reg, miss_restore_name);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +0000513 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
514 __ JumpIfSmi(value_reg, miss_restore_name);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000515 } else if (FLAG_track_double_fields && representation.IsDouble()) {
516 Label do_store, heap_number;
517 __ LoadRoot(scratch3, Heap::kHeapNumberMapRootIndex);
518 __ AllocateHeapNumber(storage_reg, scratch1, scratch2, scratch3, slow);
519
520 __ JumpIfNotSmi(value_reg, &heap_number);
521 __ SmiUntag(scratch1, value_reg);
522 __ mtc1(scratch1, f6);
523 __ cvt_d_w(f4, f6);
524 __ jmp(&do_store);
525
526 __ bind(&heap_number);
527 __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex,
528 miss_restore_name, DONT_DO_SMI_CHECK);
529 __ ldc1(f4, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
530
531 __ bind(&do_store);
532 __ sdc1(f4, FieldMemOperand(storage_reg, HeapNumber::kValueOffset));
533 }
534
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000535 // Stub never generated for non-global objects that require access
536 // checks.
537 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
538
539 // Perform map transition for the receiver if necessary.
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000540 if (details.type() == FIELD &&
541 object->map()->unused_property_fields() == 0) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000542 // The properties must be extended before we can store the value.
543 // We jump to a runtime call that extends the properties array.
544 __ push(receiver_reg);
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000545 __ li(a2, Operand(transition));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000546 __ Push(a2, a0);
547 __ TailCallExternalReference(
548 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
549 masm->isolate()),
550 3, 1);
551 return;
552 }
553
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000554 // Update the map of the object.
555 __ li(scratch1, Operand(transition));
556 __ sw(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
verwaest@chromium.org37141392012-05-31 13:27:02 +0000557
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000558 // Update the write barrier for the map field and pass the now unused
559 // name_reg as scratch register.
560 __ RecordWriteField(receiver_reg,
561 HeapObject::kMapOffset,
562 scratch1,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000563 scratch2,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000564 kRAHasNotBeenSaved,
565 kDontSaveFPRegs,
566 OMIT_REMEMBERED_SET,
567 OMIT_SMI_CHECK);
568
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000569 if (details.type() == CONSTANT_FUNCTION) {
570 ASSERT(value_reg.is(a0));
571 __ Ret(USE_DELAY_SLOT);
572 __ mov(v0, a0);
573 return;
574 }
575
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000576 int index = transition->instance_descriptors()->GetFieldIndex(
577 transition->LastAdded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000578
579 // Adjust for the number of properties stored in the object. Even in the
580 // face of a transition we can use the old map here because the size of the
581 // object and the number of in-object properties is not going to change.
582 index -= object->map()->inobject_properties();
583
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000584 // TODO(verwaest): Share this code as a code stub.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000585 SmiCheck smi_check = representation.IsTagged()
586 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000587 if (index < 0) {
588 // Set the property straight into the object.
589 int offset = object->map()->instance_size() + (index * kPointerSize);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000590 if (FLAG_track_double_fields && representation.IsDouble()) {
591 __ sw(storage_reg, FieldMemOperand(receiver_reg, offset));
592 } else {
593 __ sw(value_reg, FieldMemOperand(receiver_reg, offset));
594 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000595
danno@chromium.orgf005df62013-04-30 16:36:45 +0000596 if (!FLAG_track_fields || !representation.IsSmi()) {
597 // Skip updating write barrier if storing a smi.
598 __ JumpIfSmi(value_reg, &exit);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000599
danno@chromium.orgf005df62013-04-30 16:36:45 +0000600 // Update the write barrier for the array address.
601 // Pass the now unused name_reg as a scratch register.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000602 if (!FLAG_track_double_fields || !representation.IsDouble()) {
603 __ mov(name_reg, value_reg);
604 } else {
605 ASSERT(storage_reg.is(name_reg));
606 }
danno@chromium.orgf005df62013-04-30 16:36:45 +0000607 __ RecordWriteField(receiver_reg,
608 offset,
609 name_reg,
610 scratch1,
611 kRAHasNotBeenSaved,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000612 kDontSaveFPRegs,
613 EMIT_REMEMBERED_SET,
614 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000615 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000616 } else {
617 // Write to the properties array.
618 int offset = index * kPointerSize + FixedArray::kHeaderSize;
619 // Get the properties array
620 __ lw(scratch1,
621 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000622 if (FLAG_track_double_fields && representation.IsDouble()) {
623 __ sw(storage_reg, FieldMemOperand(scratch1, offset));
624 } else {
625 __ sw(value_reg, FieldMemOperand(scratch1, offset));
626 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000627
danno@chromium.orgf005df62013-04-30 16:36:45 +0000628 if (!FLAG_track_fields || !representation.IsSmi()) {
629 // Skip updating write barrier if storing a smi.
630 __ JumpIfSmi(value_reg, &exit);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000631
danno@chromium.orgf005df62013-04-30 16:36:45 +0000632 // Update the write barrier for the array address.
633 // Ok to clobber receiver_reg and name_reg, since we return.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000634 if (!FLAG_track_double_fields || !representation.IsDouble()) {
635 __ mov(name_reg, value_reg);
636 } else {
637 ASSERT(storage_reg.is(name_reg));
638 }
danno@chromium.orgf005df62013-04-30 16:36:45 +0000639 __ RecordWriteField(scratch1,
640 offset,
641 name_reg,
642 receiver_reg,
643 kRAHasNotBeenSaved,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000644 kDontSaveFPRegs,
645 EMIT_REMEMBERED_SET,
646 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000647 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000648 }
649
650 // Return the value (register v0).
651 ASSERT(value_reg.is(a0));
652 __ bind(&exit);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000653 __ Ret(USE_DELAY_SLOT);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000654 __ mov(v0, a0);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000655}
656
657
658// Generate StoreField code, value is passed in a0 register.
659// When leaving generated code after success, the receiver_reg and name_reg
660// may be clobbered. Upon branch to miss_label, the receiver and name
661// registers have their original values.
662void StubCompiler::GenerateStoreField(MacroAssembler* masm,
663 Handle<JSObject> object,
664 LookupResult* lookup,
665 Register receiver_reg,
666 Register name_reg,
667 Register value_reg,
668 Register scratch1,
669 Register scratch2,
670 Label* miss_label) {
671 // a0 : value
672 Label exit;
673
674 // Check that the map of the object hasn't changed.
675 __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000676 DO_SMI_CHECK);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000677
678 // Perform global security token check if needed.
679 if (object->IsJSGlobalProxy()) {
680 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
681 }
682
683 // Stub never generated for non-global objects that require access
684 // checks.
685 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
686
687 int index = lookup->GetFieldIndex().field_index();
688
689 // Adjust for the number of properties stored in the object. Even in the
690 // face of a transition we can use the old map here because the size of the
691 // object and the number of in-object properties is not going to change.
692 index -= object->map()->inobject_properties();
693
danno@chromium.orgf005df62013-04-30 16:36:45 +0000694 Representation representation = lookup->representation();
695 ASSERT(!representation.IsNone());
696 if (FLAG_track_fields && representation.IsSmi()) {
697 __ JumpIfNotSmi(value_reg, miss_label);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +0000698 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
699 __ JumpIfSmi(value_reg, miss_label);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000700 } else if (FLAG_track_double_fields && representation.IsDouble()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000701 // Load the double storage.
702 if (index < 0) {
703 int offset = object->map()->instance_size() + (index * kPointerSize);
704 __ lw(scratch1, FieldMemOperand(receiver_reg, offset));
705 } else {
706 __ lw(scratch1,
707 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
708 int offset = index * kPointerSize + FixedArray::kHeaderSize;
709 __ lw(scratch1, FieldMemOperand(scratch1, offset));
710 }
711
712 // Store the value into the storage.
713 Label do_store, heap_number;
714 __ JumpIfNotSmi(value_reg, &heap_number);
715 __ SmiUntag(scratch2, value_reg);
716 __ mtc1(scratch2, f6);
717 __ cvt_d_w(f4, f6);
718 __ jmp(&do_store);
719
720 __ bind(&heap_number);
721 __ CheckMap(value_reg, scratch2, Heap::kHeapNumberMapRootIndex,
danno@chromium.orgf005df62013-04-30 16:36:45 +0000722 miss_label, DONT_DO_SMI_CHECK);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000723 __ ldc1(f4, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
724
danno@chromium.orgf005df62013-04-30 16:36:45 +0000725 __ bind(&do_store);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000726 __ sdc1(f4, FieldMemOperand(scratch1, HeapNumber::kValueOffset));
727 // Return the value (register v0).
728 ASSERT(value_reg.is(a0));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000729 __ Ret(USE_DELAY_SLOT);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000730 __ mov(v0, a0);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000731 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +0000732 }
733
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000734 // TODO(verwaest): Share this code as a code stub.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000735 SmiCheck smi_check = representation.IsTagged()
736 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000737 if (index < 0) {
738 // Set the property straight into the object.
739 int offset = object->map()->instance_size() + (index * kPointerSize);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000740 __ sw(value_reg, FieldMemOperand(receiver_reg, offset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000741
danno@chromium.orgf005df62013-04-30 16:36:45 +0000742 if (!FLAG_track_fields || !representation.IsSmi()) {
743 // Skip updating write barrier if storing a smi.
744 __ JumpIfSmi(value_reg, &exit);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000745
danno@chromium.orgf005df62013-04-30 16:36:45 +0000746 // Update the write barrier for the array address.
747 // Pass the now unused name_reg as a scratch register.
748 __ mov(name_reg, value_reg);
749 __ RecordWriteField(receiver_reg,
750 offset,
751 name_reg,
752 scratch1,
753 kRAHasNotBeenSaved,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000754 kDontSaveFPRegs,
755 EMIT_REMEMBERED_SET,
756 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000757 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000758 } else {
759 // Write to the properties array.
760 int offset = index * kPointerSize + FixedArray::kHeaderSize;
761 // Get the properties array.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000762 __ lw(scratch1,
763 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000764 __ sw(value_reg, FieldMemOperand(scratch1, offset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000765
danno@chromium.orgf005df62013-04-30 16:36:45 +0000766 if (!FLAG_track_fields || !representation.IsSmi()) {
767 // Skip updating write barrier if storing a smi.
768 __ JumpIfSmi(value_reg, &exit);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000769
danno@chromium.orgf005df62013-04-30 16:36:45 +0000770 // Update the write barrier for the array address.
771 // Ok to clobber receiver_reg and name_reg, since we return.
772 __ mov(name_reg, value_reg);
773 __ RecordWriteField(scratch1,
774 offset,
775 name_reg,
776 receiver_reg,
777 kRAHasNotBeenSaved,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000778 kDontSaveFPRegs,
779 EMIT_REMEMBERED_SET,
780 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000781 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000782 }
783
784 // Return the value (register v0).
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000785 ASSERT(value_reg.is(a0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000786 __ bind(&exit);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000787 __ Ret(USE_DELAY_SLOT);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000788 __ mov(v0, a0);
ager@chromium.org5c838252010-02-19 08:53:10 +0000789}
790
791
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000792void BaseStoreStubCompiler::GenerateRestoreName(MacroAssembler* masm,
793 Label* label,
794 Handle<Name> name) {
795 if (!label->is_unused()) {
796 __ bind(label);
797 __ li(this->name(), Operand(name));
798 }
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000799}
800
801
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000802static void GenerateCallFunction(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000803 Handle<Object> object,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000804 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000805 Label* miss,
806 Code::ExtraICState extra_ic_state) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000807 // ----------- S t a t e -------------
808 // -- a0: receiver
809 // -- a1: function to call
810 // -----------------------------------
811 // Check that the function really is a function.
812 __ JumpIfSmi(a1, miss);
813 __ GetObjectType(a1, a3, a3);
814 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
815
816 // Patch the receiver on the stack with the global proxy if
817 // necessary.
818 if (object->IsGlobalObject()) {
819 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
820 __ sw(a3, MemOperand(sp, arguments.immediate() * kPointerSize));
821 }
822
823 // Invoke the function.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000824 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
825 ? CALL_AS_FUNCTION
826 : CALL_AS_METHOD;
827 __ InvokeFunction(a1, arguments, JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000828}
829
830
831static void PushInterceptorArguments(MacroAssembler* masm,
832 Register receiver,
833 Register holder,
834 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000835 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000836 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000837 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
838 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000839 Register scratch = name;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000840 __ li(scratch, Operand(interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000841 __ Push(scratch, receiver, holder);
842 __ lw(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
843 __ push(scratch);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000844 __ li(scratch, Operand(ExternalReference::isolate_address(masm->isolate())));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000845 __ push(scratch);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000846}
847
848
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000849static void CompileCallLoadPropertyWithInterceptor(
850 MacroAssembler* masm,
851 Register receiver,
852 Register holder,
853 Register name,
854 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000855 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
856
857 ExternalReference ref =
858 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
859 masm->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000860 __ PrepareCEntryArgs(6);
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000861 __ PrepareCEntryFunction(ref);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000862
863 CEntryStub stub(1);
864 __ CallStub(&stub);
865}
866
867
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000868static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000869
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000870// Reserves space for the extra arguments to API function in the
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000871// caller's frame.
872//
873// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
874static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
875 Register scratch) {
876 ASSERT(Smi::FromInt(0) == 0);
877 for (int i = 0; i < kFastApiCallArguments; i++) {
878 __ push(zero_reg);
879 }
880}
881
882
883// Undoes the effects of ReserveSpaceForFastApiCall.
884static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
885 __ Drop(kFastApiCallArguments);
886}
887
888
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000889static void GenerateFastApiDirectCall(MacroAssembler* masm,
890 const CallOptimization& optimization,
891 int argc) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000892 // ----------- S t a t e -------------
893 // -- sp[0] : holder (set by CheckPrototypes)
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000894 // -- sp[4] : callee JS function
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000895 // -- sp[8] : call data
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000896 // -- sp[12] : isolate
palfia@homejinni.com79d0bf72013-06-10 19:35:04 +0000897 // -- sp[16] : ReturnValue default value
898 // -- sp[20] : ReturnValue
899 // -- sp[24] : last JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000900 // -- ...
palfia@homejinni.com79d0bf72013-06-10 19:35:04 +0000901 // -- sp[(argc + 5) * 4] : first JS argument
902 // -- sp[(argc + 6) * 4] : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000903 // -----------------------------------
904 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000905 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000906 __ LoadHeapObject(t1, function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000907 __ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset));
908
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000909 // Pass the additional arguments.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000910 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000911 Handle<Object> call_data(api_call_info->data(), masm->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000912 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
913 __ li(a0, api_call_info);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000914 __ lw(t2, FieldMemOperand(a0, CallHandlerInfo::kDataOffset));
915 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000916 __ li(t2, call_data);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000917 }
918
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000919 __ li(t3, Operand(ExternalReference::isolate_address(masm->isolate())));
palfia@homejinni.com79d0bf72013-06-10 19:35:04 +0000920 // Store JS function, call data, isolate ReturnValue default and ReturnValue.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000921 __ sw(t1, MemOperand(sp, 1 * kPointerSize));
922 __ sw(t2, MemOperand(sp, 2 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000923 __ sw(t3, MemOperand(sp, 3 * kPointerSize));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000924 __ LoadRoot(t1, Heap::kUndefinedValueRootIndex);
925 __ sw(t1, MemOperand(sp, 4 * kPointerSize));
palfia@homejinni.com79d0bf72013-06-10 19:35:04 +0000926 __ sw(t1, MemOperand(sp, 5 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000927
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000928 // Prepare arguments.
palfia@homejinni.com79d0bf72013-06-10 19:35:04 +0000929 __ Addu(a2, sp, Operand(5 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000930
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000931 // Allocate the v8::Arguments structure in the arguments' space since
932 // it's not controlled by GC.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000933 const int kApiStackSpace = 4;
934
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000935 FrameScope frame_scope(masm, StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000936 __ EnterExitFrame(false, kApiStackSpace);
937
938 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
939 // struct from the function (which is currently the case). This means we pass
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +0000940 // the first argument in a1 instead of a0, if returns_handle is true.
941 // CallApiFunctionAndReturn will set up a0.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000942
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000943 Address function_address = v8::ToCData<Address>(api_call_info->callback());
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000944 bool returns_handle =
945 !CallbackTable::ReturnsVoid(masm->isolate(), function_address);
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +0000946
947 Register first_arg = returns_handle ? a1 : a0;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000948 Register second_arg = returns_handle ? a2 : a1;
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +0000949
950 // first_arg = v8::Arguments&
951 // Arguments is built at sp + 1 (sp is a reserved spot for ra).
952 __ Addu(first_arg, sp, kPointerSize);
953
954 // v8::Arguments::implicit_args_
955 __ sw(a2, MemOperand(first_arg, 0 * kPointerSize));
956 // v8::Arguments::values_
957 __ Addu(t0, a2, Operand(argc * kPointerSize));
958 __ sw(t0, MemOperand(first_arg, 1 * kPointerSize));
959 // v8::Arguments::length_ = argc
960 __ li(t0, Operand(argc));
961 __ sw(t0, MemOperand(first_arg, 2 * kPointerSize));
962 // v8::Arguments::is_construct_call = 0
963 __ sw(zero_reg, MemOperand(first_arg, 3 * kPointerSize));
964
965 const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000966 ApiFunction fun(function_address);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000967 ExternalReference::Type type =
968 returns_handle ?
969 ExternalReference::DIRECT_API_CALL :
970 ExternalReference::DIRECT_API_CALL_NEW;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000971 ExternalReference ref =
972 ExternalReference(&fun,
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000973 type,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000974 masm->isolate());
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000975
976 Address thunk_address = returns_handle
977 ? FUNCTION_ADDR(&InvokeInvocationCallback)
978 : FUNCTION_ADDR(&InvokeFunctionCallback);
979 ExternalReference::Type thunk_type =
980 returns_handle ?
981 ExternalReference::PROFILING_API_CALL :
982 ExternalReference::PROFILING_API_CALL_NEW;
983 ApiFunction thunk_fun(thunk_address);
984 ExternalReference thunk_ref = ExternalReference(&thunk_fun, thunk_type,
985 masm->isolate());
986
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000987 AllowExternalCallThatCantCauseGC scope(masm);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000988 __ CallApiFunctionAndReturn(ref,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000989 function_address,
990 thunk_ref,
991 second_arg,
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000992 kStackUnwindSpace,
993 returns_handle,
994 kFastApiCallArguments + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000995}
996
lrn@chromium.org7516f052011-03-30 08:52:27 +0000997class CallInterceptorCompiler BASE_EMBEDDED {
998 public:
999 CallInterceptorCompiler(StubCompiler* stub_compiler,
1000 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001001 Register name,
1002 Code::ExtraICState extra_ic_state)
lrn@chromium.org7516f052011-03-30 08:52:27 +00001003 : stub_compiler_(stub_compiler),
1004 arguments_(arguments),
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001005 name_(name),
1006 extra_ic_state_(extra_ic_state) {}
lrn@chromium.org7516f052011-03-30 08:52:27 +00001007
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001008 void Compile(MacroAssembler* masm,
1009 Handle<JSObject> object,
1010 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001011 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001012 LookupResult* lookup,
1013 Register receiver,
1014 Register scratch1,
1015 Register scratch2,
1016 Register scratch3,
1017 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001018 ASSERT(holder->HasNamedInterceptor());
1019 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
1020
1021 // Check that the receiver isn't a smi.
1022 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001023 CallOptimization optimization(lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001024 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001025 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
1026 holder, lookup, name, optimization, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001027 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001028 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
1029 name, holder, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001030 }
1031 }
1032
1033 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001034 void CompileCacheable(MacroAssembler* masm,
1035 Handle<JSObject> object,
1036 Register receiver,
1037 Register scratch1,
1038 Register scratch2,
1039 Register scratch3,
1040 Handle<JSObject> interceptor_holder,
1041 LookupResult* lookup,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001042 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001043 const CallOptimization& optimization,
1044 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001045 ASSERT(optimization.is_constant_call());
1046 ASSERT(!lookup->holder()->IsGlobalObject());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001047 Counters* counters = masm->isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001048 int depth1 = kInvalidProtoDepth;
1049 int depth2 = kInvalidProtoDepth;
1050 bool can_do_fast_api_call = false;
1051 if (optimization.is_simple_api_call() &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001052 !lookup->holder()->IsGlobalObject()) {
1053 depth1 = optimization.GetPrototypeDepthOfExpectedType(
1054 object, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001055 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001056 depth2 = optimization.GetPrototypeDepthOfExpectedType(
1057 interceptor_holder, Handle<JSObject>(lookup->holder()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001058 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001059 can_do_fast_api_call =
1060 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001061 }
1062
1063 __ IncrementCounter(counters->call_const_interceptor(), 1,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001064 scratch1, scratch2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001065
1066 if (can_do_fast_api_call) {
1067 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
1068 scratch1, scratch2);
1069 ReserveSpaceForFastApiCall(masm, scratch1);
1070 }
1071
1072 // Check that the maps from receiver to interceptor's holder
1073 // haven't changed and thus we can invoke interceptor.
1074 Label miss_cleanup;
1075 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
1076 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001077 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
1078 scratch1, scratch2, scratch3,
1079 name, depth1, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001080
1081 // Invoke an interceptor and if it provides a value,
1082 // branch to |regular_invoke|.
1083 Label regular_invoke;
1084 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
1085 &regular_invoke);
1086
1087 // Interceptor returned nothing for this property. Try to use cached
1088 // constant function.
1089
1090 // Check that the maps from interceptor's holder to constant function's
1091 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001092 if (*interceptor_holder != lookup->holder()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001093 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001094 Handle<JSObject>(lookup->holder()),
1095 scratch1, scratch2, scratch3,
1096 name, depth2, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001097 } else {
1098 // CheckPrototypes has a side effect of fetching a 'holder'
1099 // for API (object which is instanceof for the signature). It's
1100 // safe to omit it here, as if present, it should be fetched
1101 // by the previous CheckPrototypes.
1102 ASSERT(depth2 == kInvalidProtoDepth);
1103 }
1104
1105 // Invoke function.
1106 if (can_do_fast_api_call) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001107 GenerateFastApiDirectCall(masm, optimization, arguments_.immediate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001108 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001109 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
1110 ? CALL_AS_FUNCTION
1111 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001112 Handle<JSFunction> function = optimization.constant_function();
1113 ParameterCount expected(function);
1114 __ InvokeFunction(function, expected, arguments_,
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001115 JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001116 }
1117
1118 // Deferred code for fast API call case---clean preallocated space.
1119 if (can_do_fast_api_call) {
1120 __ bind(&miss_cleanup);
1121 FreeSpaceForFastApiCall(masm);
1122 __ Branch(miss_label);
1123 }
1124
1125 // Invoke a regular function.
1126 __ bind(&regular_invoke);
1127 if (can_do_fast_api_call) {
1128 FreeSpaceForFastApiCall(masm);
1129 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00001130 }
1131
1132 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001133 Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001134 Register receiver,
1135 Register scratch1,
1136 Register scratch2,
1137 Register scratch3,
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001138 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001139 Handle<JSObject> interceptor_holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001140 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001141 Register holder =
1142 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001143 scratch1, scratch2, scratch3,
1144 name, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001145
1146 // Call a runtime function to load the interceptor property.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001147 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001148 // Save the name_ register across the call.
1149 __ push(name_);
1150
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001151 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001152
1153 __ CallExternalReference(
1154 ExternalReference(
1155 IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
1156 masm->isolate()),
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001157 6);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001158 // Restore the name_ register.
1159 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001160 // Leave the internal frame.
lrn@chromium.org7516f052011-03-30 08:52:27 +00001161 }
1162
1163 void LoadWithInterceptor(MacroAssembler* masm,
1164 Register receiver,
1165 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001166 Handle<JSObject> holder_obj,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001167 Register scratch,
1168 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001169 {
1170 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001171
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001172 __ Push(holder, name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001173 CompileCallLoadPropertyWithInterceptor(masm,
1174 receiver,
1175 holder,
1176 name_,
1177 holder_obj);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001178 __ pop(name_); // Restore the name.
1179 __ pop(receiver); // Restore the holder.
1180 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001181 // If interceptor returns no-result sentinel, call the constant function.
1182 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
1183 __ Branch(interceptor_succeeded, ne, v0, Operand(scratch));
lrn@chromium.org7516f052011-03-30 08:52:27 +00001184 }
1185
1186 StubCompiler* stub_compiler_;
1187 const ParameterCount& arguments_;
1188 Register name_;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001189 Code::ExtraICState extra_ic_state_;
lrn@chromium.org7516f052011-03-30 08:52:27 +00001190};
1191
1192
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001193// Calls GenerateCheckPropertyCell for each global object in the prototype chain
1194// from object to (but not including) holder.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001195static void GenerateCheckPropertyCells(MacroAssembler* masm,
1196 Handle<JSObject> object,
1197 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001198 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001199 Register scratch,
1200 Label* miss) {
1201 Handle<JSObject> current = object;
1202 while (!current.is_identical_to(holder)) {
1203 if (current->IsGlobalObject()) {
1204 GenerateCheckPropertyCell(masm,
1205 Handle<GlobalObject>::cast(current),
1206 name,
1207 scratch,
1208 miss);
1209 }
1210 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
1211 }
1212}
1213
1214
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001215// Convert and store int passed in register ival to IEEE 754 single precision
1216// floating point value at memory location (dst + 4 * wordoffset)
1217// If FPU is available use it for conversion.
1218static void StoreIntAsFloat(MacroAssembler* masm,
1219 Register dst,
1220 Register wordoffset,
1221 Register ival,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001222 Register scratch1) {
1223 __ mtc1(ival, f0);
1224 __ cvt_s_w(f0, f0);
1225 __ sll(scratch1, wordoffset, 2);
1226 __ addu(scratch1, dst, scratch1);
1227 __ swc1(f0, MemOperand(scratch1, 0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001228}
1229
1230
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001231void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001232 __ Jump(code, RelocInfo::CODE_TARGET);
1233}
1234
1235
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001236#undef __
1237#define __ ACCESS_MASM(masm())
1238
1239
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001240Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
1241 Register object_reg,
1242 Handle<JSObject> holder,
1243 Register holder_reg,
1244 Register scratch1,
1245 Register scratch2,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001246 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001247 int save_at_depth,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001248 Label* miss,
1249 PrototypeCheckType check) {
1250 Handle<JSObject> first = object;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001251 // Make sure there's no overlap between holder and object registers.
1252 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1253 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1254 && !scratch2.is(scratch1));
1255
1256 // Keep track of the current object in register reg.
1257 Register reg = object_reg;
1258 int depth = 0;
1259
1260 if (save_at_depth == depth) {
1261 __ sw(reg, MemOperand(sp));
1262 }
1263
1264 // Check the maps in the prototype chain.
1265 // Traverse the prototype chain from the object and do map checks.
1266 Handle<JSObject> current = object;
1267 while (!current.is_identical_to(holder)) {
1268 ++depth;
1269
1270 // Only global objects and objects that do not require access
1271 // checks are allowed in stubs.
1272 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1273
1274 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
1275 if (!current->HasFastProperties() &&
1276 !current->IsJSGlobalObject() &&
1277 !current->IsJSGlobalProxy()) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001278 if (!name->IsUniqueName()) {
1279 ASSERT(name->IsString());
1280 name = factory()->InternalizeString(Handle<String>::cast(name));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001281 }
1282 ASSERT(current->property_dictionary()->FindEntry(*name) ==
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001283 NameDictionary::kNotFound);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001284
1285 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1286 scratch1, scratch2);
1287
1288 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1289 reg = holder_reg; // From now on the object will be in holder_reg.
1290 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1291 } else {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001292 Register map_reg = scratch1;
1293 if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) {
1294 Handle<Map> current_map(current->map());
1295 // CheckMap implicitly loads the map of |reg| into |map_reg|.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001296 __ CheckMap(reg, map_reg, current_map, miss, DONT_DO_SMI_CHECK);
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001297 } else {
1298 __ lw(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
1299 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001300 // Check access rights to the global object. This has to happen after
1301 // the map check so that we know that the object is actually a global
1302 // object.
1303 if (current->IsJSGlobalProxy()) {
1304 __ CheckAccessGlobalProxy(reg, scratch2, miss);
1305 }
1306 reg = holder_reg; // From now on the object will be in holder_reg.
1307
1308 if (heap()->InNewSpace(*prototype)) {
1309 // The prototype is in new space; we cannot store a reference to it
1310 // in the code. Load it from the map.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001311 __ lw(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001312 } else {
1313 // The prototype is in old space; load it directly.
1314 __ li(reg, Operand(prototype));
1315 }
1316 }
1317
1318 if (save_at_depth == depth) {
1319 __ sw(reg, MemOperand(sp));
1320 }
1321
1322 // Go to the next object in the prototype chain.
1323 current = prototype;
1324 }
1325
1326 // Log the check depth.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001327 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001328
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001329 if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) {
1330 // Check the holder map.
1331 __ CheckMap(reg, scratch1, Handle<Map>(holder->map()), miss,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001332 DONT_DO_SMI_CHECK);
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001333 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001334
1335 // Perform security check for access to the global object.
1336 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1337 if (holder->IsJSGlobalProxy()) {
1338 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1339 }
1340
1341 // If we've skipped any global objects, it's not enough to verify that
1342 // their maps haven't changed. We also need to check that the property
1343 // cell for the property is still empty.
1344 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1345
1346 // Return the register containing the holder.
1347 return reg;
1348}
1349
1350
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001351void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success,
1352 Label* miss) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001353 if (!miss->is_unused()) {
1354 __ Branch(success);
1355 __ bind(miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001356 TailCallBuiltin(masm(), MissBuiltin(kind()));
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001357 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001358}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001359
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001360
1361Register BaseLoadStubCompiler::CallbackHandlerFrontend(
1362 Handle<JSObject> object,
1363 Register object_reg,
1364 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001365 Handle<Name> name,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001366 Label* success,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001367 Handle<ExecutableAccessorInfo> callback) {
1368 Label miss;
1369
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001370 Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001371
1372 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
1373 ASSERT(!reg.is(scratch2()));
1374 ASSERT(!reg.is(scratch3()));
1375 ASSERT(!reg.is(scratch4()));
1376
1377 // Load the properties dictionary.
1378 Register dictionary = scratch4();
1379 __ lw(dictionary, FieldMemOperand(reg, JSObject::kPropertiesOffset));
1380
1381 // Probe the dictionary.
1382 Label probe_done;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001383 NameDictionaryLookupStub::GeneratePositiveLookup(masm(),
1384 &miss,
1385 &probe_done,
1386 dictionary,
1387 this->name(),
1388 scratch2(),
1389 scratch3());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001390 __ bind(&probe_done);
1391
1392 // If probing finds an entry in the dictionary, scratch3 contains the
1393 // pointer into the dictionary. Check that the value is the callback.
1394 Register pointer = scratch3();
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001395 const int kElementsStartOffset = NameDictionary::kHeaderSize +
1396 NameDictionary::kElementsStartIndex * kPointerSize;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001397 const int kValueOffset = kElementsStartOffset + kPointerSize;
1398 __ lw(scratch2(), FieldMemOperand(pointer, kValueOffset));
1399 __ Branch(&miss, ne, scratch2(), Operand(callback));
1400 }
1401
1402 HandlerFrontendFooter(success, &miss);
1403 return reg;
1404}
1405
1406
1407void BaseLoadStubCompiler::NonexistentHandlerFrontend(
1408 Handle<JSObject> object,
1409 Handle<JSObject> last,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001410 Handle<Name> name,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001411 Label* success,
1412 Handle<GlobalObject> global) {
1413 Label miss;
1414
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001415 HandlerFrontendHeader(object, receiver(), last, name, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001416
1417 // If the last object in the prototype chain is a global object,
1418 // check that the global property cell is empty.
1419 if (!global.is_null()) {
1420 GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
1421 }
1422
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001423 HandlerFrontendFooter(success, &miss);
1424}
1425
1426
1427void BaseLoadStubCompiler::GenerateLoadField(Register reg,
1428 Handle<JSObject> holder,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001429 PropertyIndex field,
1430 Representation representation) {
1431 if (!reg.is(receiver())) __ mov(receiver(), reg);
1432 if (kind() == Code::LOAD_IC) {
1433 LoadFieldStub stub(field.is_inobject(holder),
1434 field.translate(holder),
1435 representation);
1436 GenerateTailCall(masm(), stub.GetCode(isolate()));
1437 } else {
1438 KeyedLoadFieldStub stub(field.is_inobject(holder),
1439 field.translate(holder),
1440 representation);
1441 GenerateTailCall(masm(), stub.GetCode(isolate()));
1442 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001443}
1444
1445
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001446void BaseLoadStubCompiler::GenerateLoadConstant(Handle<JSFunction> value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001447 // Return the constant value.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001448 __ LoadHeapObject(v0, value);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001449 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001450}
1451
1452
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001453void BaseLoadStubCompiler::GenerateLoadCallback(
1454 Register reg,
1455 Handle<ExecutableAccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001456 // Build AccessorInfo::args_ list on the stack and push property name below
1457 // the exit frame to make GC aware of them and store pointers to them.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001458 __ push(receiver());
1459 __ mov(scratch2(), sp); // scratch2 = AccessorInfo::args_
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001460 if (heap()->InNewSpace(callback->data())) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001461 __ li(scratch3(), callback);
1462 __ lw(scratch3(), FieldMemOperand(scratch3(),
1463 ExecutableAccessorInfo::kDataOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001464 } else {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001465 __ li(scratch3(), Handle<Object>(callback->data(), isolate()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001466 }
palfia@homejinni.com79d0bf72013-06-10 19:35:04 +00001467 __ Subu(sp, sp, 6 * kPointerSize);
1468 __ sw(reg, MemOperand(sp, 5 * kPointerSize));
1469 __ sw(scratch3(), MemOperand(sp, 4 * kPointerSize));
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00001470 __ LoadRoot(scratch3(), Heap::kUndefinedValueRootIndex);
palfia@homejinni.com79d0bf72013-06-10 19:35:04 +00001471 __ sw(scratch3(), MemOperand(sp, 3 * kPointerSize));
1472 __ sw(scratch3(), MemOperand(sp, 2 * kPointerSize));
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00001473 __ li(scratch4(),
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001474 Operand(ExternalReference::isolate_address(isolate())));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001475 __ sw(scratch4(), MemOperand(sp, 1 * kPointerSize));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001476 __ sw(name(), MemOperand(sp, 0 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001477
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00001478 Address getter_address = v8::ToCData<Address>(callback->getter());
1479 bool returns_handle =
1480 !CallbackTable::ReturnsVoid(isolate(), getter_address);
1481
1482 Register first_arg = returns_handle ? a1 : a0;
1483 Register second_arg = returns_handle ? a2 : a1;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001484 Register third_arg = returns_handle ? a3 : a2;
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00001485
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001486 __ mov(a2, scratch2()); // Saved in case scratch2 == a1.
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00001487 __ mov(first_arg, sp); // (first argument - see note below) = Handle<Name>
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001488
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001489 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
1490 // struct from the function (which is currently the case). This means we pass
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00001491 // the arguments in a1-a2 instead of a0-a1, if returns_handle is true.
1492 // CallApiFunctionAndReturn will set up a0.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001493
1494 const int kApiStackSpace = 1;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001495 FrameScope frame_scope(masm(), StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001496 __ EnterExitFrame(false, kApiStackSpace);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001497
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001498 // Create AccessorInfo instance on the stack above the exit frame with
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001499 // scratch2 (internal::Object** args_) as the data.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001500 __ sw(a2, MemOperand(sp, kPointerSize));
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00001501 // (second argument - see note above) = AccessorInfo&
1502 __ Addu(second_arg, sp, kPointerSize);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001503
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001504 const int kStackUnwindSpace = kFastApiCallArguments + 1;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001505
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001506 ApiFunction fun(getter_address);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001507 ExternalReference::Type type =
1508 returns_handle ?
1509 ExternalReference::DIRECT_GETTER_CALL :
1510 ExternalReference::DIRECT_GETTER_CALL_NEW;
danno@chromium.orgfe578672013-06-15 14:38:35 +00001511 ExternalReference ref = ExternalReference(&fun, type, isolate());
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001512
1513 Address thunk_address = returns_handle
1514 ? FUNCTION_ADDR(&InvokeAccessorGetter)
1515 : FUNCTION_ADDR(&InvokeAccessorGetterCallback);
1516 ExternalReference::Type thunk_type =
1517 returns_handle ?
1518 ExternalReference::PROFILING_GETTER_CALL :
1519 ExternalReference::PROFILING_GETTER_CALL_NEW;
1520 ApiFunction thunk_fun(thunk_address);
1521 ExternalReference thunk_ref = ExternalReference(&thunk_fun, thunk_type,
1522 isolate());
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001523 __ CallApiFunctionAndReturn(ref,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001524 getter_address,
1525 thunk_ref,
1526 third_arg,
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001527 kStackUnwindSpace,
1528 returns_handle,
palfia@homejinni.com79d0bf72013-06-10 19:35:04 +00001529 5);
ager@chromium.org5c838252010-02-19 08:53:10 +00001530}
1531
1532
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001533void BaseLoadStubCompiler::GenerateLoadInterceptor(
1534 Register holder_reg,
1535 Handle<JSObject> object,
1536 Handle<JSObject> interceptor_holder,
1537 LookupResult* lookup,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001538 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001539 ASSERT(interceptor_holder->HasNamedInterceptor());
1540 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1541
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001542 // So far the most popular follow ups for interceptor loads are FIELD
1543 // and CALLBACKS, so inline only them, other cases may be added
1544 // later.
1545 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001546 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001547 if (lookup->IsField()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001548 compile_followup_inline = true;
1549 } else if (lookup->type() == CALLBACKS &&
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001550 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
1551 ExecutableAccessorInfo* callback =
1552 ExecutableAccessorInfo::cast(lookup->GetCallbackObject());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001553 compile_followup_inline = callback->getter() != NULL &&
1554 callback->IsCompatibleReceiver(*object);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001555 }
1556 }
1557
1558 if (compile_followup_inline) {
1559 // Compile the interceptor call, followed by inline code to load the
1560 // property from further up the prototype chain if the call fails.
1561 // Check that the maps haven't changed.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001562 ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001563
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001564 // Preserve the receiver register explicitly whenever it is different from
1565 // the holder and it is needed should the interceptor return without any
1566 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1567 // the FIELD case might cause a miss during the prototype check.
1568 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001569 bool must_preserve_receiver_reg = !receiver().is(holder_reg) &&
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001570 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1571
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001572 // Save necessary data before invoking an interceptor.
1573 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001574 {
1575 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001576 if (must_preserve_receiver_reg) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001577 __ Push(receiver(), holder_reg, this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001578 } else {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001579 __ Push(holder_reg, this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001580 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001581 // Invoke an interceptor. Note: map checks from receiver to
1582 // interceptor's holder has been compiled before (see a caller
1583 // of this method).
1584 CompileCallLoadPropertyWithInterceptor(masm(),
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001585 receiver(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001586 holder_reg,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001587 this->name(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001588 interceptor_holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001589 // Check if interceptor provided a value for property. If it's
1590 // the case, return immediately.
1591 Label interceptor_failed;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001592 __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
1593 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001594 frame_scope.GenerateLeaveFrame();
1595 __ Ret();
1596
1597 __ bind(&interceptor_failed);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001598 __ pop(this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001599 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001600 if (must_preserve_receiver_reg) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001601 __ pop(receiver());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001602 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001603 // Leave the internal frame.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001604 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001605 GenerateLoadPostInterceptor(holder_reg, interceptor_holder, name, lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001606 } else { // !compile_followup_inline
1607 // Call the runtime system to load the interceptor.
1608 // Check that the maps haven't changed.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001609 PushInterceptorArguments(masm(), receiver(), holder_reg,
1610 this->name(), interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001611
1612 ExternalReference ref = ExternalReference(
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001613 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001614 __ TailCallExternalReference(ref, 6, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001615 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001616}
1617
1618
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001619void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001620 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001621 __ Branch(miss, ne, a2, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001622 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001623}
1624
1625
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001626void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1627 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001628 Handle<Name> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001629 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001630 ASSERT(holder->IsGlobalObject());
1631
1632 // Get the number of arguments.
1633 const int argc = arguments().immediate();
1634
1635 // Get the receiver from the stack.
1636 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1637
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001638 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001639 __ JumpIfSmi(a0, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001640 CheckPrototypes(object, a0, holder, a3, a1, t0, name, miss);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001641}
1642
1643
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001644void CallStubCompiler::GenerateLoadFunctionFromCell(
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00001645 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001646 Handle<JSFunction> function,
1647 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001648 // Get the value from the cell.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001649 __ li(a3, Operand(cell));
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00001650 __ lw(a1, FieldMemOperand(a3, Cell::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001651
1652 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001653 if (heap()->InNewSpace(*function)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001654 // We can't embed a pointer to a function in new space so we have
1655 // to verify that the shared function info is unchanged. This has
1656 // the nice side effect that multiple closures based on the same
1657 // function can all use this call IC. Before we load through the
1658 // function, we have to verify that it still is a function.
1659 __ JumpIfSmi(a1, miss);
1660 __ GetObjectType(a1, a3, a3);
1661 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
1662
1663 // Check the shared function info. Make sure it hasn't changed.
1664 __ li(a3, Handle<SharedFunctionInfo>(function->shared()));
1665 __ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
1666 __ Branch(miss, ne, t0, Operand(a3));
1667 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001668 __ Branch(miss, ne, a1, Operand(function));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001669 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001670}
1671
1672
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001673void CallStubCompiler::GenerateMissBranch() {
1674 Handle<Code> code =
danno@chromium.org40cb8782011-05-25 07:58:50 +00001675 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1676 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001677 extra_state_);
1678 __ Jump(code, RelocInfo::CODE_TARGET);
1679}
1680
1681
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001682Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1683 Handle<JSObject> holder,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001684 PropertyIndex index,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001685 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001686 // ----------- S t a t e -------------
1687 // -- a2 : name
1688 // -- ra : return address
1689 // -----------------------------------
1690 Label miss;
1691
1692 GenerateNameCheck(name, &miss);
1693
1694 const int argc = arguments().immediate();
1695
1696 // Get the receiver of the function from the stack into a0.
1697 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1698 // Check that the receiver isn't a smi.
1699 __ JumpIfSmi(a0, &miss, t0);
1700
1701 // Do the right check and compute the holder register.
1702 Register reg = CheckPrototypes(object, a0, holder, a1, a3, t0, name, &miss);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001703 GenerateFastPropertyLoad(masm(), a1, reg, index.is_inobject(holder),
1704 index.translate(holder), Representation::Tagged());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001705
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001706 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001707
1708 // Handle call cache miss.
1709 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001710 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001711
1712 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001713 return GetCode(Code::FIELD, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001714}
1715
1716
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001717Handle<Code> CallStubCompiler::CompileArrayPushCall(
1718 Handle<Object> object,
1719 Handle<JSObject> holder,
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00001720 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001721 Handle<JSFunction> function,
1722 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001723 // ----------- S t a t e -------------
1724 // -- a2 : name
1725 // -- ra : return address
1726 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1727 // -- ...
1728 // -- sp[argc * 4] : receiver
1729 // -----------------------------------
1730
1731 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001732 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001733
1734 Label miss;
1735
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001736 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001737
1738 Register receiver = a1;
1739
1740 // Get the receiver from the stack.
1741 const int argc = arguments().immediate();
1742 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1743
1744 // Check that the receiver isn't a smi.
1745 __ JumpIfSmi(receiver, &miss);
1746
1747 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001748 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, a3, v0, t0,
1749 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001750
1751 if (argc == 0) {
1752 // Nothing to do, just return the length.
1753 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001754 __ DropAndRet(argc + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001755 } else {
1756 Label call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001757 if (argc == 1) { // Otherwise fall through to call the builtin.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001758 Label attempt_to_grow_elements, with_write_barrier, check_double;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001759
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001760 Register elements = t2;
1761 Register end_elements = t1;
1762 // Get the elements array of the object.
1763 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1764
1765 // Check that the elements are in fast mode and writable.
1766 __ CheckMap(elements,
1767 v0,
1768 Heap::kFixedArrayMapRootIndex,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001769 &check_double,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001770 DONT_DO_SMI_CHECK);
1771
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001772 // Get the array's length into v0 and calculate new length.
1773 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1774 STATIC_ASSERT(kSmiTagSize == 1);
1775 STATIC_ASSERT(kSmiTag == 0);
1776 __ Addu(v0, v0, Operand(Smi::FromInt(argc)));
1777
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001778 // Get the elements' length.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001779 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1780
1781 // Check if we could survive without allocation.
1782 __ Branch(&attempt_to_grow_elements, gt, v0, Operand(t0));
1783
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001784 // Check if value is a smi.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001785 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1786 __ JumpIfNotSmi(t0, &with_write_barrier);
1787
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001788 // Save new length.
1789 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1790
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001791 // Store the value.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001792 // We may need a register containing the address end_elements below,
1793 // so write back the value in end_elements.
1794 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1795 __ Addu(end_elements, elements, end_elements);
1796 const int kEndElementsOffset =
1797 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001798 __ Addu(end_elements, end_elements, kEndElementsOffset);
1799 __ sw(t0, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001800
1801 // Check for a smi.
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001802 __ DropAndRet(argc + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001803
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001804 __ bind(&check_double);
1805
1806 // Check that the elements are in fast mode and writable.
1807 __ CheckMap(elements,
1808 a0,
1809 Heap::kFixedDoubleArrayMapRootIndex,
1810 &call_builtin,
1811 DONT_DO_SMI_CHECK);
1812
1813 // Get the array's length into r0 and calculate new length.
1814 __ lw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1815 STATIC_ASSERT(kSmiTagSize == 1);
1816 STATIC_ASSERT(kSmiTag == 0);
1817 __ Addu(a0, a0, Operand(Smi::FromInt(argc)));
1818
1819 // Get the elements' length.
1820 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1821
1822 // Check if we could survive without allocation.
1823 __ Branch(&call_builtin, gt, a0, Operand(t0));
1824
1825 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1826 __ StoreNumberToDoubleElements(
1827 t0, a0, elements, a3, t1, a2, t5,
1828 &call_builtin, argc * kDoubleSize);
1829
1830 // Save new length.
1831 __ sw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1832
1833 // Check for a smi.
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001834 __ DropAndRet(argc + 1);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001835
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001836 __ bind(&with_write_barrier);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001837
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001838 __ lw(a3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1839
1840 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
1841 Label fast_object, not_fast_object;
1842 __ CheckFastObjectElements(a3, t3, &not_fast_object);
1843 __ jmp(&fast_object);
1844 // In case of fast smi-only, convert to fast object, otherwise bail out.
1845 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001846 __ CheckFastSmiElements(a3, t3, &call_builtin);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001847
1848 __ lw(t3, FieldMemOperand(t0, HeapObject::kMapOffset));
1849 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
1850 __ Branch(&call_builtin, eq, t3, Operand(at));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001851 // edx: receiver
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001852 // a3: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001853 Label try_holey_map;
1854 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001855 FAST_ELEMENTS,
1856 a3,
1857 t3,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001858 &try_holey_map);
1859 __ mov(a2, receiver);
1860 ElementsTransitionGenerator::
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001861 GenerateMapChangeElementsTransition(masm(),
1862 DONT_TRACK_ALLOCATION_SITE,
1863 NULL);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001864 __ jmp(&fast_object);
1865
1866 __ bind(&try_holey_map);
1867 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1868 FAST_HOLEY_ELEMENTS,
1869 a3,
1870 t3,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001871 &call_builtin);
1872 __ mov(a2, receiver);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001873 ElementsTransitionGenerator::
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001874 GenerateMapChangeElementsTransition(masm(),
1875 DONT_TRACK_ALLOCATION_SITE,
1876 NULL);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001877 __ bind(&fast_object);
1878 } else {
1879 __ CheckFastObjectElements(a3, a3, &call_builtin);
1880 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001881
1882 // Save new length.
1883 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1884
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001885 // Store the value.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001886 // We may need a register containing the address end_elements below,
1887 // so write back the value in end_elements.
1888 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1889 __ Addu(end_elements, elements, end_elements);
1890 __ Addu(end_elements, end_elements, kEndElementsOffset);
1891 __ sw(t0, MemOperand(end_elements));
1892
1893 __ RecordWrite(elements,
1894 end_elements,
1895 t0,
1896 kRAHasNotBeenSaved,
1897 kDontSaveFPRegs,
1898 EMIT_REMEMBERED_SET,
1899 OMIT_SMI_CHECK);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001900 __ DropAndRet(argc + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001901
1902 __ bind(&attempt_to_grow_elements);
1903 // v0: array's length + 1.
1904 // t0: elements' length.
1905
1906 if (!FLAG_inline_new) {
1907 __ Branch(&call_builtin);
1908 }
1909
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001910 __ lw(a2, MemOperand(sp, (argc - 1) * kPointerSize));
1911 // Growing elements that are SMI-only requires special handling in case
1912 // the new element is non-Smi. For now, delegate to the builtin.
1913 Label no_fast_elements_check;
1914 __ JumpIfSmi(a2, &no_fast_elements_check);
1915 __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1916 __ CheckFastObjectElements(t3, t3, &call_builtin);
1917 __ bind(&no_fast_elements_check);
1918
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001919 ExternalReference new_space_allocation_top =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001920 ExternalReference::new_space_allocation_top_address(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001921 ExternalReference new_space_allocation_limit =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001922 ExternalReference::new_space_allocation_limit_address(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001923
1924 const int kAllocationDelta = 4;
1925 // Load top and check if it is the end of elements.
1926 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1927 __ Addu(end_elements, elements, end_elements);
1928 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset));
1929 __ li(t3, Operand(new_space_allocation_top));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001930 __ lw(a3, MemOperand(t3));
1931 __ Branch(&call_builtin, ne, end_elements, Operand(a3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001932
1933 __ li(t5, Operand(new_space_allocation_limit));
1934 __ lw(t5, MemOperand(t5));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001935 __ Addu(a3, a3, Operand(kAllocationDelta * kPointerSize));
1936 __ Branch(&call_builtin, hi, a3, Operand(t5));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001937
1938 // We fit and could grow elements.
1939 // Update new_space_allocation_top.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001940 __ sw(a3, MemOperand(t3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001941 // Push the argument.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001942 __ sw(a2, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001943 // Fill the rest with holes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001944 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001945 for (int i = 1; i < kAllocationDelta; i++) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001946 __ sw(a3, MemOperand(end_elements, i * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001947 }
1948
1949 // Update elements' and array's sizes.
1950 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1951 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta)));
1952 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1953
1954 // Elements are in new space, so write barrier is not required.
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001955 __ DropAndRet(argc + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001956 }
1957 __ bind(&call_builtin);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001958 __ TailCallExternalReference(
1959 ExternalReference(Builtins::c_ArrayPush, isolate()), argc + 1, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001960 }
1961
1962 // Handle call cache miss.
1963 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001964 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001965
1966 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001967 return GetCode(function);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001968}
1969
1970
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001971Handle<Code> CallStubCompiler::CompileArrayPopCall(
1972 Handle<Object> object,
1973 Handle<JSObject> holder,
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00001974 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001975 Handle<JSFunction> function,
1976 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001977 // ----------- S t a t e -------------
1978 // -- a2 : name
1979 // -- ra : return address
1980 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1981 // -- ...
1982 // -- sp[argc * 4] : receiver
1983 // -----------------------------------
1984
1985 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001986 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001987
1988 Label miss, return_undefined, call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001989 Register receiver = a1;
1990 Register elements = a3;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001991 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001992
1993 // Get the receiver from the stack.
1994 const int argc = arguments().immediate();
1995 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001996 // Check that the receiver isn't a smi.
1997 __ JumpIfSmi(receiver, &miss);
1998
1999 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002000 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, elements,
2001 t0, v0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002002
2003 // Get the elements array of the object.
2004 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
2005
2006 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002007 __ CheckMap(elements,
2008 v0,
2009 Heap::kFixedArrayMapRootIndex,
2010 &call_builtin,
2011 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002012
2013 // Get the array's length into t0 and calculate new length.
2014 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
2015 __ Subu(t0, t0, Operand(Smi::FromInt(1)));
2016 __ Branch(&return_undefined, lt, t0, Operand(zero_reg));
2017
2018 // Get the last element.
2019 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
2020 STATIC_ASSERT(kSmiTagSize == 1);
2021 STATIC_ASSERT(kSmiTag == 0);
2022 // We can't address the last element in one operation. Compute the more
2023 // expensive shift first, and use an offset later on.
2024 __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize);
2025 __ Addu(elements, elements, t1);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00002026 __ lw(v0, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002027 __ Branch(&call_builtin, eq, v0, Operand(t2));
2028
2029 // Set the array's length.
2030 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
2031
2032 // Fill with the hole.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00002033 __ sw(t2, FieldMemOperand(elements, FixedArray::kHeaderSize));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00002034 __ DropAndRet(argc + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002035
2036 __ bind(&return_undefined);
2037 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00002038 __ DropAndRet(argc + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002039
2040 __ bind(&call_builtin);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002041 __ TailCallExternalReference(
2042 ExternalReference(Builtins::c_ArrayPop, isolate()), argc + 1, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002043
2044 // Handle call cache miss.
2045 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002046 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002047
2048 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002049 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002050}
2051
2052
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002053Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
2054 Handle<Object> object,
2055 Handle<JSObject> holder,
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002056 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002057 Handle<JSFunction> function,
2058 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002059 // ----------- S t a t e -------------
2060 // -- a2 : function name
2061 // -- ra : return address
2062 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2063 // -- ...
2064 // -- sp[argc * 4] : receiver
2065 // -----------------------------------
2066
2067 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002068 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002069
2070 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002071 Label miss;
2072 Label name_miss;
2073 Label index_out_of_range;
2074
2075 Label* index_out_of_range_label = &index_out_of_range;
2076
danno@chromium.org40cb8782011-05-25 07:58:50 +00002077 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002078 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002079 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002080 index_out_of_range_label = &miss;
2081 }
2082
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002083 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002084
2085 // Check that the maps starting from the prototype haven't changed.
2086 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2087 Context::STRING_FUNCTION_INDEX,
2088 v0,
2089 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002090 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002091 CheckPrototypes(
2092 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2093 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002094
2095 Register receiver = a1;
2096 Register index = t1;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002097 Register result = v0;
2098 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
2099 if (argc > 0) {
2100 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
2101 } else {
2102 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
2103 }
2104
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002105 StringCharCodeAtGenerator generator(receiver,
2106 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002107 result,
2108 &miss, // When not a string.
2109 &miss, // When not a number.
2110 index_out_of_range_label,
2111 STRING_INDEX_IS_NUMBER);
2112 generator.GenerateFast(masm());
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00002113 __ DropAndRet(argc + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002114
2115 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002116 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002117
2118 if (index_out_of_range.is_linked()) {
2119 __ bind(&index_out_of_range);
2120 __ LoadRoot(v0, Heap::kNanValueRootIndex);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00002121 __ DropAndRet(argc + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002122 }
2123
2124 __ bind(&miss);
2125 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002126 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002127 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002128 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002129
2130 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002131 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002132}
2133
2134
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002135Handle<Code> CallStubCompiler::CompileStringCharAtCall(
2136 Handle<Object> object,
2137 Handle<JSObject> holder,
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002138 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002139 Handle<JSFunction> function,
2140 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002141 // ----------- S t a t e -------------
2142 // -- a2 : function name
2143 // -- ra : return address
2144 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2145 // -- ...
2146 // -- sp[argc * 4] : receiver
2147 // -----------------------------------
2148
2149 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002150 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002151
2152 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002153 Label miss;
2154 Label name_miss;
2155 Label index_out_of_range;
2156 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00002157 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002158 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002159 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002160 index_out_of_range_label = &miss;
2161 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002162 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002163
2164 // Check that the maps starting from the prototype haven't changed.
2165 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2166 Context::STRING_FUNCTION_INDEX,
2167 v0,
2168 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002169 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002170 CheckPrototypes(
2171 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2172 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002173
2174 Register receiver = v0;
2175 Register index = t1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00002176 Register scratch = a3;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002177 Register result = v0;
2178 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
2179 if (argc > 0) {
2180 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
2181 } else {
2182 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
2183 }
2184
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002185 StringCharAtGenerator generator(receiver,
2186 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00002187 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002188 result,
2189 &miss, // When not a string.
2190 &miss, // When not a number.
2191 index_out_of_range_label,
2192 STRING_INDEX_IS_NUMBER);
2193 generator.GenerateFast(masm());
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00002194 __ DropAndRet(argc + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002195
2196 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002197 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002198
2199 if (index_out_of_range.is_linked()) {
2200 __ bind(&index_out_of_range);
ulan@chromium.org750145a2013-03-07 15:14:13 +00002201 __ LoadRoot(v0, Heap::kempty_stringRootIndex);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00002202 __ DropAndRet(argc + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002203 }
2204
2205 __ bind(&miss);
2206 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002207 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002208 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002209 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002210
2211 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002212 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002213}
2214
2215
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002216Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
2217 Handle<Object> object,
2218 Handle<JSObject> holder,
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002219 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002220 Handle<JSFunction> function,
2221 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002222 // ----------- S t a t e -------------
2223 // -- a2 : function name
2224 // -- ra : return address
2225 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2226 // -- ...
2227 // -- sp[argc * 4] : receiver
2228 // -----------------------------------
2229
2230 const int argc = arguments().immediate();
2231
2232 // If the object is not a JSObject or we got an unexpected number of
2233 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002234 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002235
2236 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002237 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002238
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002239 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002240 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
2241
2242 STATIC_ASSERT(kSmiTag == 0);
2243 __ JumpIfSmi(a1, &miss);
2244
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002245 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2246 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002247 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002248 ASSERT(cell->value() == *function);
2249 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2250 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002251 GenerateLoadFunctionFromCell(cell, function, &miss);
2252 }
2253
2254 // Load the char code argument.
2255 Register code = a1;
2256 __ lw(code, MemOperand(sp, 0 * kPointerSize));
2257
2258 // Check the code is a smi.
2259 Label slow;
2260 STATIC_ASSERT(kSmiTag == 0);
2261 __ JumpIfNotSmi(code, &slow);
2262
2263 // Convert the smi code to uint16.
2264 __ And(code, code, Operand(Smi::FromInt(0xffff)));
2265
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002266 StringCharFromCodeGenerator generator(code, v0);
2267 generator.GenerateFast(masm());
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00002268 __ DropAndRet(argc + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002269
2270 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002271 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002272
2273 // Tail call the full function. We do not have to patch the receiver
2274 // because the function makes no use of it.
2275 __ bind(&slow);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002276 ParameterCount expected(function);
2277 __ InvokeFunction(function, expected, arguments(),
2278 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002279
2280 __ bind(&miss);
2281 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002282 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002283
2284 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002285 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002286}
2287
2288
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002289Handle<Code> CallStubCompiler::CompileMathFloorCall(
2290 Handle<Object> object,
2291 Handle<JSObject> holder,
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002292 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002293 Handle<JSFunction> function,
2294 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002295 // ----------- S t a t e -------------
2296 // -- a2 : function name
2297 // -- ra : return address
2298 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2299 // -- ...
2300 // -- sp[argc * 4] : receiver
2301 // -----------------------------------
2302
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002303
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002304 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002305 // If the object is not a JSObject or we got an unexpected number of
2306 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002307 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002308
2309 Label miss, slow;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002310 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002311
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002312 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002313 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002314 STATIC_ASSERT(kSmiTag == 0);
2315 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002316 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2317 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002318 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002319 ASSERT(cell->value() == *function);
2320 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2321 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002322 GenerateLoadFunctionFromCell(cell, function, &miss);
2323 }
2324
2325 // Load the (only) argument into v0.
2326 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2327
2328 // If the argument is a smi, just return.
2329 STATIC_ASSERT(kSmiTag == 0);
2330 __ And(t0, v0, Operand(kSmiTagMask));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00002331 __ DropAndRet(argc + 1, eq, t0, Operand(zero_reg));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002332
danno@chromium.org40cb8782011-05-25 07:58:50 +00002333 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002334
2335 Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return;
2336
2337 // If fpu is enabled, we use the floor instruction.
2338
2339 // Load the HeapNumber value.
2340 __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2341
2342 // Backup FCSR.
2343 __ cfc1(a3, FCSR);
2344 // Clearing FCSR clears the exception mask with no side-effects.
2345 __ ctc1(zero_reg, FCSR);
2346 // Convert the argument to an integer.
2347 __ floor_w_d(f0, f0);
2348
2349 // Start checking for special cases.
2350 // Get the argument exponent and clear the sign bit.
2351 __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize));
2352 __ And(t2, t1, Operand(~HeapNumber::kSignMask));
2353 __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord);
2354
2355 // Retrieve FCSR and check for fpu errors.
2356 __ cfc1(t5, FCSR);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002357 __ And(t5, t5, Operand(kFCSRExceptionFlagMask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002358 __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));
2359
2360 // Check for NaN, Infinity, and -Infinity.
2361 // They are invariant through a Math.Floor call, so just
2362 // return the original argument.
2363 __ Subu(t3, t2, Operand(HeapNumber::kExponentMask
2364 >> HeapNumber::kMantissaBitsInTopWord));
2365 __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg));
2366 // We had an overflow or underflow in the conversion. Check if we
2367 // have a big exponent.
2368 // If greater or equal, the argument is already round and in v0.
2369 __ Branch(&restore_fcsr_and_return, ge, t3,
2370 Operand(HeapNumber::kMantissaBits));
2371 __ Branch(&wont_fit_smi);
2372
2373 __ bind(&no_fpu_error);
2374 // Move the result back to v0.
2375 __ mfc1(v0, f0);
2376 // Check if the result fits into a smi.
2377 __ Addu(a1, v0, Operand(0x40000000));
2378 __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg));
2379 // Tag the result.
2380 STATIC_ASSERT(kSmiTag == 0);
2381 __ sll(v0, v0, kSmiTagSize);
2382
2383 // Check for -0.
2384 __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg));
2385 // t1 already holds the HeapNumber exponent.
2386 __ And(t0, t1, Operand(HeapNumber::kSignMask));
2387 // If our HeapNumber is negative it was -0, so load its address and return.
2388 // Else v0 is loaded with 0, so we can also just return.
2389 __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg));
2390 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2391
2392 __ bind(&restore_fcsr_and_return);
2393 // Restore FCSR and return.
2394 __ ctc1(a3, FCSR);
2395
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00002396 __ DropAndRet(argc + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002397
2398 __ bind(&wont_fit_smi);
2399 // Restore FCSR and fall to slow case.
2400 __ ctc1(a3, FCSR);
2401
2402 __ bind(&slow);
2403 // Tail call the full function. We do not have to patch the receiver
2404 // because the function makes no use of it.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002405 ParameterCount expected(function);
2406 __ InvokeFunction(function, expected, arguments(),
2407 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002408
2409 __ bind(&miss);
2410 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002411 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002412
2413 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002414 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002415}
2416
2417
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002418Handle<Code> CallStubCompiler::CompileMathAbsCall(
2419 Handle<Object> object,
2420 Handle<JSObject> holder,
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002421 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002422 Handle<JSFunction> function,
2423 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002424 // ----------- S t a t e -------------
2425 // -- a2 : function name
2426 // -- ra : return address
2427 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2428 // -- ...
2429 // -- sp[argc * 4] : receiver
2430 // -----------------------------------
2431
2432 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002433 // If the object is not a JSObject or we got an unexpected number of
2434 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002435 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002436
2437 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002438
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002439 GenerateNameCheck(name, &miss);
2440 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002441 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002442 STATIC_ASSERT(kSmiTag == 0);
2443 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002444 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2445 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002446 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002447 ASSERT(cell->value() == *function);
2448 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2449 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002450 GenerateLoadFunctionFromCell(cell, function, &miss);
2451 }
2452
2453 // Load the (only) argument into v0.
2454 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2455
2456 // Check if the argument is a smi.
2457 Label not_smi;
2458 STATIC_ASSERT(kSmiTag == 0);
2459 __ JumpIfNotSmi(v0, &not_smi);
2460
2461 // Do bitwise not or do nothing depending on the sign of the
2462 // argument.
2463 __ sra(t0, v0, kBitsPerInt - 1);
2464 __ Xor(a1, v0, t0);
2465
2466 // Add 1 or do nothing depending on the sign of the argument.
2467 __ Subu(v0, a1, t0);
2468
2469 // If the result is still negative, go to the slow case.
2470 // This only happens for the most negative smi.
2471 Label slow;
2472 __ Branch(&slow, lt, v0, Operand(zero_reg));
2473
2474 // Smi case done.
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00002475 __ DropAndRet(argc + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002476
2477 // Check if the argument is a heap number and load its exponent and
2478 // sign.
2479 __ bind(&not_smi);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002480 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002481 __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2482
2483 // Check the sign of the argument. If the argument is positive,
2484 // just return it.
2485 Label negative_sign;
2486 __ And(t0, a1, Operand(HeapNumber::kSignMask));
2487 __ Branch(&negative_sign, ne, t0, Operand(zero_reg));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00002488 __ DropAndRet(argc + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002489
2490 // If the argument is negative, clear the sign, and return a new
2491 // number.
2492 __ bind(&negative_sign);
2493 __ Xor(a1, a1, Operand(HeapNumber::kSignMask));
2494 __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2495 __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
2496 __ AllocateHeapNumber(v0, t0, t1, t2, &slow);
2497 __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2498 __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00002499 __ DropAndRet(argc + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002500
2501 // Tail call the full function. We do not have to patch the receiver
2502 // because the function makes no use of it.
2503 __ bind(&slow);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002504 ParameterCount expected(function);
2505 __ InvokeFunction(function, expected, arguments(),
2506 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002507
2508 __ bind(&miss);
2509 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002510 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002511
2512 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002513 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002514}
2515
2516
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002517Handle<Code> CallStubCompiler::CompileFastApiCall(
lrn@chromium.org7516f052011-03-30 08:52:27 +00002518 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002519 Handle<Object> object,
2520 Handle<JSObject> holder,
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002521 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002522 Handle<JSFunction> function,
2523 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002524
danno@chromium.org40cb8782011-05-25 07:58:50 +00002525 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002526
2527 ASSERT(optimization.is_simple_api_call());
2528 // Bail out if object is a global object as we don't want to
2529 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002530 if (object->IsGlobalObject()) return Handle<Code>::null();
2531 if (!cell.is_null()) return Handle<Code>::null();
2532 if (!object->IsJSObject()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002533 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002534 Handle<JSObject>::cast(object), holder);
2535 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002536
2537 Label miss, miss_before_stack_reserved;
2538
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002539 GenerateNameCheck(name, &miss_before_stack_reserved);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002540
2541 // Get the receiver from the stack.
2542 const int argc = arguments().immediate();
2543 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2544
2545 // Check that the receiver isn't a smi.
2546 __ JumpIfSmi(a1, &miss_before_stack_reserved);
2547
2548 __ IncrementCounter(counters->call_const(), 1, a0, a3);
2549 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2550
2551 ReserveSpaceForFastApiCall(masm(), a0);
2552
2553 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002554 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002555 depth, &miss);
2556
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002557 GenerateFastApiDirectCall(masm(), optimization, argc);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002558
2559 __ bind(&miss);
2560 FreeSpaceForFastApiCall(masm());
2561
2562 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002563 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002564
2565 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002566 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002567}
2568
2569
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002570void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
2571 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002572 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002573 CheckType check,
2574 Label* success) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002575 // ----------- S t a t e -------------
2576 // -- a2 : name
2577 // -- ra : return address
2578 // -----------------------------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002579 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002580 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002581
2582 // Get the receiver from the stack.
2583 const int argc = arguments().immediate();
2584 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2585
2586 // Check that the receiver isn't a smi.
2587 if (check != NUMBER_CHECK) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002588 __ JumpIfSmi(a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002589 }
2590
2591 // Make sure that it's okay not to patch the on stack receiver
2592 // unless we're doing a receiver map check.
2593 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002594 switch (check) {
2595 case RECEIVER_MAP_CHECK:
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002596 __ IncrementCounter(isolate()->counters()->call_const(), 1, a0, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002597
2598 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002599 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2600 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002601
2602 // Patch the receiver on the stack with the global proxy if
2603 // necessary.
2604 if (object->IsGlobalObject()) {
2605 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2606 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2607 }
2608 break;
2609
2610 case STRING_CHECK:
ulan@chromium.org750145a2013-03-07 15:14:13 +00002611 // Check that the object is a string.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002612 __ GetObjectType(a1, a3, a3);
2613 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2614 // Check that the maps starting from the prototype haven't changed.
2615 GenerateDirectLoadGlobalFunctionPrototype(
2616 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
2617 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002618 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002619 a0, holder, a3, a1, t0, name, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002620 break;
2621
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002622 case SYMBOL_CHECK:
2623 // Check that the object is a symbol.
2624 __ GetObjectType(a1, a1, a3);
2625 __ Branch(&miss, ne, a3, Operand(SYMBOL_TYPE));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002626 // Check that the maps starting from the prototype haven't changed.
2627 GenerateDirectLoadGlobalFunctionPrototype(
2628 masm(), Context::SYMBOL_FUNCTION_INDEX, a0, &miss);
2629 CheckPrototypes(
2630 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2631 a0, holder, a3, a1, t0, name, &miss);
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002632 break;
2633
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002634 case NUMBER_CHECK: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002635 Label fast;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002636 // Check that the object is a smi or a heap number.
2637 __ JumpIfSmi(a1, &fast);
2638 __ GetObjectType(a1, a0, a0);
2639 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
2640 __ bind(&fast);
2641 // Check that the maps starting from the prototype haven't changed.
2642 GenerateDirectLoadGlobalFunctionPrototype(
2643 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
2644 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002645 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002646 a0, holder, a3, a1, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002647 break;
2648 }
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002649 case BOOLEAN_CHECK: {
2650 Label fast;
2651 // Check that the object is a boolean.
2652 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
2653 __ Branch(&fast, eq, a1, Operand(t0));
2654 __ LoadRoot(t0, Heap::kFalseValueRootIndex);
2655 __ Branch(&miss, ne, a1, Operand(t0));
2656 __ bind(&fast);
2657 // Check that the maps starting from the prototype haven't changed.
2658 GenerateDirectLoadGlobalFunctionPrototype(
2659 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
2660 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002661 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002662 a0, holder, a3, a1, t0, name, &miss);
2663 break;
2664 }
2665 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002666
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002667 __ jmp(success);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002668
2669 // Handle call cache miss.
2670 __ bind(&miss);
2671
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002672 GenerateMissBranch();
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002673}
2674
2675
2676void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) {
2677 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
2678 ? CALL_AS_FUNCTION
2679 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002680 ParameterCount expected(function);
2681 __ InvokeFunction(function, expected, arguments(),
2682 JUMP_FUNCTION, NullCallWrapper(), call_kind);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002683}
2684
2685
2686Handle<Code> CallStubCompiler::CompileCallConstant(
2687 Handle<Object> object,
2688 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002689 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002690 CheckType check,
2691 Handle<JSFunction> function) {
2692 if (HasCustomCallGenerator(function)) {
2693 Handle<Code> code = CompileCustomCall(object, holder,
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002694 Handle<Cell>::null(),
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002695 function, Handle<String>::cast(name));
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002696 // A null handle means bail out to the regular compiler code below.
2697 if (!code.is_null()) return code;
2698 }
2699
2700 Label success;
2701
2702 CompileHandlerFrontend(object, holder, name, check, &success);
2703 __ bind(&success);
2704 CompileHandlerBackend(function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002705
2706 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002707 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002708}
2709
2710
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002711Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2712 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002713 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002714 // ----------- S t a t e -------------
2715 // -- a2 : name
2716 // -- ra : return address
2717 // -----------------------------------
2718
2719 Label miss;
2720
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002721 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002722
2723 // Get the number of arguments.
2724 const int argc = arguments().immediate();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002725 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002726 LookupPostInterceptor(holder, name, &lookup);
2727
2728 // Get the receiver from the stack.
2729 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2730
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002731 CallInterceptorCompiler compiler(this, arguments(), a2, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002732 compiler.Compile(masm(), object, holder, name, &lookup, a1, a3, t0, a0,
2733 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002734
2735 // Move returned value, the function to call, to a1.
2736 __ mov(a1, v0);
2737 // Restore receiver.
2738 __ lw(a0, MemOperand(sp, argc * kPointerSize));
2739
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002740 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002741
2742 // Handle call cache miss.
2743 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002744 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002745
2746 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002747 return GetCode(Code::INTERCEPTOR, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002748}
2749
2750
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002751Handle<Code> CallStubCompiler::CompileCallGlobal(
2752 Handle<JSObject> object,
2753 Handle<GlobalObject> holder,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002754 Handle<PropertyCell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002755 Handle<JSFunction> function,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002756 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002757 // ----------- S t a t e -------------
2758 // -- a2 : name
2759 // -- ra : return address
2760 // -----------------------------------
2761
2762 if (HasCustomCallGenerator(function)) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002763 Handle<Code> code = CompileCustomCall(
2764 object, holder, cell, function, Handle<String>::cast(name));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002765 // A null handle means bail out to the regular compiler code below.
2766 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002767 }
2768
2769 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002770 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002771
2772 // Get the number of arguments.
2773 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002774 GenerateGlobalReceiverCheck(object, holder, name, &miss);
2775 GenerateLoadFunctionFromCell(cell, function, &miss);
2776
2777 // Patch the receiver on the stack with the global proxy if
2778 // necessary.
2779 if (object->IsGlobalObject()) {
2780 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
2781 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2782 }
2783
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002784 // Set up the context (function already in r1).
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002785 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
2786
2787 // Jump to the cached code (tail call).
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002788 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002789 __ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002790 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002791 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002792 ? CALL_AS_FUNCTION
2793 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002794 // We call indirectly through the code field in the function to
2795 // allow recompilation to take effect without changing any of the
2796 // call sites.
2797 __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
2798 __ InvokeCode(a3, expected, arguments(), JUMP_FUNCTION,
2799 NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002800
2801 // Handle call cache miss.
2802 __ bind(&miss);
2803 __ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002804 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002805
2806 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002807 return GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002808}
2809
2810
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002811Handle<Code> StoreStubCompiler::CompileStoreCallback(
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002812 Handle<Name> name,
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002813 Handle<JSObject> object,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002814 Handle<JSObject> holder,
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002815 Handle<ExecutableAccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002816 Label miss;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002817 // Check that the maps haven't changed.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002818 __ JumpIfSmi(receiver(), &miss);
2819 CheckPrototypes(object, receiver(), holder,
2820 scratch1(), scratch2(), scratch3(), name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002821
2822 // Stub never generated for non-global objects that require access
2823 // checks.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002824 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002825
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002826 __ push(receiver()); // Receiver.
2827 __ li(at, Operand(callback)); // Callback info.
2828 __ Push(at, this->name(), value());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002829
2830 // Do tail-call to the runtime system.
2831 ExternalReference store_callback_property =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002832 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002833 __ TailCallExternalReference(store_callback_property, 4, 1);
2834
2835 // Handle store cache miss.
2836 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002837 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002838
2839 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002840 return GetICCode(kind(), Code::CALLBACKS, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002841}
2842
2843
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002844#undef __
2845#define __ ACCESS_MASM(masm)
2846
2847
2848void StoreStubCompiler::GenerateStoreViaSetter(
2849 MacroAssembler* masm,
2850 Handle<JSFunction> setter) {
2851 // ----------- S t a t e -------------
2852 // -- a0 : value
2853 // -- a1 : receiver
2854 // -- a2 : name
2855 // -- ra : return address
2856 // -----------------------------------
2857 {
2858 FrameScope scope(masm, StackFrame::INTERNAL);
2859
2860 // Save value register, so we can restore it later.
2861 __ push(a0);
2862
2863 if (!setter.is_null()) {
2864 // Call the JavaScript setter with receiver and value on the stack.
2865 __ push(a1);
2866 __ push(a0);
2867 ParameterCount actual(1);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002868 ParameterCount expected(setter);
2869 __ InvokeFunction(setter, expected, actual,
2870 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002871 } else {
2872 // If we generate a global code snippet for deoptimization only, remember
2873 // the place to continue after deoptimization.
2874 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2875 }
2876
2877 // We have to return the passed value, not the return value of the setter.
2878 __ pop(v0);
2879
2880 // Restore context register.
2881 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2882 }
2883 __ Ret();
2884}
2885
2886
2887#undef __
2888#define __ ACCESS_MASM(masm())
2889
2890
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002891Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002892 Handle<JSObject> object,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002893 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002894 Label miss;
2895
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002896 // Check that the map of the object hasn't changed.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002897 __ CheckMap(receiver(), scratch1(), Handle<Map>(object->map()), &miss,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002898 DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002899
2900 // Perform global security token check if needed.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002901 if (object->IsJSGlobalProxy()) {
2902 __ CheckAccessGlobalProxy(receiver(), scratch1(), &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002903 }
2904
2905 // Stub is never generated for non-global objects that require access
2906 // checks.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002907 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002908
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002909 __ Push(receiver(), this->name(), value());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002910
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002911 __ li(scratch1(), Operand(Smi::FromInt(strict_mode())));
2912 __ push(scratch1()); // strict mode
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002913
2914 // Do tail-call to the runtime system.
2915 ExternalReference store_ic_property =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002916 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002917 __ TailCallExternalReference(store_ic_property, 4, 1);
2918
2919 // Handle store cache miss.
2920 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002921 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002922
2923 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002924 return GetICCode(kind(), Code::INTERCEPTOR, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002925}
2926
2927
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002928Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2929 Handle<GlobalObject> object,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002930 Handle<PropertyCell> cell,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002931 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002932 Label miss;
2933
2934 // Check that the map of the global has not changed.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002935 __ lw(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset));
2936 __ Branch(&miss, ne, scratch1(), Operand(Handle<Map>(object->map())));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002937
2938 // Check that the value in the cell is not the hole. If it is, this
2939 // cell could have been deleted and reintroducing the global needs
2940 // to update the property details in the property dictionary of the
2941 // global object. We bail out to the runtime system to do that.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002942 __ li(scratch1(), Operand(cell));
2943 __ LoadRoot(scratch2(), Heap::kTheHoleValueRootIndex);
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002944 __ lw(scratch3(), FieldMemOperand(scratch1(), Cell::kValueOffset));
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002945 __ Branch(&miss, eq, scratch3(), Operand(scratch2()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002946
2947 // Store the value in the cell.
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002948 __ sw(value(), FieldMemOperand(scratch1(), Cell::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002949 __ mov(v0, a0); // Stored value must be returned in v0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002950 // Cells are always rescanned, so no write barrier here.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002951
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002952 Counters* counters = isolate()->counters();
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002953 __ IncrementCounter(
2954 counters->named_store_global_inline(), 1, scratch1(), scratch2());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002955 __ Ret();
2956
2957 // Handle store cache miss.
2958 __ bind(&miss);
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002959 __ IncrementCounter(
2960 counters->named_store_global_inline_miss(), 1, scratch1(), scratch2());
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002961 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002962
2963 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002964 return GetICCode(kind(), Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002965}
2966
2967
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002968Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
2969 Handle<JSObject> object,
2970 Handle<JSObject> last,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002971 Handle<Name> name,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002972 Handle<GlobalObject> global) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002973 Label success;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002974
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002975 NonexistentHandlerFrontend(object, last, name, &success, global);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002976
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002977 __ bind(&success);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002978 // Return undefined if maps of the full prototype chain is still the same.
2979 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2980 __ Ret();
2981
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002982 // Return the generated code.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002983 return GetCode(kind(), Code::NONEXISTENT, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002984}
2985
2986
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002987Register* LoadStubCompiler::registers() {
2988 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2989 static Register registers[] = { a0, a2, a3, a1, t0, t1 };
2990 return registers;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002991}
2992
2993
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002994Register* KeyedLoadStubCompiler::registers() {
2995 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2996 static Register registers[] = { a1, a0, a2, a3, t0, t1 };
2997 return registers;
2998}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002999
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00003000
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003001Register* StoreStubCompiler::registers() {
3002 // receiver, name, value, scratch1, scratch2, scratch3.
3003 static Register registers[] = { a1, a2, a0, a3, t0, t1 };
3004 return registers;
3005}
3006
3007
3008Register* KeyedStoreStubCompiler::registers() {
3009 // receiver, name, value, scratch1, scratch2, scratch3.
3010 static Register registers[] = { a2, a1, a0, a3, t0, t1 };
3011 return registers;
3012}
3013
3014
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003015void KeyedLoadStubCompiler::GenerateNameCheck(Handle<Name> name,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00003016 Register name_reg,
3017 Label* miss) {
3018 __ Branch(miss, ne, name_reg, Operand(name));
lrn@chromium.org7516f052011-03-30 08:52:27 +00003019}
3020
3021
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003022void KeyedStoreStubCompiler::GenerateNameCheck(Handle<Name> name,
3023 Register name_reg,
3024 Label* miss) {
3025 __ Branch(miss, ne, name_reg, Operand(name));
3026}
3027
3028
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003029#undef __
3030#define __ ACCESS_MASM(masm)
3031
3032
3033void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
3034 Handle<JSFunction> getter) {
3035 // ----------- S t a t e -------------
3036 // -- a0 : receiver
3037 // -- a2 : name
3038 // -- ra : return address
3039 // -----------------------------------
3040 {
3041 FrameScope scope(masm, StackFrame::INTERNAL);
3042
3043 if (!getter.is_null()) {
3044 // Call the JavaScript getter with the receiver on the stack.
3045 __ push(a0);
3046 ParameterCount actual(0);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003047 ParameterCount expected(getter);
3048 __ InvokeFunction(getter, expected, actual,
3049 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003050 } else {
3051 // If we generate a global code snippet for deoptimization only, remember
3052 // the place to continue after deoptimization.
3053 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
3054 }
3055
3056 // Restore context register.
3057 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
3058 }
3059 __ Ret();
3060}
3061
3062
3063#undef __
3064#define __ ACCESS_MASM(masm())
3065
3066
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003067Handle<Code> LoadStubCompiler::CompileLoadGlobal(
3068 Handle<JSObject> object,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003069 Handle<GlobalObject> global,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00003070 Handle<PropertyCell> cell,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003071 Handle<Name> name,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003072 bool is_dont_delete) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003073 Label success, miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003074
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003075 __ CheckMap(
3076 receiver(), scratch1(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
3077 HandlerFrontendHeader(
3078 object, receiver(), Handle<JSObject>::cast(global), name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003079
3080 // Get the value from the cell.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003081 __ li(a3, Operand(cell));
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00003082 __ lw(t0, FieldMemOperand(a3, Cell::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003083
3084 // Check for deleted property if property can actually be deleted.
3085 if (!is_dont_delete) {
3086 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
3087 __ Branch(&miss, eq, t0, Operand(at));
3088 }
3089
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003090 HandlerFrontendFooter(&success, &miss);
3091 __ bind(&success);
3092
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003093 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003094 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00003095 __ Ret(USE_DELAY_SLOT);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003096 __ mov(v0, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003097
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003098 // Return the generated code.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003099 return GetICCode(kind(), Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003100}
3101
3102
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003103Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003104 MapHandleList* receiver_maps,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003105 CodeHandleList* handlers,
3106 Handle<Name> name,
3107 Code::StubType type,
3108 IcCheckType check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003109 Label miss;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003110
3111 if (check == PROPERTY) {
3112 GenerateNameCheck(name, this->name(), &miss);
3113 }
3114
3115 __ JumpIfSmi(receiver(), &miss);
3116 Register map_reg = scratch1();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003117
danno@chromium.org40cb8782011-05-25 07:58:50 +00003118 int receiver_count = receiver_maps->length();
danno@chromium.orgf005df62013-04-30 16:36:45 +00003119 int number_of_handled_maps = 0;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003120 __ lw(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003121 for (int current = 0; current < receiver_count; ++current) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00003122 Handle<Map> map = receiver_maps->at(current);
3123 if (!map->is_deprecated()) {
3124 number_of_handled_maps++;
3125 __ Jump(handlers->at(current), RelocInfo::CODE_TARGET,
3126 eq, map_reg, Operand(receiver_maps->at(current)));
3127 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003128 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00003129 ASSERT(number_of_handled_maps != 0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003130
3131 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003132 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003133
3134 // Return the generated code.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003135 InlineCacheState state =
danno@chromium.orgf005df62013-04-30 16:36:45 +00003136 number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003137 return GetICCode(kind(), type, name, state);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003138}
3139
3140
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003141Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
3142 MapHandleList* receiver_maps,
3143 CodeHandleList* handler_stubs,
3144 MapHandleList* transitioned_maps) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003145 Label miss;
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003146 __ JumpIfSmi(receiver(), &miss);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003147
3148 int receiver_count = receiver_maps->length();
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003149 __ lw(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003150 for (int i = 0; i < receiver_count; ++i) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003151 if (transitioned_maps->at(i).is_null()) {
3152 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq,
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003153 scratch1(), Operand(receiver_maps->at(i)));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003154 } else {
3155 Label next_map;
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003156 __ Branch(&next_map, ne, scratch1(), Operand(receiver_maps->at(i)));
3157 __ li(transition_map(), Operand(transitioned_maps->at(i)));
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003158 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003159 __ bind(&next_map);
3160 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003161 }
3162
3163 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003164 TailCallBuiltin(masm(), MissBuiltin(kind()));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003165
3166 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003167 return GetICCode(
3168 kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003169}
3170
3171
danno@chromium.org40cb8782011-05-25 07:58:50 +00003172#undef __
3173#define __ ACCESS_MASM(masm)
3174
3175
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003176void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3177 MacroAssembler* masm) {
3178 // ---------- S t a t e --------------
3179 // -- ra : return address
3180 // -- a0 : key
3181 // -- a1 : receiver
3182 // -----------------------------------
3183 Label slow, miss_force_generic;
3184
3185 Register key = a0;
3186 Register receiver = a1;
3187
3188 __ JumpIfNotSmi(key, &miss_force_generic);
3189 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
3190 __ sra(a2, a0, kSmiTagSize);
3191 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
3192 __ Ret();
3193
3194 // Slow case, key and receiver still in a0 and a1.
3195 __ bind(&slow);
3196 __ IncrementCounter(
3197 masm->isolate()->counters()->keyed_load_external_array_slow(),
3198 1, a2, a3);
3199 // Entry registers are intact.
3200 // ---------- S t a t e --------------
3201 // -- ra : return address
3202 // -- a0 : key
3203 // -- a1 : receiver
3204 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003205 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003206
3207 // Miss case, call the runtime.
3208 __ bind(&miss_force_generic);
3209
3210 // ---------- S t a t e --------------
3211 // -- ra : return address
3212 // -- a0 : key
3213 // -- a1 : receiver
3214 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003215 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_MissForceGeneric);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003216}
3217
3218
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003219static void GenerateSmiKeyCheck(MacroAssembler* masm,
3220 Register key,
3221 Register scratch0,
3222 Register scratch1,
3223 FPURegister double_scratch0,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003224 FPURegister double_scratch1,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003225 Label* fail) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003226 Label key_ok;
3227 // Check for smi or a smi inside a heap number. We convert the heap
3228 // number and check if the conversion is exact and fits into the smi
3229 // range.
3230 __ JumpIfSmi(key, &key_ok);
3231 __ CheckMap(key,
3232 scratch0,
3233 Heap::kHeapNumberMapRootIndex,
3234 fail,
3235 DONT_DO_SMI_CHECK);
3236 __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
3237 __ EmitFPUTruncate(kRoundToZero,
3238 scratch0,
3239 double_scratch0,
3240 at,
3241 double_scratch1,
3242 scratch1,
3243 kCheckForInexactConversion);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003244
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003245 __ Branch(fail, ne, scratch1, Operand(zero_reg));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003246
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003247 __ SmiTagCheckOverflow(key, scratch0, scratch1);
3248 __ BranchOnOverflow(fail, scratch1);
3249 __ bind(&key_ok);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003250}
3251
3252
danno@chromium.org40cb8782011-05-25 07:58:50 +00003253void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3254 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003255 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003256 // ---------- S t a t e --------------
3257 // -- a0 : value
3258 // -- a1 : key
3259 // -- a2 : receiver
3260 // -- ra : return address
3261 // -----------------------------------
3262
danno@chromium.org40cb8782011-05-25 07:58:50 +00003263 Label slow, check_heap_number, miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003264
3265 // Register usage.
3266 Register value = a0;
3267 Register key = a1;
3268 Register receiver = a2;
3269 // a3 mostly holds the elements array or the destination external array.
3270
danno@chromium.org40cb8782011-05-25 07:58:50 +00003271 // This stub is meant to be tail-jumped to, the receiver must already
3272 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003273
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003274 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003275 GenerateSmiKeyCheck(masm, key, t0, t1, f2, f4, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003276
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003277 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3278
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003279 // Check that the index is in range.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003280 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3281 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003282 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003283
3284 // Handle both smis and HeapNumbers in the fast path. Go to the
3285 // runtime for all other kinds of values.
3286 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003287
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003288 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003289 // Double to pixel conversion is only implemented in the runtime for now.
3290 __ JumpIfNotSmi(value, &slow);
3291 } else {
3292 __ JumpIfNotSmi(value, &check_heap_number);
3293 }
3294 __ SmiUntag(t1, value);
3295 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3296
3297 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003298 // t1: value (integer).
3299
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003300 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003301 case EXTERNAL_PIXEL_ELEMENTS: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003302 // Clamp the value to [0..255].
3303 // v0 is used as a scratch register here.
3304 Label done;
3305 __ li(v0, Operand(255));
3306 // Normal branch: nop in delay slot.
3307 __ Branch(&done, gt, t1, Operand(v0));
3308 // Use delay slot in this branch.
3309 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg));
3310 __ mov(v0, zero_reg); // In delay slot.
3311 __ mov(v0, t1); // Value is in range 0..255.
3312 __ bind(&done);
3313 __ mov(t1, v0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003314
3315 __ srl(t8, key, 1);
3316 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003317 __ sb(t1, MemOperand(t8, 0));
3318 }
3319 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003320 case EXTERNAL_BYTE_ELEMENTS:
3321 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003322 __ srl(t8, key, 1);
3323 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003324 __ sb(t1, MemOperand(t8, 0));
3325 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003326 case EXTERNAL_SHORT_ELEMENTS:
3327 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003328 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003329 __ sh(t1, MemOperand(t8, 0));
3330 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003331 case EXTERNAL_INT_ELEMENTS:
3332 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003333 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003334 __ addu(t8, a3, t8);
3335 __ sw(t1, MemOperand(t8, 0));
3336 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003337 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003338 // Perform int-to-float conversion and store to memory.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003339 __ SmiUntag(t0, key);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003340 StoreIntAsFloat(masm, a3, t0, t1, t2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003341 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003342 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003343 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003344 __ addu(a3, a3, t8);
3345 // a3: effective address of the double element
3346 FloatingPointHelper::Destination destination;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003347 destination = FloatingPointHelper::kFPURegisters;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003348 FloatingPointHelper::ConvertIntToDouble(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003349 masm, t1, destination,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003350 f0, t2, t3, // These are: double_dst, dst_mantissa, dst_exponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003351 t0, f2); // These are: scratch2, single_scratch.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003352 __ sdc1(f0, MemOperand(a3, 0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003353 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003354 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003355 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003356 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003357 case FAST_HOLEY_ELEMENTS:
3358 case FAST_HOLEY_SMI_ELEMENTS:
3359 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003360 case DICTIONARY_ELEMENTS:
3361 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003362 UNREACHABLE();
3363 break;
3364 }
3365
3366 // Entry registers are intact, a0 holds the value which is the return value.
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00003367 __ Ret(USE_DELAY_SLOT);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003368 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003369
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003370 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003371 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003372 __ bind(&check_heap_number);
3373 __ GetObjectType(value, t1, t2);
3374 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE));
3375
3376 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3377
3378 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003379
3380 // The WebGL specification leaves the behavior of storing NaN and
3381 // +/-Infinity into integer arrays basically undefined. For more
3382 // reproducible behavior, convert these to zero.
3383
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003384
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003385 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003386
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003387 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
3388 __ cvt_s_d(f0, f0);
3389 __ sll(t8, key, 1);
3390 __ addu(t8, a3, t8);
3391 __ swc1(f0, MemOperand(t8, 0));
3392 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
3393 __ sll(t8, key, 2);
3394 __ addu(t8, a3, t8);
3395 __ sdc1(f0, MemOperand(t8, 0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003396 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003397 __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003398
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003399 switch (elements_kind) {
3400 case EXTERNAL_BYTE_ELEMENTS:
3401 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3402 __ srl(t8, key, 1);
3403 __ addu(t8, a3, t8);
3404 __ sb(t3, MemOperand(t8, 0));
3405 break;
3406 case EXTERNAL_SHORT_ELEMENTS:
3407 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3408 __ addu(t8, a3, key);
3409 __ sh(t3, MemOperand(t8, 0));
3410 break;
3411 case EXTERNAL_INT_ELEMENTS:
3412 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3413 __ sll(t8, key, 1);
3414 __ addu(t8, a3, t8);
3415 __ sw(t3, MemOperand(t8, 0));
3416 break;
3417 case EXTERNAL_PIXEL_ELEMENTS:
3418 case EXTERNAL_FLOAT_ELEMENTS:
3419 case EXTERNAL_DOUBLE_ELEMENTS:
3420 case FAST_ELEMENTS:
3421 case FAST_SMI_ELEMENTS:
3422 case FAST_DOUBLE_ELEMENTS:
3423 case FAST_HOLEY_ELEMENTS:
3424 case FAST_HOLEY_SMI_ELEMENTS:
3425 case FAST_HOLEY_DOUBLE_ELEMENTS:
3426 case DICTIONARY_ELEMENTS:
3427 case NON_STRICT_ARGUMENTS_ELEMENTS:
3428 UNREACHABLE();
3429 break;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003430 }
3431 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003432
3433 // Entry registers are intact, a0 holds the value
3434 // which is the return value.
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00003435 __ Ret(USE_DELAY_SLOT);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003436 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003437 }
3438
danno@chromium.org40cb8782011-05-25 07:58:50 +00003439 // Slow case, key and receiver still in a0 and a1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003440 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003441 __ IncrementCounter(
3442 masm->isolate()->counters()->keyed_load_external_array_slow(),
3443 1, a2, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003444 // Entry registers are intact.
3445 // ---------- S t a t e --------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003446 // -- ra : return address
danno@chromium.org40cb8782011-05-25 07:58:50 +00003447 // -- a0 : key
3448 // -- a1 : receiver
3449 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003450 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003451
3452 // Miss case, call the runtime.
3453 __ bind(&miss_force_generic);
3454
3455 // ---------- S t a t e --------------
3456 // -- ra : return address
3457 // -- a0 : key
3458 // -- a1 : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003459 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003460 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003461}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003462
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003463
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003464void KeyedStoreStubCompiler::GenerateStoreFastElement(
3465 MacroAssembler* masm,
3466 bool is_js_array,
yangguo@chromium.org56454712012-02-16 15:33:53 +00003467 ElementsKind elements_kind,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003468 KeyedAccessStoreMode store_mode) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003469 // ----------- S t a t e -------------
3470 // -- a0 : value
3471 // -- a1 : key
3472 // -- a2 : receiver
3473 // -- ra : return address
3474 // -- a3 : scratch
3475 // -- a4 : scratch (elements)
3476 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00003477 Label miss_force_generic, transition_elements_kind, grow, slow;
3478 Label finish_store, check_capacity;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003479
3480 Register value_reg = a0;
3481 Register key_reg = a1;
3482 Register receiver_reg = a2;
yangguo@chromium.org56454712012-02-16 15:33:53 +00003483 Register scratch = t0;
3484 Register elements_reg = a3;
3485 Register length_reg = t1;
3486 Register scratch2 = t2;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003487
3488 // This stub is meant to be tail-jumped to, the receiver must already
3489 // have been verified by the caller to not be a smi.
3490
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003491 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003492 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003493
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003494 if (IsFastSmiElementsKind(elements_kind)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003495 __ JumpIfNotSmi(value_reg, &transition_elements_kind);
3496 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003497
3498 // Check that the key is within bounds.
yangguo@chromium.org56454712012-02-16 15:33:53 +00003499 __ lw(elements_reg,
3500 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003501 if (is_js_array) {
3502 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3503 } else {
3504 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3505 }
3506 // Compare smis.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003507 if (is_js_array && IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003508 __ Branch(&grow, hs, key_reg, Operand(scratch));
3509 } else {
3510 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
3511 }
3512
3513 // Make sure elements is a fast element array, not 'cow'.
3514 __ CheckMap(elements_reg,
3515 scratch,
3516 Heap::kFixedArrayMapRootIndex,
3517 &miss_force_generic,
3518 DONT_DO_SMI_CHECK);
3519
3520 __ bind(&finish_store);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003521
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003522 if (IsFastSmiElementsKind(elements_kind)) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003523 __ Addu(scratch,
3524 elements_reg,
3525 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3526 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
3527 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
3528 __ Addu(scratch, scratch, scratch2);
3529 __ sw(value_reg, MemOperand(scratch));
3530 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003531 ASSERT(IsFastObjectElementsKind(elements_kind));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003532 __ Addu(scratch,
3533 elements_reg,
3534 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3535 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
3536 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
3537 __ Addu(scratch, scratch, scratch2);
3538 __ sw(value_reg, MemOperand(scratch));
3539 __ mov(receiver_reg, value_reg);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003540 __ RecordWrite(elements_reg, // Object.
3541 scratch, // Address.
3542 receiver_reg, // Value.
3543 kRAHasNotBeenSaved,
3544 kDontSaveFPRegs);
3545 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003546 // value_reg (a0) is preserved.
3547 // Done.
3548 __ Ret();
3549
3550 __ bind(&miss_force_generic);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003551 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003552
3553 __ bind(&transition_elements_kind);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003554 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003555
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003556 if (is_js_array && IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003557 // Grow the array by a single element if possible.
3558 __ bind(&grow);
3559
3560 // Make sure the array is only growing by a single element, anything else
3561 // must be handled by the runtime.
3562 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch));
3563
3564 // Check for the empty array, and preallocate a small backing store if
3565 // possible.
3566 __ lw(length_reg,
3567 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3568 __ lw(elements_reg,
3569 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3570 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
3571 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
3572
3573 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003574 __ Allocate(size, elements_reg, scratch, scratch2, &slow, TAG_OBJECT);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003575
3576 __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex);
3577 __ sw(scratch, FieldMemOperand(elements_reg, JSObject::kMapOffset));
3578 __ li(scratch, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
3579 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3580 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
3581 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
3582 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::SizeFor(i)));
3583 }
3584
3585 // Store the element at index zero.
3586 __ sw(value_reg, FieldMemOperand(elements_reg, FixedArray::SizeFor(0)));
3587
3588 // Install the new backing store in the JSArray.
3589 __ sw(elements_reg,
3590 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3591 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
3592 scratch, kRAHasNotBeenSaved, kDontSaveFPRegs,
3593 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3594
3595 // Increment the length of the array.
3596 __ li(length_reg, Operand(Smi::FromInt(1)));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00003597 __ Ret(USE_DELAY_SLOT);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003598 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
yangguo@chromium.org56454712012-02-16 15:33:53 +00003599
3600 __ bind(&check_capacity);
3601 // Check for cow elements, in general they are not handled by this stub
3602 __ CheckMap(elements_reg,
3603 scratch,
3604 Heap::kFixedCOWArrayMapRootIndex,
3605 &miss_force_generic,
3606 DONT_DO_SMI_CHECK);
3607
3608 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3609 __ Branch(&slow, hs, length_reg, Operand(scratch));
3610
3611 // Grow the array and finish the store.
3612 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
3613 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3614 __ jmp(&finish_store);
3615
3616 __ bind(&slow);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003617 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003618 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003619}
3620
3621
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003622void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
3623 MacroAssembler* masm,
yangguo@chromium.org56454712012-02-16 15:33:53 +00003624 bool is_js_array,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003625 KeyedAccessStoreMode store_mode) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003626 // ----------- S t a t e -------------
3627 // -- a0 : value
3628 // -- a1 : key
3629 // -- a2 : receiver
3630 // -- ra : return address
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003631 // -- a3 : scratch (elements backing store)
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003632 // -- t0 : scratch (elements_reg)
3633 // -- t1 : scratch (mantissa_reg)
3634 // -- t2 : scratch (exponent_reg)
3635 // -- t3 : scratch4
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003636 // -- t4 : scratch
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003637 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00003638 Label miss_force_generic, transition_elements_kind, grow, slow;
3639 Label finish_store, check_capacity;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003640
3641 Register value_reg = a0;
3642 Register key_reg = a1;
3643 Register receiver_reg = a2;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003644 Register elements_reg = a3;
3645 Register scratch1 = t0;
3646 Register scratch2 = t1;
3647 Register scratch3 = t2;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003648 Register scratch4 = t3;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003649 Register scratch5 = t4;
yangguo@chromium.org56454712012-02-16 15:33:53 +00003650 Register length_reg = t3;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003651
3652 // This stub is meant to be tail-jumped to, the receiver must already
3653 // have been verified by the caller to not be a smi.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003654
3655 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003656 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003657
3658 __ lw(elements_reg,
3659 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3660
3661 // Check that the key is within bounds.
3662 if (is_js_array) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003663 __ lw(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003664 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003665 __ lw(scratch1,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003666 FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3667 }
3668 // Compare smis, unsigned compare catches both negative and out-of-bound
3669 // indexes.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003670 if (IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003671 __ Branch(&grow, hs, key_reg, Operand(scratch1));
3672 } else {
3673 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch1));
3674 }
3675
3676 __ bind(&finish_store);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003677
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003678 __ StoreNumberToDoubleElements(value_reg,
3679 key_reg,
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00003680 // All registers after this are overwritten.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003681 elements_reg,
3682 scratch1,
3683 scratch2,
3684 scratch3,
3685 scratch4,
3686 &transition_elements_kind);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003687
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003688 __ Ret(USE_DELAY_SLOT);
3689 __ mov(v0, value_reg); // In delay slot.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003690
3691 // Handle store cache miss, replacing the ic with the generic stub.
3692 __ bind(&miss_force_generic);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003693 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003694
3695 __ bind(&transition_elements_kind);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003696 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003697
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003698 if (is_js_array && IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003699 // Grow the array by a single element if possible.
3700 __ bind(&grow);
3701
3702 // Make sure the array is only growing by a single element, anything else
3703 // must be handled by the runtime.
3704 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch1));
3705
3706 // Transition on values that can't be stored in a FixedDoubleArray.
3707 Label value_is_smi;
3708 __ JumpIfSmi(value_reg, &value_is_smi);
3709 __ lw(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
3710 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
3711 __ Branch(&transition_elements_kind, ne, scratch1, Operand(at));
3712 __ bind(&value_is_smi);
3713
3714 // Check for the empty array, and preallocate a small backing store if
3715 // possible.
3716 __ lw(length_reg,
3717 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3718 __ lw(elements_reg,
3719 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3720 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
3721 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
3722
3723 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003724 __ Allocate(size, elements_reg, scratch1, scratch2, &slow, TAG_OBJECT);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003725
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003726 // Initialize the new FixedDoubleArray.
yangguo@chromium.org56454712012-02-16 15:33:53 +00003727 __ LoadRoot(scratch1, Heap::kFixedDoubleArrayMapRootIndex);
3728 __ sw(scratch1, FieldMemOperand(elements_reg, JSObject::kMapOffset));
3729 __ li(scratch1, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
3730 __ sw(scratch1,
3731 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
3732
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003733 __ mov(scratch1, elements_reg);
3734 __ StoreNumberToDoubleElements(value_reg,
3735 key_reg,
3736 // All registers after this are overwritten.
3737 scratch1,
3738 scratch2,
3739 scratch3,
3740 scratch4,
3741 scratch5,
3742 &transition_elements_kind);
3743
3744 __ li(scratch1, Operand(kHoleNanLower32));
3745 __ li(scratch2, Operand(kHoleNanUpper32));
3746 for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) {
3747 int offset = FixedDoubleArray::OffsetOfElementAt(i);
3748 __ sw(scratch1, FieldMemOperand(elements_reg, offset));
3749 __ sw(scratch2, FieldMemOperand(elements_reg, offset + kPointerSize));
3750 }
3751
yangguo@chromium.org56454712012-02-16 15:33:53 +00003752 // Install the new backing store in the JSArray.
3753 __ sw(elements_reg,
3754 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3755 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
3756 scratch1, kRAHasNotBeenSaved, kDontSaveFPRegs,
3757 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3758
3759 // Increment the length of the array.
3760 __ li(length_reg, Operand(Smi::FromInt(1)));
3761 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00003762 __ Ret(USE_DELAY_SLOT);
danno@chromium.org00379b82012-05-04 09:16:29 +00003763 __ lw(elements_reg,
3764 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
yangguo@chromium.org56454712012-02-16 15:33:53 +00003765
3766 __ bind(&check_capacity);
3767 // Make sure that the backing store can hold additional elements.
3768 __ lw(scratch1,
3769 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
3770 __ Branch(&slow, hs, length_reg, Operand(scratch1));
3771
3772 // Grow the array and finish the store.
3773 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
3774 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3775 __ jmp(&finish_store);
3776
3777 __ bind(&slow);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003778 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003779 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003780}
3781
3782
ager@chromium.org5c838252010-02-19 08:53:10 +00003783#undef __
3784
3785} } // namespace v8::internal
3786
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003787#endif // V8_TARGET_ARCH_MIPS