blob: 959da8e7489c43bbdb38db7b0e0b198120a48261 [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
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000310void StubCompiler::DoGenerateFastPropertyLoad(MacroAssembler* masm,
311 Register dst,
312 Register src,
313 bool inobject,
314 int index) {
315 int offset = index * kPointerSize;
316 if (!inobject) {
317 // Calculate the offset into the properties array.
318 offset = offset + FixedArray::kHeaderSize;
319 __ lw(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
320 src = dst;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000321 }
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000322 __ lw(dst, FieldMemOperand(src, offset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000323}
324
325
326void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
327 Register receiver,
328 Register scratch,
329 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000330 // Check that the receiver isn't a smi.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000331 __ JumpIfSmi(receiver, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000332
333 // Check that the object is a JS array.
334 __ GetObjectType(receiver, scratch, scratch);
335 __ Branch(miss_label, ne, scratch, Operand(JS_ARRAY_TYPE));
336
337 // Load length directly from the JS array.
338 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
339 __ Ret();
340}
341
342
343// Generate code to check if an object is a string. If the object is a
344// heap object, its map's instance type is left in the scratch1 register.
345// If this is not needed, scratch1 and scratch2 may be the same register.
346static void GenerateStringCheck(MacroAssembler* masm,
347 Register receiver,
348 Register scratch1,
349 Register scratch2,
350 Label* smi,
351 Label* non_string_object) {
352 // Check that the receiver isn't a smi.
353 __ JumpIfSmi(receiver, smi, t0);
354
355 // Check that the object is a string.
356 __ lw(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
357 __ lbu(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
358 __ And(scratch2, scratch1, Operand(kIsNotStringMask));
359 // The cast is to resolve the overload for the argument of 0x0.
360 __ Branch(non_string_object,
361 ne,
362 scratch2,
363 Operand(static_cast<int32_t>(kStringTag)));
ager@chromium.org5c838252010-02-19 08:53:10 +0000364}
365
366
lrn@chromium.org7516f052011-03-30 08:52:27 +0000367// Generate code to load the length from a string object and return the length.
368// If the receiver object is not a string or a wrapped string object the
369// execution continues at the miss label. The register containing the
370// receiver is potentially clobbered.
371void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
372 Register receiver,
373 Register scratch1,
374 Register scratch2,
375 Label* miss,
376 bool support_wrappers) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000377 Label check_wrapper;
378
379 // Check if the object is a string leaving the instance type in the
380 // scratch1 register.
381 GenerateStringCheck(masm, receiver, scratch1, scratch2, miss,
382 support_wrappers ? &check_wrapper : miss);
383
384 // Load length directly from the string.
385 __ lw(v0, FieldMemOperand(receiver, String::kLengthOffset));
386 __ Ret();
387
388 if (support_wrappers) {
389 // Check if the object is a JSValue wrapper.
390 __ bind(&check_wrapper);
391 __ Branch(miss, ne, scratch1, Operand(JS_VALUE_TYPE));
392
393 // Unwrap the value and check if the wrapped value is a string.
394 __ lw(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
395 GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
396 __ lw(v0, FieldMemOperand(scratch1, String::kLengthOffset));
397 __ Ret();
398 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000399}
400
401
ager@chromium.org5c838252010-02-19 08:53:10 +0000402void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
403 Register receiver,
404 Register scratch1,
405 Register scratch2,
406 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000407 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
408 __ mov(v0, scratch1);
409 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000410}
411
412
lrn@chromium.org7516f052011-03-30 08:52:27 +0000413// Generate StoreField code, value is passed in a0 register.
ager@chromium.org5c838252010-02-19 08:53:10 +0000414// After executing generated code, the receiver_reg and name_reg
415// may be clobbered.
416void StubCompiler::GenerateStoreField(MacroAssembler* masm,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000417 Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +0000418 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000419 Handle<Map> transition,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000420 Handle<Name> name,
ager@chromium.org5c838252010-02-19 08:53:10 +0000421 Register receiver_reg,
422 Register name_reg,
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000423 Register value_reg,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000424 Register scratch1,
425 Register scratch2,
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000426 Label* miss_label,
427 Label* miss_restore_name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000428 // a0 : value.
429 Label exit;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000430
431 LookupResult lookup(masm->isolate());
432 object->Lookup(*name, &lookup);
433 if (lookup.IsFound() && (lookup.IsReadOnly() || !lookup.IsCacheable())) {
434 // In sloppy mode, we could just return the value and be done. However, we
435 // might be in strict mode, where we have to throw. Since we cannot tell,
436 // go into slow case unconditionally.
437 __ jmp(miss_label);
438 return;
439 }
440
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000441 // Check that the map of the object hasn't changed.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000442 CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
443 : REQUIRE_EXACT_MAP;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000444 __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000445 DO_SMI_CHECK, mode);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000446
447 // Perform global security token check if needed.
448 if (object->IsJSGlobalProxy()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000449 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
450 }
451
452 // Check that we are allowed to write this.
453 if (!transition.is_null() && object->GetPrototype()->IsJSObject()) {
454 JSObject* holder;
455 if (lookup.IsFound()) {
456 holder = lookup.holder();
457 } else {
458 // Find the top object.
459 holder = *object;
460 do {
461 holder = JSObject::cast(holder->GetPrototype());
462 } while (holder->GetPrototype()->IsJSObject());
463 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000464 CheckPrototypes(object, receiver_reg, Handle<JSObject>(holder), name_reg,
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000465 scratch1, scratch2, name, miss_restore_name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000466 }
467
468 // Stub never generated for non-global objects that require access
469 // checks.
470 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
471
472 // Perform map transition for the receiver if necessary.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000473 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000474 // The properties must be extended before we can store the value.
475 // We jump to a runtime call that extends the properties array.
476 __ push(receiver_reg);
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000477 __ li(a2, Operand(transition));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000478 __ Push(a2, a0);
479 __ TailCallExternalReference(
480 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
481 masm->isolate()),
482 3, 1);
483 return;
484 }
485
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000486 if (!transition.is_null()) {
verwaest@chromium.org37141392012-05-31 13:27:02 +0000487 // Update the map of the object.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000488 __ li(scratch1, Operand(transition));
489 __ sw(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
verwaest@chromium.org37141392012-05-31 13:27:02 +0000490
491 // Update the write barrier for the map field and pass the now unused
492 // name_reg as scratch register.
493 __ RecordWriteField(receiver_reg,
494 HeapObject::kMapOffset,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000495 scratch1,
verwaest@chromium.org37141392012-05-31 13:27:02 +0000496 name_reg,
497 kRAHasNotBeenSaved,
498 kDontSaveFPRegs,
499 OMIT_REMEMBERED_SET,
500 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000501 }
502
503 // Adjust for the number of properties stored in the object. Even in the
504 // face of a transition we can use the old map here because the size of the
505 // object and the number of in-object properties is not going to change.
506 index -= object->map()->inobject_properties();
507
508 if (index < 0) {
509 // Set the property straight into the object.
510 int offset = object->map()->instance_size() + (index * kPointerSize);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000511 __ sw(value_reg, FieldMemOperand(receiver_reg, offset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000512
513 // Skip updating write barrier if storing a smi.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000514 __ JumpIfSmi(value_reg, &exit);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000515
516 // Update the write barrier for the array address.
517 // Pass the now unused name_reg as a scratch register.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000518 __ mov(name_reg, value_reg);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000519 __ RecordWriteField(receiver_reg,
520 offset,
521 name_reg,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000522 scratch1,
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000523 kRAHasNotBeenSaved,
524 kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000525 } else {
526 // Write to the properties array.
527 int offset = index * kPointerSize + FixedArray::kHeaderSize;
528 // Get the properties array.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000529 __ lw(scratch1,
530 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000531 __ sw(value_reg, FieldMemOperand(scratch1, offset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000532
533 // Skip updating write barrier if storing a smi.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000534 __ JumpIfSmi(value_reg, &exit);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000535
536 // Update the write barrier for the array address.
537 // Ok to clobber receiver_reg and name_reg, since we return.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000538 __ mov(name_reg, value_reg);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000539 __ RecordWriteField(scratch1,
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000540 offset,
541 name_reg,
542 receiver_reg,
543 kRAHasNotBeenSaved,
544 kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000545 }
546
547 // Return the value (register v0).
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000548 ASSERT(value_reg.is(a0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000549 __ bind(&exit);
550 __ mov(v0, a0);
551 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000552}
553
554
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000555void BaseStoreStubCompiler::GenerateRestoreName(MacroAssembler* masm,
556 Label* label,
557 Handle<Name> name) {
558 if (!label->is_unused()) {
559 __ bind(label);
560 __ li(this->name(), Operand(name));
561 }
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000562}
563
564
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000565static void GenerateCallFunction(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000566 Handle<Object> object,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000567 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000568 Label* miss,
569 Code::ExtraICState extra_ic_state) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000570 // ----------- S t a t e -------------
571 // -- a0: receiver
572 // -- a1: function to call
573 // -----------------------------------
574 // Check that the function really is a function.
575 __ JumpIfSmi(a1, miss);
576 __ GetObjectType(a1, a3, a3);
577 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
578
579 // Patch the receiver on the stack with the global proxy if
580 // necessary.
581 if (object->IsGlobalObject()) {
582 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
583 __ sw(a3, MemOperand(sp, arguments.immediate() * kPointerSize));
584 }
585
586 // Invoke the function.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000587 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
588 ? CALL_AS_FUNCTION
589 : CALL_AS_METHOD;
590 __ InvokeFunction(a1, arguments, JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000591}
592
593
594static void PushInterceptorArguments(MacroAssembler* masm,
595 Register receiver,
596 Register holder,
597 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000598 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000599 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000600 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
601 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000602 Register scratch = name;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000603 __ li(scratch, Operand(interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000604 __ Push(scratch, receiver, holder);
605 __ lw(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
606 __ push(scratch);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000607 __ li(scratch, Operand(ExternalReference::isolate_address()));
608 __ push(scratch);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000609}
610
611
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000612static void CompileCallLoadPropertyWithInterceptor(
613 MacroAssembler* masm,
614 Register receiver,
615 Register holder,
616 Register name,
617 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000618 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
619
620 ExternalReference ref =
621 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
622 masm->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000623 __ PrepareCEntryArgs(6);
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000624 __ PrepareCEntryFunction(ref);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000625
626 CEntryStub stub(1);
627 __ CallStub(&stub);
628}
629
630
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000631static const int kFastApiCallArguments = 4;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000632
633
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000634// Reserves space for the extra arguments to API function in the
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000635// caller's frame.
636//
637// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
638static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
639 Register scratch) {
640 ASSERT(Smi::FromInt(0) == 0);
641 for (int i = 0; i < kFastApiCallArguments; i++) {
642 __ push(zero_reg);
643 }
644}
645
646
647// Undoes the effects of ReserveSpaceForFastApiCall.
648static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
649 __ Drop(kFastApiCallArguments);
650}
651
652
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000653static void GenerateFastApiDirectCall(MacroAssembler* masm,
654 const CallOptimization& optimization,
655 int argc) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000656 // ----------- S t a t e -------------
657 // -- sp[0] : holder (set by CheckPrototypes)
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000658 // -- sp[4] : callee JS function
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000659 // -- sp[8] : call data
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000660 // -- sp[12] : isolate
661 // -- sp[16] : last JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000662 // -- ...
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000663 // -- sp[(argc + 3) * 4] : first JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000664 // -- sp[(argc + 4) * 4] : receiver
665 // -----------------------------------
666 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000667 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000668 __ LoadHeapObject(t1, function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000669 __ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset));
670
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000671 // Pass the additional arguments.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000672 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000673 Handle<Object> call_data(api_call_info->data(), masm->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000674 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
675 __ li(a0, api_call_info);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000676 __ lw(t2, FieldMemOperand(a0, CallHandlerInfo::kDataOffset));
677 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000678 __ li(t2, call_data);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000679 }
680
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000681 __ li(t3, Operand(ExternalReference::isolate_address()));
682 // Store JS function, call data and isolate.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000683 __ sw(t1, MemOperand(sp, 1 * kPointerSize));
684 __ sw(t2, MemOperand(sp, 2 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000685 __ sw(t3, MemOperand(sp, 3 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000686
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000687 // Prepare arguments.
688 __ Addu(a2, sp, Operand(3 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000689
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000690 // Allocate the v8::Arguments structure in the arguments' space since
691 // it's not controlled by GC.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000692 const int kApiStackSpace = 4;
693
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000694 FrameScope frame_scope(masm, StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000695 __ EnterExitFrame(false, kApiStackSpace);
696
697 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
698 // struct from the function (which is currently the case). This means we pass
699 // the first argument in a1 instead of a0. TryCallApiFunctionAndReturn
700 // will handle setting up a0.
701
702 // a1 = v8::Arguments&
703 // Arguments is built at sp + 1 (sp is a reserved spot for ra).
704 __ Addu(a1, sp, kPointerSize);
705
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000706 // v8::Arguments::implicit_args_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000707 __ sw(a2, MemOperand(a1, 0 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000708 // v8::Arguments::values_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000709 __ Addu(t0, a2, Operand(argc * kPointerSize));
710 __ sw(t0, MemOperand(a1, 1 * kPointerSize));
711 // v8::Arguments::length_ = argc
712 __ li(t0, Operand(argc));
713 __ sw(t0, MemOperand(a1, 2 * kPointerSize));
714 // v8::Arguments::is_construct_call = 0
715 __ sw(zero_reg, MemOperand(a1, 3 * kPointerSize));
716
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000717 const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000718 Address function_address = v8::ToCData<Address>(api_call_info->callback());
719 ApiFunction fun(function_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000720 ExternalReference ref =
721 ExternalReference(&fun,
722 ExternalReference::DIRECT_API_CALL,
723 masm->isolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000724 AllowExternalCallThatCantCauseGC scope(masm);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000725 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000726}
727
lrn@chromium.org7516f052011-03-30 08:52:27 +0000728class CallInterceptorCompiler BASE_EMBEDDED {
729 public:
730 CallInterceptorCompiler(StubCompiler* stub_compiler,
731 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000732 Register name,
733 Code::ExtraICState extra_ic_state)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000734 : stub_compiler_(stub_compiler),
735 arguments_(arguments),
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000736 name_(name),
737 extra_ic_state_(extra_ic_state) {}
lrn@chromium.org7516f052011-03-30 08:52:27 +0000738
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000739 void Compile(MacroAssembler* masm,
740 Handle<JSObject> object,
741 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000742 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000743 LookupResult* lookup,
744 Register receiver,
745 Register scratch1,
746 Register scratch2,
747 Register scratch3,
748 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000749 ASSERT(holder->HasNamedInterceptor());
750 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
751
752 // Check that the receiver isn't a smi.
753 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000754 CallOptimization optimization(lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000755 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000756 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
757 holder, lookup, name, optimization, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000758 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000759 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
760 name, holder, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000761 }
762 }
763
764 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000765 void CompileCacheable(MacroAssembler* masm,
766 Handle<JSObject> object,
767 Register receiver,
768 Register scratch1,
769 Register scratch2,
770 Register scratch3,
771 Handle<JSObject> interceptor_holder,
772 LookupResult* lookup,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000773 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000774 const CallOptimization& optimization,
775 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000776 ASSERT(optimization.is_constant_call());
777 ASSERT(!lookup->holder()->IsGlobalObject());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000778 Counters* counters = masm->isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000779 int depth1 = kInvalidProtoDepth;
780 int depth2 = kInvalidProtoDepth;
781 bool can_do_fast_api_call = false;
782 if (optimization.is_simple_api_call() &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000783 !lookup->holder()->IsGlobalObject()) {
784 depth1 = optimization.GetPrototypeDepthOfExpectedType(
785 object, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000786 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000787 depth2 = optimization.GetPrototypeDepthOfExpectedType(
788 interceptor_holder, Handle<JSObject>(lookup->holder()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000789 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000790 can_do_fast_api_call =
791 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000792 }
793
794 __ IncrementCounter(counters->call_const_interceptor(), 1,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000795 scratch1, scratch2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000796
797 if (can_do_fast_api_call) {
798 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
799 scratch1, scratch2);
800 ReserveSpaceForFastApiCall(masm, scratch1);
801 }
802
803 // Check that the maps from receiver to interceptor's holder
804 // haven't changed and thus we can invoke interceptor.
805 Label miss_cleanup;
806 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
807 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000808 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
809 scratch1, scratch2, scratch3,
810 name, depth1, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000811
812 // Invoke an interceptor and if it provides a value,
813 // branch to |regular_invoke|.
814 Label regular_invoke;
815 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
816 &regular_invoke);
817
818 // Interceptor returned nothing for this property. Try to use cached
819 // constant function.
820
821 // Check that the maps from interceptor's holder to constant function's
822 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000823 if (*interceptor_holder != lookup->holder()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000824 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000825 Handle<JSObject>(lookup->holder()),
826 scratch1, scratch2, scratch3,
827 name, depth2, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000828 } else {
829 // CheckPrototypes has a side effect of fetching a 'holder'
830 // for API (object which is instanceof for the signature). It's
831 // safe to omit it here, as if present, it should be fetched
832 // by the previous CheckPrototypes.
833 ASSERT(depth2 == kInvalidProtoDepth);
834 }
835
836 // Invoke function.
837 if (can_do_fast_api_call) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000838 GenerateFastApiDirectCall(masm, optimization, arguments_.immediate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000839 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000840 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
841 ? CALL_AS_FUNCTION
842 : CALL_AS_METHOD;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000843 __ InvokeFunction(optimization.constant_function(), arguments_,
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000844 JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000845 }
846
847 // Deferred code for fast API call case---clean preallocated space.
848 if (can_do_fast_api_call) {
849 __ bind(&miss_cleanup);
850 FreeSpaceForFastApiCall(masm);
851 __ Branch(miss_label);
852 }
853
854 // Invoke a regular function.
855 __ bind(&regular_invoke);
856 if (can_do_fast_api_call) {
857 FreeSpaceForFastApiCall(masm);
858 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000859 }
860
861 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000862 Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000863 Register receiver,
864 Register scratch1,
865 Register scratch2,
866 Register scratch3,
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000867 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000868 Handle<JSObject> interceptor_holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000869 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000870 Register holder =
871 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000872 scratch1, scratch2, scratch3,
873 name, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000874
875 // Call a runtime function to load the interceptor property.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000876 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000877 // Save the name_ register across the call.
878 __ push(name_);
879
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000880 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000881
882 __ CallExternalReference(
883 ExternalReference(
884 IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
885 masm->isolate()),
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000886 6);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000887 // Restore the name_ register.
888 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000889 // Leave the internal frame.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000890 }
891
892 void LoadWithInterceptor(MacroAssembler* masm,
893 Register receiver,
894 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000895 Handle<JSObject> holder_obj,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000896 Register scratch,
897 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000898 {
899 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000900
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000901 __ Push(holder, name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000902 CompileCallLoadPropertyWithInterceptor(masm,
903 receiver,
904 holder,
905 name_,
906 holder_obj);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000907 __ pop(name_); // Restore the name.
908 __ pop(receiver); // Restore the holder.
909 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000910 // If interceptor returns no-result sentinel, call the constant function.
911 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
912 __ Branch(interceptor_succeeded, ne, v0, Operand(scratch));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000913 }
914
915 StubCompiler* stub_compiler_;
916 const ParameterCount& arguments_;
917 Register name_;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000918 Code::ExtraICState extra_ic_state_;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000919};
920
921
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000922
923// Generate code to check that a global property cell is empty. Create
924// the property cell at compilation time if no cell exists for the
925// property.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000926static void GenerateCheckPropertyCell(MacroAssembler* masm,
927 Handle<GlobalObject> global,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000928 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000929 Register scratch,
930 Label* miss) {
931 Handle<JSGlobalPropertyCell> cell =
932 GlobalObject::EnsurePropertyCell(global, name);
933 ASSERT(cell->value()->IsTheHole());
934 __ li(scratch, Operand(cell));
935 __ lw(scratch,
936 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
937 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
938 __ Branch(miss, ne, scratch, Operand(at));
939}
940
941
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000942// Calls GenerateCheckPropertyCell for each global object in the prototype chain
943// from object to (but not including) holder.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000944static void GenerateCheckPropertyCells(MacroAssembler* masm,
945 Handle<JSObject> object,
946 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000947 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000948 Register scratch,
949 Label* miss) {
950 Handle<JSObject> current = object;
951 while (!current.is_identical_to(holder)) {
952 if (current->IsGlobalObject()) {
953 GenerateCheckPropertyCell(masm,
954 Handle<GlobalObject>::cast(current),
955 name,
956 scratch,
957 miss);
958 }
959 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
960 }
961}
962
963
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000964// Convert and store int passed in register ival to IEEE 754 single precision
965// floating point value at memory location (dst + 4 * wordoffset)
966// If FPU is available use it for conversion.
967static void StoreIntAsFloat(MacroAssembler* masm,
968 Register dst,
969 Register wordoffset,
970 Register ival,
971 Register fval,
972 Register scratch1,
973 Register scratch2) {
974 if (CpuFeatures::IsSupported(FPU)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000975 CpuFeatureScope scope(masm, FPU);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000976 __ mtc1(ival, f0);
977 __ cvt_s_w(f0, f0);
978 __ sll(scratch1, wordoffset, 2);
979 __ addu(scratch1, dst, scratch1);
980 __ swc1(f0, MemOperand(scratch1, 0));
981 } else {
982 // FPU is not available, do manual conversions.
983
984 Label not_special, done;
985 // Move sign bit from source to destination. This works because the sign
986 // bit in the exponent word of the double has the same position and polarity
987 // as the 2's complement sign bit in a Smi.
988 ASSERT(kBinary32SignMask == 0x80000000u);
989
990 __ And(fval, ival, Operand(kBinary32SignMask));
991 // Negate value if it is negative.
992 __ subu(scratch1, zero_reg, ival);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +0000993 __ Movn(ival, scratch1, fval);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000994
995 // We have -1, 0 or 1, which we treat specially. Register ival contains
996 // absolute value: it is either equal to 1 (special case of -1 and 1),
997 // greater than 1 (not a special case) or less than 1 (special case of 0).
998 __ Branch(&not_special, gt, ival, Operand(1));
999
1000 // For 1 or -1 we need to or in the 0 exponent (biased).
1001 static const uint32_t exponent_word_for_1 =
1002 kBinary32ExponentBias << kBinary32ExponentShift;
1003
1004 __ Xor(scratch1, ival, Operand(1));
1005 __ li(scratch2, exponent_word_for_1);
1006 __ or_(scratch2, fval, scratch2);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001007 __ Movz(fval, scratch2, scratch1); // Only if ival is equal to 1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001008 __ Branch(&done);
1009
1010 __ bind(&not_special);
1011 // Count leading zeros.
1012 // Gets the wrong answer for 0, but we already checked for that case above.
1013 Register zeros = scratch2;
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001014 __ Clz(zeros, ival);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001015
1016 // Compute exponent and or it into the exponent register.
1017 __ li(scratch1, (kBitsPerInt - 1) + kBinary32ExponentBias);
1018 __ subu(scratch1, scratch1, zeros);
1019
1020 __ sll(scratch1, scratch1, kBinary32ExponentShift);
1021 __ or_(fval, fval, scratch1);
1022
1023 // Shift up the source chopping the top bit off.
1024 __ Addu(zeros, zeros, Operand(1));
1025 // This wouldn't work for 1 and -1 as the shift would be 32 which means 0.
1026 __ sllv(ival, ival, zeros);
1027 // And the top (top 20 bits).
1028 __ srl(scratch1, ival, kBitsPerInt - kBinary32MantissaBits);
1029 __ or_(fval, fval, scratch1);
1030
1031 __ bind(&done);
1032
1033 __ sll(scratch1, wordoffset, 2);
1034 __ addu(scratch1, dst, scratch1);
1035 __ sw(fval, MemOperand(scratch1, 0));
1036 }
1037}
1038
1039
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001040void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001041 __ Jump(code, RelocInfo::CODE_TARGET);
1042}
1043
1044
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001045#undef __
1046#define __ ACCESS_MASM(masm())
1047
1048
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001049Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
1050 Register object_reg,
1051 Handle<JSObject> holder,
1052 Register holder_reg,
1053 Register scratch1,
1054 Register scratch2,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001055 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001056 int save_at_depth,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001057 Label* miss,
1058 PrototypeCheckType check) {
1059 Handle<JSObject> first = object;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001060 // Make sure there's no overlap between holder and object registers.
1061 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1062 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1063 && !scratch2.is(scratch1));
1064
1065 // Keep track of the current object in register reg.
1066 Register reg = object_reg;
1067 int depth = 0;
1068
1069 if (save_at_depth == depth) {
1070 __ sw(reg, MemOperand(sp));
1071 }
1072
1073 // Check the maps in the prototype chain.
1074 // Traverse the prototype chain from the object and do map checks.
1075 Handle<JSObject> current = object;
1076 while (!current.is_identical_to(holder)) {
1077 ++depth;
1078
1079 // Only global objects and objects that do not require access
1080 // checks are allowed in stubs.
1081 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1082
1083 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
1084 if (!current->HasFastProperties() &&
1085 !current->IsJSGlobalObject() &&
1086 !current->IsJSGlobalProxy()) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001087 if (!name->IsUniqueName()) {
1088 ASSERT(name->IsString());
1089 name = factory()->InternalizeString(Handle<String>::cast(name));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001090 }
1091 ASSERT(current->property_dictionary()->FindEntry(*name) ==
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001092 NameDictionary::kNotFound);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001093
1094 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1095 scratch1, scratch2);
1096
1097 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1098 reg = holder_reg; // From now on the object will be in holder_reg.
1099 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1100 } else {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001101 Register map_reg = scratch1;
1102 if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) {
1103 Handle<Map> current_map(current->map());
1104 // CheckMap implicitly loads the map of |reg| into |map_reg|.
1105 __ CheckMap(reg, map_reg, current_map, miss, DONT_DO_SMI_CHECK,
1106 ALLOW_ELEMENT_TRANSITION_MAPS);
1107 } else {
1108 __ lw(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
1109 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001110 // Check access rights to the global object. This has to happen after
1111 // the map check so that we know that the object is actually a global
1112 // object.
1113 if (current->IsJSGlobalProxy()) {
1114 __ CheckAccessGlobalProxy(reg, scratch2, miss);
1115 }
1116 reg = holder_reg; // From now on the object will be in holder_reg.
1117
1118 if (heap()->InNewSpace(*prototype)) {
1119 // The prototype is in new space; we cannot store a reference to it
1120 // in the code. Load it from the map.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001121 __ lw(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001122 } else {
1123 // The prototype is in old space; load it directly.
1124 __ li(reg, Operand(prototype));
1125 }
1126 }
1127
1128 if (save_at_depth == depth) {
1129 __ sw(reg, MemOperand(sp));
1130 }
1131
1132 // Go to the next object in the prototype chain.
1133 current = prototype;
1134 }
1135
1136 // Log the check depth.
1137 LOG(masm()->isolate(), IntEvent("check-maps-depth", depth + 1));
1138
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001139 if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) {
1140 // Check the holder map.
1141 __ CheckMap(reg, scratch1, Handle<Map>(holder->map()), miss,
1142 DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
1143 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001144
1145 // Perform security check for access to the global object.
1146 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1147 if (holder->IsJSGlobalProxy()) {
1148 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1149 }
1150
1151 // If we've skipped any global objects, it's not enough to verify that
1152 // their maps haven't changed. We also need to check that the property
1153 // cell for the property is still empty.
1154 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1155
1156 // Return the register containing the holder.
1157 return reg;
1158}
1159
1160
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001161void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success,
1162 Label* miss) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001163 if (!miss->is_unused()) {
1164 __ Branch(success);
1165 __ bind(miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001166 TailCallBuiltin(masm(), MissBuiltin(kind()));
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001167 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001168}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001169
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001170
1171Register BaseLoadStubCompiler::CallbackHandlerFrontend(
1172 Handle<JSObject> object,
1173 Register object_reg,
1174 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001175 Handle<Name> name,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001176 Label* success,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001177 Handle<ExecutableAccessorInfo> callback) {
1178 Label miss;
1179
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001180 Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001181
1182 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
1183 ASSERT(!reg.is(scratch2()));
1184 ASSERT(!reg.is(scratch3()));
1185 ASSERT(!reg.is(scratch4()));
1186
1187 // Load the properties dictionary.
1188 Register dictionary = scratch4();
1189 __ lw(dictionary, FieldMemOperand(reg, JSObject::kPropertiesOffset));
1190
1191 // Probe the dictionary.
1192 Label probe_done;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001193 NameDictionaryLookupStub::GeneratePositiveLookup(masm(),
1194 &miss,
1195 &probe_done,
1196 dictionary,
1197 this->name(),
1198 scratch2(),
1199 scratch3());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001200 __ bind(&probe_done);
1201
1202 // If probing finds an entry in the dictionary, scratch3 contains the
1203 // pointer into the dictionary. Check that the value is the callback.
1204 Register pointer = scratch3();
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001205 const int kElementsStartOffset = NameDictionary::kHeaderSize +
1206 NameDictionary::kElementsStartIndex * kPointerSize;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001207 const int kValueOffset = kElementsStartOffset + kPointerSize;
1208 __ lw(scratch2(), FieldMemOperand(pointer, kValueOffset));
1209 __ Branch(&miss, ne, scratch2(), Operand(callback));
1210 }
1211
1212 HandlerFrontendFooter(success, &miss);
1213 return reg;
1214}
1215
1216
1217void BaseLoadStubCompiler::NonexistentHandlerFrontend(
1218 Handle<JSObject> object,
1219 Handle<JSObject> last,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001220 Handle<Name> name,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001221 Label* success,
1222 Handle<GlobalObject> global) {
1223 Label miss;
1224
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001225 Register reg = HandlerFrontendHeader(object, receiver(), last, name, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001226
1227 // If the last object in the prototype chain is a global object,
1228 // check that the global property cell is empty.
1229 if (!global.is_null()) {
1230 GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
1231 }
1232
1233 if (!last->HasFastProperties()) {
1234 __ lw(scratch2(), FieldMemOperand(reg, HeapObject::kMapOffset));
1235 __ lw(scratch2(), FieldMemOperand(scratch2(), Map::kPrototypeOffset));
1236 __ Branch(&miss, ne, scratch2(),
1237 Operand(isolate()->factory()->null_value()));
1238 }
1239
1240 HandlerFrontendFooter(success, &miss);
1241}
1242
1243
1244void BaseLoadStubCompiler::GenerateLoadField(Register reg,
1245 Handle<JSObject> holder,
1246 PropertyIndex index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001247 GenerateFastPropertyLoad(masm(), v0, reg, holder, index);
1248 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001249}
1250
1251
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001252void BaseLoadStubCompiler::GenerateLoadConstant(Handle<JSFunction> value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001253 // Return the constant value.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001254 __ LoadHeapObject(v0, value);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001255 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001256}
1257
1258
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001259void BaseLoadStubCompiler::GenerateLoadCallback(
1260 Register reg,
1261 Handle<ExecutableAccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001262 // Build AccessorInfo::args_ list on the stack and push property name below
1263 // the exit frame to make GC aware of them and store pointers to them.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001264 __ push(receiver());
1265 __ mov(scratch2(), sp); // scratch2 = AccessorInfo::args_
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001266 if (heap()->InNewSpace(callback->data())) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001267 __ li(scratch3(), callback);
1268 __ lw(scratch3(), FieldMemOperand(scratch3(),
1269 ExecutableAccessorInfo::kDataOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001270 } else {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001271 __ li(scratch3(), Handle<Object>(callback->data(),
1272 callback->GetIsolate()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001273 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001274 __ Subu(sp, sp, 4 * kPointerSize);
1275 __ sw(reg, MemOperand(sp, 3 * kPointerSize));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001276 __ sw(scratch3(), MemOperand(sp, 2 * kPointerSize));
1277 __ li(scratch3(), Operand(ExternalReference::isolate_address()));
1278 __ sw(scratch3(), MemOperand(sp, 1 * kPointerSize));
1279 __ sw(name(), MemOperand(sp, 0 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001280
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001281 __ mov(a2, scratch2()); // Saved in case scratch2 == a1.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001282 __ mov(a1, sp); // a1 (first argument - see note below) = Handle<Name>
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001283
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001284 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
1285 // struct from the function (which is currently the case). This means we pass
1286 // the arguments in a1-a2 instead of a0-a1. TryCallApiFunctionAndReturn
1287 // will handle setting up a0.
1288
1289 const int kApiStackSpace = 1;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001290 FrameScope frame_scope(masm(), StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001291 __ EnterExitFrame(false, kApiStackSpace);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001292
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001293 // Create AccessorInfo instance on the stack above the exit frame with
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001294 // scratch2 (internal::Object** args_) as the data.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001295 __ sw(a2, MemOperand(sp, kPointerSize));
1296 // a2 (second argument - see note above) = AccessorInfo&
1297 __ Addu(a2, sp, kPointerSize);
1298
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001299 const int kStackUnwindSpace = 5;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001300 Address getter_address = v8::ToCData<Address>(callback->getter());
1301 ApiFunction fun(getter_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001302 ExternalReference ref =
1303 ExternalReference(&fun,
1304 ExternalReference::DIRECT_GETTER_CALL,
1305 masm()->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001306 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
ager@chromium.org5c838252010-02-19 08:53:10 +00001307}
1308
1309
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001310void BaseLoadStubCompiler::GenerateLoadInterceptor(
1311 Register holder_reg,
1312 Handle<JSObject> object,
1313 Handle<JSObject> interceptor_holder,
1314 LookupResult* lookup,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001315 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001316 ASSERT(interceptor_holder->HasNamedInterceptor());
1317 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1318
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001319 // So far the most popular follow ups for interceptor loads are FIELD
1320 // and CALLBACKS, so inline only them, other cases may be added
1321 // later.
1322 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001323 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001324 if (lookup->IsField()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001325 compile_followup_inline = true;
1326 } else if (lookup->type() == CALLBACKS &&
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001327 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
1328 ExecutableAccessorInfo* callback =
1329 ExecutableAccessorInfo::cast(lookup->GetCallbackObject());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001330 compile_followup_inline = callback->getter() != NULL &&
1331 callback->IsCompatibleReceiver(*object);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001332 }
1333 }
1334
1335 if (compile_followup_inline) {
1336 // Compile the interceptor call, followed by inline code to load the
1337 // property from further up the prototype chain if the call fails.
1338 // Check that the maps haven't changed.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001339 ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001340
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001341 // Preserve the receiver register explicitly whenever it is different from
1342 // the holder and it is needed should the interceptor return without any
1343 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1344 // the FIELD case might cause a miss during the prototype check.
1345 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001346 bool must_preserve_receiver_reg = !receiver().is(holder_reg) &&
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001347 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1348
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001349 // Save necessary data before invoking an interceptor.
1350 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001351 {
1352 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001353 if (must_preserve_receiver_reg) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001354 __ Push(receiver(), holder_reg, this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001355 } else {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001356 __ Push(holder_reg, this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001357 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001358 // Invoke an interceptor. Note: map checks from receiver to
1359 // interceptor's holder has been compiled before (see a caller
1360 // of this method).
1361 CompileCallLoadPropertyWithInterceptor(masm(),
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001362 receiver(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001363 holder_reg,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001364 this->name(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001365 interceptor_holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001366 // Check if interceptor provided a value for property. If it's
1367 // the case, return immediately.
1368 Label interceptor_failed;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001369 __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
1370 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001371 frame_scope.GenerateLeaveFrame();
1372 __ Ret();
1373
1374 __ bind(&interceptor_failed);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001375 __ pop(this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001376 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001377 if (must_preserve_receiver_reg) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001378 __ pop(receiver());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001379 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001380 // Leave the internal frame.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001381 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001382 GenerateLoadPostInterceptor(holder_reg, interceptor_holder, name, lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001383 } else { // !compile_followup_inline
1384 // Call the runtime system to load the interceptor.
1385 // Check that the maps haven't changed.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001386 PushInterceptorArguments(masm(), receiver(), holder_reg,
1387 this->name(), interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001388
1389 ExternalReference ref = ExternalReference(
1390 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), masm()->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001391 __ TailCallExternalReference(ref, 6, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001392 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001393}
1394
1395
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001396void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001397 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001398 __ Branch(miss, ne, a2, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001399 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001400}
1401
1402
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001403void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1404 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001405 Handle<Name> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001406 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001407 ASSERT(holder->IsGlobalObject());
1408
1409 // Get the number of arguments.
1410 const int argc = arguments().immediate();
1411
1412 // Get the receiver from the stack.
1413 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1414
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001415 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001416 __ JumpIfSmi(a0, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001417 CheckPrototypes(object, a0, holder, a3, a1, t0, name, miss);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001418}
1419
1420
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001421void CallStubCompiler::GenerateLoadFunctionFromCell(
1422 Handle<JSGlobalPropertyCell> cell,
1423 Handle<JSFunction> function,
1424 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001425 // Get the value from the cell.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001426 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001427 __ lw(a1, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
1428
1429 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001430 if (heap()->InNewSpace(*function)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001431 // We can't embed a pointer to a function in new space so we have
1432 // to verify that the shared function info is unchanged. This has
1433 // the nice side effect that multiple closures based on the same
1434 // function can all use this call IC. Before we load through the
1435 // function, we have to verify that it still is a function.
1436 __ JumpIfSmi(a1, miss);
1437 __ GetObjectType(a1, a3, a3);
1438 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
1439
1440 // Check the shared function info. Make sure it hasn't changed.
1441 __ li(a3, Handle<SharedFunctionInfo>(function->shared()));
1442 __ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
1443 __ Branch(miss, ne, t0, Operand(a3));
1444 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001445 __ Branch(miss, ne, a1, Operand(function));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001446 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001447}
1448
1449
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001450void CallStubCompiler::GenerateMissBranch() {
1451 Handle<Code> code =
danno@chromium.org40cb8782011-05-25 07:58:50 +00001452 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1453 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001454 extra_state_);
1455 __ Jump(code, RelocInfo::CODE_TARGET);
1456}
1457
1458
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001459Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1460 Handle<JSObject> holder,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001461 PropertyIndex index,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001462 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001463 // ----------- S t a t e -------------
1464 // -- a2 : name
1465 // -- ra : return address
1466 // -----------------------------------
1467 Label miss;
1468
1469 GenerateNameCheck(name, &miss);
1470
1471 const int argc = arguments().immediate();
1472
1473 // Get the receiver of the function from the stack into a0.
1474 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1475 // Check that the receiver isn't a smi.
1476 __ JumpIfSmi(a0, &miss, t0);
1477
1478 // Do the right check and compute the holder register.
1479 Register reg = CheckPrototypes(object, a0, holder, a1, a3, t0, name, &miss);
1480 GenerateFastPropertyLoad(masm(), a1, reg, holder, index);
1481
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001482 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001483
1484 // Handle call cache miss.
1485 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001486 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001487
1488 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001489 return GetCode(Code::FIELD, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001490}
1491
1492
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001493Handle<Code> CallStubCompiler::CompileArrayPushCall(
1494 Handle<Object> object,
1495 Handle<JSObject> holder,
1496 Handle<JSGlobalPropertyCell> cell,
1497 Handle<JSFunction> function,
1498 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001499 // ----------- S t a t e -------------
1500 // -- a2 : name
1501 // -- ra : return address
1502 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1503 // -- ...
1504 // -- sp[argc * 4] : receiver
1505 // -----------------------------------
1506
1507 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001508 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001509
1510 Label miss;
1511
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001512 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001513
1514 Register receiver = a1;
1515
1516 // Get the receiver from the stack.
1517 const int argc = arguments().immediate();
1518 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1519
1520 // Check that the receiver isn't a smi.
1521 __ JumpIfSmi(receiver, &miss);
1522
1523 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001524 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, a3, v0, t0,
1525 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001526
1527 if (argc == 0) {
1528 // Nothing to do, just return the length.
1529 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1530 __ Drop(argc + 1);
1531 __ Ret();
1532 } else {
1533 Label call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001534 if (argc == 1) { // Otherwise fall through to call the builtin.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001535 Label attempt_to_grow_elements, with_write_barrier, check_double;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001536
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001537 Register elements = t2;
1538 Register end_elements = t1;
1539 // Get the elements array of the object.
1540 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1541
1542 // Check that the elements are in fast mode and writable.
1543 __ CheckMap(elements,
1544 v0,
1545 Heap::kFixedArrayMapRootIndex,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001546 &check_double,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001547 DONT_DO_SMI_CHECK);
1548
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001549 // Get the array's length into v0 and calculate new length.
1550 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1551 STATIC_ASSERT(kSmiTagSize == 1);
1552 STATIC_ASSERT(kSmiTag == 0);
1553 __ Addu(v0, v0, Operand(Smi::FromInt(argc)));
1554
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001555 // Get the elements' length.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001556 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1557
1558 // Check if we could survive without allocation.
1559 __ Branch(&attempt_to_grow_elements, gt, v0, Operand(t0));
1560
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001561 // Check if value is a smi.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001562 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1563 __ JumpIfNotSmi(t0, &with_write_barrier);
1564
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001565 // Save new length.
1566 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1567
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001568 // Store the value.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001569 // We may need a register containing the address end_elements below,
1570 // so write back the value in end_elements.
1571 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1572 __ Addu(end_elements, elements, end_elements);
1573 const int kEndElementsOffset =
1574 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001575 __ Addu(end_elements, end_elements, kEndElementsOffset);
1576 __ sw(t0, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001577
1578 // Check for a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001579 __ Drop(argc + 1);
1580 __ Ret();
1581
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001582 __ bind(&check_double);
1583
1584 // Check that the elements are in fast mode and writable.
1585 __ CheckMap(elements,
1586 a0,
1587 Heap::kFixedDoubleArrayMapRootIndex,
1588 &call_builtin,
1589 DONT_DO_SMI_CHECK);
1590
1591 // Get the array's length into r0 and calculate new length.
1592 __ lw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1593 STATIC_ASSERT(kSmiTagSize == 1);
1594 STATIC_ASSERT(kSmiTag == 0);
1595 __ Addu(a0, a0, Operand(Smi::FromInt(argc)));
1596
1597 // Get the elements' length.
1598 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1599
1600 // Check if we could survive without allocation.
1601 __ Branch(&call_builtin, gt, a0, Operand(t0));
1602
1603 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1604 __ StoreNumberToDoubleElements(
1605 t0, a0, elements, a3, t1, a2, t5,
1606 &call_builtin, argc * kDoubleSize);
1607
1608 // Save new length.
1609 __ sw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1610
1611 // Check for a smi.
1612 __ Drop(argc + 1);
1613 __ Ret();
1614
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001615 __ bind(&with_write_barrier);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001616
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001617 __ lw(a3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1618
1619 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
1620 Label fast_object, not_fast_object;
1621 __ CheckFastObjectElements(a3, t3, &not_fast_object);
1622 __ jmp(&fast_object);
1623 // In case of fast smi-only, convert to fast object, otherwise bail out.
1624 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001625 __ CheckFastSmiElements(a3, t3, &call_builtin);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001626
1627 __ lw(t3, FieldMemOperand(t0, HeapObject::kMapOffset));
1628 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
1629 __ Branch(&call_builtin, eq, t3, Operand(at));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001630 // edx: receiver
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001631 // a3: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001632 Label try_holey_map;
1633 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001634 FAST_ELEMENTS,
1635 a3,
1636 t3,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001637 &try_holey_map);
1638 __ mov(a2, receiver);
1639 ElementsTransitionGenerator::
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001640 GenerateMapChangeElementsTransition(masm(),
1641 DONT_TRACK_ALLOCATION_SITE,
1642 NULL);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001643 __ jmp(&fast_object);
1644
1645 __ bind(&try_holey_map);
1646 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1647 FAST_HOLEY_ELEMENTS,
1648 a3,
1649 t3,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001650 &call_builtin);
1651 __ mov(a2, receiver);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001652 ElementsTransitionGenerator::
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001653 GenerateMapChangeElementsTransition(masm(),
1654 DONT_TRACK_ALLOCATION_SITE,
1655 NULL);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001656 __ bind(&fast_object);
1657 } else {
1658 __ CheckFastObjectElements(a3, a3, &call_builtin);
1659 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001660
1661 // Save new length.
1662 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1663
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001664 // Store the value.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001665 // We may need a register containing the address end_elements below,
1666 // so write back the value in end_elements.
1667 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1668 __ Addu(end_elements, elements, end_elements);
1669 __ Addu(end_elements, end_elements, kEndElementsOffset);
1670 __ sw(t0, MemOperand(end_elements));
1671
1672 __ RecordWrite(elements,
1673 end_elements,
1674 t0,
1675 kRAHasNotBeenSaved,
1676 kDontSaveFPRegs,
1677 EMIT_REMEMBERED_SET,
1678 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001679 __ Drop(argc + 1);
1680 __ Ret();
1681
1682 __ bind(&attempt_to_grow_elements);
1683 // v0: array's length + 1.
1684 // t0: elements' length.
1685
1686 if (!FLAG_inline_new) {
1687 __ Branch(&call_builtin);
1688 }
1689
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001690 __ lw(a2, MemOperand(sp, (argc - 1) * kPointerSize));
1691 // Growing elements that are SMI-only requires special handling in case
1692 // the new element is non-Smi. For now, delegate to the builtin.
1693 Label no_fast_elements_check;
1694 __ JumpIfSmi(a2, &no_fast_elements_check);
1695 __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1696 __ CheckFastObjectElements(t3, t3, &call_builtin);
1697 __ bind(&no_fast_elements_check);
1698
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001699 ExternalReference new_space_allocation_top =
1700 ExternalReference::new_space_allocation_top_address(
1701 masm()->isolate());
1702 ExternalReference new_space_allocation_limit =
1703 ExternalReference::new_space_allocation_limit_address(
1704 masm()->isolate());
1705
1706 const int kAllocationDelta = 4;
1707 // Load top and check if it is the end of elements.
1708 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1709 __ Addu(end_elements, elements, end_elements);
1710 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset));
1711 __ li(t3, Operand(new_space_allocation_top));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001712 __ lw(a3, MemOperand(t3));
1713 __ Branch(&call_builtin, ne, end_elements, Operand(a3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001714
1715 __ li(t5, Operand(new_space_allocation_limit));
1716 __ lw(t5, MemOperand(t5));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001717 __ Addu(a3, a3, Operand(kAllocationDelta * kPointerSize));
1718 __ Branch(&call_builtin, hi, a3, Operand(t5));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001719
1720 // We fit and could grow elements.
1721 // Update new_space_allocation_top.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001722 __ sw(a3, MemOperand(t3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001723 // Push the argument.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001724 __ sw(a2, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001725 // Fill the rest with holes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001726 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001727 for (int i = 1; i < kAllocationDelta; i++) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001728 __ sw(a3, MemOperand(end_elements, i * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001729 }
1730
1731 // Update elements' and array's sizes.
1732 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1733 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta)));
1734 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1735
1736 // Elements are in new space, so write barrier is not required.
1737 __ Drop(argc + 1);
1738 __ Ret();
1739 }
1740 __ bind(&call_builtin);
1741 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
1742 masm()->isolate()),
1743 argc + 1,
1744 1);
1745 }
1746
1747 // Handle call cache miss.
1748 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001749 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001750
1751 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001752 return GetCode(function);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001753}
1754
1755
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001756Handle<Code> CallStubCompiler::CompileArrayPopCall(
1757 Handle<Object> object,
1758 Handle<JSObject> holder,
1759 Handle<JSGlobalPropertyCell> cell,
1760 Handle<JSFunction> function,
1761 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001762 // ----------- S t a t e -------------
1763 // -- a2 : name
1764 // -- ra : return address
1765 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1766 // -- ...
1767 // -- sp[argc * 4] : receiver
1768 // -----------------------------------
1769
1770 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001771 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001772
1773 Label miss, return_undefined, call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001774 Register receiver = a1;
1775 Register elements = a3;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001776 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001777
1778 // Get the receiver from the stack.
1779 const int argc = arguments().immediate();
1780 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001781 // Check that the receiver isn't a smi.
1782 __ JumpIfSmi(receiver, &miss);
1783
1784 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001785 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, elements,
1786 t0, v0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001787
1788 // Get the elements array of the object.
1789 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1790
1791 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001792 __ CheckMap(elements,
1793 v0,
1794 Heap::kFixedArrayMapRootIndex,
1795 &call_builtin,
1796 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001797
1798 // Get the array's length into t0 and calculate new length.
1799 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1800 __ Subu(t0, t0, Operand(Smi::FromInt(1)));
1801 __ Branch(&return_undefined, lt, t0, Operand(zero_reg));
1802
1803 // Get the last element.
1804 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1805 STATIC_ASSERT(kSmiTagSize == 1);
1806 STATIC_ASSERT(kSmiTag == 0);
1807 // We can't address the last element in one operation. Compute the more
1808 // expensive shift first, and use an offset later on.
1809 __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize);
1810 __ Addu(elements, elements, t1);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001811 __ lw(v0, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001812 __ Branch(&call_builtin, eq, v0, Operand(t2));
1813
1814 // Set the array's length.
1815 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1816
1817 // Fill with the hole.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001818 __ sw(t2, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001819 __ Drop(argc + 1);
1820 __ Ret();
1821
1822 __ bind(&return_undefined);
1823 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
1824 __ Drop(argc + 1);
1825 __ Ret();
1826
1827 __ bind(&call_builtin);
1828 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop,
1829 masm()->isolate()),
1830 argc + 1,
1831 1);
1832
1833 // Handle call cache miss.
1834 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001835 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001836
1837 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001838 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001839}
1840
1841
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001842Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1843 Handle<Object> object,
1844 Handle<JSObject> holder,
1845 Handle<JSGlobalPropertyCell> cell,
1846 Handle<JSFunction> function,
1847 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001848 // ----------- S t a t e -------------
1849 // -- a2 : function name
1850 // -- ra : return address
1851 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1852 // -- ...
1853 // -- sp[argc * 4] : receiver
1854 // -----------------------------------
1855
1856 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001857 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001858
1859 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001860 Label miss;
1861 Label name_miss;
1862 Label index_out_of_range;
1863
1864 Label* index_out_of_range_label = &index_out_of_range;
1865
danno@chromium.org40cb8782011-05-25 07:58:50 +00001866 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001867 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001868 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001869 index_out_of_range_label = &miss;
1870 }
1871
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001872 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001873
1874 // Check that the maps starting from the prototype haven't changed.
1875 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1876 Context::STRING_FUNCTION_INDEX,
1877 v0,
1878 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001879 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001880 CheckPrototypes(
1881 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
1882 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001883
1884 Register receiver = a1;
1885 Register index = t1;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001886 Register result = v0;
1887 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1888 if (argc > 0) {
1889 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1890 } else {
1891 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1892 }
1893
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001894 StringCharCodeAtGenerator generator(receiver,
1895 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001896 result,
1897 &miss, // When not a string.
1898 &miss, // When not a number.
1899 index_out_of_range_label,
1900 STRING_INDEX_IS_NUMBER);
1901 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001902 __ Drop(argc + 1);
1903 __ Ret();
1904
1905 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001906 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001907
1908 if (index_out_of_range.is_linked()) {
1909 __ bind(&index_out_of_range);
1910 __ LoadRoot(v0, Heap::kNanValueRootIndex);
1911 __ Drop(argc + 1);
1912 __ Ret();
1913 }
1914
1915 __ bind(&miss);
1916 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001917 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001918 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001919 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001920
1921 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001922 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001923}
1924
1925
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001926Handle<Code> CallStubCompiler::CompileStringCharAtCall(
1927 Handle<Object> object,
1928 Handle<JSObject> holder,
1929 Handle<JSGlobalPropertyCell> cell,
1930 Handle<JSFunction> function,
1931 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001932 // ----------- S t a t e -------------
1933 // -- a2 : function name
1934 // -- ra : return address
1935 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1936 // -- ...
1937 // -- sp[argc * 4] : receiver
1938 // -----------------------------------
1939
1940 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001941 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001942
1943 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001944 Label miss;
1945 Label name_miss;
1946 Label index_out_of_range;
1947 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00001948 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001949 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001950 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001951 index_out_of_range_label = &miss;
1952 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001953 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001954
1955 // Check that the maps starting from the prototype haven't changed.
1956 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1957 Context::STRING_FUNCTION_INDEX,
1958 v0,
1959 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001960 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001961 CheckPrototypes(
1962 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
1963 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001964
1965 Register receiver = v0;
1966 Register index = t1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001967 Register scratch = a3;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001968 Register result = v0;
1969 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1970 if (argc > 0) {
1971 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1972 } else {
1973 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1974 }
1975
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001976 StringCharAtGenerator generator(receiver,
1977 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00001978 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001979 result,
1980 &miss, // When not a string.
1981 &miss, // When not a number.
1982 index_out_of_range_label,
1983 STRING_INDEX_IS_NUMBER);
1984 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001985 __ Drop(argc + 1);
1986 __ Ret();
1987
1988 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001989 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001990
1991 if (index_out_of_range.is_linked()) {
1992 __ bind(&index_out_of_range);
ulan@chromium.org750145a2013-03-07 15:14:13 +00001993 __ LoadRoot(v0, Heap::kempty_stringRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001994 __ Drop(argc + 1);
1995 __ Ret();
1996 }
1997
1998 __ bind(&miss);
1999 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002000 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002001 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002002 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002003
2004 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002005 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002006}
2007
2008
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002009Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
2010 Handle<Object> object,
2011 Handle<JSObject> holder,
2012 Handle<JSGlobalPropertyCell> cell,
2013 Handle<JSFunction> function,
2014 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002015 // ----------- S t a t e -------------
2016 // -- a2 : function name
2017 // -- ra : return address
2018 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2019 // -- ...
2020 // -- sp[argc * 4] : receiver
2021 // -----------------------------------
2022
2023 const int argc = arguments().immediate();
2024
2025 // If the object is not a JSObject or we got an unexpected number of
2026 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002027 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002028
2029 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002030 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002031
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002032 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002033 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
2034
2035 STATIC_ASSERT(kSmiTag == 0);
2036 __ JumpIfSmi(a1, &miss);
2037
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002038 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2039 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002040 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002041 ASSERT(cell->value() == *function);
2042 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2043 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002044 GenerateLoadFunctionFromCell(cell, function, &miss);
2045 }
2046
2047 // Load the char code argument.
2048 Register code = a1;
2049 __ lw(code, MemOperand(sp, 0 * kPointerSize));
2050
2051 // Check the code is a smi.
2052 Label slow;
2053 STATIC_ASSERT(kSmiTag == 0);
2054 __ JumpIfNotSmi(code, &slow);
2055
2056 // Convert the smi code to uint16.
2057 __ And(code, code, Operand(Smi::FromInt(0xffff)));
2058
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002059 StringCharFromCodeGenerator generator(code, v0);
2060 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002061 __ Drop(argc + 1);
2062 __ Ret();
2063
2064 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002065 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002066
2067 // Tail call the full function. We do not have to patch the receiver
2068 // because the function makes no use of it.
2069 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002070 __ InvokeFunction(
2071 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002072
2073 __ bind(&miss);
2074 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002075 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002076
2077 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002078 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002079}
2080
2081
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002082Handle<Code> CallStubCompiler::CompileMathFloorCall(
2083 Handle<Object> object,
2084 Handle<JSObject> holder,
2085 Handle<JSGlobalPropertyCell> cell,
2086 Handle<JSFunction> function,
2087 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002088 // ----------- S t a t e -------------
2089 // -- a2 : function name
2090 // -- ra : return address
2091 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2092 // -- ...
2093 // -- sp[argc * 4] : receiver
2094 // -----------------------------------
2095
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002096 if (!CpuFeatures::IsSupported(FPU)) {
2097 return Handle<Code>::null();
2098 }
2099
ulan@chromium.org750145a2013-03-07 15:14:13 +00002100 CpuFeatureScope scope_fpu(masm(), FPU);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002101 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002102 // If the object is not a JSObject or we got an unexpected number of
2103 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002104 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002105
2106 Label miss, slow;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002107 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002108
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002109 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002110 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002111 STATIC_ASSERT(kSmiTag == 0);
2112 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002113 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2114 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002115 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002116 ASSERT(cell->value() == *function);
2117 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2118 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002119 GenerateLoadFunctionFromCell(cell, function, &miss);
2120 }
2121
2122 // Load the (only) argument into v0.
2123 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2124
2125 // If the argument is a smi, just return.
2126 STATIC_ASSERT(kSmiTag == 0);
2127 __ And(t0, v0, Operand(kSmiTagMask));
2128 __ Drop(argc + 1, eq, t0, Operand(zero_reg));
2129 __ Ret(eq, t0, Operand(zero_reg));
2130
danno@chromium.org40cb8782011-05-25 07:58:50 +00002131 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002132
2133 Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return;
2134
2135 // If fpu is enabled, we use the floor instruction.
2136
2137 // Load the HeapNumber value.
2138 __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2139
2140 // Backup FCSR.
2141 __ cfc1(a3, FCSR);
2142 // Clearing FCSR clears the exception mask with no side-effects.
2143 __ ctc1(zero_reg, FCSR);
2144 // Convert the argument to an integer.
2145 __ floor_w_d(f0, f0);
2146
2147 // Start checking for special cases.
2148 // Get the argument exponent and clear the sign bit.
2149 __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize));
2150 __ And(t2, t1, Operand(~HeapNumber::kSignMask));
2151 __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord);
2152
2153 // Retrieve FCSR and check for fpu errors.
2154 __ cfc1(t5, FCSR);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002155 __ And(t5, t5, Operand(kFCSRExceptionFlagMask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002156 __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));
2157
2158 // Check for NaN, Infinity, and -Infinity.
2159 // They are invariant through a Math.Floor call, so just
2160 // return the original argument.
2161 __ Subu(t3, t2, Operand(HeapNumber::kExponentMask
2162 >> HeapNumber::kMantissaBitsInTopWord));
2163 __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg));
2164 // We had an overflow or underflow in the conversion. Check if we
2165 // have a big exponent.
2166 // If greater or equal, the argument is already round and in v0.
2167 __ Branch(&restore_fcsr_and_return, ge, t3,
2168 Operand(HeapNumber::kMantissaBits));
2169 __ Branch(&wont_fit_smi);
2170
2171 __ bind(&no_fpu_error);
2172 // Move the result back to v0.
2173 __ mfc1(v0, f0);
2174 // Check if the result fits into a smi.
2175 __ Addu(a1, v0, Operand(0x40000000));
2176 __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg));
2177 // Tag the result.
2178 STATIC_ASSERT(kSmiTag == 0);
2179 __ sll(v0, v0, kSmiTagSize);
2180
2181 // Check for -0.
2182 __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg));
2183 // t1 already holds the HeapNumber exponent.
2184 __ And(t0, t1, Operand(HeapNumber::kSignMask));
2185 // If our HeapNumber is negative it was -0, so load its address and return.
2186 // Else v0 is loaded with 0, so we can also just return.
2187 __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg));
2188 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2189
2190 __ bind(&restore_fcsr_and_return);
2191 // Restore FCSR and return.
2192 __ ctc1(a3, FCSR);
2193
2194 __ Drop(argc + 1);
2195 __ Ret();
2196
2197 __ bind(&wont_fit_smi);
2198 // Restore FCSR and fall to slow case.
2199 __ ctc1(a3, FCSR);
2200
2201 __ bind(&slow);
2202 // Tail call the full function. We do not have to patch the receiver
2203 // because the function makes no use of it.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002204 __ InvokeFunction(
2205 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002206
2207 __ bind(&miss);
2208 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002209 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002210
2211 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002212 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002213}
2214
2215
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002216Handle<Code> CallStubCompiler::CompileMathAbsCall(
2217 Handle<Object> object,
2218 Handle<JSObject> holder,
2219 Handle<JSGlobalPropertyCell> cell,
2220 Handle<JSFunction> function,
2221 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002222 // ----------- S t a t e -------------
2223 // -- a2 : function name
2224 // -- ra : return address
2225 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2226 // -- ...
2227 // -- sp[argc * 4] : receiver
2228 // -----------------------------------
2229
2230 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002231 // If the object is not a JSObject or we got an unexpected number of
2232 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002233 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002234
2235 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002236
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002237 GenerateNameCheck(name, &miss);
2238 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002239 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002240 STATIC_ASSERT(kSmiTag == 0);
2241 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002242 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2243 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002244 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002245 ASSERT(cell->value() == *function);
2246 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2247 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002248 GenerateLoadFunctionFromCell(cell, function, &miss);
2249 }
2250
2251 // Load the (only) argument into v0.
2252 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2253
2254 // Check if the argument is a smi.
2255 Label not_smi;
2256 STATIC_ASSERT(kSmiTag == 0);
2257 __ JumpIfNotSmi(v0, &not_smi);
2258
2259 // Do bitwise not or do nothing depending on the sign of the
2260 // argument.
2261 __ sra(t0, v0, kBitsPerInt - 1);
2262 __ Xor(a1, v0, t0);
2263
2264 // Add 1 or do nothing depending on the sign of the argument.
2265 __ Subu(v0, a1, t0);
2266
2267 // If the result is still negative, go to the slow case.
2268 // This only happens for the most negative smi.
2269 Label slow;
2270 __ Branch(&slow, lt, v0, Operand(zero_reg));
2271
2272 // Smi case done.
2273 __ Drop(argc + 1);
2274 __ Ret();
2275
2276 // Check if the argument is a heap number and load its exponent and
2277 // sign.
2278 __ bind(&not_smi);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002279 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002280 __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2281
2282 // Check the sign of the argument. If the argument is positive,
2283 // just return it.
2284 Label negative_sign;
2285 __ And(t0, a1, Operand(HeapNumber::kSignMask));
2286 __ Branch(&negative_sign, ne, t0, Operand(zero_reg));
2287 __ Drop(argc + 1);
2288 __ Ret();
2289
2290 // If the argument is negative, clear the sign, and return a new
2291 // number.
2292 __ bind(&negative_sign);
2293 __ Xor(a1, a1, Operand(HeapNumber::kSignMask));
2294 __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2295 __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
2296 __ AllocateHeapNumber(v0, t0, t1, t2, &slow);
2297 __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2298 __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2299 __ Drop(argc + 1);
2300 __ Ret();
2301
2302 // Tail call the full function. We do not have to patch the receiver
2303 // because the function makes no use of it.
2304 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002305 __ InvokeFunction(
2306 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002307
2308 __ bind(&miss);
2309 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002310 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002311
2312 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002313 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002314}
2315
2316
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002317Handle<Code> CallStubCompiler::CompileFastApiCall(
lrn@chromium.org7516f052011-03-30 08:52:27 +00002318 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002319 Handle<Object> object,
2320 Handle<JSObject> holder,
2321 Handle<JSGlobalPropertyCell> cell,
2322 Handle<JSFunction> function,
2323 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002324
danno@chromium.org40cb8782011-05-25 07:58:50 +00002325 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002326
2327 ASSERT(optimization.is_simple_api_call());
2328 // Bail out if object is a global object as we don't want to
2329 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002330 if (object->IsGlobalObject()) return Handle<Code>::null();
2331 if (!cell.is_null()) return Handle<Code>::null();
2332 if (!object->IsJSObject()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002333 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002334 Handle<JSObject>::cast(object), holder);
2335 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002336
2337 Label miss, miss_before_stack_reserved;
2338
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002339 GenerateNameCheck(name, &miss_before_stack_reserved);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002340
2341 // Get the receiver from the stack.
2342 const int argc = arguments().immediate();
2343 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2344
2345 // Check that the receiver isn't a smi.
2346 __ JumpIfSmi(a1, &miss_before_stack_reserved);
2347
2348 __ IncrementCounter(counters->call_const(), 1, a0, a3);
2349 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2350
2351 ReserveSpaceForFastApiCall(masm(), a0);
2352
2353 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002354 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002355 depth, &miss);
2356
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002357 GenerateFastApiDirectCall(masm(), optimization, argc);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002358
2359 __ bind(&miss);
2360 FreeSpaceForFastApiCall(masm());
2361
2362 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002363 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002364
2365 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002366 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002367}
2368
2369
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002370void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
2371 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002372 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002373 CheckType check,
2374 Label* success) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002375 // ----------- S t a t e -------------
2376 // -- a2 : name
2377 // -- ra : return address
2378 // -----------------------------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002379 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002380 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002381
2382 // Get the receiver from the stack.
2383 const int argc = arguments().immediate();
2384 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2385
2386 // Check that the receiver isn't a smi.
2387 if (check != NUMBER_CHECK) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002388 __ JumpIfSmi(a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002389 }
2390
2391 // Make sure that it's okay not to patch the on stack receiver
2392 // unless we're doing a receiver map check.
2393 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002394 switch (check) {
2395 case RECEIVER_MAP_CHECK:
2396 __ IncrementCounter(masm()->isolate()->counters()->call_const(),
2397 1, a0, a3);
2398
2399 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002400 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2401 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002402
2403 // Patch the receiver on the stack with the global proxy if
2404 // necessary.
2405 if (object->IsGlobalObject()) {
2406 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2407 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2408 }
2409 break;
2410
2411 case STRING_CHECK:
ulan@chromium.org750145a2013-03-07 15:14:13 +00002412 // Check that the object is a string.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002413 __ GetObjectType(a1, a3, a3);
2414 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2415 // Check that the maps starting from the prototype haven't changed.
2416 GenerateDirectLoadGlobalFunctionPrototype(
2417 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
2418 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002419 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002420 a0, holder, a3, a1, t0, name, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002421 break;
2422
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002423 case SYMBOL_CHECK:
2424 // Check that the object is a symbol.
2425 __ GetObjectType(a1, a1, a3);
2426 __ Branch(&miss, ne, a3, Operand(SYMBOL_TYPE));
2427 break;
2428
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002429 case NUMBER_CHECK: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002430 Label fast;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002431 // Check that the object is a smi or a heap number.
2432 __ JumpIfSmi(a1, &fast);
2433 __ GetObjectType(a1, a0, a0);
2434 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
2435 __ bind(&fast);
2436 // Check that the maps starting from the prototype haven't changed.
2437 GenerateDirectLoadGlobalFunctionPrototype(
2438 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
2439 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002440 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002441 a0, holder, a3, a1, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002442 break;
2443 }
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002444 case BOOLEAN_CHECK: {
2445 Label fast;
2446 // Check that the object is a boolean.
2447 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
2448 __ Branch(&fast, eq, a1, Operand(t0));
2449 __ LoadRoot(t0, Heap::kFalseValueRootIndex);
2450 __ Branch(&miss, ne, a1, Operand(t0));
2451 __ bind(&fast);
2452 // Check that the maps starting from the prototype haven't changed.
2453 GenerateDirectLoadGlobalFunctionPrototype(
2454 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
2455 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002456 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002457 a0, holder, a3, a1, t0, name, &miss);
2458 break;
2459 }
2460 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002461
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002462 __ jmp(success);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002463
2464 // Handle call cache miss.
2465 __ bind(&miss);
2466
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002467 GenerateMissBranch();
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002468}
2469
2470
2471void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) {
2472 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
2473 ? CALL_AS_FUNCTION
2474 : CALL_AS_METHOD;
2475 __ InvokeFunction(
2476 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), call_kind);
2477}
2478
2479
2480Handle<Code> CallStubCompiler::CompileCallConstant(
2481 Handle<Object> object,
2482 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002483 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002484 CheckType check,
2485 Handle<JSFunction> function) {
2486 if (HasCustomCallGenerator(function)) {
2487 Handle<Code> code = CompileCustomCall(object, holder,
2488 Handle<JSGlobalPropertyCell>::null(),
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002489 function, Handle<String>::cast(name));
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002490 // A null handle means bail out to the regular compiler code below.
2491 if (!code.is_null()) return code;
2492 }
2493
2494 Label success;
2495
2496 CompileHandlerFrontend(object, holder, name, check, &success);
2497 __ bind(&success);
2498 CompileHandlerBackend(function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002499
2500 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002501 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002502}
2503
2504
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002505Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2506 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002507 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002508 // ----------- S t a t e -------------
2509 // -- a2 : name
2510 // -- ra : return address
2511 // -----------------------------------
2512
2513 Label miss;
2514
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002515 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002516
2517 // Get the number of arguments.
2518 const int argc = arguments().immediate();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002519 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002520 LookupPostInterceptor(holder, name, &lookup);
2521
2522 // Get the receiver from the stack.
2523 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2524
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002525 CallInterceptorCompiler compiler(this, arguments(), a2, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002526 compiler.Compile(masm(), object, holder, name, &lookup, a1, a3, t0, a0,
2527 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002528
2529 // Move returned value, the function to call, to a1.
2530 __ mov(a1, v0);
2531 // Restore receiver.
2532 __ lw(a0, MemOperand(sp, argc * kPointerSize));
2533
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002534 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002535
2536 // Handle call cache miss.
2537 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002538 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002539
2540 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002541 return GetCode(Code::INTERCEPTOR, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002542}
2543
2544
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002545Handle<Code> CallStubCompiler::CompileCallGlobal(
2546 Handle<JSObject> object,
2547 Handle<GlobalObject> holder,
2548 Handle<JSGlobalPropertyCell> cell,
2549 Handle<JSFunction> function,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002550 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002551 // ----------- S t a t e -------------
2552 // -- a2 : name
2553 // -- ra : return address
2554 // -----------------------------------
2555
2556 if (HasCustomCallGenerator(function)) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002557 Handle<Code> code = CompileCustomCall(
2558 object, holder, cell, function, Handle<String>::cast(name));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002559 // A null handle means bail out to the regular compiler code below.
2560 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002561 }
2562
2563 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002564 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002565
2566 // Get the number of arguments.
2567 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002568 GenerateGlobalReceiverCheck(object, holder, name, &miss);
2569 GenerateLoadFunctionFromCell(cell, function, &miss);
2570
2571 // Patch the receiver on the stack with the global proxy if
2572 // necessary.
2573 if (object->IsGlobalObject()) {
2574 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
2575 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2576 }
2577
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002578 // Set up the context (function already in r1).
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002579 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
2580
2581 // Jump to the cached code (tail call).
2582 Counters* counters = masm()->isolate()->counters();
2583 __ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002584 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002585 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002586 ? CALL_AS_FUNCTION
2587 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002588 // We call indirectly through the code field in the function to
2589 // allow recompilation to take effect without changing any of the
2590 // call sites.
2591 __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
2592 __ InvokeCode(a3, expected, arguments(), JUMP_FUNCTION,
2593 NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002594
2595 // Handle call cache miss.
2596 __ bind(&miss);
2597 __ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002598 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002599
2600 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002601 return GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002602}
2603
2604
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002605Handle<Code> StoreStubCompiler::CompileStoreCallback(
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002606 Handle<Name> name,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002607 Handle<JSObject> receiver,
2608 Handle<JSObject> holder,
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002609 Handle<ExecutableAccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002610 // ----------- S t a t e -------------
2611 // -- a0 : value
2612 // -- a1 : receiver
2613 // -- a2 : name
2614 // -- ra : return address
2615 // -----------------------------------
2616 Label miss;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002617 // Check that the maps haven't changed.
2618 __ JumpIfSmi(a1, &miss, a3);
2619 CheckPrototypes(receiver, a1, holder, a3, t0, t1, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002620
2621 // Stub never generated for non-global objects that require access
2622 // checks.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002623 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002624
2625 __ push(a1); // Receiver.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002626 __ li(a3, Operand(callback)); // Callback info.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002627 __ Push(a3, a2, a0);
2628
2629 // Do tail-call to the runtime system.
2630 ExternalReference store_callback_property =
2631 ExternalReference(IC_Utility(IC::kStoreCallbackProperty),
2632 masm()->isolate());
2633 __ TailCallExternalReference(store_callback_property, 4, 1);
2634
2635 // Handle store cache miss.
2636 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002637 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002638
2639 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002640 return GetICCode(kind(), Code::CALLBACKS, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002641}
2642
2643
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002644#undef __
2645#define __ ACCESS_MASM(masm)
2646
2647
2648void StoreStubCompiler::GenerateStoreViaSetter(
2649 MacroAssembler* masm,
2650 Handle<JSFunction> setter) {
2651 // ----------- S t a t e -------------
2652 // -- a0 : value
2653 // -- a1 : receiver
2654 // -- a2 : name
2655 // -- ra : return address
2656 // -----------------------------------
2657 {
2658 FrameScope scope(masm, StackFrame::INTERNAL);
2659
2660 // Save value register, so we can restore it later.
2661 __ push(a0);
2662
2663 if (!setter.is_null()) {
2664 // Call the JavaScript setter with receiver and value on the stack.
2665 __ push(a1);
2666 __ push(a0);
2667 ParameterCount actual(1);
2668 __ InvokeFunction(setter, actual, CALL_FUNCTION, NullCallWrapper(),
2669 CALL_AS_METHOD);
2670 } else {
2671 // If we generate a global code snippet for deoptimization only, remember
2672 // the place to continue after deoptimization.
2673 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2674 }
2675
2676 // We have to return the passed value, not the return value of the setter.
2677 __ pop(v0);
2678
2679 // Restore context register.
2680 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2681 }
2682 __ Ret();
2683}
2684
2685
2686#undef __
2687#define __ ACCESS_MASM(masm())
2688
2689
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002690Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002691 Handle<Name> name,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002692 Handle<JSObject> receiver,
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002693 Handle<JSObject> holder,
2694 Handle<JSFunction> setter) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002695 // ----------- S t a t e -------------
2696 // -- a0 : value
2697 // -- a1 : receiver
2698 // -- a2 : name
2699 // -- ra : return address
2700 // -----------------------------------
2701 Label miss;
2702
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002703 // Check that the maps haven't changed.
2704 __ JumpIfSmi(a1, &miss);
2705 CheckPrototypes(receiver, a1, holder, a3, t0, t1, name, &miss);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002706
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002707 GenerateStoreViaSetter(masm(), setter);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002708
2709 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002710 TailCallBuiltin(masm(), MissBuiltin(kind()));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002711
2712 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002713 return GetICCode(kind(), Code::CALLBACKS, name);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002714}
2715
2716
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002717Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
2718 Handle<JSObject> receiver,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002719 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002720 // ----------- S t a t e -------------
2721 // -- a0 : value
2722 // -- a1 : receiver
2723 // -- a2 : name
2724 // -- ra : return address
2725 // -----------------------------------
2726 Label miss;
2727
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002728 // Check that the map of the object hasn't changed.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002729 __ CheckMap(a1, a3, Handle<Map>(receiver->map()), &miss,
2730 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002731
2732 // Perform global security token check if needed.
2733 if (receiver->IsJSGlobalProxy()) {
2734 __ CheckAccessGlobalProxy(a1, a3, &miss);
2735 }
2736
2737 // Stub is never generated for non-global objects that require access
2738 // checks.
2739 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2740
2741 __ Push(a1, a2, a0); // Receiver, name, value.
2742
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002743 __ li(a0, Operand(Smi::FromInt(strict_mode())));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002744 __ push(a0); // Strict mode.
2745
2746 // Do tail-call to the runtime system.
2747 ExternalReference store_ic_property =
2748 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty),
2749 masm()->isolate());
2750 __ TailCallExternalReference(store_ic_property, 4, 1);
2751
2752 // Handle store cache miss.
2753 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002754 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002755
2756 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002757 return GetICCode(kind(), Code::INTERCEPTOR, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002758}
2759
2760
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002761Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2762 Handle<GlobalObject> object,
2763 Handle<JSGlobalPropertyCell> cell,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002764 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002765 // ----------- S t a t e -------------
2766 // -- a0 : value
2767 // -- a1 : receiver
2768 // -- a2 : name
2769 // -- ra : return address
2770 // -----------------------------------
2771 Label miss;
2772
2773 // Check that the map of the global has not changed.
2774 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2775 __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map())));
2776
2777 // Check that the value in the cell is not the hole. If it is, this
2778 // cell could have been deleted and reintroducing the global needs
2779 // to update the property details in the property dictionary of the
2780 // global object. We bail out to the runtime system to do that.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002781 __ li(t0, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002782 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
2783 __ lw(t2, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2784 __ Branch(&miss, eq, t1, Operand(t2));
2785
2786 // Store the value in the cell.
2787 __ sw(a0, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2788 __ mov(v0, a0); // Stored value must be returned in v0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002789 // Cells are always rescanned, so no write barrier here.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002790
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002791 Counters* counters = masm()->isolate()->counters();
2792 __ IncrementCounter(counters->named_store_global_inline(), 1, a1, a3);
2793 __ Ret();
2794
2795 // Handle store cache miss.
2796 __ bind(&miss);
2797 __ IncrementCounter(counters->named_store_global_inline_miss(), 1, a1, a3);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002798 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002799
2800 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002801 return GetICCode(kind(), Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002802}
2803
2804
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002805Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
2806 Handle<JSObject> object,
2807 Handle<JSObject> last,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002808 Handle<Name> name,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002809 Handle<GlobalObject> global) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002810 Label success;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002811
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002812 NonexistentHandlerFrontend(object, last, name, &success, global);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002813
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002814 __ bind(&success);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002815 // Return undefined if maps of the full prototype chain is still the same.
2816 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2817 __ Ret();
2818
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002819 // Return the generated code.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002820 return GetCode(kind(), Code::NONEXISTENT, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002821}
2822
2823
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002824Register* LoadStubCompiler::registers() {
2825 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2826 static Register registers[] = { a0, a2, a3, a1, t0, t1 };
2827 return registers;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002828}
2829
2830
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002831Register* KeyedLoadStubCompiler::registers() {
2832 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2833 static Register registers[] = { a1, a0, a2, a3, t0, t1 };
2834 return registers;
2835}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002836
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002837
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002838Register* StoreStubCompiler::registers() {
2839 // receiver, name, value, scratch1, scratch2, scratch3.
2840 static Register registers[] = { a1, a2, a0, a3, t0, t1 };
2841 return registers;
2842}
2843
2844
2845Register* KeyedStoreStubCompiler::registers() {
2846 // receiver, name, value, scratch1, scratch2, scratch3.
2847 static Register registers[] = { a2, a1, a0, a3, t0, t1 };
2848 return registers;
2849}
2850
2851
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002852void KeyedLoadStubCompiler::GenerateNameCheck(Handle<Name> name,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002853 Register name_reg,
2854 Label* miss) {
2855 __ Branch(miss, ne, name_reg, Operand(name));
lrn@chromium.org7516f052011-03-30 08:52:27 +00002856}
2857
2858
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002859void KeyedStoreStubCompiler::GenerateNameCheck(Handle<Name> name,
2860 Register name_reg,
2861 Label* miss) {
2862 __ Branch(miss, ne, name_reg, Operand(name));
2863}
2864
2865
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002866#undef __
2867#define __ ACCESS_MASM(masm)
2868
2869
2870void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
2871 Handle<JSFunction> getter) {
2872 // ----------- S t a t e -------------
2873 // -- a0 : receiver
2874 // -- a2 : name
2875 // -- ra : return address
2876 // -----------------------------------
2877 {
2878 FrameScope scope(masm, StackFrame::INTERNAL);
2879
2880 if (!getter.is_null()) {
2881 // Call the JavaScript getter with the receiver on the stack.
2882 __ push(a0);
2883 ParameterCount actual(0);
2884 __ InvokeFunction(getter, actual, CALL_FUNCTION, NullCallWrapper(),
2885 CALL_AS_METHOD);
2886 } else {
2887 // If we generate a global code snippet for deoptimization only, remember
2888 // the place to continue after deoptimization.
2889 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
2890 }
2891
2892 // Restore context register.
2893 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2894 }
2895 __ Ret();
2896}
2897
2898
2899#undef __
2900#define __ ACCESS_MASM(masm())
2901
2902
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002903Handle<Code> LoadStubCompiler::CompileLoadGlobal(
2904 Handle<JSObject> object,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002905 Handle<GlobalObject> global,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002906 Handle<JSGlobalPropertyCell> cell,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002907 Handle<Name> name,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002908 bool is_dont_delete) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002909 Label success, miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002910
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002911 __ CheckMap(
2912 receiver(), scratch1(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
2913 HandlerFrontendHeader(
2914 object, receiver(), Handle<JSObject>::cast(global), name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002915
2916 // Get the value from the cell.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002917 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002918 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
2919
2920 // Check for deleted property if property can actually be deleted.
2921 if (!is_dont_delete) {
2922 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
2923 __ Branch(&miss, eq, t0, Operand(at));
2924 }
2925
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002926 HandlerFrontendFooter(&success, &miss);
2927 __ bind(&success);
2928
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002929 Counters* counters = masm()->isolate()->counters();
2930 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002931 __ mov(v0, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002932 __ Ret();
2933
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002934 // Return the generated code.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002935 return GetICCode(kind(), Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002936}
2937
2938
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002939Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
2940 Handle<Map> receiver_map) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00002941 // ----------- S t a t e -------------
2942 // -- ra : return address
2943 // -- a0 : key
2944 // -- a1 : receiver
2945 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002946 ElementsKind elements_kind = receiver_map->elements_kind();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002947 if (receiver_map->has_fast_elements() ||
2948 receiver_map->has_external_array_elements()) {
2949 Handle<Code> stub = KeyedLoadFastElementStub(
2950 receiver_map->instance_type() == JS_ARRAY_TYPE,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002951 elements_kind).GetCode(isolate());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002952 __ DispatchMap(a1, a2, receiver_map, stub, DO_SMI_CHECK);
2953 } else {
2954 Handle<Code> stub =
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002955 KeyedLoadDictionaryElementStub().GetCode(isolate());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002956 __ DispatchMap(a1, a2, receiver_map, stub, DO_SMI_CHECK);
2957 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00002958
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002959 TailCallBuiltin(masm(), MissBuiltin(kind()));
danno@chromium.org40cb8782011-05-25 07:58:50 +00002960
2961 // Return the generated code.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002962 return GetICCode(kind(), Code::NORMAL, factory()->empty_string());
danno@chromium.org40cb8782011-05-25 07:58:50 +00002963}
2964
2965
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002966Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002967 MapHandleList* receiver_maps,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002968 CodeHandleList* handlers,
2969 Handle<Name> name,
2970 Code::StubType type,
2971 IcCheckType check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002972 Label miss;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002973
2974 if (check == PROPERTY) {
2975 GenerateNameCheck(name, this->name(), &miss);
2976 }
2977
2978 __ JumpIfSmi(receiver(), &miss);
2979 Register map_reg = scratch1();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002980
danno@chromium.org40cb8782011-05-25 07:58:50 +00002981 int receiver_count = receiver_maps->length();
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002982 __ lw(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00002983 for (int current = 0; current < receiver_count; ++current) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002984 __ Jump(handlers->at(current), RelocInfo::CODE_TARGET,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002985 eq, map_reg, Operand(receiver_maps->at(current)));
danno@chromium.org40cb8782011-05-25 07:58:50 +00002986 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002987
2988 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002989 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002990
2991 // Return the generated code.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002992 InlineCacheState state =
2993 receiver_maps->length() > 1 ? POLYMORPHIC : MONOMORPHIC;
2994 return GetICCode(kind(), type, name, state);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002995}
2996
2997
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002998Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
2999 Handle<Map> receiver_map) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003000 // ----------- S t a t e -------------
3001 // -- a0 : value
3002 // -- a1 : key
3003 // -- a2 : receiver
3004 // -- ra : return address
3005 // -- a3 : scratch
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003006 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003007 ElementsKind elements_kind = receiver_map->elements_kind();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003008 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003009 Handle<Code> stub =
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003010 KeyedStoreElementStub(is_js_array,
3011 elements_kind,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003012 store_mode_).GetCode(isolate());
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003013
3014 __ DispatchMap(a2, a3, receiver_map, stub, DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003015
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003016 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003017
3018 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003019 return GetICCode(kind(), Code::NORMAL, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00003020}
3021
3022
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003023Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
3024 MapHandleList* receiver_maps,
3025 CodeHandleList* handler_stubs,
3026 MapHandleList* transitioned_maps) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003027 // ----------- S t a t e -------------
3028 // -- a0 : value
3029 // -- a1 : key
3030 // -- a2 : receiver
3031 // -- ra : return address
3032 // -- a3 : scratch
3033 // -----------------------------------
3034 Label miss;
3035 __ JumpIfSmi(a2, &miss);
3036
3037 int receiver_count = receiver_maps->length();
3038 __ lw(a3, FieldMemOperand(a2, HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003039 for (int i = 0; i < receiver_count; ++i) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003040 if (transitioned_maps->at(i).is_null()) {
3041 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq,
3042 a3, Operand(receiver_maps->at(i)));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003043 } else {
3044 Label next_map;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003045 __ Branch(&next_map, ne, a3, Operand(receiver_maps->at(i)));
3046 __ li(a3, Operand(transitioned_maps->at(i)));
3047 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003048 __ bind(&next_map);
3049 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003050 }
3051
3052 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003053 TailCallBuiltin(masm(), MissBuiltin(kind()));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003054
3055 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003056 return GetICCode(
3057 kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003058}
3059
3060
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003061Handle<Code> ConstructStubCompiler::CompileConstructStub(
3062 Handle<JSFunction> function) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003063 // a0 : argc
3064 // a1 : constructor
3065 // ra : return address
3066 // [sp] : last argument
3067 Label generic_stub_call;
3068
3069 // Use t7 for holding undefined which is used in several places below.
3070 __ LoadRoot(t7, Heap::kUndefinedValueRootIndex);
3071
3072#ifdef ENABLE_DEBUGGER_SUPPORT
3073 // Check to see whether there are any break points in the function code. If
3074 // there are jump to the generic constructor stub which calls the actual
3075 // code for the function thereby hitting the break points.
3076 __ lw(t5, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3077 __ lw(a2, FieldMemOperand(t5, SharedFunctionInfo::kDebugInfoOffset));
3078 __ Branch(&generic_stub_call, ne, a2, Operand(t7));
3079#endif
3080
3081 // Load the initial map and verify that it is in fact a map.
3082 // a1: constructor function
3083 // t7: undefined
3084 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003085 __ JumpIfSmi(a2, &generic_stub_call);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003086 __ GetObjectType(a2, a3, t0);
3087 __ Branch(&generic_stub_call, ne, t0, Operand(MAP_TYPE));
3088
3089#ifdef DEBUG
3090 // Cannot construct functions this way.
3091 // a0: argc
3092 // a1: constructor function
3093 // a2: initial map
3094 // t7: undefined
3095 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
3096 __ Check(ne, "Function constructed by construct stub.",
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003097 a3, Operand(JS_FUNCTION_TYPE));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003098#endif
3099
3100 // Now allocate the JSObject in new space.
3101 // a0: argc
3102 // a1: constructor function
3103 // a2: initial map
3104 // t7: undefined
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003105 ASSERT(function->has_initial_map());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003106 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003107#ifdef DEBUG
3108 int instance_size = function->initial_map()->instance_size();
3109 __ Check(eq, "Instance size of initial map changed.",
3110 a3, Operand(instance_size >> kPointerSizeLog2));
3111#endif
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003112 __ AllocateInNewSpace(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003113
3114 // Allocated the JSObject, now initialize the fields. Map is set to initial
3115 // map and properties and elements are set to empty fixed array.
3116 // a0: argc
3117 // a1: constructor function
3118 // a2: initial map
3119 // a3: object size (in words)
3120 // t4: JSObject (not tagged)
3121 // t7: undefined
3122 __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex);
3123 __ mov(t5, t4);
3124 __ sw(a2, MemOperand(t5, JSObject::kMapOffset));
3125 __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset));
3126 __ sw(t6, MemOperand(t5, JSObject::kElementsOffset));
3127 __ Addu(t5, t5, Operand(3 * kPointerSize));
3128 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
3129 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
3130 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
3131
3132
3133 // Calculate the location of the first argument. The stack contains only the
3134 // argc arguments.
3135 __ sll(a1, a0, kPointerSizeLog2);
3136 __ Addu(a1, a1, sp);
3137
3138 // Fill all the in-object properties with undefined.
3139 // a0: argc
3140 // a1: first argument
3141 // a3: object size (in words)
3142 // t4: JSObject (not tagged)
3143 // t5: First in-object property of JSObject (not tagged)
3144 // t7: undefined
3145 // Fill the initialized properties with a constant value or a passed argument
3146 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003147 Handle<SharedFunctionInfo> shared(function->shared());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003148 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3149 if (shared->IsThisPropertyAssignmentArgument(i)) {
3150 Label not_passed, next;
3151 // Check if the argument assigned to the property is actually passed.
3152 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3153 __ Branch(&not_passed, less_equal, a0, Operand(arg_number));
3154 // Argument passed - find it on the stack.
3155 __ lw(a2, MemOperand(a1, (arg_number + 1) * -kPointerSize));
3156 __ sw(a2, MemOperand(t5));
3157 __ Addu(t5, t5, kPointerSize);
3158 __ jmp(&next);
3159 __ bind(&not_passed);
3160 // Set the property to undefined.
3161 __ sw(t7, MemOperand(t5));
3162 __ Addu(t5, t5, Operand(kPointerSize));
3163 __ bind(&next);
3164 } else {
3165 // Set the property to the constant value.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003166 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i),
3167 masm()->isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003168 __ li(a2, Operand(constant));
3169 __ sw(a2, MemOperand(t5));
3170 __ Addu(t5, t5, kPointerSize);
3171 }
3172 }
3173
3174 // Fill the unused in-object property fields with undefined.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003175 for (int i = shared->this_property_assignments_count();
3176 i < function->initial_map()->inobject_properties();
3177 i++) {
3178 __ sw(t7, MemOperand(t5));
3179 __ Addu(t5, t5, kPointerSize);
3180 }
3181
3182 // a0: argc
3183 // t4: JSObject (not tagged)
3184 // Move argc to a1 and the JSObject to return to v0 and tag it.
3185 __ mov(a1, a0);
3186 __ mov(v0, t4);
3187 __ Or(v0, v0, Operand(kHeapObjectTag));
3188
3189 // v0: JSObject
3190 // a1: argc
3191 // Remove caller arguments and receiver from the stack and return.
3192 __ sll(t0, a1, kPointerSizeLog2);
3193 __ Addu(sp, sp, t0);
3194 __ Addu(sp, sp, Operand(kPointerSize));
3195 Counters* counters = masm()->isolate()->counters();
3196 __ IncrementCounter(counters->constructed_objects(), 1, a1, a2);
3197 __ IncrementCounter(counters->constructed_objects_stub(), 1, a1, a2);
3198 __ Ret();
3199
3200 // Jump to the generic stub in case the specialized code cannot handle the
3201 // construction.
3202 __ bind(&generic_stub_call);
3203 Handle<Code> generic_construct_stub =
3204 masm()->isolate()->builtins()->JSConstructStubGeneric();
3205 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
3206
3207 // Return the generated code.
3208 return GetCode();
3209}
3210
3211
danno@chromium.org40cb8782011-05-25 07:58:50 +00003212#undef __
3213#define __ ACCESS_MASM(masm)
3214
3215
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003216void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3217 MacroAssembler* masm) {
3218 // ---------- S t a t e --------------
3219 // -- ra : return address
3220 // -- a0 : key
3221 // -- a1 : receiver
3222 // -----------------------------------
3223 Label slow, miss_force_generic;
3224
3225 Register key = a0;
3226 Register receiver = a1;
3227
3228 __ JumpIfNotSmi(key, &miss_force_generic);
3229 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
3230 __ sra(a2, a0, kSmiTagSize);
3231 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
3232 __ Ret();
3233
3234 // Slow case, key and receiver still in a0 and a1.
3235 __ bind(&slow);
3236 __ IncrementCounter(
3237 masm->isolate()->counters()->keyed_load_external_array_slow(),
3238 1, a2, a3);
3239 // Entry registers are intact.
3240 // ---------- S t a t e --------------
3241 // -- ra : return address
3242 // -- a0 : key
3243 // -- a1 : receiver
3244 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003245 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003246
3247 // Miss case, call the runtime.
3248 __ bind(&miss_force_generic);
3249
3250 // ---------- S t a t e --------------
3251 // -- ra : return address
3252 // -- a0 : key
3253 // -- a1 : receiver
3254 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003255 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_MissForceGeneric);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003256}
3257
3258
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003259static bool IsElementTypeSigned(ElementsKind elements_kind) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003260 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003261 case EXTERNAL_BYTE_ELEMENTS:
3262 case EXTERNAL_SHORT_ELEMENTS:
3263 case EXTERNAL_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003264 return true;
3265
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003266 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3267 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3268 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3269 case EXTERNAL_PIXEL_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003270 return false;
3271
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003272 case EXTERNAL_FLOAT_ELEMENTS:
3273 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003274 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003275 case FAST_ELEMENTS:
3276 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003277 case FAST_HOLEY_SMI_ELEMENTS:
3278 case FAST_HOLEY_ELEMENTS:
3279 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003280 case DICTIONARY_ELEMENTS:
3281 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003282 UNREACHABLE();
3283 return false;
3284 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003285 return false;
lrn@chromium.org7516f052011-03-30 08:52:27 +00003286}
3287
3288
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003289static void GenerateSmiKeyCheck(MacroAssembler* masm,
3290 Register key,
3291 Register scratch0,
3292 Register scratch1,
3293 FPURegister double_scratch0,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003294 FPURegister double_scratch1,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003295 Label* fail) {
3296 if (CpuFeatures::IsSupported(FPU)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003297 CpuFeatureScope scope(masm, FPU);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003298 Label key_ok;
3299 // Check for smi or a smi inside a heap number. We convert the heap
3300 // number and check if the conversion is exact and fits into the smi
3301 // range.
3302 __ JumpIfSmi(key, &key_ok);
3303 __ CheckMap(key,
3304 scratch0,
3305 Heap::kHeapNumberMapRootIndex,
3306 fail,
3307 DONT_DO_SMI_CHECK);
3308 __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
3309 __ EmitFPUTruncate(kRoundToZero,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003310 scratch0,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003311 double_scratch0,
3312 at,
3313 double_scratch1,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003314 scratch1,
3315 kCheckForInexactConversion);
3316
3317 __ Branch(fail, ne, scratch1, Operand(zero_reg));
3318
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003319 __ SmiTagCheckOverflow(key, scratch0, scratch1);
3320 __ BranchOnOverflow(fail, scratch1);
3321 __ bind(&key_ok);
3322 } else {
3323 // Check that the key is a smi.
3324 __ JumpIfNotSmi(key, fail);
3325 }
3326}
3327
3328
danno@chromium.org40cb8782011-05-25 07:58:50 +00003329void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3330 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003331 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003332 // ---------- S t a t e --------------
3333 // -- a0 : value
3334 // -- a1 : key
3335 // -- a2 : receiver
3336 // -- ra : return address
3337 // -----------------------------------
3338
danno@chromium.org40cb8782011-05-25 07:58:50 +00003339 Label slow, check_heap_number, miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003340
3341 // Register usage.
3342 Register value = a0;
3343 Register key = a1;
3344 Register receiver = a2;
3345 // a3 mostly holds the elements array or the destination external array.
3346
danno@chromium.org40cb8782011-05-25 07:58:50 +00003347 // This stub is meant to be tail-jumped to, the receiver must already
3348 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003349
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003350 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003351 GenerateSmiKeyCheck(masm, key, t0, t1, f2, f4, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003352
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003353 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3354
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003355 // Check that the index is in range.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003356 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3357 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003358 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003359
3360 // Handle both smis and HeapNumbers in the fast path. Go to the
3361 // runtime for all other kinds of values.
3362 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003363
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003364 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003365 // Double to pixel conversion is only implemented in the runtime for now.
3366 __ JumpIfNotSmi(value, &slow);
3367 } else {
3368 __ JumpIfNotSmi(value, &check_heap_number);
3369 }
3370 __ SmiUntag(t1, value);
3371 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3372
3373 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003374 // t1: value (integer).
3375
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003376 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003377 case EXTERNAL_PIXEL_ELEMENTS: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003378 // Clamp the value to [0..255].
3379 // v0 is used as a scratch register here.
3380 Label done;
3381 __ li(v0, Operand(255));
3382 // Normal branch: nop in delay slot.
3383 __ Branch(&done, gt, t1, Operand(v0));
3384 // Use delay slot in this branch.
3385 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg));
3386 __ mov(v0, zero_reg); // In delay slot.
3387 __ mov(v0, t1); // Value is in range 0..255.
3388 __ bind(&done);
3389 __ mov(t1, v0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003390
3391 __ srl(t8, key, 1);
3392 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003393 __ sb(t1, MemOperand(t8, 0));
3394 }
3395 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003396 case EXTERNAL_BYTE_ELEMENTS:
3397 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003398 __ srl(t8, key, 1);
3399 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003400 __ sb(t1, MemOperand(t8, 0));
3401 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003402 case EXTERNAL_SHORT_ELEMENTS:
3403 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003404 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003405 __ sh(t1, MemOperand(t8, 0));
3406 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003407 case EXTERNAL_INT_ELEMENTS:
3408 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003409 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003410 __ addu(t8, a3, t8);
3411 __ sw(t1, MemOperand(t8, 0));
3412 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003413 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003414 // Perform int-to-float conversion and store to memory.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003415 __ SmiUntag(t0, key);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003416 StoreIntAsFloat(masm, a3, t0, t1, t2, t3, t4);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003417 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003418 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003419 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003420 __ addu(a3, a3, t8);
3421 // a3: effective address of the double element
3422 FloatingPointHelper::Destination destination;
3423 if (CpuFeatures::IsSupported(FPU)) {
3424 destination = FloatingPointHelper::kFPURegisters;
3425 } else {
3426 destination = FloatingPointHelper::kCoreRegisters;
3427 }
3428 FloatingPointHelper::ConvertIntToDouble(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003429 masm, t1, destination,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003430 f0, t2, t3, // These are: double_dst, dst_mantissa, dst_exponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003431 t0, f2); // These are: scratch2, single_scratch.
3432 if (destination == FloatingPointHelper::kFPURegisters) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003433 CpuFeatureScope scope(masm, FPU);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003434 __ sdc1(f0, MemOperand(a3, 0));
3435 } else {
3436 __ sw(t2, MemOperand(a3, 0));
3437 __ sw(t3, MemOperand(a3, Register::kSizeInBytes));
3438 }
3439 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003440 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003441 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003442 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003443 case FAST_HOLEY_ELEMENTS:
3444 case FAST_HOLEY_SMI_ELEMENTS:
3445 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003446 case DICTIONARY_ELEMENTS:
3447 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003448 UNREACHABLE();
3449 break;
3450 }
3451
3452 // Entry registers are intact, a0 holds the value which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003453 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003454 __ Ret();
3455
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003456 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003457 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003458 __ bind(&check_heap_number);
3459 __ GetObjectType(value, t1, t2);
3460 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE));
3461
3462 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3463
3464 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003465
3466 // The WebGL specification leaves the behavior of storing NaN and
3467 // +/-Infinity into integer arrays basically undefined. For more
3468 // reproducible behavior, convert these to zero.
3469
3470 if (CpuFeatures::IsSupported(FPU)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003471 CpuFeatureScope scope(masm, FPU);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003472
3473 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
3474
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003475 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003476 __ cvt_s_d(f0, f0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003477 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003478 __ addu(t8, a3, t8);
3479 __ swc1(f0, MemOperand(t8, 0));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003480 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003481 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003482 __ addu(t8, a3, t8);
3483 __ sdc1(f0, MemOperand(t8, 0));
3484 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003485 __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003486
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003487 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003488 case EXTERNAL_BYTE_ELEMENTS:
3489 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003490 __ srl(t8, key, 1);
3491 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003492 __ sb(t3, MemOperand(t8, 0));
3493 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003494 case EXTERNAL_SHORT_ELEMENTS:
3495 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003496 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003497 __ sh(t3, MemOperand(t8, 0));
3498 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003499 case EXTERNAL_INT_ELEMENTS:
3500 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003501 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003502 __ addu(t8, a3, t8);
3503 __ sw(t3, MemOperand(t8, 0));
3504 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003505 case EXTERNAL_PIXEL_ELEMENTS:
3506 case EXTERNAL_FLOAT_ELEMENTS:
3507 case EXTERNAL_DOUBLE_ELEMENTS:
3508 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003509 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003510 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003511 case FAST_HOLEY_ELEMENTS:
3512 case FAST_HOLEY_SMI_ELEMENTS:
3513 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003514 case DICTIONARY_ELEMENTS:
3515 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003516 UNREACHABLE();
3517 break;
3518 }
3519 }
3520
3521 // Entry registers are intact, a0 holds the value
3522 // which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003523 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003524 __ Ret();
3525 } else {
3526 // FPU is not available, do manual conversions.
3527
3528 __ lw(t3, FieldMemOperand(value, HeapNumber::kExponentOffset));
3529 __ lw(t4, FieldMemOperand(value, HeapNumber::kMantissaOffset));
3530
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003531 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003532 Label done, nan_or_infinity_or_zero;
3533 static const int kMantissaInHiWordShift =
3534 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3535
3536 static const int kMantissaInLoWordShift =
3537 kBitsPerInt - kMantissaInHiWordShift;
3538
3539 // Test for all special exponent values: zeros, subnormal numbers, NaNs
3540 // and infinities. All these should be converted to 0.
3541 __ li(t5, HeapNumber::kExponentMask);
3542 __ and_(t6, t3, t5);
3543 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(zero_reg));
3544
3545 __ xor_(t1, t6, t5);
3546 __ li(t2, kBinary32ExponentMask);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003547 __ Movz(t6, t2, t1); // Only if t6 is equal to t5.
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003548 __ Branch(&nan_or_infinity_or_zero, eq, t1, Operand(zero_reg));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003549
3550 // Rebias exponent.
3551 __ srl(t6, t6, HeapNumber::kExponentShift);
3552 __ Addu(t6,
3553 t6,
3554 Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
3555
3556 __ li(t1, Operand(kBinary32MaxExponent));
3557 __ Slt(t1, t1, t6);
3558 __ And(t2, t3, Operand(HeapNumber::kSignMask));
3559 __ Or(t2, t2, Operand(kBinary32ExponentMask));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003560 __ Movn(t3, t2, t1); // Only if t6 is gt kBinary32MaxExponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003561 __ Branch(&done, gt, t6, Operand(kBinary32MaxExponent));
3562
3563 __ Slt(t1, t6, Operand(kBinary32MinExponent));
3564 __ And(t2, t3, Operand(HeapNumber::kSignMask));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003565 __ Movn(t3, t2, t1); // Only if t6 is lt kBinary32MinExponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003566 __ Branch(&done, lt, t6, Operand(kBinary32MinExponent));
3567
3568 __ And(t7, t3, Operand(HeapNumber::kSignMask));
3569 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3570 __ sll(t3, t3, kMantissaInHiWordShift);
3571 __ or_(t7, t7, t3);
3572 __ srl(t4, t4, kMantissaInLoWordShift);
3573 __ or_(t7, t7, t4);
3574 __ sll(t6, t6, kBinary32ExponentShift);
3575 __ or_(t3, t7, t6);
3576
3577 __ bind(&done);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003578 __ sll(t9, key, 1);
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003579 __ addu(t9, a3, t9);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003580 __ sw(t3, MemOperand(t9, 0));
3581
3582 // Entry registers are intact, a0 holds the value which is the return
3583 // value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003584 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003585 __ Ret();
3586
3587 __ bind(&nan_or_infinity_or_zero);
3588 __ And(t7, t3, Operand(HeapNumber::kSignMask));
3589 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3590 __ or_(t6, t6, t7);
3591 __ sll(t3, t3, kMantissaInHiWordShift);
3592 __ or_(t6, t6, t3);
3593 __ srl(t4, t4, kMantissaInLoWordShift);
3594 __ or_(t3, t6, t4);
3595 __ Branch(&done);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003596 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003597 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003598 __ addu(t8, a3, t8);
3599 // t8: effective address of destination element.
3600 __ sw(t4, MemOperand(t8, 0));
3601 __ sw(t3, MemOperand(t8, Register::kSizeInBytes));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003602 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003603 __ Ret();
3604 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003605 bool is_signed_type = IsElementTypeSigned(elements_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003606 int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
3607 int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
3608
3609 Label done, sign;
3610
3611 // Test for all special exponent values: zeros, subnormal numbers, NaNs
3612 // and infinities. All these should be converted to 0.
3613 __ li(t5, HeapNumber::kExponentMask);
3614 __ and_(t6, t3, t5);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003615 __ Movz(t3, zero_reg, t6); // Only if t6 is equal to zero.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003616 __ Branch(&done, eq, t6, Operand(zero_reg));
3617
3618 __ xor_(t2, t6, t5);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003619 __ Movz(t3, zero_reg, t2); // Only if t6 is equal to t5.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003620 __ Branch(&done, eq, t6, Operand(t5));
3621
3622 // Unbias exponent.
3623 __ srl(t6, t6, HeapNumber::kExponentShift);
3624 __ Subu(t6, t6, Operand(HeapNumber::kExponentBias));
3625 // If exponent is negative then result is 0.
3626 __ slt(t2, t6, zero_reg);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003627 __ Movn(t3, zero_reg, t2); // Only if exponent is negative.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003628 __ Branch(&done, lt, t6, Operand(zero_reg));
3629
3630 // If exponent is too big then result is minimal value.
3631 __ slti(t1, t6, meaningfull_bits - 1);
3632 __ li(t2, min_value);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003633 __ Movz(t3, t2, t1); // Only if t6 is ge meaningfull_bits - 1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003634 __ Branch(&done, ge, t6, Operand(meaningfull_bits - 1));
3635
3636 __ And(t5, t3, Operand(HeapNumber::kSignMask));
3637 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3638 __ Or(t3, t3, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
3639
3640 __ li(t9, HeapNumber::kMantissaBitsInTopWord);
3641 __ subu(t6, t9, t6);
3642 __ slt(t1, t6, zero_reg);
3643 __ srlv(t2, t3, t6);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003644 __ Movz(t3, t2, t1); // Only if t6 is positive.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003645 __ Branch(&sign, ge, t6, Operand(zero_reg));
3646
3647 __ subu(t6, zero_reg, t6);
3648 __ sllv(t3, t3, t6);
3649 __ li(t9, meaningfull_bits);
3650 __ subu(t6, t9, t6);
3651 __ srlv(t4, t4, t6);
3652 __ or_(t3, t3, t4);
3653
3654 __ bind(&sign);
3655 __ subu(t2, t3, zero_reg);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003656 __ Movz(t3, t2, t5); // Only if t5 is zero.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003657
3658 __ bind(&done);
3659
3660 // Result is in t3.
3661 // This switch block should be exactly the same as above (FPU mode).
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003662 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003663 case EXTERNAL_BYTE_ELEMENTS:
3664 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003665 __ srl(t8, key, 1);
3666 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003667 __ sb(t3, MemOperand(t8, 0));
3668 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003669 case EXTERNAL_SHORT_ELEMENTS:
3670 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003671 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003672 __ sh(t3, MemOperand(t8, 0));
3673 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003674 case EXTERNAL_INT_ELEMENTS:
3675 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003676 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003677 __ addu(t8, a3, t8);
3678 __ sw(t3, MemOperand(t8, 0));
3679 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003680 case EXTERNAL_PIXEL_ELEMENTS:
3681 case EXTERNAL_FLOAT_ELEMENTS:
3682 case EXTERNAL_DOUBLE_ELEMENTS:
3683 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003684 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003685 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003686 case FAST_HOLEY_ELEMENTS:
3687 case FAST_HOLEY_SMI_ELEMENTS:
3688 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003689 case DICTIONARY_ELEMENTS:
3690 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003691 UNREACHABLE();
3692 break;
3693 }
3694 }
3695 }
3696 }
3697
danno@chromium.org40cb8782011-05-25 07:58:50 +00003698 // Slow case, key and receiver still in a0 and a1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003699 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003700 __ IncrementCounter(
3701 masm->isolate()->counters()->keyed_load_external_array_slow(),
3702 1, a2, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003703 // Entry registers are intact.
3704 // ---------- S t a t e --------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003705 // -- ra : return address
danno@chromium.org40cb8782011-05-25 07:58:50 +00003706 // -- a0 : key
3707 // -- a1 : receiver
3708 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003709 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003710
3711 // Miss case, call the runtime.
3712 __ bind(&miss_force_generic);
3713
3714 // ---------- S t a t e --------------
3715 // -- ra : return address
3716 // -- a0 : key
3717 // -- a1 : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003718 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003719 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003720}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003721
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003722
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003723void KeyedStoreStubCompiler::GenerateStoreFastElement(
3724 MacroAssembler* masm,
3725 bool is_js_array,
yangguo@chromium.org56454712012-02-16 15:33:53 +00003726 ElementsKind elements_kind,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003727 KeyedAccessStoreMode store_mode) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003728 // ----------- S t a t e -------------
3729 // -- a0 : value
3730 // -- a1 : key
3731 // -- a2 : receiver
3732 // -- ra : return address
3733 // -- a3 : scratch
3734 // -- a4 : scratch (elements)
3735 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00003736 Label miss_force_generic, transition_elements_kind, grow, slow;
3737 Label finish_store, check_capacity;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003738
3739 Register value_reg = a0;
3740 Register key_reg = a1;
3741 Register receiver_reg = a2;
yangguo@chromium.org56454712012-02-16 15:33:53 +00003742 Register scratch = t0;
3743 Register elements_reg = a3;
3744 Register length_reg = t1;
3745 Register scratch2 = t2;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003746
3747 // This stub is meant to be tail-jumped to, the receiver must already
3748 // have been verified by the caller to not be a smi.
3749
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003750 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003751 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003752
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003753 if (IsFastSmiElementsKind(elements_kind)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003754 __ JumpIfNotSmi(value_reg, &transition_elements_kind);
3755 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003756
3757 // Check that the key is within bounds.
yangguo@chromium.org56454712012-02-16 15:33:53 +00003758 __ lw(elements_reg,
3759 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003760 if (is_js_array) {
3761 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3762 } else {
3763 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3764 }
3765 // Compare smis.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003766 if (is_js_array && IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003767 __ Branch(&grow, hs, key_reg, Operand(scratch));
3768 } else {
3769 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
3770 }
3771
3772 // Make sure elements is a fast element array, not 'cow'.
3773 __ CheckMap(elements_reg,
3774 scratch,
3775 Heap::kFixedArrayMapRootIndex,
3776 &miss_force_generic,
3777 DONT_DO_SMI_CHECK);
3778
3779 __ bind(&finish_store);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003780
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003781 if (IsFastSmiElementsKind(elements_kind)) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003782 __ Addu(scratch,
3783 elements_reg,
3784 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3785 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
3786 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
3787 __ Addu(scratch, scratch, scratch2);
3788 __ sw(value_reg, MemOperand(scratch));
3789 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003790 ASSERT(IsFastObjectElementsKind(elements_kind));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003791 __ Addu(scratch,
3792 elements_reg,
3793 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3794 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
3795 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
3796 __ Addu(scratch, scratch, scratch2);
3797 __ sw(value_reg, MemOperand(scratch));
3798 __ mov(receiver_reg, value_reg);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003799 __ RecordWrite(elements_reg, // Object.
3800 scratch, // Address.
3801 receiver_reg, // Value.
3802 kRAHasNotBeenSaved,
3803 kDontSaveFPRegs);
3804 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003805 // value_reg (a0) is preserved.
3806 // Done.
3807 __ Ret();
3808
3809 __ bind(&miss_force_generic);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003810 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003811
3812 __ bind(&transition_elements_kind);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003813 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003814
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003815 if (is_js_array && IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003816 // Grow the array by a single element if possible.
3817 __ bind(&grow);
3818
3819 // Make sure the array is only growing by a single element, anything else
3820 // must be handled by the runtime.
3821 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch));
3822
3823 // Check for the empty array, and preallocate a small backing store if
3824 // possible.
3825 __ lw(length_reg,
3826 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3827 __ lw(elements_reg,
3828 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3829 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
3830 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
3831
3832 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
3833 __ AllocateInNewSpace(size, elements_reg, scratch, scratch2, &slow,
3834 TAG_OBJECT);
3835
3836 __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex);
3837 __ sw(scratch, FieldMemOperand(elements_reg, JSObject::kMapOffset));
3838 __ li(scratch, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
3839 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3840 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
3841 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
3842 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::SizeFor(i)));
3843 }
3844
3845 // Store the element at index zero.
3846 __ sw(value_reg, FieldMemOperand(elements_reg, FixedArray::SizeFor(0)));
3847
3848 // Install the new backing store in the JSArray.
3849 __ sw(elements_reg,
3850 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3851 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
3852 scratch, kRAHasNotBeenSaved, kDontSaveFPRegs,
3853 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3854
3855 // Increment the length of the array.
3856 __ li(length_reg, Operand(Smi::FromInt(1)));
3857 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3858 __ Ret();
3859
3860 __ bind(&check_capacity);
3861 // Check for cow elements, in general they are not handled by this stub
3862 __ CheckMap(elements_reg,
3863 scratch,
3864 Heap::kFixedCOWArrayMapRootIndex,
3865 &miss_force_generic,
3866 DONT_DO_SMI_CHECK);
3867
3868 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3869 __ Branch(&slow, hs, length_reg, Operand(scratch));
3870
3871 // Grow the array and finish the store.
3872 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
3873 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3874 __ jmp(&finish_store);
3875
3876 __ bind(&slow);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003877 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003878 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003879}
3880
3881
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003882void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
3883 MacroAssembler* masm,
yangguo@chromium.org56454712012-02-16 15:33:53 +00003884 bool is_js_array,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003885 KeyedAccessStoreMode store_mode) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003886 // ----------- S t a t e -------------
3887 // -- a0 : value
3888 // -- a1 : key
3889 // -- a2 : receiver
3890 // -- ra : return address
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003891 // -- a3 : scratch (elements backing store)
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003892 // -- t0 : scratch (elements_reg)
3893 // -- t1 : scratch (mantissa_reg)
3894 // -- t2 : scratch (exponent_reg)
3895 // -- t3 : scratch4
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003896 // -- t4 : scratch
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003897 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00003898 Label miss_force_generic, transition_elements_kind, grow, slow;
3899 Label finish_store, check_capacity;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003900
3901 Register value_reg = a0;
3902 Register key_reg = a1;
3903 Register receiver_reg = a2;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003904 Register elements_reg = a3;
3905 Register scratch1 = t0;
3906 Register scratch2 = t1;
3907 Register scratch3 = t2;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003908 Register scratch4 = t3;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003909 Register scratch5 = t4;
yangguo@chromium.org56454712012-02-16 15:33:53 +00003910 Register length_reg = t3;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003911
3912 // This stub is meant to be tail-jumped to, the receiver must already
3913 // have been verified by the caller to not be a smi.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003914
3915 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003916 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003917
3918 __ lw(elements_reg,
3919 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3920
3921 // Check that the key is within bounds.
3922 if (is_js_array) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003923 __ lw(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003924 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003925 __ lw(scratch1,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003926 FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3927 }
3928 // Compare smis, unsigned compare catches both negative and out-of-bound
3929 // indexes.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003930 if (IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003931 __ Branch(&grow, hs, key_reg, Operand(scratch1));
3932 } else {
3933 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch1));
3934 }
3935
3936 __ bind(&finish_store);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003937
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003938 __ StoreNumberToDoubleElements(value_reg,
3939 key_reg,
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00003940 // All registers after this are overwritten.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003941 elements_reg,
3942 scratch1,
3943 scratch2,
3944 scratch3,
3945 scratch4,
3946 &transition_elements_kind);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003947
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003948 __ Ret(USE_DELAY_SLOT);
3949 __ mov(v0, value_reg); // In delay slot.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003950
3951 // Handle store cache miss, replacing the ic with the generic stub.
3952 __ bind(&miss_force_generic);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003953 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003954
3955 __ bind(&transition_elements_kind);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003956 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003957
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003958 if (is_js_array && IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003959 // Grow the array by a single element if possible.
3960 __ bind(&grow);
3961
3962 // Make sure the array is only growing by a single element, anything else
3963 // must be handled by the runtime.
3964 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch1));
3965
3966 // Transition on values that can't be stored in a FixedDoubleArray.
3967 Label value_is_smi;
3968 __ JumpIfSmi(value_reg, &value_is_smi);
3969 __ lw(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
3970 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
3971 __ Branch(&transition_elements_kind, ne, scratch1, Operand(at));
3972 __ bind(&value_is_smi);
3973
3974 // Check for the empty array, and preallocate a small backing store if
3975 // possible.
3976 __ lw(length_reg,
3977 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3978 __ lw(elements_reg,
3979 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3980 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
3981 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
3982
3983 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
3984 __ AllocateInNewSpace(size, elements_reg, scratch1, scratch2, &slow,
3985 TAG_OBJECT);
3986
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003987 // Initialize the new FixedDoubleArray.
yangguo@chromium.org56454712012-02-16 15:33:53 +00003988 __ LoadRoot(scratch1, Heap::kFixedDoubleArrayMapRootIndex);
3989 __ sw(scratch1, FieldMemOperand(elements_reg, JSObject::kMapOffset));
3990 __ li(scratch1, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
3991 __ sw(scratch1,
3992 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
3993
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003994 __ mov(scratch1, elements_reg);
3995 __ StoreNumberToDoubleElements(value_reg,
3996 key_reg,
3997 // All registers after this are overwritten.
3998 scratch1,
3999 scratch2,
4000 scratch3,
4001 scratch4,
4002 scratch5,
4003 &transition_elements_kind);
4004
4005 __ li(scratch1, Operand(kHoleNanLower32));
4006 __ li(scratch2, Operand(kHoleNanUpper32));
4007 for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) {
4008 int offset = FixedDoubleArray::OffsetOfElementAt(i);
4009 __ sw(scratch1, FieldMemOperand(elements_reg, offset));
4010 __ sw(scratch2, FieldMemOperand(elements_reg, offset + kPointerSize));
4011 }
4012
yangguo@chromium.org56454712012-02-16 15:33:53 +00004013 // Install the new backing store in the JSArray.
4014 __ sw(elements_reg,
4015 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4016 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
4017 scratch1, kRAHasNotBeenSaved, kDontSaveFPRegs,
4018 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4019
4020 // Increment the length of the array.
4021 __ li(length_reg, Operand(Smi::FromInt(1)));
4022 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
danno@chromium.org00379b82012-05-04 09:16:29 +00004023 __ lw(elements_reg,
4024 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004025 __ Ret();
yangguo@chromium.org56454712012-02-16 15:33:53 +00004026
4027 __ bind(&check_capacity);
4028 // Make sure that the backing store can hold additional elements.
4029 __ lw(scratch1,
4030 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
4031 __ Branch(&slow, hs, length_reg, Operand(scratch1));
4032
4033 // Grow the array and finish the store.
4034 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
4035 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4036 __ jmp(&finish_store);
4037
4038 __ bind(&slow);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004039 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
yangguo@chromium.org56454712012-02-16 15:33:53 +00004040 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004041}
4042
4043
ager@chromium.org5c838252010-02-19 08:53:10 +00004044#undef __
4045
4046} } // namespace v8::internal
4047
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004048#endif // V8_TARGET_ARCH_MIPS