blob: 4d58c75e28a18f2cb017c88124b8c7d360822629 [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
ager@chromium.org5c838252010-02-19 08:53:10 +0000310// Load a fast property out of a holder object (src). In-object properties
311// are loaded directly otherwise the property is loaded from the properties
312// fixed array.
313void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000314 Register dst,
315 Register src,
316 Handle<JSObject> holder,
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +0000317 PropertyIndex index) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000318 DoGenerateFastPropertyLoad(
319 masm, dst, src, index.is_inobject(holder), index.translate(holder));
320}
321
322
323void StubCompiler::DoGenerateFastPropertyLoad(MacroAssembler* masm,
324 Register dst,
325 Register src,
326 bool inobject,
327 int index) {
328 int offset = index * kPointerSize;
329 if (!inobject) {
330 // Calculate the offset into the properties array.
331 offset = offset + FixedArray::kHeaderSize;
332 __ lw(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
333 src = dst;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000334 }
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000335 __ lw(dst, FieldMemOperand(src, offset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000336}
337
338
339void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
340 Register receiver,
341 Register scratch,
342 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000343 // Check that the receiver isn't a smi.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000344 __ JumpIfSmi(receiver, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000345
346 // Check that the object is a JS array.
347 __ GetObjectType(receiver, scratch, scratch);
348 __ Branch(miss_label, ne, scratch, Operand(JS_ARRAY_TYPE));
349
350 // Load length directly from the JS array.
351 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
352 __ Ret();
353}
354
355
356// Generate code to check if an object is a string. If the object is a
357// heap object, its map's instance type is left in the scratch1 register.
358// If this is not needed, scratch1 and scratch2 may be the same register.
359static void GenerateStringCheck(MacroAssembler* masm,
360 Register receiver,
361 Register scratch1,
362 Register scratch2,
363 Label* smi,
364 Label* non_string_object) {
365 // Check that the receiver isn't a smi.
366 __ JumpIfSmi(receiver, smi, t0);
367
368 // Check that the object is a string.
369 __ lw(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
370 __ lbu(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
371 __ And(scratch2, scratch1, Operand(kIsNotStringMask));
372 // The cast is to resolve the overload for the argument of 0x0.
373 __ Branch(non_string_object,
374 ne,
375 scratch2,
376 Operand(static_cast<int32_t>(kStringTag)));
ager@chromium.org5c838252010-02-19 08:53:10 +0000377}
378
379
lrn@chromium.org7516f052011-03-30 08:52:27 +0000380// Generate code to load the length from a string object and return the length.
381// If the receiver object is not a string or a wrapped string object the
382// execution continues at the miss label. The register containing the
383// receiver is potentially clobbered.
384void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
385 Register receiver,
386 Register scratch1,
387 Register scratch2,
388 Label* miss,
389 bool support_wrappers) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000390 Label check_wrapper;
391
392 // Check if the object is a string leaving the instance type in the
393 // scratch1 register.
394 GenerateStringCheck(masm, receiver, scratch1, scratch2, miss,
395 support_wrappers ? &check_wrapper : miss);
396
397 // Load length directly from the string.
398 __ lw(v0, FieldMemOperand(receiver, String::kLengthOffset));
399 __ Ret();
400
401 if (support_wrappers) {
402 // Check if the object is a JSValue wrapper.
403 __ bind(&check_wrapper);
404 __ Branch(miss, ne, scratch1, Operand(JS_VALUE_TYPE));
405
406 // Unwrap the value and check if the wrapped value is a string.
407 __ lw(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
408 GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
409 __ lw(v0, FieldMemOperand(scratch1, String::kLengthOffset));
410 __ Ret();
411 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000412}
413
414
ager@chromium.org5c838252010-02-19 08:53:10 +0000415void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
416 Register receiver,
417 Register scratch1,
418 Register scratch2,
419 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000420 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
421 __ mov(v0, scratch1);
422 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000423}
424
425
lrn@chromium.org7516f052011-03-30 08:52:27 +0000426// Generate StoreField code, value is passed in a0 register.
ager@chromium.org5c838252010-02-19 08:53:10 +0000427// After executing generated code, the receiver_reg and name_reg
428// may be clobbered.
429void StubCompiler::GenerateStoreField(MacroAssembler* masm,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000430 Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +0000431 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000432 Handle<Map> transition,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000433 Handle<Name> name,
ager@chromium.org5c838252010-02-19 08:53:10 +0000434 Register receiver_reg,
435 Register name_reg,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000436 Register scratch1,
437 Register scratch2,
ager@chromium.org5c838252010-02-19 08:53:10 +0000438 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000439 // a0 : value.
440 Label exit;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000441
442 LookupResult lookup(masm->isolate());
443 object->Lookup(*name, &lookup);
444 if (lookup.IsFound() && (lookup.IsReadOnly() || !lookup.IsCacheable())) {
445 // In sloppy mode, we could just return the value and be done. However, we
446 // might be in strict mode, where we have to throw. Since we cannot tell,
447 // go into slow case unconditionally.
448 __ jmp(miss_label);
449 return;
450 }
451
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000452 // Check that the map of the object hasn't changed.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000453 CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
454 : REQUIRE_EXACT_MAP;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000455 __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000456 DO_SMI_CHECK, mode);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000457
458 // Perform global security token check if needed.
459 if (object->IsJSGlobalProxy()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000460 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
461 }
462
463 // Check that we are allowed to write this.
464 if (!transition.is_null() && object->GetPrototype()->IsJSObject()) {
465 JSObject* holder;
466 if (lookup.IsFound()) {
467 holder = lookup.holder();
468 } else {
469 // Find the top object.
470 holder = *object;
471 do {
472 holder = JSObject::cast(holder->GetPrototype());
473 } while (holder->GetPrototype()->IsJSObject());
474 }
475 // We need an extra register, push
476 __ push(name_reg);
477 Label miss_pop, done_check;
478 CheckPrototypes(object, receiver_reg, Handle<JSObject>(holder), name_reg,
479 scratch1, scratch2, name, &miss_pop);
480 __ jmp(&done_check);
481 __ bind(&miss_pop);
482 __ pop(name_reg);
483 __ jmp(miss_label);
484 __ bind(&done_check);
485 __ pop(name_reg);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000486 }
487
488 // Stub never generated for non-global objects that require access
489 // checks.
490 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
491
492 // Perform map transition for the receiver if necessary.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000493 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000494 // The properties must be extended before we can store the value.
495 // We jump to a runtime call that extends the properties array.
496 __ push(receiver_reg);
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000497 __ li(a2, Operand(transition));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000498 __ Push(a2, a0);
499 __ TailCallExternalReference(
500 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
501 masm->isolate()),
502 3, 1);
503 return;
504 }
505
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000506 if (!transition.is_null()) {
verwaest@chromium.org37141392012-05-31 13:27:02 +0000507 // Update the map of the object.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000508 __ li(scratch1, Operand(transition));
509 __ sw(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
verwaest@chromium.org37141392012-05-31 13:27:02 +0000510
511 // Update the write barrier for the map field and pass the now unused
512 // name_reg as scratch register.
513 __ RecordWriteField(receiver_reg,
514 HeapObject::kMapOffset,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000515 scratch1,
verwaest@chromium.org37141392012-05-31 13:27:02 +0000516 name_reg,
517 kRAHasNotBeenSaved,
518 kDontSaveFPRegs,
519 OMIT_REMEMBERED_SET,
520 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000521 }
522
523 // Adjust for the number of properties stored in the object. Even in the
524 // face of a transition we can use the old map here because the size of the
525 // object and the number of in-object properties is not going to change.
526 index -= object->map()->inobject_properties();
527
528 if (index < 0) {
529 // Set the property straight into the object.
530 int offset = object->map()->instance_size() + (index * kPointerSize);
531 __ sw(a0, FieldMemOperand(receiver_reg, offset));
532
533 // Skip updating write barrier if storing a smi.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000534 __ JumpIfSmi(a0, &exit, scratch1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000535
536 // Update the write barrier for the array address.
537 // Pass the now unused name_reg as a scratch register.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000538 __ mov(name_reg, a0);
539 __ RecordWriteField(receiver_reg,
540 offset,
541 name_reg,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000542 scratch1,
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000543 kRAHasNotBeenSaved,
544 kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000545 } else {
546 // Write to the properties array.
547 int offset = index * kPointerSize + FixedArray::kHeaderSize;
548 // Get the properties array.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000549 __ lw(scratch1,
550 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
551 __ sw(a0, FieldMemOperand(scratch1, offset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000552
553 // Skip updating write barrier if storing a smi.
554 __ JumpIfSmi(a0, &exit);
555
556 // Update the write barrier for the array address.
557 // Ok to clobber receiver_reg and name_reg, since we return.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000558 __ mov(name_reg, a0);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000559 __ RecordWriteField(scratch1,
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000560 offset,
561 name_reg,
562 receiver_reg,
563 kRAHasNotBeenSaved,
564 kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000565 }
566
567 // Return the value (register v0).
568 __ bind(&exit);
569 __ mov(v0, a0);
570 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000571}
572
573
574void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000575 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000576 Handle<Code> code = (kind == Code::LOAD_IC)
577 ? masm->isolate()->builtins()->LoadIC_Miss()
578 : masm->isolate()->builtins()->KeyedLoadIC_Miss();
579 __ Jump(code, RelocInfo::CODE_TARGET);
ager@chromium.org5c838252010-02-19 08:53:10 +0000580}
581
582
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000583void StubCompiler::GenerateStoreMiss(MacroAssembler* masm, Code::Kind kind) {
584 ASSERT(kind == Code::STORE_IC || kind == Code::KEYED_STORE_IC);
585 Handle<Code> code = (kind == Code::STORE_IC)
586 ? masm->isolate()->builtins()->StoreIC_Miss()
587 : masm->isolate()->builtins()->KeyedStoreIC_Miss();
588 __ Jump(code, RelocInfo::CODE_TARGET);
589}
590
591
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000592static void GenerateCallFunction(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000593 Handle<Object> object,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000594 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000595 Label* miss,
596 Code::ExtraICState extra_ic_state) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000597 // ----------- S t a t e -------------
598 // -- a0: receiver
599 // -- a1: function to call
600 // -----------------------------------
601 // Check that the function really is a function.
602 __ JumpIfSmi(a1, miss);
603 __ GetObjectType(a1, a3, a3);
604 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
605
606 // Patch the receiver on the stack with the global proxy if
607 // necessary.
608 if (object->IsGlobalObject()) {
609 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
610 __ sw(a3, MemOperand(sp, arguments.immediate() * kPointerSize));
611 }
612
613 // Invoke the function.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000614 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
615 ? CALL_AS_FUNCTION
616 : CALL_AS_METHOD;
617 __ InvokeFunction(a1, arguments, JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000618}
619
620
621static void PushInterceptorArguments(MacroAssembler* masm,
622 Register receiver,
623 Register holder,
624 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000625 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000626 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000627 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
628 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000629 Register scratch = name;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000630 __ li(scratch, Operand(interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000631 __ Push(scratch, receiver, holder);
632 __ lw(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
633 __ push(scratch);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000634 __ li(scratch, Operand(ExternalReference::isolate_address()));
635 __ push(scratch);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000636}
637
638
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000639static void CompileCallLoadPropertyWithInterceptor(
640 MacroAssembler* masm,
641 Register receiver,
642 Register holder,
643 Register name,
644 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000645 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
646
647 ExternalReference ref =
648 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
649 masm->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000650 __ PrepareCEntryArgs(6);
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000651 __ PrepareCEntryFunction(ref);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000652
653 CEntryStub stub(1);
654 __ CallStub(&stub);
655}
656
657
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000658static const int kFastApiCallArguments = 4;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000659
660
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000661// Reserves space for the extra arguments to API function in the
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000662// caller's frame.
663//
664// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
665static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
666 Register scratch) {
667 ASSERT(Smi::FromInt(0) == 0);
668 for (int i = 0; i < kFastApiCallArguments; i++) {
669 __ push(zero_reg);
670 }
671}
672
673
674// Undoes the effects of ReserveSpaceForFastApiCall.
675static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
676 __ Drop(kFastApiCallArguments);
677}
678
679
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000680static void GenerateFastApiDirectCall(MacroAssembler* masm,
681 const CallOptimization& optimization,
682 int argc) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000683 // ----------- S t a t e -------------
684 // -- sp[0] : holder (set by CheckPrototypes)
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000685 // -- sp[4] : callee JS function
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000686 // -- sp[8] : call data
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000687 // -- sp[12] : isolate
688 // -- sp[16] : last JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000689 // -- ...
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000690 // -- sp[(argc + 3) * 4] : first JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000691 // -- sp[(argc + 4) * 4] : receiver
692 // -----------------------------------
693 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000694 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000695 __ LoadHeapObject(t1, function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000696 __ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset));
697
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000698 // Pass the additional arguments.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000699 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000700 Handle<Object> call_data(api_call_info->data(), masm->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000701 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
702 __ li(a0, api_call_info);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000703 __ lw(t2, FieldMemOperand(a0, CallHandlerInfo::kDataOffset));
704 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000705 __ li(t2, call_data);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000706 }
707
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000708 __ li(t3, Operand(ExternalReference::isolate_address()));
709 // Store JS function, call data and isolate.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000710 __ sw(t1, MemOperand(sp, 1 * kPointerSize));
711 __ sw(t2, MemOperand(sp, 2 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000712 __ sw(t3, MemOperand(sp, 3 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000713
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000714 // Prepare arguments.
715 __ Addu(a2, sp, Operand(3 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000716
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000717 // Allocate the v8::Arguments structure in the arguments' space since
718 // it's not controlled by GC.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000719 const int kApiStackSpace = 4;
720
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000721 FrameScope frame_scope(masm, StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000722 __ EnterExitFrame(false, kApiStackSpace);
723
724 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
725 // struct from the function (which is currently the case). This means we pass
726 // the first argument in a1 instead of a0. TryCallApiFunctionAndReturn
727 // will handle setting up a0.
728
729 // a1 = v8::Arguments&
730 // Arguments is built at sp + 1 (sp is a reserved spot for ra).
731 __ Addu(a1, sp, kPointerSize);
732
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000733 // v8::Arguments::implicit_args_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000734 __ sw(a2, MemOperand(a1, 0 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000735 // v8::Arguments::values_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000736 __ Addu(t0, a2, Operand(argc * kPointerSize));
737 __ sw(t0, MemOperand(a1, 1 * kPointerSize));
738 // v8::Arguments::length_ = argc
739 __ li(t0, Operand(argc));
740 __ sw(t0, MemOperand(a1, 2 * kPointerSize));
741 // v8::Arguments::is_construct_call = 0
742 __ sw(zero_reg, MemOperand(a1, 3 * kPointerSize));
743
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000744 const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000745 Address function_address = v8::ToCData<Address>(api_call_info->callback());
746 ApiFunction fun(function_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000747 ExternalReference ref =
748 ExternalReference(&fun,
749 ExternalReference::DIRECT_API_CALL,
750 masm->isolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000751 AllowExternalCallThatCantCauseGC scope(masm);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000752 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000753}
754
lrn@chromium.org7516f052011-03-30 08:52:27 +0000755class CallInterceptorCompiler BASE_EMBEDDED {
756 public:
757 CallInterceptorCompiler(StubCompiler* stub_compiler,
758 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000759 Register name,
760 Code::ExtraICState extra_ic_state)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000761 : stub_compiler_(stub_compiler),
762 arguments_(arguments),
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000763 name_(name),
764 extra_ic_state_(extra_ic_state) {}
lrn@chromium.org7516f052011-03-30 08:52:27 +0000765
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000766 void Compile(MacroAssembler* masm,
767 Handle<JSObject> object,
768 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000769 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000770 LookupResult* lookup,
771 Register receiver,
772 Register scratch1,
773 Register scratch2,
774 Register scratch3,
775 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000776 ASSERT(holder->HasNamedInterceptor());
777 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
778
779 // Check that the receiver isn't a smi.
780 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000781 CallOptimization optimization(lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000782 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000783 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
784 holder, lookup, name, optimization, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000785 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000786 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
787 name, holder, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000788 }
789 }
790
791 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000792 void CompileCacheable(MacroAssembler* masm,
793 Handle<JSObject> object,
794 Register receiver,
795 Register scratch1,
796 Register scratch2,
797 Register scratch3,
798 Handle<JSObject> interceptor_holder,
799 LookupResult* lookup,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000800 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000801 const CallOptimization& optimization,
802 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000803 ASSERT(optimization.is_constant_call());
804 ASSERT(!lookup->holder()->IsGlobalObject());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000805 Counters* counters = masm->isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000806 int depth1 = kInvalidProtoDepth;
807 int depth2 = kInvalidProtoDepth;
808 bool can_do_fast_api_call = false;
809 if (optimization.is_simple_api_call() &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000810 !lookup->holder()->IsGlobalObject()) {
811 depth1 = optimization.GetPrototypeDepthOfExpectedType(
812 object, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000813 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000814 depth2 = optimization.GetPrototypeDepthOfExpectedType(
815 interceptor_holder, Handle<JSObject>(lookup->holder()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000816 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000817 can_do_fast_api_call =
818 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000819 }
820
821 __ IncrementCounter(counters->call_const_interceptor(), 1,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000822 scratch1, scratch2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000823
824 if (can_do_fast_api_call) {
825 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
826 scratch1, scratch2);
827 ReserveSpaceForFastApiCall(masm, scratch1);
828 }
829
830 // Check that the maps from receiver to interceptor's holder
831 // haven't changed and thus we can invoke interceptor.
832 Label miss_cleanup;
833 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
834 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000835 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
836 scratch1, scratch2, scratch3,
837 name, depth1, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000838
839 // Invoke an interceptor and if it provides a value,
840 // branch to |regular_invoke|.
841 Label regular_invoke;
842 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
843 &regular_invoke);
844
845 // Interceptor returned nothing for this property. Try to use cached
846 // constant function.
847
848 // Check that the maps from interceptor's holder to constant function's
849 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000850 if (*interceptor_holder != lookup->holder()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000851 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000852 Handle<JSObject>(lookup->holder()),
853 scratch1, scratch2, scratch3,
854 name, depth2, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000855 } else {
856 // CheckPrototypes has a side effect of fetching a 'holder'
857 // for API (object which is instanceof for the signature). It's
858 // safe to omit it here, as if present, it should be fetched
859 // by the previous CheckPrototypes.
860 ASSERT(depth2 == kInvalidProtoDepth);
861 }
862
863 // Invoke function.
864 if (can_do_fast_api_call) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000865 GenerateFastApiDirectCall(masm, optimization, arguments_.immediate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000866 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000867 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
868 ? CALL_AS_FUNCTION
869 : CALL_AS_METHOD;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000870 __ InvokeFunction(optimization.constant_function(), arguments_,
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000871 JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000872 }
873
874 // Deferred code for fast API call case---clean preallocated space.
875 if (can_do_fast_api_call) {
876 __ bind(&miss_cleanup);
877 FreeSpaceForFastApiCall(masm);
878 __ Branch(miss_label);
879 }
880
881 // Invoke a regular function.
882 __ bind(&regular_invoke);
883 if (can_do_fast_api_call) {
884 FreeSpaceForFastApiCall(masm);
885 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000886 }
887
888 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000889 Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000890 Register receiver,
891 Register scratch1,
892 Register scratch2,
893 Register scratch3,
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000894 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000895 Handle<JSObject> interceptor_holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000896 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000897 Register holder =
898 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000899 scratch1, scratch2, scratch3,
900 name, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000901
902 // Call a runtime function to load the interceptor property.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000903 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000904 // Save the name_ register across the call.
905 __ push(name_);
906
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000907 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000908
909 __ CallExternalReference(
910 ExternalReference(
911 IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
912 masm->isolate()),
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000913 6);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000914 // Restore the name_ register.
915 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000916 // Leave the internal frame.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000917 }
918
919 void LoadWithInterceptor(MacroAssembler* masm,
920 Register receiver,
921 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000922 Handle<JSObject> holder_obj,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000923 Register scratch,
924 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000925 {
926 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000927
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000928 __ Push(holder, name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000929 CompileCallLoadPropertyWithInterceptor(masm,
930 receiver,
931 holder,
932 name_,
933 holder_obj);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000934 __ pop(name_); // Restore the name.
935 __ pop(receiver); // Restore the holder.
936 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000937 // If interceptor returns no-result sentinel, call the constant function.
938 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
939 __ Branch(interceptor_succeeded, ne, v0, Operand(scratch));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000940 }
941
942 StubCompiler* stub_compiler_;
943 const ParameterCount& arguments_;
944 Register name_;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000945 Code::ExtraICState extra_ic_state_;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000946};
947
948
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000949
950// Generate code to check that a global property cell is empty. Create
951// the property cell at compilation time if no cell exists for the
952// property.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000953static void GenerateCheckPropertyCell(MacroAssembler* masm,
954 Handle<GlobalObject> global,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000955 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000956 Register scratch,
957 Label* miss) {
958 Handle<JSGlobalPropertyCell> cell =
959 GlobalObject::EnsurePropertyCell(global, name);
960 ASSERT(cell->value()->IsTheHole());
961 __ li(scratch, Operand(cell));
962 __ lw(scratch,
963 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
964 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
965 __ Branch(miss, ne, scratch, Operand(at));
966}
967
968
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000969// Calls GenerateCheckPropertyCell for each global object in the prototype chain
970// from object to (but not including) holder.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000971static void GenerateCheckPropertyCells(MacroAssembler* masm,
972 Handle<JSObject> object,
973 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000974 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000975 Register scratch,
976 Label* miss) {
977 Handle<JSObject> current = object;
978 while (!current.is_identical_to(holder)) {
979 if (current->IsGlobalObject()) {
980 GenerateCheckPropertyCell(masm,
981 Handle<GlobalObject>::cast(current),
982 name,
983 scratch,
984 miss);
985 }
986 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
987 }
988}
989
990
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000991// Convert and store int passed in register ival to IEEE 754 single precision
992// floating point value at memory location (dst + 4 * wordoffset)
993// If FPU is available use it for conversion.
994static void StoreIntAsFloat(MacroAssembler* masm,
995 Register dst,
996 Register wordoffset,
997 Register ival,
998 Register fval,
999 Register scratch1,
1000 Register scratch2) {
1001 if (CpuFeatures::IsSupported(FPU)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001002 CpuFeatureScope scope(masm, FPU);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001003 __ mtc1(ival, f0);
1004 __ cvt_s_w(f0, f0);
1005 __ sll(scratch1, wordoffset, 2);
1006 __ addu(scratch1, dst, scratch1);
1007 __ swc1(f0, MemOperand(scratch1, 0));
1008 } else {
1009 // FPU is not available, do manual conversions.
1010
1011 Label not_special, done;
1012 // Move sign bit from source to destination. This works because the sign
1013 // bit in the exponent word of the double has the same position and polarity
1014 // as the 2's complement sign bit in a Smi.
1015 ASSERT(kBinary32SignMask == 0x80000000u);
1016
1017 __ And(fval, ival, Operand(kBinary32SignMask));
1018 // Negate value if it is negative.
1019 __ subu(scratch1, zero_reg, ival);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001020 __ Movn(ival, scratch1, fval);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001021
1022 // We have -1, 0 or 1, which we treat specially. Register ival contains
1023 // absolute value: it is either equal to 1 (special case of -1 and 1),
1024 // greater than 1 (not a special case) or less than 1 (special case of 0).
1025 __ Branch(&not_special, gt, ival, Operand(1));
1026
1027 // For 1 or -1 we need to or in the 0 exponent (biased).
1028 static const uint32_t exponent_word_for_1 =
1029 kBinary32ExponentBias << kBinary32ExponentShift;
1030
1031 __ Xor(scratch1, ival, Operand(1));
1032 __ li(scratch2, exponent_word_for_1);
1033 __ or_(scratch2, fval, scratch2);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001034 __ Movz(fval, scratch2, scratch1); // Only if ival is equal to 1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001035 __ Branch(&done);
1036
1037 __ bind(&not_special);
1038 // Count leading zeros.
1039 // Gets the wrong answer for 0, but we already checked for that case above.
1040 Register zeros = scratch2;
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001041 __ Clz(zeros, ival);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001042
1043 // Compute exponent and or it into the exponent register.
1044 __ li(scratch1, (kBitsPerInt - 1) + kBinary32ExponentBias);
1045 __ subu(scratch1, scratch1, zeros);
1046
1047 __ sll(scratch1, scratch1, kBinary32ExponentShift);
1048 __ or_(fval, fval, scratch1);
1049
1050 // Shift up the source chopping the top bit off.
1051 __ Addu(zeros, zeros, Operand(1));
1052 // This wouldn't work for 1 and -1 as the shift would be 32 which means 0.
1053 __ sllv(ival, ival, zeros);
1054 // And the top (top 20 bits).
1055 __ srl(scratch1, ival, kBitsPerInt - kBinary32MantissaBits);
1056 __ or_(fval, fval, scratch1);
1057
1058 __ bind(&done);
1059
1060 __ sll(scratch1, wordoffset, 2);
1061 __ addu(scratch1, dst, scratch1);
1062 __ sw(fval, MemOperand(scratch1, 0));
1063 }
1064}
1065
1066
ager@chromium.org5c838252010-02-19 08:53:10 +00001067#undef __
1068#define __ ACCESS_MASM(masm())
1069
1070
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001071void StubCompiler::GenerateTailCall(Handle<Code> code) {
1072 __ Jump(code, RelocInfo::CODE_TARGET);
1073}
1074
1075
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001076Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
1077 Register object_reg,
1078 Handle<JSObject> holder,
1079 Register holder_reg,
1080 Register scratch1,
1081 Register scratch2,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001082 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001083 int save_at_depth,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001084 Label* miss,
1085 PrototypeCheckType check) {
1086 Handle<JSObject> first = object;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001087 // Make sure there's no overlap between holder and object registers.
1088 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1089 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1090 && !scratch2.is(scratch1));
1091
1092 // Keep track of the current object in register reg.
1093 Register reg = object_reg;
1094 int depth = 0;
1095
1096 if (save_at_depth == depth) {
1097 __ sw(reg, MemOperand(sp));
1098 }
1099
1100 // Check the maps in the prototype chain.
1101 // Traverse the prototype chain from the object and do map checks.
1102 Handle<JSObject> current = object;
1103 while (!current.is_identical_to(holder)) {
1104 ++depth;
1105
1106 // Only global objects and objects that do not require access
1107 // checks are allowed in stubs.
1108 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1109
1110 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
1111 if (!current->HasFastProperties() &&
1112 !current->IsJSGlobalObject() &&
1113 !current->IsJSGlobalProxy()) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001114 if (!name->IsUniqueName()) {
1115 ASSERT(name->IsString());
1116 name = factory()->InternalizeString(Handle<String>::cast(name));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001117 }
1118 ASSERT(current->property_dictionary()->FindEntry(*name) ==
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001119 NameDictionary::kNotFound);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001120
1121 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1122 scratch1, scratch2);
1123
1124 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1125 reg = holder_reg; // From now on the object will be in holder_reg.
1126 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1127 } else {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001128 Register map_reg = scratch1;
1129 if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) {
1130 Handle<Map> current_map(current->map());
1131 // CheckMap implicitly loads the map of |reg| into |map_reg|.
1132 __ CheckMap(reg, map_reg, current_map, miss, DONT_DO_SMI_CHECK,
1133 ALLOW_ELEMENT_TRANSITION_MAPS);
1134 } else {
1135 __ lw(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
1136 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001137 // Check access rights to the global object. This has to happen after
1138 // the map check so that we know that the object is actually a global
1139 // object.
1140 if (current->IsJSGlobalProxy()) {
1141 __ CheckAccessGlobalProxy(reg, scratch2, miss);
1142 }
1143 reg = holder_reg; // From now on the object will be in holder_reg.
1144
1145 if (heap()->InNewSpace(*prototype)) {
1146 // The prototype is in new space; we cannot store a reference to it
1147 // in the code. Load it from the map.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001148 __ lw(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001149 } else {
1150 // The prototype is in old space; load it directly.
1151 __ li(reg, Operand(prototype));
1152 }
1153 }
1154
1155 if (save_at_depth == depth) {
1156 __ sw(reg, MemOperand(sp));
1157 }
1158
1159 // Go to the next object in the prototype chain.
1160 current = prototype;
1161 }
1162
1163 // Log the check depth.
1164 LOG(masm()->isolate(), IntEvent("check-maps-depth", depth + 1));
1165
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001166 if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) {
1167 // Check the holder map.
1168 __ CheckMap(reg, scratch1, Handle<Map>(holder->map()), miss,
1169 DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
1170 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001171
1172 // Perform security check for access to the global object.
1173 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1174 if (holder->IsJSGlobalProxy()) {
1175 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1176 }
1177
1178 // If we've skipped any global objects, it's not enough to verify that
1179 // their maps haven't changed. We also need to check that the property
1180 // cell for the property is still empty.
1181 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1182
1183 // Return the register containing the holder.
1184 return reg;
1185}
1186
1187
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001188void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success,
1189 Label* miss) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001190 if (!miss->is_unused()) {
1191 __ Branch(success);
1192 __ bind(miss);
1193 GenerateLoadMiss(masm(), kind());
1194 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001195}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001196
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001197
1198Register BaseLoadStubCompiler::CallbackHandlerFrontend(
1199 Handle<JSObject> object,
1200 Register object_reg,
1201 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001202 Handle<Name> name,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001203 Label* success,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001204 Handle<ExecutableAccessorInfo> callback) {
1205 Label miss;
1206
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001207 Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001208
1209 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
1210 ASSERT(!reg.is(scratch2()));
1211 ASSERT(!reg.is(scratch3()));
1212 ASSERT(!reg.is(scratch4()));
1213
1214 // Load the properties dictionary.
1215 Register dictionary = scratch4();
1216 __ lw(dictionary, FieldMemOperand(reg, JSObject::kPropertiesOffset));
1217
1218 // Probe the dictionary.
1219 Label probe_done;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001220 NameDictionaryLookupStub::GeneratePositiveLookup(masm(),
1221 &miss,
1222 &probe_done,
1223 dictionary,
1224 this->name(),
1225 scratch2(),
1226 scratch3());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001227 __ bind(&probe_done);
1228
1229 // If probing finds an entry in the dictionary, scratch3 contains the
1230 // pointer into the dictionary. Check that the value is the callback.
1231 Register pointer = scratch3();
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001232 const int kElementsStartOffset = NameDictionary::kHeaderSize +
1233 NameDictionary::kElementsStartIndex * kPointerSize;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001234 const int kValueOffset = kElementsStartOffset + kPointerSize;
1235 __ lw(scratch2(), FieldMemOperand(pointer, kValueOffset));
1236 __ Branch(&miss, ne, scratch2(), Operand(callback));
1237 }
1238
1239 HandlerFrontendFooter(success, &miss);
1240 return reg;
1241}
1242
1243
1244void BaseLoadStubCompiler::NonexistentHandlerFrontend(
1245 Handle<JSObject> object,
1246 Handle<JSObject> last,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001247 Handle<Name> name,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001248 Label* success,
1249 Handle<GlobalObject> global) {
1250 Label miss;
1251
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001252 Register reg = HandlerFrontendHeader(object, receiver(), last, name, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001253
1254 // If the last object in the prototype chain is a global object,
1255 // check that the global property cell is empty.
1256 if (!global.is_null()) {
1257 GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
1258 }
1259
1260 if (!last->HasFastProperties()) {
1261 __ lw(scratch2(), FieldMemOperand(reg, HeapObject::kMapOffset));
1262 __ lw(scratch2(), FieldMemOperand(scratch2(), Map::kPrototypeOffset));
1263 __ Branch(&miss, ne, scratch2(),
1264 Operand(isolate()->factory()->null_value()));
1265 }
1266
1267 HandlerFrontendFooter(success, &miss);
1268}
1269
1270
1271void BaseLoadStubCompiler::GenerateLoadField(Register reg,
1272 Handle<JSObject> holder,
1273 PropertyIndex index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001274 GenerateFastPropertyLoad(masm(), v0, reg, holder, index);
1275 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001276}
1277
1278
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001279void BaseLoadStubCompiler::GenerateLoadConstant(Handle<JSFunction> value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001280 // Return the constant value.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001281 __ LoadHeapObject(v0, value);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001282 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001283}
1284
1285
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001286void BaseLoadStubCompiler::GenerateLoadCallback(
1287 Register reg,
1288 Handle<ExecutableAccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001289 // Build AccessorInfo::args_ list on the stack and push property name below
1290 // the exit frame to make GC aware of them and store pointers to them.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001291 __ push(receiver());
1292 __ mov(scratch2(), sp); // scratch2 = AccessorInfo::args_
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001293 if (heap()->InNewSpace(callback->data())) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001294 __ li(scratch3(), callback);
1295 __ lw(scratch3(), FieldMemOperand(scratch3(),
1296 ExecutableAccessorInfo::kDataOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001297 } else {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001298 __ li(scratch3(), Handle<Object>(callback->data(),
1299 callback->GetIsolate()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001300 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001301 __ Subu(sp, sp, 4 * kPointerSize);
1302 __ sw(reg, MemOperand(sp, 3 * kPointerSize));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001303 __ sw(scratch3(), MemOperand(sp, 2 * kPointerSize));
1304 __ li(scratch3(), Operand(ExternalReference::isolate_address()));
1305 __ sw(scratch3(), MemOperand(sp, 1 * kPointerSize));
1306 __ sw(name(), MemOperand(sp, 0 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001307
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001308 __ mov(a2, scratch2()); // Saved in case scratch2 == a1.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001309 __ mov(a1, sp); // a1 (first argument - see note below) = Handle<Name>
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001310
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001311 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
1312 // struct from the function (which is currently the case). This means we pass
1313 // the arguments in a1-a2 instead of a0-a1. TryCallApiFunctionAndReturn
1314 // will handle setting up a0.
1315
1316 const int kApiStackSpace = 1;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001317 FrameScope frame_scope(masm(), StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001318 __ EnterExitFrame(false, kApiStackSpace);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001319
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001320 // Create AccessorInfo instance on the stack above the exit frame with
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001321 // scratch2 (internal::Object** args_) as the data.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001322 __ sw(a2, MemOperand(sp, kPointerSize));
1323 // a2 (second argument - see note above) = AccessorInfo&
1324 __ Addu(a2, sp, kPointerSize);
1325
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001326 const int kStackUnwindSpace = 5;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001327 Address getter_address = v8::ToCData<Address>(callback->getter());
1328 ApiFunction fun(getter_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001329 ExternalReference ref =
1330 ExternalReference(&fun,
1331 ExternalReference::DIRECT_GETTER_CALL,
1332 masm()->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001333 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
ager@chromium.org5c838252010-02-19 08:53:10 +00001334}
1335
1336
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001337void BaseLoadStubCompiler::GenerateLoadInterceptor(
1338 Register holder_reg,
1339 Handle<JSObject> object,
1340 Handle<JSObject> interceptor_holder,
1341 LookupResult* lookup,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001342 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001343 ASSERT(interceptor_holder->HasNamedInterceptor());
1344 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1345
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001346 // So far the most popular follow ups for interceptor loads are FIELD
1347 // and CALLBACKS, so inline only them, other cases may be added
1348 // later.
1349 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001350 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001351 if (lookup->IsField()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001352 compile_followup_inline = true;
1353 } else if (lookup->type() == CALLBACKS &&
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001354 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
1355 ExecutableAccessorInfo* callback =
1356 ExecutableAccessorInfo::cast(lookup->GetCallbackObject());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001357 compile_followup_inline = callback->getter() != NULL &&
1358 callback->IsCompatibleReceiver(*object);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001359 }
1360 }
1361
1362 if (compile_followup_inline) {
1363 // Compile the interceptor call, followed by inline code to load the
1364 // property from further up the prototype chain if the call fails.
1365 // Check that the maps haven't changed.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001366 ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001367
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001368 // Preserve the receiver register explicitly whenever it is different from
1369 // the holder and it is needed should the interceptor return without any
1370 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1371 // the FIELD case might cause a miss during the prototype check.
1372 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001373 bool must_preserve_receiver_reg = !receiver().is(holder_reg) &&
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001374 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1375
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001376 // Save necessary data before invoking an interceptor.
1377 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001378 {
1379 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001380 if (must_preserve_receiver_reg) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001381 __ Push(receiver(), holder_reg, this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001382 } else {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001383 __ Push(holder_reg, this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001384 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001385 // Invoke an interceptor. Note: map checks from receiver to
1386 // interceptor's holder has been compiled before (see a caller
1387 // of this method).
1388 CompileCallLoadPropertyWithInterceptor(masm(),
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001389 receiver(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001390 holder_reg,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001391 this->name(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001392 interceptor_holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001393 // Check if interceptor provided a value for property. If it's
1394 // the case, return immediately.
1395 Label interceptor_failed;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001396 __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
1397 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001398 frame_scope.GenerateLeaveFrame();
1399 __ Ret();
1400
1401 __ bind(&interceptor_failed);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001402 __ pop(this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001403 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001404 if (must_preserve_receiver_reg) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001405 __ pop(receiver());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001406 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001407 // Leave the internal frame.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001408 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001409 GenerateLoadPostInterceptor(holder_reg, interceptor_holder, name, lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001410 } else { // !compile_followup_inline
1411 // Call the runtime system to load the interceptor.
1412 // Check that the maps haven't changed.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001413 PushInterceptorArguments(masm(), receiver(), holder_reg,
1414 this->name(), interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001415
1416 ExternalReference ref = ExternalReference(
1417 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), masm()->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001418 __ TailCallExternalReference(ref, 6, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001419 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001420}
1421
1422
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001423void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001424 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001425 __ Branch(miss, ne, a2, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001426 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001427}
1428
1429
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001430void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1431 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001432 Handle<Name> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001433 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001434 ASSERT(holder->IsGlobalObject());
1435
1436 // Get the number of arguments.
1437 const int argc = arguments().immediate();
1438
1439 // Get the receiver from the stack.
1440 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1441
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001442 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001443 __ JumpIfSmi(a0, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001444 CheckPrototypes(object, a0, holder, a3, a1, t0, name, miss);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001445}
1446
1447
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001448void CallStubCompiler::GenerateLoadFunctionFromCell(
1449 Handle<JSGlobalPropertyCell> cell,
1450 Handle<JSFunction> function,
1451 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001452 // Get the value from the cell.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001453 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001454 __ lw(a1, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
1455
1456 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001457 if (heap()->InNewSpace(*function)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001458 // We can't embed a pointer to a function in new space so we have
1459 // to verify that the shared function info is unchanged. This has
1460 // the nice side effect that multiple closures based on the same
1461 // function can all use this call IC. Before we load through the
1462 // function, we have to verify that it still is a function.
1463 __ JumpIfSmi(a1, miss);
1464 __ GetObjectType(a1, a3, a3);
1465 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
1466
1467 // Check the shared function info. Make sure it hasn't changed.
1468 __ li(a3, Handle<SharedFunctionInfo>(function->shared()));
1469 __ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
1470 __ Branch(miss, ne, t0, Operand(a3));
1471 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001472 __ Branch(miss, ne, a1, Operand(function));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001473 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001474}
1475
1476
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001477void CallStubCompiler::GenerateMissBranch() {
1478 Handle<Code> code =
danno@chromium.org40cb8782011-05-25 07:58:50 +00001479 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1480 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001481 extra_state_);
1482 __ Jump(code, RelocInfo::CODE_TARGET);
1483}
1484
1485
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001486Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1487 Handle<JSObject> holder,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001488 PropertyIndex index,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001489 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001490 // ----------- S t a t e -------------
1491 // -- a2 : name
1492 // -- ra : return address
1493 // -----------------------------------
1494 Label miss;
1495
1496 GenerateNameCheck(name, &miss);
1497
1498 const int argc = arguments().immediate();
1499
1500 // Get the receiver of the function from the stack into a0.
1501 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1502 // Check that the receiver isn't a smi.
1503 __ JumpIfSmi(a0, &miss, t0);
1504
1505 // Do the right check and compute the holder register.
1506 Register reg = CheckPrototypes(object, a0, holder, a1, a3, t0, name, &miss);
1507 GenerateFastPropertyLoad(masm(), a1, reg, holder, index);
1508
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001509 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001510
1511 // Handle call cache miss.
1512 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001513 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001514
1515 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001516 return GetCode(Code::FIELD, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001517}
1518
1519
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001520Handle<Code> CallStubCompiler::CompileArrayPushCall(
1521 Handle<Object> object,
1522 Handle<JSObject> holder,
1523 Handle<JSGlobalPropertyCell> cell,
1524 Handle<JSFunction> function,
1525 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001526 // ----------- S t a t e -------------
1527 // -- a2 : name
1528 // -- ra : return address
1529 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1530 // -- ...
1531 // -- sp[argc * 4] : receiver
1532 // -----------------------------------
1533
1534 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001535 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001536
1537 Label miss;
1538
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001539 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001540
1541 Register receiver = a1;
1542
1543 // Get the receiver from the stack.
1544 const int argc = arguments().immediate();
1545 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1546
1547 // Check that the receiver isn't a smi.
1548 __ JumpIfSmi(receiver, &miss);
1549
1550 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001551 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, a3, v0, t0,
1552 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001553
1554 if (argc == 0) {
1555 // Nothing to do, just return the length.
1556 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1557 __ Drop(argc + 1);
1558 __ Ret();
1559 } else {
1560 Label call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001561 if (argc == 1) { // Otherwise fall through to call the builtin.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001562 Label attempt_to_grow_elements, with_write_barrier, check_double;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001563
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001564 Register elements = t2;
1565 Register end_elements = t1;
1566 // Get the elements array of the object.
1567 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1568
1569 // Check that the elements are in fast mode and writable.
1570 __ CheckMap(elements,
1571 v0,
1572 Heap::kFixedArrayMapRootIndex,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001573 &check_double,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001574 DONT_DO_SMI_CHECK);
1575
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001576 // Get the array's length into v0 and calculate new length.
1577 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1578 STATIC_ASSERT(kSmiTagSize == 1);
1579 STATIC_ASSERT(kSmiTag == 0);
1580 __ Addu(v0, v0, Operand(Smi::FromInt(argc)));
1581
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001582 // Get the elements' length.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001583 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1584
1585 // Check if we could survive without allocation.
1586 __ Branch(&attempt_to_grow_elements, gt, v0, Operand(t0));
1587
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001588 // Check if value is a smi.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001589 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1590 __ JumpIfNotSmi(t0, &with_write_barrier);
1591
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001592 // Save new length.
1593 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1594
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001595 // Store the value.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001596 // We may need a register containing the address end_elements below,
1597 // so write back the value in end_elements.
1598 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1599 __ Addu(end_elements, elements, end_elements);
1600 const int kEndElementsOffset =
1601 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001602 __ Addu(end_elements, end_elements, kEndElementsOffset);
1603 __ sw(t0, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001604
1605 // Check for a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001606 __ Drop(argc + 1);
1607 __ Ret();
1608
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001609 __ bind(&check_double);
1610
1611 // Check that the elements are in fast mode and writable.
1612 __ CheckMap(elements,
1613 a0,
1614 Heap::kFixedDoubleArrayMapRootIndex,
1615 &call_builtin,
1616 DONT_DO_SMI_CHECK);
1617
1618 // Get the array's length into r0 and calculate new length.
1619 __ lw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1620 STATIC_ASSERT(kSmiTagSize == 1);
1621 STATIC_ASSERT(kSmiTag == 0);
1622 __ Addu(a0, a0, Operand(Smi::FromInt(argc)));
1623
1624 // Get the elements' length.
1625 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1626
1627 // Check if we could survive without allocation.
1628 __ Branch(&call_builtin, gt, a0, Operand(t0));
1629
1630 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1631 __ StoreNumberToDoubleElements(
1632 t0, a0, elements, a3, t1, a2, t5,
1633 &call_builtin, argc * kDoubleSize);
1634
1635 // Save new length.
1636 __ sw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1637
1638 // Check for a smi.
1639 __ Drop(argc + 1);
1640 __ Ret();
1641
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001642 __ bind(&with_write_barrier);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001643
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001644 __ lw(a3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1645
1646 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
1647 Label fast_object, not_fast_object;
1648 __ CheckFastObjectElements(a3, t3, &not_fast_object);
1649 __ jmp(&fast_object);
1650 // In case of fast smi-only, convert to fast object, otherwise bail out.
1651 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001652 __ CheckFastSmiElements(a3, t3, &call_builtin);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001653
1654 __ lw(t3, FieldMemOperand(t0, HeapObject::kMapOffset));
1655 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
1656 __ Branch(&call_builtin, eq, t3, Operand(at));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001657 // edx: receiver
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001658 // a3: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001659 Label try_holey_map;
1660 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001661 FAST_ELEMENTS,
1662 a3,
1663 t3,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001664 &try_holey_map);
1665 __ mov(a2, receiver);
1666 ElementsTransitionGenerator::
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001667 GenerateMapChangeElementsTransition(masm(),
1668 DONT_TRACK_ALLOCATION_SITE,
1669 NULL);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001670 __ jmp(&fast_object);
1671
1672 __ bind(&try_holey_map);
1673 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1674 FAST_HOLEY_ELEMENTS,
1675 a3,
1676 t3,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001677 &call_builtin);
1678 __ mov(a2, receiver);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001679 ElementsTransitionGenerator::
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001680 GenerateMapChangeElementsTransition(masm(),
1681 DONT_TRACK_ALLOCATION_SITE,
1682 NULL);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001683 __ bind(&fast_object);
1684 } else {
1685 __ CheckFastObjectElements(a3, a3, &call_builtin);
1686 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001687
1688 // Save new length.
1689 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1690
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001691 // Store the value.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001692 // We may need a register containing the address end_elements below,
1693 // so write back the value in end_elements.
1694 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1695 __ Addu(end_elements, elements, end_elements);
1696 __ Addu(end_elements, end_elements, kEndElementsOffset);
1697 __ sw(t0, MemOperand(end_elements));
1698
1699 __ RecordWrite(elements,
1700 end_elements,
1701 t0,
1702 kRAHasNotBeenSaved,
1703 kDontSaveFPRegs,
1704 EMIT_REMEMBERED_SET,
1705 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001706 __ Drop(argc + 1);
1707 __ Ret();
1708
1709 __ bind(&attempt_to_grow_elements);
1710 // v0: array's length + 1.
1711 // t0: elements' length.
1712
1713 if (!FLAG_inline_new) {
1714 __ Branch(&call_builtin);
1715 }
1716
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001717 __ lw(a2, MemOperand(sp, (argc - 1) * kPointerSize));
1718 // Growing elements that are SMI-only requires special handling in case
1719 // the new element is non-Smi. For now, delegate to the builtin.
1720 Label no_fast_elements_check;
1721 __ JumpIfSmi(a2, &no_fast_elements_check);
1722 __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1723 __ CheckFastObjectElements(t3, t3, &call_builtin);
1724 __ bind(&no_fast_elements_check);
1725
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001726 ExternalReference new_space_allocation_top =
1727 ExternalReference::new_space_allocation_top_address(
1728 masm()->isolate());
1729 ExternalReference new_space_allocation_limit =
1730 ExternalReference::new_space_allocation_limit_address(
1731 masm()->isolate());
1732
1733 const int kAllocationDelta = 4;
1734 // Load top and check if it is the end of elements.
1735 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1736 __ Addu(end_elements, elements, end_elements);
1737 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset));
1738 __ li(t3, Operand(new_space_allocation_top));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001739 __ lw(a3, MemOperand(t3));
1740 __ Branch(&call_builtin, ne, end_elements, Operand(a3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001741
1742 __ li(t5, Operand(new_space_allocation_limit));
1743 __ lw(t5, MemOperand(t5));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001744 __ Addu(a3, a3, Operand(kAllocationDelta * kPointerSize));
1745 __ Branch(&call_builtin, hi, a3, Operand(t5));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001746
1747 // We fit and could grow elements.
1748 // Update new_space_allocation_top.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001749 __ sw(a3, MemOperand(t3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001750 // Push the argument.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001751 __ sw(a2, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001752 // Fill the rest with holes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001753 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001754 for (int i = 1; i < kAllocationDelta; i++) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001755 __ sw(a3, MemOperand(end_elements, i * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001756 }
1757
1758 // Update elements' and array's sizes.
1759 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1760 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta)));
1761 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1762
1763 // Elements are in new space, so write barrier is not required.
1764 __ Drop(argc + 1);
1765 __ Ret();
1766 }
1767 __ bind(&call_builtin);
1768 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
1769 masm()->isolate()),
1770 argc + 1,
1771 1);
1772 }
1773
1774 // Handle call cache miss.
1775 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001776 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001777
1778 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001779 return GetCode(function);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001780}
1781
1782
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001783Handle<Code> CallStubCompiler::CompileArrayPopCall(
1784 Handle<Object> object,
1785 Handle<JSObject> holder,
1786 Handle<JSGlobalPropertyCell> cell,
1787 Handle<JSFunction> function,
1788 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001789 // ----------- S t a t e -------------
1790 // -- a2 : name
1791 // -- ra : return address
1792 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1793 // -- ...
1794 // -- sp[argc * 4] : receiver
1795 // -----------------------------------
1796
1797 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001798 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001799
1800 Label miss, return_undefined, call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001801 Register receiver = a1;
1802 Register elements = a3;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001803 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001804
1805 // Get the receiver from the stack.
1806 const int argc = arguments().immediate();
1807 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001808 // Check that the receiver isn't a smi.
1809 __ JumpIfSmi(receiver, &miss);
1810
1811 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001812 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, elements,
1813 t0, v0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001814
1815 // Get the elements array of the object.
1816 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1817
1818 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001819 __ CheckMap(elements,
1820 v0,
1821 Heap::kFixedArrayMapRootIndex,
1822 &call_builtin,
1823 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001824
1825 // Get the array's length into t0 and calculate new length.
1826 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1827 __ Subu(t0, t0, Operand(Smi::FromInt(1)));
1828 __ Branch(&return_undefined, lt, t0, Operand(zero_reg));
1829
1830 // Get the last element.
1831 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1832 STATIC_ASSERT(kSmiTagSize == 1);
1833 STATIC_ASSERT(kSmiTag == 0);
1834 // We can't address the last element in one operation. Compute the more
1835 // expensive shift first, and use an offset later on.
1836 __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize);
1837 __ Addu(elements, elements, t1);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001838 __ lw(v0, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001839 __ Branch(&call_builtin, eq, v0, Operand(t2));
1840
1841 // Set the array's length.
1842 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1843
1844 // Fill with the hole.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001845 __ sw(t2, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001846 __ Drop(argc + 1);
1847 __ Ret();
1848
1849 __ bind(&return_undefined);
1850 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
1851 __ Drop(argc + 1);
1852 __ Ret();
1853
1854 __ bind(&call_builtin);
1855 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop,
1856 masm()->isolate()),
1857 argc + 1,
1858 1);
1859
1860 // Handle call cache miss.
1861 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001862 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001863
1864 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001865 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001866}
1867
1868
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001869Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1870 Handle<Object> object,
1871 Handle<JSObject> holder,
1872 Handle<JSGlobalPropertyCell> cell,
1873 Handle<JSFunction> function,
1874 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001875 // ----------- S t a t e -------------
1876 // -- a2 : function name
1877 // -- ra : return address
1878 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1879 // -- ...
1880 // -- sp[argc * 4] : receiver
1881 // -----------------------------------
1882
1883 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001884 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001885
1886 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001887 Label miss;
1888 Label name_miss;
1889 Label index_out_of_range;
1890
1891 Label* index_out_of_range_label = &index_out_of_range;
1892
danno@chromium.org40cb8782011-05-25 07:58:50 +00001893 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001894 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001895 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001896 index_out_of_range_label = &miss;
1897 }
1898
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001899 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001900
1901 // Check that the maps starting from the prototype haven't changed.
1902 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1903 Context::STRING_FUNCTION_INDEX,
1904 v0,
1905 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001906 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001907 CheckPrototypes(
1908 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
1909 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001910
1911 Register receiver = a1;
1912 Register index = t1;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001913 Register result = v0;
1914 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1915 if (argc > 0) {
1916 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1917 } else {
1918 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1919 }
1920
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001921 StringCharCodeAtGenerator generator(receiver,
1922 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001923 result,
1924 &miss, // When not a string.
1925 &miss, // When not a number.
1926 index_out_of_range_label,
1927 STRING_INDEX_IS_NUMBER);
1928 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001929 __ Drop(argc + 1);
1930 __ Ret();
1931
1932 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001933 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001934
1935 if (index_out_of_range.is_linked()) {
1936 __ bind(&index_out_of_range);
1937 __ LoadRoot(v0, Heap::kNanValueRootIndex);
1938 __ Drop(argc + 1);
1939 __ Ret();
1940 }
1941
1942 __ bind(&miss);
1943 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001944 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001945 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001946 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001947
1948 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001949 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001950}
1951
1952
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001953Handle<Code> CallStubCompiler::CompileStringCharAtCall(
1954 Handle<Object> object,
1955 Handle<JSObject> holder,
1956 Handle<JSGlobalPropertyCell> cell,
1957 Handle<JSFunction> function,
1958 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001959 // ----------- S t a t e -------------
1960 // -- a2 : function name
1961 // -- ra : return address
1962 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1963 // -- ...
1964 // -- sp[argc * 4] : receiver
1965 // -----------------------------------
1966
1967 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001968 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001969
1970 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001971 Label miss;
1972 Label name_miss;
1973 Label index_out_of_range;
1974 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00001975 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001976 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001977 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001978 index_out_of_range_label = &miss;
1979 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001980 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001981
1982 // Check that the maps starting from the prototype haven't changed.
1983 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1984 Context::STRING_FUNCTION_INDEX,
1985 v0,
1986 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001987 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001988 CheckPrototypes(
1989 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
1990 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001991
1992 Register receiver = v0;
1993 Register index = t1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001994 Register scratch = a3;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001995 Register result = v0;
1996 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1997 if (argc > 0) {
1998 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1999 } else {
2000 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
2001 }
2002
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002003 StringCharAtGenerator generator(receiver,
2004 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00002005 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002006 result,
2007 &miss, // When not a string.
2008 &miss, // When not a number.
2009 index_out_of_range_label,
2010 STRING_INDEX_IS_NUMBER);
2011 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002012 __ Drop(argc + 1);
2013 __ Ret();
2014
2015 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002016 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002017
2018 if (index_out_of_range.is_linked()) {
2019 __ bind(&index_out_of_range);
ulan@chromium.org750145a2013-03-07 15:14:13 +00002020 __ LoadRoot(v0, Heap::kempty_stringRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002021 __ Drop(argc + 1);
2022 __ Ret();
2023 }
2024
2025 __ bind(&miss);
2026 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002027 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002028 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002029 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002030
2031 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002032 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002033}
2034
2035
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002036Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
2037 Handle<Object> object,
2038 Handle<JSObject> holder,
2039 Handle<JSGlobalPropertyCell> cell,
2040 Handle<JSFunction> function,
2041 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002042 // ----------- S t a t e -------------
2043 // -- a2 : function name
2044 // -- ra : return address
2045 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2046 // -- ...
2047 // -- sp[argc * 4] : receiver
2048 // -----------------------------------
2049
2050 const int argc = arguments().immediate();
2051
2052 // If the object is not a JSObject or we got an unexpected number of
2053 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002054 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002055
2056 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002057 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002058
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002059 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002060 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
2061
2062 STATIC_ASSERT(kSmiTag == 0);
2063 __ JumpIfSmi(a1, &miss);
2064
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002065 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2066 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002067 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002068 ASSERT(cell->value() == *function);
2069 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2070 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002071 GenerateLoadFunctionFromCell(cell, function, &miss);
2072 }
2073
2074 // Load the char code argument.
2075 Register code = a1;
2076 __ lw(code, MemOperand(sp, 0 * kPointerSize));
2077
2078 // Check the code is a smi.
2079 Label slow;
2080 STATIC_ASSERT(kSmiTag == 0);
2081 __ JumpIfNotSmi(code, &slow);
2082
2083 // Convert the smi code to uint16.
2084 __ And(code, code, Operand(Smi::FromInt(0xffff)));
2085
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002086 StringCharFromCodeGenerator generator(code, v0);
2087 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002088 __ Drop(argc + 1);
2089 __ Ret();
2090
2091 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002092 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002093
2094 // Tail call the full function. We do not have to patch the receiver
2095 // because the function makes no use of it.
2096 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002097 __ InvokeFunction(
2098 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002099
2100 __ bind(&miss);
2101 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002102 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002103
2104 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002105 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002106}
2107
2108
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002109Handle<Code> CallStubCompiler::CompileMathFloorCall(
2110 Handle<Object> object,
2111 Handle<JSObject> holder,
2112 Handle<JSGlobalPropertyCell> cell,
2113 Handle<JSFunction> function,
2114 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002115 // ----------- S t a t e -------------
2116 // -- a2 : function name
2117 // -- ra : return address
2118 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2119 // -- ...
2120 // -- sp[argc * 4] : receiver
2121 // -----------------------------------
2122
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002123 if (!CpuFeatures::IsSupported(FPU)) {
2124 return Handle<Code>::null();
2125 }
2126
ulan@chromium.org750145a2013-03-07 15:14:13 +00002127 CpuFeatureScope scope_fpu(masm(), FPU);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002128 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002129 // If the object is not a JSObject or we got an unexpected number of
2130 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002131 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002132
2133 Label miss, slow;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002134 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002135
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002136 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002137 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002138 STATIC_ASSERT(kSmiTag == 0);
2139 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002140 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2141 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002142 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002143 ASSERT(cell->value() == *function);
2144 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2145 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002146 GenerateLoadFunctionFromCell(cell, function, &miss);
2147 }
2148
2149 // Load the (only) argument into v0.
2150 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2151
2152 // If the argument is a smi, just return.
2153 STATIC_ASSERT(kSmiTag == 0);
2154 __ And(t0, v0, Operand(kSmiTagMask));
2155 __ Drop(argc + 1, eq, t0, Operand(zero_reg));
2156 __ Ret(eq, t0, Operand(zero_reg));
2157
danno@chromium.org40cb8782011-05-25 07:58:50 +00002158 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002159
2160 Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return;
2161
2162 // If fpu is enabled, we use the floor instruction.
2163
2164 // Load the HeapNumber value.
2165 __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2166
2167 // Backup FCSR.
2168 __ cfc1(a3, FCSR);
2169 // Clearing FCSR clears the exception mask with no side-effects.
2170 __ ctc1(zero_reg, FCSR);
2171 // Convert the argument to an integer.
2172 __ floor_w_d(f0, f0);
2173
2174 // Start checking for special cases.
2175 // Get the argument exponent and clear the sign bit.
2176 __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize));
2177 __ And(t2, t1, Operand(~HeapNumber::kSignMask));
2178 __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord);
2179
2180 // Retrieve FCSR and check for fpu errors.
2181 __ cfc1(t5, FCSR);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002182 __ And(t5, t5, Operand(kFCSRExceptionFlagMask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002183 __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));
2184
2185 // Check for NaN, Infinity, and -Infinity.
2186 // They are invariant through a Math.Floor call, so just
2187 // return the original argument.
2188 __ Subu(t3, t2, Operand(HeapNumber::kExponentMask
2189 >> HeapNumber::kMantissaBitsInTopWord));
2190 __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg));
2191 // We had an overflow or underflow in the conversion. Check if we
2192 // have a big exponent.
2193 // If greater or equal, the argument is already round and in v0.
2194 __ Branch(&restore_fcsr_and_return, ge, t3,
2195 Operand(HeapNumber::kMantissaBits));
2196 __ Branch(&wont_fit_smi);
2197
2198 __ bind(&no_fpu_error);
2199 // Move the result back to v0.
2200 __ mfc1(v0, f0);
2201 // Check if the result fits into a smi.
2202 __ Addu(a1, v0, Operand(0x40000000));
2203 __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg));
2204 // Tag the result.
2205 STATIC_ASSERT(kSmiTag == 0);
2206 __ sll(v0, v0, kSmiTagSize);
2207
2208 // Check for -0.
2209 __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg));
2210 // t1 already holds the HeapNumber exponent.
2211 __ And(t0, t1, Operand(HeapNumber::kSignMask));
2212 // If our HeapNumber is negative it was -0, so load its address and return.
2213 // Else v0 is loaded with 0, so we can also just return.
2214 __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg));
2215 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2216
2217 __ bind(&restore_fcsr_and_return);
2218 // Restore FCSR and return.
2219 __ ctc1(a3, FCSR);
2220
2221 __ Drop(argc + 1);
2222 __ Ret();
2223
2224 __ bind(&wont_fit_smi);
2225 // Restore FCSR and fall to slow case.
2226 __ ctc1(a3, FCSR);
2227
2228 __ bind(&slow);
2229 // Tail call the full function. We do not have to patch the receiver
2230 // because the function makes no use of it.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002231 __ InvokeFunction(
2232 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002233
2234 __ bind(&miss);
2235 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002236 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002237
2238 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002239 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002240}
2241
2242
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002243Handle<Code> CallStubCompiler::CompileMathAbsCall(
2244 Handle<Object> object,
2245 Handle<JSObject> holder,
2246 Handle<JSGlobalPropertyCell> cell,
2247 Handle<JSFunction> function,
2248 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002249 // ----------- S t a t e -------------
2250 // -- a2 : function name
2251 // -- ra : return address
2252 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2253 // -- ...
2254 // -- sp[argc * 4] : receiver
2255 // -----------------------------------
2256
2257 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002258 // If the object is not a JSObject or we got an unexpected number of
2259 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002260 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002261
2262 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002263
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002264 GenerateNameCheck(name, &miss);
2265 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002266 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002267 STATIC_ASSERT(kSmiTag == 0);
2268 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002269 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2270 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002271 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002272 ASSERT(cell->value() == *function);
2273 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2274 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002275 GenerateLoadFunctionFromCell(cell, function, &miss);
2276 }
2277
2278 // Load the (only) argument into v0.
2279 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2280
2281 // Check if the argument is a smi.
2282 Label not_smi;
2283 STATIC_ASSERT(kSmiTag == 0);
2284 __ JumpIfNotSmi(v0, &not_smi);
2285
2286 // Do bitwise not or do nothing depending on the sign of the
2287 // argument.
2288 __ sra(t0, v0, kBitsPerInt - 1);
2289 __ Xor(a1, v0, t0);
2290
2291 // Add 1 or do nothing depending on the sign of the argument.
2292 __ Subu(v0, a1, t0);
2293
2294 // If the result is still negative, go to the slow case.
2295 // This only happens for the most negative smi.
2296 Label slow;
2297 __ Branch(&slow, lt, v0, Operand(zero_reg));
2298
2299 // Smi case done.
2300 __ Drop(argc + 1);
2301 __ Ret();
2302
2303 // Check if the argument is a heap number and load its exponent and
2304 // sign.
2305 __ bind(&not_smi);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002306 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002307 __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2308
2309 // Check the sign of the argument. If the argument is positive,
2310 // just return it.
2311 Label negative_sign;
2312 __ And(t0, a1, Operand(HeapNumber::kSignMask));
2313 __ Branch(&negative_sign, ne, t0, Operand(zero_reg));
2314 __ Drop(argc + 1);
2315 __ Ret();
2316
2317 // If the argument is negative, clear the sign, and return a new
2318 // number.
2319 __ bind(&negative_sign);
2320 __ Xor(a1, a1, Operand(HeapNumber::kSignMask));
2321 __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2322 __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
2323 __ AllocateHeapNumber(v0, t0, t1, t2, &slow);
2324 __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2325 __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2326 __ Drop(argc + 1);
2327 __ Ret();
2328
2329 // Tail call the full function. We do not have to patch the receiver
2330 // because the function makes no use of it.
2331 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002332 __ InvokeFunction(
2333 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002334
2335 __ bind(&miss);
2336 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002337 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002338
2339 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002340 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002341}
2342
2343
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002344Handle<Code> CallStubCompiler::CompileFastApiCall(
lrn@chromium.org7516f052011-03-30 08:52:27 +00002345 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002346 Handle<Object> object,
2347 Handle<JSObject> holder,
2348 Handle<JSGlobalPropertyCell> cell,
2349 Handle<JSFunction> function,
2350 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002351
danno@chromium.org40cb8782011-05-25 07:58:50 +00002352 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002353
2354 ASSERT(optimization.is_simple_api_call());
2355 // Bail out if object is a global object as we don't want to
2356 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002357 if (object->IsGlobalObject()) return Handle<Code>::null();
2358 if (!cell.is_null()) return Handle<Code>::null();
2359 if (!object->IsJSObject()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002360 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002361 Handle<JSObject>::cast(object), holder);
2362 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002363
2364 Label miss, miss_before_stack_reserved;
2365
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002366 GenerateNameCheck(name, &miss_before_stack_reserved);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002367
2368 // Get the receiver from the stack.
2369 const int argc = arguments().immediate();
2370 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2371
2372 // Check that the receiver isn't a smi.
2373 __ JumpIfSmi(a1, &miss_before_stack_reserved);
2374
2375 __ IncrementCounter(counters->call_const(), 1, a0, a3);
2376 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2377
2378 ReserveSpaceForFastApiCall(masm(), a0);
2379
2380 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002381 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002382 depth, &miss);
2383
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002384 GenerateFastApiDirectCall(masm(), optimization, argc);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002385
2386 __ bind(&miss);
2387 FreeSpaceForFastApiCall(masm());
2388
2389 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002390 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002391
2392 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002393 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002394}
2395
2396
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002397void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
2398 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002399 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002400 CheckType check,
2401 Label* success) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002402 // ----------- S t a t e -------------
2403 // -- a2 : name
2404 // -- ra : return address
2405 // -----------------------------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002406 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002407 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002408
2409 // Get the receiver from the stack.
2410 const int argc = arguments().immediate();
2411 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2412
2413 // Check that the receiver isn't a smi.
2414 if (check != NUMBER_CHECK) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002415 __ JumpIfSmi(a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002416 }
2417
2418 // Make sure that it's okay not to patch the on stack receiver
2419 // unless we're doing a receiver map check.
2420 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002421 switch (check) {
2422 case RECEIVER_MAP_CHECK:
2423 __ IncrementCounter(masm()->isolate()->counters()->call_const(),
2424 1, a0, a3);
2425
2426 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002427 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2428 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002429
2430 // Patch the receiver on the stack with the global proxy if
2431 // necessary.
2432 if (object->IsGlobalObject()) {
2433 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2434 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2435 }
2436 break;
2437
2438 case STRING_CHECK:
ulan@chromium.org750145a2013-03-07 15:14:13 +00002439 // Check that the object is a string.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002440 __ GetObjectType(a1, a3, a3);
2441 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2442 // Check that the maps starting from the prototype haven't changed.
2443 GenerateDirectLoadGlobalFunctionPrototype(
2444 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
2445 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002446 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002447 a0, holder, a3, a1, t0, name, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002448 break;
2449
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002450 case SYMBOL_CHECK:
2451 // Check that the object is a symbol.
2452 __ GetObjectType(a1, a1, a3);
2453 __ Branch(&miss, ne, a3, Operand(SYMBOL_TYPE));
2454 break;
2455
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002456 case NUMBER_CHECK: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002457 Label fast;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002458 // Check that the object is a smi or a heap number.
2459 __ JumpIfSmi(a1, &fast);
2460 __ GetObjectType(a1, a0, a0);
2461 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
2462 __ bind(&fast);
2463 // Check that the maps starting from the prototype haven't changed.
2464 GenerateDirectLoadGlobalFunctionPrototype(
2465 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
2466 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002467 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002468 a0, holder, a3, a1, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002469 break;
2470 }
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002471 case BOOLEAN_CHECK: {
2472 Label fast;
2473 // Check that the object is a boolean.
2474 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
2475 __ Branch(&fast, eq, a1, Operand(t0));
2476 __ LoadRoot(t0, Heap::kFalseValueRootIndex);
2477 __ Branch(&miss, ne, a1, Operand(t0));
2478 __ bind(&fast);
2479 // Check that the maps starting from the prototype haven't changed.
2480 GenerateDirectLoadGlobalFunctionPrototype(
2481 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
2482 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002483 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002484 a0, holder, a3, a1, t0, name, &miss);
2485 break;
2486 }
2487 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002488
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002489 __ jmp(success);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002490
2491 // Handle call cache miss.
2492 __ bind(&miss);
2493
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002494 GenerateMissBranch();
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002495}
2496
2497
2498void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) {
2499 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
2500 ? CALL_AS_FUNCTION
2501 : CALL_AS_METHOD;
2502 __ InvokeFunction(
2503 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), call_kind);
2504}
2505
2506
2507Handle<Code> CallStubCompiler::CompileCallConstant(
2508 Handle<Object> object,
2509 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002510 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002511 CheckType check,
2512 Handle<JSFunction> function) {
2513 if (HasCustomCallGenerator(function)) {
2514 Handle<Code> code = CompileCustomCall(object, holder,
2515 Handle<JSGlobalPropertyCell>::null(),
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002516 function, Handle<String>::cast(name));
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002517 // A null handle means bail out to the regular compiler code below.
2518 if (!code.is_null()) return code;
2519 }
2520
2521 Label success;
2522
2523 CompileHandlerFrontend(object, holder, name, check, &success);
2524 __ bind(&success);
2525 CompileHandlerBackend(function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002526
2527 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002528 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002529}
2530
2531
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002532Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2533 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002534 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002535 // ----------- S t a t e -------------
2536 // -- a2 : name
2537 // -- ra : return address
2538 // -----------------------------------
2539
2540 Label miss;
2541
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002542 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002543
2544 // Get the number of arguments.
2545 const int argc = arguments().immediate();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002546 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002547 LookupPostInterceptor(holder, name, &lookup);
2548
2549 // Get the receiver from the stack.
2550 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2551
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002552 CallInterceptorCompiler compiler(this, arguments(), a2, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002553 compiler.Compile(masm(), object, holder, name, &lookup, a1, a3, t0, a0,
2554 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002555
2556 // Move returned value, the function to call, to a1.
2557 __ mov(a1, v0);
2558 // Restore receiver.
2559 __ lw(a0, MemOperand(sp, argc * kPointerSize));
2560
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002561 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002562
2563 // Handle call cache miss.
2564 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002565 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002566
2567 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002568 return GetCode(Code::INTERCEPTOR, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002569}
2570
2571
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002572Handle<Code> CallStubCompiler::CompileCallGlobal(
2573 Handle<JSObject> object,
2574 Handle<GlobalObject> holder,
2575 Handle<JSGlobalPropertyCell> cell,
2576 Handle<JSFunction> function,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002577 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002578 // ----------- S t a t e -------------
2579 // -- a2 : name
2580 // -- ra : return address
2581 // -----------------------------------
2582
2583 if (HasCustomCallGenerator(function)) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002584 Handle<Code> code = CompileCustomCall(
2585 object, holder, cell, function, Handle<String>::cast(name));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002586 // A null handle means bail out to the regular compiler code below.
2587 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002588 }
2589
2590 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002591 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002592
2593 // Get the number of arguments.
2594 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002595 GenerateGlobalReceiverCheck(object, holder, name, &miss);
2596 GenerateLoadFunctionFromCell(cell, function, &miss);
2597
2598 // Patch the receiver on the stack with the global proxy if
2599 // necessary.
2600 if (object->IsGlobalObject()) {
2601 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
2602 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2603 }
2604
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002605 // Set up the context (function already in r1).
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002606 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
2607
2608 // Jump to the cached code (tail call).
2609 Counters* counters = masm()->isolate()->counters();
2610 __ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002611 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002612 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002613 ? CALL_AS_FUNCTION
2614 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002615 // We call indirectly through the code field in the function to
2616 // allow recompilation to take effect without changing any of the
2617 // call sites.
2618 __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
2619 __ InvokeCode(a3, expected, arguments(), JUMP_FUNCTION,
2620 NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002621
2622 // Handle call cache miss.
2623 __ bind(&miss);
2624 __ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002625 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002626
2627 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002628 return GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002629}
2630
2631
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002632Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +00002633 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002634 Handle<Map> transition,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002635 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002636 // ----------- S t a t e -------------
2637 // -- a0 : value
2638 // -- a1 : receiver
2639 // -- a2 : name
2640 // -- ra : return address
2641 // -----------------------------------
2642 Label miss;
2643
2644 // Name register might be clobbered.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002645 GenerateStoreField(masm(),
2646 object,
2647 index,
2648 transition,
2649 name,
2650 a1, a2, a3, t0,
2651 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002652 __ bind(&miss);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00002653 __ li(a2, Operand(Handle<Name>(name))); // Restore name.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002654 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2655 __ Jump(ic, RelocInfo::CODE_TARGET);
2656
2657 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002658 return GetCode(transition.is_null()
2659 ? Code::FIELD
2660 : Code::MAP_TRANSITION, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002661}
2662
2663
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002664Handle<Code> StoreStubCompiler::CompileStoreCallback(
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002665 Handle<Name> name,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002666 Handle<JSObject> receiver,
2667 Handle<JSObject> holder,
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002668 Handle<ExecutableAccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002669 // ----------- S t a t e -------------
2670 // -- a0 : value
2671 // -- a1 : receiver
2672 // -- a2 : name
2673 // -- ra : return address
2674 // -----------------------------------
2675 Label miss;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002676 // Check that the maps haven't changed.
2677 __ JumpIfSmi(a1, &miss, a3);
2678 CheckPrototypes(receiver, a1, holder, a3, t0, t1, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002679
2680 // Stub never generated for non-global objects that require access
2681 // checks.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002682 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002683
2684 __ push(a1); // Receiver.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002685 __ li(a3, Operand(callback)); // Callback info.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002686 __ Push(a3, a2, a0);
2687
2688 // Do tail-call to the runtime system.
2689 ExternalReference store_callback_property =
2690 ExternalReference(IC_Utility(IC::kStoreCallbackProperty),
2691 masm()->isolate());
2692 __ TailCallExternalReference(store_callback_property, 4, 1);
2693
2694 // Handle store cache miss.
2695 __ bind(&miss);
2696 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2697 __ Jump(ic, RelocInfo::CODE_TARGET);
2698
2699 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002700 return GetCode(Code::CALLBACKS, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002701}
2702
2703
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002704#undef __
2705#define __ ACCESS_MASM(masm)
2706
2707
2708void StoreStubCompiler::GenerateStoreViaSetter(
2709 MacroAssembler* masm,
2710 Handle<JSFunction> setter) {
2711 // ----------- S t a t e -------------
2712 // -- a0 : value
2713 // -- a1 : receiver
2714 // -- a2 : name
2715 // -- ra : return address
2716 // -----------------------------------
2717 {
2718 FrameScope scope(masm, StackFrame::INTERNAL);
2719
2720 // Save value register, so we can restore it later.
2721 __ push(a0);
2722
2723 if (!setter.is_null()) {
2724 // Call the JavaScript setter with receiver and value on the stack.
2725 __ push(a1);
2726 __ push(a0);
2727 ParameterCount actual(1);
2728 __ InvokeFunction(setter, actual, CALL_FUNCTION, NullCallWrapper(),
2729 CALL_AS_METHOD);
2730 } else {
2731 // If we generate a global code snippet for deoptimization only, remember
2732 // the place to continue after deoptimization.
2733 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2734 }
2735
2736 // We have to return the passed value, not the return value of the setter.
2737 __ pop(v0);
2738
2739 // Restore context register.
2740 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2741 }
2742 __ Ret();
2743}
2744
2745
2746#undef __
2747#define __ ACCESS_MASM(masm())
2748
2749
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002750Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002751 Handle<Name> name,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002752 Handle<JSObject> receiver,
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002753 Handle<JSObject> holder,
2754 Handle<JSFunction> setter) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002755 // ----------- S t a t e -------------
2756 // -- a0 : value
2757 // -- a1 : receiver
2758 // -- a2 : name
2759 // -- ra : return address
2760 // -----------------------------------
2761 Label miss;
2762
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002763 // Check that the maps haven't changed.
2764 __ JumpIfSmi(a1, &miss);
2765 CheckPrototypes(receiver, a1, holder, a3, t0, t1, name, &miss);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002766
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002767 GenerateStoreViaSetter(masm(), setter);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002768
2769 __ bind(&miss);
2770 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2771 __ Jump(ic, RelocInfo::CODE_TARGET);
2772
2773 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002774 return GetCode(Code::CALLBACKS, name);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002775}
2776
2777
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002778Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
2779 Handle<JSObject> receiver,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002780 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002781 // ----------- S t a t e -------------
2782 // -- a0 : value
2783 // -- a1 : receiver
2784 // -- a2 : name
2785 // -- ra : return address
2786 // -----------------------------------
2787 Label miss;
2788
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002789 // Check that the map of the object hasn't changed.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002790 __ CheckMap(a1, a3, Handle<Map>(receiver->map()), &miss,
2791 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002792
2793 // Perform global security token check if needed.
2794 if (receiver->IsJSGlobalProxy()) {
2795 __ CheckAccessGlobalProxy(a1, a3, &miss);
2796 }
2797
2798 // Stub is never generated for non-global objects that require access
2799 // checks.
2800 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2801
2802 __ Push(a1, a2, a0); // Receiver, name, value.
2803
2804 __ li(a0, Operand(Smi::FromInt(strict_mode_)));
2805 __ push(a0); // Strict mode.
2806
2807 // Do tail-call to the runtime system.
2808 ExternalReference store_ic_property =
2809 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty),
2810 masm()->isolate());
2811 __ TailCallExternalReference(store_ic_property, 4, 1);
2812
2813 // Handle store cache miss.
2814 __ bind(&miss);
2815 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2816 __ Jump(ic, RelocInfo::CODE_TARGET);
2817
2818 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002819 return GetCode(Code::INTERCEPTOR, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002820}
2821
2822
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002823Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2824 Handle<GlobalObject> object,
2825 Handle<JSGlobalPropertyCell> cell,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002826 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002827 // ----------- S t a t e -------------
2828 // -- a0 : value
2829 // -- a1 : receiver
2830 // -- a2 : name
2831 // -- ra : return address
2832 // -----------------------------------
2833 Label miss;
2834
2835 // Check that the map of the global has not changed.
2836 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2837 __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map())));
2838
2839 // Check that the value in the cell is not the hole. If it is, this
2840 // cell could have been deleted and reintroducing the global needs
2841 // to update the property details in the property dictionary of the
2842 // global object. We bail out to the runtime system to do that.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002843 __ li(t0, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002844 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
2845 __ lw(t2, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2846 __ Branch(&miss, eq, t1, Operand(t2));
2847
2848 // Store the value in the cell.
2849 __ sw(a0, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2850 __ mov(v0, a0); // Stored value must be returned in v0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002851 // Cells are always rescanned, so no write barrier here.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002852
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002853 Counters* counters = masm()->isolate()->counters();
2854 __ IncrementCounter(counters->named_store_global_inline(), 1, a1, a3);
2855 __ Ret();
2856
2857 // Handle store cache miss.
2858 __ bind(&miss);
2859 __ IncrementCounter(counters->named_store_global_inline_miss(), 1, a1, a3);
2860 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2861 __ Jump(ic, RelocInfo::CODE_TARGET);
2862
2863 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002864 return GetCode(Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002865}
2866
2867
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002868Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
2869 Handle<JSObject> object,
2870 Handle<JSObject> last,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002871 Handle<Name> name,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002872 Handle<GlobalObject> global) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002873 Label success;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002874
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002875 NonexistentHandlerFrontend(object, last, name, &success, global);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002876
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002877 __ bind(&success);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002878 // Return undefined if maps of the full prototype chain is still the same.
2879 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2880 __ Ret();
2881
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002882 // Return the generated code.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002883 return GetCode(kind(), Code::NONEXISTENT, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002884}
2885
2886
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002887Register* LoadStubCompiler::registers() {
2888 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2889 static Register registers[] = { a0, a2, a3, a1, t0, t1 };
2890 return registers;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002891}
2892
2893
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002894Register* KeyedLoadStubCompiler::registers() {
2895 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2896 static Register registers[] = { a1, a0, a2, a3, t0, t1 };
2897 return registers;
2898}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002899
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002900
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002901void KeyedLoadStubCompiler::GenerateNameCheck(Handle<Name> name,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002902 Register name_reg,
2903 Label* miss) {
2904 __ Branch(miss, ne, name_reg, Operand(name));
lrn@chromium.org7516f052011-03-30 08:52:27 +00002905}
2906
2907
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002908#undef __
2909#define __ ACCESS_MASM(masm)
2910
2911
2912void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
2913 Handle<JSFunction> getter) {
2914 // ----------- S t a t e -------------
2915 // -- a0 : receiver
2916 // -- a2 : name
2917 // -- ra : return address
2918 // -----------------------------------
2919 {
2920 FrameScope scope(masm, StackFrame::INTERNAL);
2921
2922 if (!getter.is_null()) {
2923 // Call the JavaScript getter with the receiver on the stack.
2924 __ push(a0);
2925 ParameterCount actual(0);
2926 __ InvokeFunction(getter, actual, CALL_FUNCTION, NullCallWrapper(),
2927 CALL_AS_METHOD);
2928 } else {
2929 // If we generate a global code snippet for deoptimization only, remember
2930 // the place to continue after deoptimization.
2931 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
2932 }
2933
2934 // Restore context register.
2935 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2936 }
2937 __ Ret();
2938}
2939
2940
2941#undef __
2942#define __ ACCESS_MASM(masm())
2943
2944
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002945Handle<Code> LoadStubCompiler::CompileLoadGlobal(
2946 Handle<JSObject> object,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002947 Handle<GlobalObject> global,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002948 Handle<JSGlobalPropertyCell> cell,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002949 Handle<Name> name,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002950 bool is_dont_delete) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002951 Label success, miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002952
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002953 __ CheckMap(
2954 receiver(), scratch1(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
2955 HandlerFrontendHeader(
2956 object, receiver(), Handle<JSObject>::cast(global), name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002957
2958 // Get the value from the cell.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002959 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002960 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
2961
2962 // Check for deleted property if property can actually be deleted.
2963 if (!is_dont_delete) {
2964 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
2965 __ Branch(&miss, eq, t0, Operand(at));
2966 }
2967
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002968 HandlerFrontendFooter(&success, &miss);
2969 __ bind(&success);
2970
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002971 Counters* counters = masm()->isolate()->counters();
2972 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002973 __ mov(v0, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002974 __ Ret();
2975
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002976 // Return the generated code.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002977 return GetICCode(kind(), Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002978}
2979
2980
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002981Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
2982 Handle<Map> receiver_map) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00002983 // ----------- S t a t e -------------
2984 // -- ra : return address
2985 // -- a0 : key
2986 // -- a1 : receiver
2987 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002988 ElementsKind elements_kind = receiver_map->elements_kind();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002989 if (receiver_map->has_fast_elements() ||
2990 receiver_map->has_external_array_elements()) {
2991 Handle<Code> stub = KeyedLoadFastElementStub(
2992 receiver_map->instance_type() == JS_ARRAY_TYPE,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002993 elements_kind).GetCode(isolate());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002994 __ DispatchMap(a1, a2, receiver_map, stub, DO_SMI_CHECK);
2995 } else {
2996 Handle<Code> stub =
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002997 KeyedLoadDictionaryElementStub().GetCode(isolate());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002998 __ DispatchMap(a1, a2, receiver_map, stub, DO_SMI_CHECK);
2999 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003000
3001 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
3002 __ Jump(ic, RelocInfo::CODE_TARGET);
3003
3004 // Return the generated code.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003005 return GetICCode(kind(), Code::NORMAL, factory()->empty_string());
danno@chromium.org40cb8782011-05-25 07:58:50 +00003006}
3007
3008
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003009Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003010 MapHandleList* receiver_maps,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003011 CodeHandleList* handlers,
3012 Handle<Name> name,
3013 Code::StubType type,
3014 IcCheckType check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003015 Label miss;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003016
3017 if (check == PROPERTY) {
3018 GenerateNameCheck(name, this->name(), &miss);
3019 }
3020
3021 __ JumpIfSmi(receiver(), &miss);
3022 Register map_reg = scratch1();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003023
danno@chromium.org40cb8782011-05-25 07:58:50 +00003024 int receiver_count = receiver_maps->length();
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003025 __ lw(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003026 for (int current = 0; current < receiver_count; ++current) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003027 __ Jump(handlers->at(current), RelocInfo::CODE_TARGET,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003028 eq, map_reg, Operand(receiver_maps->at(current)));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003029 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003030
3031 __ bind(&miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003032 GenerateLoadMiss(masm(), kind());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003033
3034 // Return the generated code.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003035 InlineCacheState state =
3036 receiver_maps->length() > 1 ? POLYMORPHIC : MONOMORPHIC;
3037 return GetICCode(kind(), type, name, state);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003038}
3039
3040
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003041Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +00003042 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003043 Handle<Map> transition,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003044 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003045 // ----------- S t a t e -------------
3046 // -- a0 : value
3047 // -- a1 : key
3048 // -- a2 : receiver
3049 // -- ra : return address
3050 // -----------------------------------
3051
3052 Label miss;
3053
3054 Counters* counters = masm()->isolate()->counters();
3055 __ IncrementCounter(counters->keyed_store_field(), 1, a3, t0);
3056
3057 // Check that the name has not changed.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003058 __ Branch(&miss, ne, a1, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003059
3060 // a3 is used as scratch register. a1 and a2 keep their values if a jump to
3061 // the miss label is generated.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003062 GenerateStoreField(masm(),
3063 object,
3064 index,
3065 transition,
3066 name,
3067 a2, a1, a3, t0,
3068 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003069 __ bind(&miss);
3070
3071 __ DecrementCounter(counters->keyed_store_field(), 1, a3, t0);
3072 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss();
3073 __ Jump(ic, RelocInfo::CODE_TARGET);
3074
3075 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003076 return GetCode(transition.is_null()
3077 ? Code::FIELD
3078 : Code::MAP_TRANSITION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003079}
3080
3081
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003082Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
3083 Handle<Map> receiver_map) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003084 // ----------- S t a t e -------------
3085 // -- a0 : value
3086 // -- a1 : key
3087 // -- a2 : receiver
3088 // -- ra : return address
3089 // -- a3 : scratch
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003090 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003091 ElementsKind elements_kind = receiver_map->elements_kind();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003092 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003093 Handle<Code> stub =
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003094 KeyedStoreElementStub(is_js_array,
3095 elements_kind,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003096 store_mode_).GetCode(isolate());
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003097
3098 __ DispatchMap(a2, a3, receiver_map, stub, DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003099
danno@chromium.org40cb8782011-05-25 07:58:50 +00003100 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003101 __ Jump(ic, RelocInfo::CODE_TARGET);
3102
3103 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003104 return GetCode(Code::NORMAL, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00003105}
3106
3107
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003108Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
3109 MapHandleList* receiver_maps,
3110 CodeHandleList* handler_stubs,
3111 MapHandleList* transitioned_maps) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003112 // ----------- S t a t e -------------
3113 // -- a0 : value
3114 // -- a1 : key
3115 // -- a2 : receiver
3116 // -- ra : return address
3117 // -- a3 : scratch
3118 // -----------------------------------
3119 Label miss;
3120 __ JumpIfSmi(a2, &miss);
3121
3122 int receiver_count = receiver_maps->length();
3123 __ lw(a3, FieldMemOperand(a2, HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003124 for (int i = 0; i < receiver_count; ++i) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003125 if (transitioned_maps->at(i).is_null()) {
3126 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq,
3127 a3, Operand(receiver_maps->at(i)));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003128 } else {
3129 Label next_map;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003130 __ Branch(&next_map, ne, a3, Operand(receiver_maps->at(i)));
3131 __ li(a3, Operand(transitioned_maps->at(i)));
3132 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003133 __ bind(&next_map);
3134 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003135 }
3136
3137 __ bind(&miss);
3138 Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
3139 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3140
3141 // Return the generated code.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003142 return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003143}
3144
3145
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003146Handle<Code> ConstructStubCompiler::CompileConstructStub(
3147 Handle<JSFunction> function) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003148 // a0 : argc
3149 // a1 : constructor
3150 // ra : return address
3151 // [sp] : last argument
3152 Label generic_stub_call;
3153
3154 // Use t7 for holding undefined which is used in several places below.
3155 __ LoadRoot(t7, Heap::kUndefinedValueRootIndex);
3156
3157#ifdef ENABLE_DEBUGGER_SUPPORT
3158 // Check to see whether there are any break points in the function code. If
3159 // there are jump to the generic constructor stub which calls the actual
3160 // code for the function thereby hitting the break points.
3161 __ lw(t5, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3162 __ lw(a2, FieldMemOperand(t5, SharedFunctionInfo::kDebugInfoOffset));
3163 __ Branch(&generic_stub_call, ne, a2, Operand(t7));
3164#endif
3165
3166 // Load the initial map and verify that it is in fact a map.
3167 // a1: constructor function
3168 // t7: undefined
3169 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003170 __ JumpIfSmi(a2, &generic_stub_call);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003171 __ GetObjectType(a2, a3, t0);
3172 __ Branch(&generic_stub_call, ne, t0, Operand(MAP_TYPE));
3173
3174#ifdef DEBUG
3175 // Cannot construct functions this way.
3176 // a0: argc
3177 // a1: constructor function
3178 // a2: initial map
3179 // t7: undefined
3180 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
3181 __ Check(ne, "Function constructed by construct stub.",
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003182 a3, Operand(JS_FUNCTION_TYPE));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003183#endif
3184
3185 // Now allocate the JSObject in new space.
3186 // a0: argc
3187 // a1: constructor function
3188 // a2: initial map
3189 // t7: undefined
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003190 ASSERT(function->has_initial_map());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003191 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003192#ifdef DEBUG
3193 int instance_size = function->initial_map()->instance_size();
3194 __ Check(eq, "Instance size of initial map changed.",
3195 a3, Operand(instance_size >> kPointerSizeLog2));
3196#endif
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003197 __ AllocateInNewSpace(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003198
3199 // Allocated the JSObject, now initialize the fields. Map is set to initial
3200 // map and properties and elements are set to empty fixed array.
3201 // a0: argc
3202 // a1: constructor function
3203 // a2: initial map
3204 // a3: object size (in words)
3205 // t4: JSObject (not tagged)
3206 // t7: undefined
3207 __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex);
3208 __ mov(t5, t4);
3209 __ sw(a2, MemOperand(t5, JSObject::kMapOffset));
3210 __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset));
3211 __ sw(t6, MemOperand(t5, JSObject::kElementsOffset));
3212 __ Addu(t5, t5, Operand(3 * kPointerSize));
3213 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
3214 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
3215 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
3216
3217
3218 // Calculate the location of the first argument. The stack contains only the
3219 // argc arguments.
3220 __ sll(a1, a0, kPointerSizeLog2);
3221 __ Addu(a1, a1, sp);
3222
3223 // Fill all the in-object properties with undefined.
3224 // a0: argc
3225 // a1: first argument
3226 // a3: object size (in words)
3227 // t4: JSObject (not tagged)
3228 // t5: First in-object property of JSObject (not tagged)
3229 // t7: undefined
3230 // Fill the initialized properties with a constant value or a passed argument
3231 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003232 Handle<SharedFunctionInfo> shared(function->shared());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003233 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3234 if (shared->IsThisPropertyAssignmentArgument(i)) {
3235 Label not_passed, next;
3236 // Check if the argument assigned to the property is actually passed.
3237 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3238 __ Branch(&not_passed, less_equal, a0, Operand(arg_number));
3239 // Argument passed - find it on the stack.
3240 __ lw(a2, MemOperand(a1, (arg_number + 1) * -kPointerSize));
3241 __ sw(a2, MemOperand(t5));
3242 __ Addu(t5, t5, kPointerSize);
3243 __ jmp(&next);
3244 __ bind(&not_passed);
3245 // Set the property to undefined.
3246 __ sw(t7, MemOperand(t5));
3247 __ Addu(t5, t5, Operand(kPointerSize));
3248 __ bind(&next);
3249 } else {
3250 // Set the property to the constant value.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003251 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i),
3252 masm()->isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003253 __ li(a2, Operand(constant));
3254 __ sw(a2, MemOperand(t5));
3255 __ Addu(t5, t5, kPointerSize);
3256 }
3257 }
3258
3259 // Fill the unused in-object property fields with undefined.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003260 for (int i = shared->this_property_assignments_count();
3261 i < function->initial_map()->inobject_properties();
3262 i++) {
3263 __ sw(t7, MemOperand(t5));
3264 __ Addu(t5, t5, kPointerSize);
3265 }
3266
3267 // a0: argc
3268 // t4: JSObject (not tagged)
3269 // Move argc to a1 and the JSObject to return to v0 and tag it.
3270 __ mov(a1, a0);
3271 __ mov(v0, t4);
3272 __ Or(v0, v0, Operand(kHeapObjectTag));
3273
3274 // v0: JSObject
3275 // a1: argc
3276 // Remove caller arguments and receiver from the stack and return.
3277 __ sll(t0, a1, kPointerSizeLog2);
3278 __ Addu(sp, sp, t0);
3279 __ Addu(sp, sp, Operand(kPointerSize));
3280 Counters* counters = masm()->isolate()->counters();
3281 __ IncrementCounter(counters->constructed_objects(), 1, a1, a2);
3282 __ IncrementCounter(counters->constructed_objects_stub(), 1, a1, a2);
3283 __ Ret();
3284
3285 // Jump to the generic stub in case the specialized code cannot handle the
3286 // construction.
3287 __ bind(&generic_stub_call);
3288 Handle<Code> generic_construct_stub =
3289 masm()->isolate()->builtins()->JSConstructStubGeneric();
3290 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
3291
3292 // Return the generated code.
3293 return GetCode();
3294}
3295
3296
danno@chromium.org40cb8782011-05-25 07:58:50 +00003297#undef __
3298#define __ ACCESS_MASM(masm)
3299
3300
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003301void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3302 MacroAssembler* masm) {
3303 // ---------- S t a t e --------------
3304 // -- ra : return address
3305 // -- a0 : key
3306 // -- a1 : receiver
3307 // -----------------------------------
3308 Label slow, miss_force_generic;
3309
3310 Register key = a0;
3311 Register receiver = a1;
3312
3313 __ JumpIfNotSmi(key, &miss_force_generic);
3314 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
3315 __ sra(a2, a0, kSmiTagSize);
3316 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
3317 __ Ret();
3318
3319 // Slow case, key and receiver still in a0 and a1.
3320 __ bind(&slow);
3321 __ IncrementCounter(
3322 masm->isolate()->counters()->keyed_load_external_array_slow(),
3323 1, a2, a3);
3324 // Entry registers are intact.
3325 // ---------- S t a t e --------------
3326 // -- ra : return address
3327 // -- a0 : key
3328 // -- a1 : receiver
3329 // -----------------------------------
3330 Handle<Code> slow_ic =
3331 masm->isolate()->builtins()->KeyedLoadIC_Slow();
3332 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
3333
3334 // Miss case, call the runtime.
3335 __ bind(&miss_force_generic);
3336
3337 // ---------- S t a t e --------------
3338 // -- ra : return address
3339 // -- a0 : key
3340 // -- a1 : receiver
3341 // -----------------------------------
3342
3343 Handle<Code> miss_ic =
3344 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3345 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3346}
3347
3348
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003349static bool IsElementTypeSigned(ElementsKind elements_kind) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003350 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003351 case EXTERNAL_BYTE_ELEMENTS:
3352 case EXTERNAL_SHORT_ELEMENTS:
3353 case EXTERNAL_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003354 return true;
3355
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003356 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3357 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3358 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3359 case EXTERNAL_PIXEL_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003360 return false;
3361
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003362 case EXTERNAL_FLOAT_ELEMENTS:
3363 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003364 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003365 case FAST_ELEMENTS:
3366 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003367 case FAST_HOLEY_SMI_ELEMENTS:
3368 case FAST_HOLEY_ELEMENTS:
3369 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003370 case DICTIONARY_ELEMENTS:
3371 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003372 UNREACHABLE();
3373 return false;
3374 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003375 return false;
lrn@chromium.org7516f052011-03-30 08:52:27 +00003376}
3377
3378
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003379static void GenerateSmiKeyCheck(MacroAssembler* masm,
3380 Register key,
3381 Register scratch0,
3382 Register scratch1,
3383 FPURegister double_scratch0,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003384 FPURegister double_scratch1,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003385 Label* fail) {
3386 if (CpuFeatures::IsSupported(FPU)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003387 CpuFeatureScope scope(masm, FPU);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003388 Label key_ok;
3389 // Check for smi or a smi inside a heap number. We convert the heap
3390 // number and check if the conversion is exact and fits into the smi
3391 // range.
3392 __ JumpIfSmi(key, &key_ok);
3393 __ CheckMap(key,
3394 scratch0,
3395 Heap::kHeapNumberMapRootIndex,
3396 fail,
3397 DONT_DO_SMI_CHECK);
3398 __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
3399 __ EmitFPUTruncate(kRoundToZero,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003400 scratch0,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003401 double_scratch0,
3402 at,
3403 double_scratch1,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003404 scratch1,
3405 kCheckForInexactConversion);
3406
3407 __ Branch(fail, ne, scratch1, Operand(zero_reg));
3408
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003409 __ SmiTagCheckOverflow(key, scratch0, scratch1);
3410 __ BranchOnOverflow(fail, scratch1);
3411 __ bind(&key_ok);
3412 } else {
3413 // Check that the key is a smi.
3414 __ JumpIfNotSmi(key, fail);
3415 }
3416}
3417
3418
danno@chromium.org40cb8782011-05-25 07:58:50 +00003419void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3420 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003421 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003422 // ---------- S t a t e --------------
3423 // -- a0 : value
3424 // -- a1 : key
3425 // -- a2 : receiver
3426 // -- ra : return address
3427 // -----------------------------------
3428
danno@chromium.org40cb8782011-05-25 07:58:50 +00003429 Label slow, check_heap_number, miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003430
3431 // Register usage.
3432 Register value = a0;
3433 Register key = a1;
3434 Register receiver = a2;
3435 // a3 mostly holds the elements array or the destination external array.
3436
danno@chromium.org40cb8782011-05-25 07:58:50 +00003437 // This stub is meant to be tail-jumped to, the receiver must already
3438 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003439
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003440 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003441 GenerateSmiKeyCheck(masm, key, t0, t1, f2, f4, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003442
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003443 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3444
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003445 // Check that the index is in range.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003446 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3447 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003448 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003449
3450 // Handle both smis and HeapNumbers in the fast path. Go to the
3451 // runtime for all other kinds of values.
3452 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003453
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003454 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003455 // Double to pixel conversion is only implemented in the runtime for now.
3456 __ JumpIfNotSmi(value, &slow);
3457 } else {
3458 __ JumpIfNotSmi(value, &check_heap_number);
3459 }
3460 __ SmiUntag(t1, value);
3461 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3462
3463 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003464 // t1: value (integer).
3465
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003466 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003467 case EXTERNAL_PIXEL_ELEMENTS: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003468 // Clamp the value to [0..255].
3469 // v0 is used as a scratch register here.
3470 Label done;
3471 __ li(v0, Operand(255));
3472 // Normal branch: nop in delay slot.
3473 __ Branch(&done, gt, t1, Operand(v0));
3474 // Use delay slot in this branch.
3475 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg));
3476 __ mov(v0, zero_reg); // In delay slot.
3477 __ mov(v0, t1); // Value is in range 0..255.
3478 __ bind(&done);
3479 __ mov(t1, v0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003480
3481 __ srl(t8, key, 1);
3482 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003483 __ sb(t1, MemOperand(t8, 0));
3484 }
3485 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003486 case EXTERNAL_BYTE_ELEMENTS:
3487 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003488 __ srl(t8, key, 1);
3489 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003490 __ sb(t1, MemOperand(t8, 0));
3491 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003492 case EXTERNAL_SHORT_ELEMENTS:
3493 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003494 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003495 __ sh(t1, MemOperand(t8, 0));
3496 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003497 case EXTERNAL_INT_ELEMENTS:
3498 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003499 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003500 __ addu(t8, a3, t8);
3501 __ sw(t1, MemOperand(t8, 0));
3502 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003503 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003504 // Perform int-to-float conversion and store to memory.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003505 __ SmiUntag(t0, key);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003506 StoreIntAsFloat(masm, a3, t0, t1, t2, t3, t4);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003507 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003508 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003509 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003510 __ addu(a3, a3, t8);
3511 // a3: effective address of the double element
3512 FloatingPointHelper::Destination destination;
3513 if (CpuFeatures::IsSupported(FPU)) {
3514 destination = FloatingPointHelper::kFPURegisters;
3515 } else {
3516 destination = FloatingPointHelper::kCoreRegisters;
3517 }
3518 FloatingPointHelper::ConvertIntToDouble(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003519 masm, t1, destination,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003520 f0, t2, t3, // These are: double_dst, dst_mantissa, dst_exponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003521 t0, f2); // These are: scratch2, single_scratch.
3522 if (destination == FloatingPointHelper::kFPURegisters) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003523 CpuFeatureScope scope(masm, FPU);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003524 __ sdc1(f0, MemOperand(a3, 0));
3525 } else {
3526 __ sw(t2, MemOperand(a3, 0));
3527 __ sw(t3, MemOperand(a3, Register::kSizeInBytes));
3528 }
3529 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003530 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003531 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003532 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003533 case FAST_HOLEY_ELEMENTS:
3534 case FAST_HOLEY_SMI_ELEMENTS:
3535 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003536 case DICTIONARY_ELEMENTS:
3537 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003538 UNREACHABLE();
3539 break;
3540 }
3541
3542 // Entry registers are intact, a0 holds the value which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003543 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003544 __ Ret();
3545
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003546 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003547 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003548 __ bind(&check_heap_number);
3549 __ GetObjectType(value, t1, t2);
3550 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE));
3551
3552 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3553
3554 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003555
3556 // The WebGL specification leaves the behavior of storing NaN and
3557 // +/-Infinity into integer arrays basically undefined. For more
3558 // reproducible behavior, convert these to zero.
3559
3560 if (CpuFeatures::IsSupported(FPU)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003561 CpuFeatureScope scope(masm, FPU);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003562
3563 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
3564
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003565 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003566 __ cvt_s_d(f0, f0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003567 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003568 __ addu(t8, a3, t8);
3569 __ swc1(f0, MemOperand(t8, 0));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003570 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003571 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003572 __ addu(t8, a3, t8);
3573 __ sdc1(f0, MemOperand(t8, 0));
3574 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003575 __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003576
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003577 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003578 case EXTERNAL_BYTE_ELEMENTS:
3579 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003580 __ srl(t8, key, 1);
3581 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003582 __ sb(t3, MemOperand(t8, 0));
3583 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003584 case EXTERNAL_SHORT_ELEMENTS:
3585 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003586 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003587 __ sh(t3, MemOperand(t8, 0));
3588 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003589 case EXTERNAL_INT_ELEMENTS:
3590 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003591 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003592 __ addu(t8, a3, t8);
3593 __ sw(t3, MemOperand(t8, 0));
3594 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003595 case EXTERNAL_PIXEL_ELEMENTS:
3596 case EXTERNAL_FLOAT_ELEMENTS:
3597 case EXTERNAL_DOUBLE_ELEMENTS:
3598 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003599 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003600 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003601 case FAST_HOLEY_ELEMENTS:
3602 case FAST_HOLEY_SMI_ELEMENTS:
3603 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003604 case DICTIONARY_ELEMENTS:
3605 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003606 UNREACHABLE();
3607 break;
3608 }
3609 }
3610
3611 // Entry registers are intact, a0 holds the value
3612 // which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003613 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003614 __ Ret();
3615 } else {
3616 // FPU is not available, do manual conversions.
3617
3618 __ lw(t3, FieldMemOperand(value, HeapNumber::kExponentOffset));
3619 __ lw(t4, FieldMemOperand(value, HeapNumber::kMantissaOffset));
3620
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003621 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003622 Label done, nan_or_infinity_or_zero;
3623 static const int kMantissaInHiWordShift =
3624 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3625
3626 static const int kMantissaInLoWordShift =
3627 kBitsPerInt - kMantissaInHiWordShift;
3628
3629 // Test for all special exponent values: zeros, subnormal numbers, NaNs
3630 // and infinities. All these should be converted to 0.
3631 __ li(t5, HeapNumber::kExponentMask);
3632 __ and_(t6, t3, t5);
3633 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(zero_reg));
3634
3635 __ xor_(t1, t6, t5);
3636 __ li(t2, kBinary32ExponentMask);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003637 __ Movz(t6, t2, t1); // Only if t6 is equal to t5.
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003638 __ Branch(&nan_or_infinity_or_zero, eq, t1, Operand(zero_reg));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003639
3640 // Rebias exponent.
3641 __ srl(t6, t6, HeapNumber::kExponentShift);
3642 __ Addu(t6,
3643 t6,
3644 Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
3645
3646 __ li(t1, Operand(kBinary32MaxExponent));
3647 __ Slt(t1, t1, t6);
3648 __ And(t2, t3, Operand(HeapNumber::kSignMask));
3649 __ Or(t2, t2, Operand(kBinary32ExponentMask));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003650 __ Movn(t3, t2, t1); // Only if t6 is gt kBinary32MaxExponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003651 __ Branch(&done, gt, t6, Operand(kBinary32MaxExponent));
3652
3653 __ Slt(t1, t6, Operand(kBinary32MinExponent));
3654 __ And(t2, t3, Operand(HeapNumber::kSignMask));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003655 __ Movn(t3, t2, t1); // Only if t6 is lt kBinary32MinExponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003656 __ Branch(&done, lt, t6, Operand(kBinary32MinExponent));
3657
3658 __ And(t7, t3, Operand(HeapNumber::kSignMask));
3659 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3660 __ sll(t3, t3, kMantissaInHiWordShift);
3661 __ or_(t7, t7, t3);
3662 __ srl(t4, t4, kMantissaInLoWordShift);
3663 __ or_(t7, t7, t4);
3664 __ sll(t6, t6, kBinary32ExponentShift);
3665 __ or_(t3, t7, t6);
3666
3667 __ bind(&done);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003668 __ sll(t9, key, 1);
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003669 __ addu(t9, a3, t9);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003670 __ sw(t3, MemOperand(t9, 0));
3671
3672 // Entry registers are intact, a0 holds the value which is the return
3673 // value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003674 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003675 __ Ret();
3676
3677 __ bind(&nan_or_infinity_or_zero);
3678 __ And(t7, t3, Operand(HeapNumber::kSignMask));
3679 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3680 __ or_(t6, t6, t7);
3681 __ sll(t3, t3, kMantissaInHiWordShift);
3682 __ or_(t6, t6, t3);
3683 __ srl(t4, t4, kMantissaInLoWordShift);
3684 __ or_(t3, t6, t4);
3685 __ Branch(&done);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003686 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003687 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003688 __ addu(t8, a3, t8);
3689 // t8: effective address of destination element.
3690 __ sw(t4, MemOperand(t8, 0));
3691 __ sw(t3, MemOperand(t8, Register::kSizeInBytes));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003692 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003693 __ Ret();
3694 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003695 bool is_signed_type = IsElementTypeSigned(elements_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003696 int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
3697 int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
3698
3699 Label done, sign;
3700
3701 // Test for all special exponent values: zeros, subnormal numbers, NaNs
3702 // and infinities. All these should be converted to 0.
3703 __ li(t5, HeapNumber::kExponentMask);
3704 __ and_(t6, t3, t5);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003705 __ Movz(t3, zero_reg, t6); // Only if t6 is equal to zero.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003706 __ Branch(&done, eq, t6, Operand(zero_reg));
3707
3708 __ xor_(t2, t6, t5);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003709 __ Movz(t3, zero_reg, t2); // Only if t6 is equal to t5.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003710 __ Branch(&done, eq, t6, Operand(t5));
3711
3712 // Unbias exponent.
3713 __ srl(t6, t6, HeapNumber::kExponentShift);
3714 __ Subu(t6, t6, Operand(HeapNumber::kExponentBias));
3715 // If exponent is negative then result is 0.
3716 __ slt(t2, t6, zero_reg);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003717 __ Movn(t3, zero_reg, t2); // Only if exponent is negative.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003718 __ Branch(&done, lt, t6, Operand(zero_reg));
3719
3720 // If exponent is too big then result is minimal value.
3721 __ slti(t1, t6, meaningfull_bits - 1);
3722 __ li(t2, min_value);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003723 __ Movz(t3, t2, t1); // Only if t6 is ge meaningfull_bits - 1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003724 __ Branch(&done, ge, t6, Operand(meaningfull_bits - 1));
3725
3726 __ And(t5, t3, Operand(HeapNumber::kSignMask));
3727 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3728 __ Or(t3, t3, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
3729
3730 __ li(t9, HeapNumber::kMantissaBitsInTopWord);
3731 __ subu(t6, t9, t6);
3732 __ slt(t1, t6, zero_reg);
3733 __ srlv(t2, t3, t6);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003734 __ Movz(t3, t2, t1); // Only if t6 is positive.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003735 __ Branch(&sign, ge, t6, Operand(zero_reg));
3736
3737 __ subu(t6, zero_reg, t6);
3738 __ sllv(t3, t3, t6);
3739 __ li(t9, meaningfull_bits);
3740 __ subu(t6, t9, t6);
3741 __ srlv(t4, t4, t6);
3742 __ or_(t3, t3, t4);
3743
3744 __ bind(&sign);
3745 __ subu(t2, t3, zero_reg);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003746 __ Movz(t3, t2, t5); // Only if t5 is zero.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003747
3748 __ bind(&done);
3749
3750 // Result is in t3.
3751 // This switch block should be exactly the same as above (FPU mode).
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003752 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003753 case EXTERNAL_BYTE_ELEMENTS:
3754 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003755 __ srl(t8, key, 1);
3756 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003757 __ sb(t3, MemOperand(t8, 0));
3758 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003759 case EXTERNAL_SHORT_ELEMENTS:
3760 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003761 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003762 __ sh(t3, MemOperand(t8, 0));
3763 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003764 case EXTERNAL_INT_ELEMENTS:
3765 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003766 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003767 __ addu(t8, a3, t8);
3768 __ sw(t3, MemOperand(t8, 0));
3769 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003770 case EXTERNAL_PIXEL_ELEMENTS:
3771 case EXTERNAL_FLOAT_ELEMENTS:
3772 case EXTERNAL_DOUBLE_ELEMENTS:
3773 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003774 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003775 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003776 case FAST_HOLEY_ELEMENTS:
3777 case FAST_HOLEY_SMI_ELEMENTS:
3778 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003779 case DICTIONARY_ELEMENTS:
3780 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003781 UNREACHABLE();
3782 break;
3783 }
3784 }
3785 }
3786 }
3787
danno@chromium.org40cb8782011-05-25 07:58:50 +00003788 // Slow case, key and receiver still in a0 and a1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003789 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003790 __ IncrementCounter(
3791 masm->isolate()->counters()->keyed_load_external_array_slow(),
3792 1, a2, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003793 // Entry registers are intact.
3794 // ---------- S t a t e --------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003795 // -- ra : return address
danno@chromium.org40cb8782011-05-25 07:58:50 +00003796 // -- a0 : key
3797 // -- a1 : receiver
3798 // -----------------------------------
3799 Handle<Code> slow_ic =
3800 masm->isolate()->builtins()->KeyedStoreIC_Slow();
3801 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
3802
3803 // Miss case, call the runtime.
3804 __ bind(&miss_force_generic);
3805
3806 // ---------- S t a t e --------------
3807 // -- ra : return address
3808 // -- a0 : key
3809 // -- a1 : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003810 // -----------------------------------
3811
danno@chromium.org40cb8782011-05-25 07:58:50 +00003812 Handle<Code> miss_ic =
3813 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
3814 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3815}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003816
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003817
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003818void KeyedStoreStubCompiler::GenerateStoreFastElement(
3819 MacroAssembler* masm,
3820 bool is_js_array,
yangguo@chromium.org56454712012-02-16 15:33:53 +00003821 ElementsKind elements_kind,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003822 KeyedAccessStoreMode store_mode) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003823 // ----------- S t a t e -------------
3824 // -- a0 : value
3825 // -- a1 : key
3826 // -- a2 : receiver
3827 // -- ra : return address
3828 // -- a3 : scratch
3829 // -- a4 : scratch (elements)
3830 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00003831 Label miss_force_generic, transition_elements_kind, grow, slow;
3832 Label finish_store, check_capacity;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003833
3834 Register value_reg = a0;
3835 Register key_reg = a1;
3836 Register receiver_reg = a2;
yangguo@chromium.org56454712012-02-16 15:33:53 +00003837 Register scratch = t0;
3838 Register elements_reg = a3;
3839 Register length_reg = t1;
3840 Register scratch2 = t2;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003841
3842 // This stub is meant to be tail-jumped to, the receiver must already
3843 // have been verified by the caller to not be a smi.
3844
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003845 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003846 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003847
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003848 if (IsFastSmiElementsKind(elements_kind)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003849 __ JumpIfNotSmi(value_reg, &transition_elements_kind);
3850 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003851
3852 // Check that the key is within bounds.
yangguo@chromium.org56454712012-02-16 15:33:53 +00003853 __ lw(elements_reg,
3854 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003855 if (is_js_array) {
3856 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3857 } else {
3858 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3859 }
3860 // Compare smis.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003861 if (is_js_array && IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003862 __ Branch(&grow, hs, key_reg, Operand(scratch));
3863 } else {
3864 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
3865 }
3866
3867 // Make sure elements is a fast element array, not 'cow'.
3868 __ CheckMap(elements_reg,
3869 scratch,
3870 Heap::kFixedArrayMapRootIndex,
3871 &miss_force_generic,
3872 DONT_DO_SMI_CHECK);
3873
3874 __ bind(&finish_store);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003875
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003876 if (IsFastSmiElementsKind(elements_kind)) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003877 __ Addu(scratch,
3878 elements_reg,
3879 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3880 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
3881 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
3882 __ Addu(scratch, scratch, scratch2);
3883 __ sw(value_reg, MemOperand(scratch));
3884 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003885 ASSERT(IsFastObjectElementsKind(elements_kind));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003886 __ Addu(scratch,
3887 elements_reg,
3888 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3889 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
3890 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
3891 __ Addu(scratch, scratch, scratch2);
3892 __ sw(value_reg, MemOperand(scratch));
3893 __ mov(receiver_reg, value_reg);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003894 __ RecordWrite(elements_reg, // Object.
3895 scratch, // Address.
3896 receiver_reg, // Value.
3897 kRAHasNotBeenSaved,
3898 kDontSaveFPRegs);
3899 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003900 // value_reg (a0) is preserved.
3901 // Done.
3902 __ Ret();
3903
3904 __ bind(&miss_force_generic);
3905 Handle<Code> ic =
3906 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
3907 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003908
3909 __ bind(&transition_elements_kind);
3910 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
3911 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003912
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003913 if (is_js_array && IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003914 // Grow the array by a single element if possible.
3915 __ bind(&grow);
3916
3917 // Make sure the array is only growing by a single element, anything else
3918 // must be handled by the runtime.
3919 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch));
3920
3921 // Check for the empty array, and preallocate a small backing store if
3922 // possible.
3923 __ lw(length_reg,
3924 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3925 __ lw(elements_reg,
3926 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3927 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
3928 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
3929
3930 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
3931 __ AllocateInNewSpace(size, elements_reg, scratch, scratch2, &slow,
3932 TAG_OBJECT);
3933
3934 __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex);
3935 __ sw(scratch, FieldMemOperand(elements_reg, JSObject::kMapOffset));
3936 __ li(scratch, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
3937 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3938 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
3939 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
3940 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::SizeFor(i)));
3941 }
3942
3943 // Store the element at index zero.
3944 __ sw(value_reg, FieldMemOperand(elements_reg, FixedArray::SizeFor(0)));
3945
3946 // Install the new backing store in the JSArray.
3947 __ sw(elements_reg,
3948 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3949 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
3950 scratch, kRAHasNotBeenSaved, kDontSaveFPRegs,
3951 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3952
3953 // Increment the length of the array.
3954 __ li(length_reg, Operand(Smi::FromInt(1)));
3955 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3956 __ Ret();
3957
3958 __ bind(&check_capacity);
3959 // Check for cow elements, in general they are not handled by this stub
3960 __ CheckMap(elements_reg,
3961 scratch,
3962 Heap::kFixedCOWArrayMapRootIndex,
3963 &miss_force_generic,
3964 DONT_DO_SMI_CHECK);
3965
3966 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3967 __ Branch(&slow, hs, length_reg, Operand(scratch));
3968
3969 // Grow the array and finish the store.
3970 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
3971 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3972 __ jmp(&finish_store);
3973
3974 __ bind(&slow);
3975 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
3976 __ Jump(ic_slow, RelocInfo::CODE_TARGET);
3977 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003978}
3979
3980
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003981void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
3982 MacroAssembler* masm,
yangguo@chromium.org56454712012-02-16 15:33:53 +00003983 bool is_js_array,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003984 KeyedAccessStoreMode store_mode) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003985 // ----------- S t a t e -------------
3986 // -- a0 : value
3987 // -- a1 : key
3988 // -- a2 : receiver
3989 // -- ra : return address
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003990 // -- a3 : scratch (elements backing store)
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003991 // -- t0 : scratch (elements_reg)
3992 // -- t1 : scratch (mantissa_reg)
3993 // -- t2 : scratch (exponent_reg)
3994 // -- t3 : scratch4
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003995 // -- t4 : scratch
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003996 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00003997 Label miss_force_generic, transition_elements_kind, grow, slow;
3998 Label finish_store, check_capacity;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003999
4000 Register value_reg = a0;
4001 Register key_reg = a1;
4002 Register receiver_reg = a2;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004003 Register elements_reg = a3;
4004 Register scratch1 = t0;
4005 Register scratch2 = t1;
4006 Register scratch3 = t2;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004007 Register scratch4 = t3;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004008 Register scratch5 = t4;
yangguo@chromium.org56454712012-02-16 15:33:53 +00004009 Register length_reg = t3;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004010
4011 // This stub is meant to be tail-jumped to, the receiver must already
4012 // have been verified by the caller to not be a smi.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004013
4014 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004015 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004016
4017 __ lw(elements_reg,
4018 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4019
4020 // Check that the key is within bounds.
4021 if (is_js_array) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004022 __ lw(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004023 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004024 __ lw(scratch1,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004025 FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4026 }
4027 // Compare smis, unsigned compare catches both negative and out-of-bound
4028 // indexes.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00004029 if (IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00004030 __ Branch(&grow, hs, key_reg, Operand(scratch1));
4031 } else {
4032 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch1));
4033 }
4034
4035 __ bind(&finish_store);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004036
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004037 __ StoreNumberToDoubleElements(value_reg,
4038 key_reg,
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004039 // All registers after this are overwritten.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004040 elements_reg,
4041 scratch1,
4042 scratch2,
4043 scratch3,
4044 scratch4,
4045 &transition_elements_kind);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004046
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004047 __ Ret(USE_DELAY_SLOT);
4048 __ mov(v0, value_reg); // In delay slot.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004049
4050 // Handle store cache miss, replacing the ic with the generic stub.
4051 __ bind(&miss_force_generic);
4052 Handle<Code> ic =
4053 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4054 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004055
4056 __ bind(&transition_elements_kind);
4057 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4058 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
yangguo@chromium.org56454712012-02-16 15:33:53 +00004059
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00004060 if (is_js_array && IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00004061 // Grow the array by a single element if possible.
4062 __ bind(&grow);
4063
4064 // Make sure the array is only growing by a single element, anything else
4065 // must be handled by the runtime.
4066 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch1));
4067
4068 // Transition on values that can't be stored in a FixedDoubleArray.
4069 Label value_is_smi;
4070 __ JumpIfSmi(value_reg, &value_is_smi);
4071 __ lw(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
4072 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
4073 __ Branch(&transition_elements_kind, ne, scratch1, Operand(at));
4074 __ bind(&value_is_smi);
4075
4076 // Check for the empty array, and preallocate a small backing store if
4077 // possible.
4078 __ lw(length_reg,
4079 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4080 __ lw(elements_reg,
4081 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4082 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
4083 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
4084
4085 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
4086 __ AllocateInNewSpace(size, elements_reg, scratch1, scratch2, &slow,
4087 TAG_OBJECT);
4088
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004089 // Initialize the new FixedDoubleArray.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004090 __ LoadRoot(scratch1, Heap::kFixedDoubleArrayMapRootIndex);
4091 __ sw(scratch1, FieldMemOperand(elements_reg, JSObject::kMapOffset));
4092 __ li(scratch1, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4093 __ sw(scratch1,
4094 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
4095
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004096 __ mov(scratch1, elements_reg);
4097 __ StoreNumberToDoubleElements(value_reg,
4098 key_reg,
4099 // All registers after this are overwritten.
4100 scratch1,
4101 scratch2,
4102 scratch3,
4103 scratch4,
4104 scratch5,
4105 &transition_elements_kind);
4106
4107 __ li(scratch1, Operand(kHoleNanLower32));
4108 __ li(scratch2, Operand(kHoleNanUpper32));
4109 for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) {
4110 int offset = FixedDoubleArray::OffsetOfElementAt(i);
4111 __ sw(scratch1, FieldMemOperand(elements_reg, offset));
4112 __ sw(scratch2, FieldMemOperand(elements_reg, offset + kPointerSize));
4113 }
4114
yangguo@chromium.org56454712012-02-16 15:33:53 +00004115 // Install the new backing store in the JSArray.
4116 __ sw(elements_reg,
4117 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4118 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
4119 scratch1, kRAHasNotBeenSaved, kDontSaveFPRegs,
4120 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4121
4122 // Increment the length of the array.
4123 __ li(length_reg, Operand(Smi::FromInt(1)));
4124 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
danno@chromium.org00379b82012-05-04 09:16:29 +00004125 __ lw(elements_reg,
4126 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004127 __ Ret();
yangguo@chromium.org56454712012-02-16 15:33:53 +00004128
4129 __ bind(&check_capacity);
4130 // Make sure that the backing store can hold additional elements.
4131 __ lw(scratch1,
4132 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
4133 __ Branch(&slow, hs, length_reg, Operand(scratch1));
4134
4135 // Grow the array and finish the store.
4136 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
4137 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4138 __ jmp(&finish_store);
4139
4140 __ bind(&slow);
4141 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4142 __ Jump(ic_slow, RelocInfo::CODE_TARGET);
4143 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004144}
4145
4146
ager@chromium.org5c838252010-02-19 08:53:10 +00004147#undef __
4148
4149} } // namespace v8::internal
4150
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004151#endif // V8_TARGET_ARCH_MIPS