blob: e110c47c6f12a7d46ae04f094b21e75ff4af4844 [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
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000413// Generate code to check that a global property cell is empty. Create
414// the property cell at compilation time if no cell exists for the
415// property.
416static void GenerateCheckPropertyCell(MacroAssembler* masm,
417 Handle<GlobalObject> global,
418 Handle<Name> name,
419 Register scratch,
420 Label* miss) {
421 Handle<JSGlobalPropertyCell> cell =
422 GlobalObject::EnsurePropertyCell(global, name);
423 ASSERT(cell->value()->IsTheHole());
424 __ li(scratch, Operand(cell));
425 __ lw(scratch,
426 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
427 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
428 __ Branch(miss, ne, scratch, Operand(at));
429}
430
431
432// Generate StoreTransition code, value is passed in a0 register.
ager@chromium.org5c838252010-02-19 08:53:10 +0000433// After executing generated code, the receiver_reg and name_reg
434// may be clobbered.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000435void StubCompiler::GenerateStoreTransition(MacroAssembler* masm,
436 Handle<JSObject> object,
437 LookupResult* lookup,
438 Handle<Map> transition,
439 Handle<Name> name,
440 Register receiver_reg,
441 Register name_reg,
442 Register value_reg,
443 Register scratch1,
444 Register scratch2,
445 Label* miss_label,
446 Label* miss_restore_name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000447 // a0 : value.
448 Label exit;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000449
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000450 // Check that the map of the object hasn't changed.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000451 __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000452 DO_SMI_CHECK, REQUIRE_EXACT_MAP);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000453
454 // Perform global security token check if needed.
455 if (object->IsJSGlobalProxy()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000456 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
457 }
458
459 // Check that we are allowed to write this.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000460 if (object->GetPrototype()->IsJSObject()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000461 JSObject* holder;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000462 // holder == object indicates that no property was found.
463 if (lookup->holder() != *object) {
464 holder = lookup->holder();
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000465 } else {
466 // Find the top object.
467 holder = *object;
468 do {
469 holder = JSObject::cast(holder->GetPrototype());
470 } while (holder->GetPrototype()->IsJSObject());
471 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000472 Register holder_reg = CheckPrototypes(
473 object, receiver_reg, Handle<JSObject>(holder), name_reg,
474 scratch1, scratch2, name, miss_restore_name);
475 // If no property was found, and the holder (the last object in the
476 // prototype chain) is in slow mode, we need to do a negative lookup on the
477 // holder.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000478 if (lookup->holder() == *object) {
479 if (holder->IsJSGlobalObject()) {
480 GenerateCheckPropertyCell(
481 masm,
482 Handle<GlobalObject>(GlobalObject::cast(holder)),
483 name,
484 scratch1,
485 miss_restore_name);
486 } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
487 GenerateDictionaryNegativeLookup(
488 masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
489 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000490 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000491 }
492
493 // Stub never generated for non-global objects that require access
494 // checks.
495 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
496
497 // Perform map transition for the receiver if necessary.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000498 if (object->map()->unused_property_fields() == 0) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000499 // The properties must be extended before we can store the value.
500 // We jump to a runtime call that extends the properties array.
501 __ push(receiver_reg);
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000502 __ li(a2, Operand(transition));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000503 __ Push(a2, a0);
504 __ TailCallExternalReference(
505 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
506 masm->isolate()),
507 3, 1);
508 return;
509 }
510
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000511 // Update the map of the object.
512 __ li(scratch1, Operand(transition));
513 __ sw(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
verwaest@chromium.org37141392012-05-31 13:27:02 +0000514
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000515 // Update the write barrier for the map field and pass the now unused
516 // name_reg as scratch register.
517 __ RecordWriteField(receiver_reg,
518 HeapObject::kMapOffset,
519 scratch1,
520 name_reg,
521 kRAHasNotBeenSaved,
522 kDontSaveFPRegs,
523 OMIT_REMEMBERED_SET,
524 OMIT_SMI_CHECK);
525
526 int index = transition->instance_descriptors()->GetFieldIndex(
527 transition->LastAdded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000528
529 // Adjust for the number of properties stored in the object. Even in the
530 // face of a transition we can use the old map here because the size of the
531 // object and the number of in-object properties is not going to change.
532 index -= object->map()->inobject_properties();
533
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000534 // TODO(verwaest): Share this code as a code stub.
535 if (index < 0) {
536 // Set the property straight into the object.
537 int offset = object->map()->instance_size() + (index * kPointerSize);
538 __ sw(value_reg, FieldMemOperand(receiver_reg, offset));
539
540 // Skip updating write barrier if storing a smi.
541 __ JumpIfSmi(value_reg, &exit);
542
543 // Update the write barrier for the array address.
544 // Pass the now unused name_reg as a scratch register.
545 __ mov(name_reg, value_reg);
546 __ RecordWriteField(receiver_reg,
547 offset,
548 name_reg,
549 scratch1,
550 kRAHasNotBeenSaved,
551 kDontSaveFPRegs);
552 } else {
553 // Write to the properties array.
554 int offset = index * kPointerSize + FixedArray::kHeaderSize;
555 // Get the properties array
556 __ lw(scratch1,
557 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
558 __ sw(value_reg, FieldMemOperand(scratch1, offset));
559
560 // Skip updating write barrier if storing a smi.
561 __ JumpIfSmi(value_reg, &exit);
562
563 // Update the write barrier for the array address.
564 // Ok to clobber receiver_reg and name_reg, since we return.
565 __ mov(name_reg, value_reg);
566 __ RecordWriteField(scratch1,
567 offset,
568 name_reg,
569 receiver_reg,
570 kRAHasNotBeenSaved,
571 kDontSaveFPRegs);
572 }
573
574 // Return the value (register v0).
575 ASSERT(value_reg.is(a0));
576 __ bind(&exit);
577 __ mov(v0, a0);
578 __ Ret();
579}
580
581
582// Generate StoreField code, value is passed in a0 register.
583// When leaving generated code after success, the receiver_reg and name_reg
584// may be clobbered. Upon branch to miss_label, the receiver and name
585// registers have their original values.
586void StubCompiler::GenerateStoreField(MacroAssembler* masm,
587 Handle<JSObject> object,
588 LookupResult* lookup,
589 Register receiver_reg,
590 Register name_reg,
591 Register value_reg,
592 Register scratch1,
593 Register scratch2,
594 Label* miss_label) {
595 // a0 : value
596 Label exit;
597
598 // Check that the map of the object hasn't changed.
599 __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
600 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
601
602 // Perform global security token check if needed.
603 if (object->IsJSGlobalProxy()) {
604 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
605 }
606
607 // Stub never generated for non-global objects that require access
608 // checks.
609 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
610
611 int index = lookup->GetFieldIndex().field_index();
612
613 // Adjust for the number of properties stored in the object. Even in the
614 // face of a transition we can use the old map here because the size of the
615 // object and the number of in-object properties is not going to change.
616 index -= object->map()->inobject_properties();
617
618 // TODO(verwaest): Share this code as a code stub.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000619 if (index < 0) {
620 // Set the property straight into the object.
621 int offset = object->map()->instance_size() + (index * kPointerSize);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000622 __ sw(value_reg, FieldMemOperand(receiver_reg, offset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000623
624 // Skip updating write barrier if storing a smi.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000625 __ JumpIfSmi(value_reg, &exit);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000626
627 // Update the write barrier for the array address.
628 // Pass the now unused name_reg as a scratch register.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000629 __ mov(name_reg, value_reg);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000630 __ RecordWriteField(receiver_reg,
631 offset,
632 name_reg,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000633 scratch1,
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000634 kRAHasNotBeenSaved,
635 kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000636 } else {
637 // Write to the properties array.
638 int offset = index * kPointerSize + FixedArray::kHeaderSize;
639 // Get the properties array.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000640 __ lw(scratch1,
641 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000642 __ sw(value_reg, FieldMemOperand(scratch1, offset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000643
644 // Skip updating write barrier if storing a smi.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000645 __ JumpIfSmi(value_reg, &exit);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000646
647 // Update the write barrier for the array address.
648 // Ok to clobber receiver_reg and name_reg, since we return.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000649 __ mov(name_reg, value_reg);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000650 __ RecordWriteField(scratch1,
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000651 offset,
652 name_reg,
653 receiver_reg,
654 kRAHasNotBeenSaved,
655 kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000656 }
657
658 // Return the value (register v0).
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000659 ASSERT(value_reg.is(a0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000660 __ bind(&exit);
661 __ mov(v0, a0);
662 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000663}
664
665
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000666void BaseStoreStubCompiler::GenerateRestoreName(MacroAssembler* masm,
667 Label* label,
668 Handle<Name> name) {
669 if (!label->is_unused()) {
670 __ bind(label);
671 __ li(this->name(), Operand(name));
672 }
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000673}
674
675
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000676static void GenerateCallFunction(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000677 Handle<Object> object,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000678 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000679 Label* miss,
680 Code::ExtraICState extra_ic_state) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000681 // ----------- S t a t e -------------
682 // -- a0: receiver
683 // -- a1: function to call
684 // -----------------------------------
685 // Check that the function really is a function.
686 __ JumpIfSmi(a1, miss);
687 __ GetObjectType(a1, a3, a3);
688 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
689
690 // Patch the receiver on the stack with the global proxy if
691 // necessary.
692 if (object->IsGlobalObject()) {
693 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
694 __ sw(a3, MemOperand(sp, arguments.immediate() * kPointerSize));
695 }
696
697 // Invoke the function.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000698 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
699 ? CALL_AS_FUNCTION
700 : CALL_AS_METHOD;
701 __ InvokeFunction(a1, arguments, JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000702}
703
704
705static void PushInterceptorArguments(MacroAssembler* masm,
706 Register receiver,
707 Register holder,
708 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000709 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000710 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000711 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
712 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000713 Register scratch = name;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000714 __ li(scratch, Operand(interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000715 __ Push(scratch, receiver, holder);
716 __ lw(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
717 __ push(scratch);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000718 __ li(scratch, Operand(ExternalReference::isolate_address(masm->isolate())));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000719 __ push(scratch);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000720}
721
722
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000723static void CompileCallLoadPropertyWithInterceptor(
724 MacroAssembler* masm,
725 Register receiver,
726 Register holder,
727 Register name,
728 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000729 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
730
731 ExternalReference ref =
732 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
733 masm->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000734 __ PrepareCEntryArgs(6);
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000735 __ PrepareCEntryFunction(ref);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000736
737 CEntryStub stub(1);
738 __ CallStub(&stub);
739}
740
741
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000742static const int kFastApiCallArguments = 4;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000743
744
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000745// Reserves space for the extra arguments to API function in the
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000746// caller's frame.
747//
748// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
749static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
750 Register scratch) {
751 ASSERT(Smi::FromInt(0) == 0);
752 for (int i = 0; i < kFastApiCallArguments; i++) {
753 __ push(zero_reg);
754 }
755}
756
757
758// Undoes the effects of ReserveSpaceForFastApiCall.
759static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
760 __ Drop(kFastApiCallArguments);
761}
762
763
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000764static void GenerateFastApiDirectCall(MacroAssembler* masm,
765 const CallOptimization& optimization,
766 int argc) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000767 // ----------- S t a t e -------------
768 // -- sp[0] : holder (set by CheckPrototypes)
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000769 // -- sp[4] : callee JS function
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000770 // -- sp[8] : call data
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000771 // -- sp[12] : isolate
772 // -- sp[16] : last JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000773 // -- ...
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000774 // -- sp[(argc + 3) * 4] : first JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000775 // -- sp[(argc + 4) * 4] : receiver
776 // -----------------------------------
777 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000778 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000779 __ LoadHeapObject(t1, function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000780 __ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset));
781
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000782 // Pass the additional arguments.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000783 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000784 Handle<Object> call_data(api_call_info->data(), masm->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000785 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
786 __ li(a0, api_call_info);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000787 __ lw(t2, FieldMemOperand(a0, CallHandlerInfo::kDataOffset));
788 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000789 __ li(t2, call_data);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000790 }
791
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000792 __ li(t3, Operand(ExternalReference::isolate_address(masm->isolate())));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000793 // Store JS function, call data and isolate.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000794 __ sw(t1, MemOperand(sp, 1 * kPointerSize));
795 __ sw(t2, MemOperand(sp, 2 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000796 __ sw(t3, MemOperand(sp, 3 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000797
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000798 // Prepare arguments.
799 __ Addu(a2, sp, Operand(3 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000800
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000801 // Allocate the v8::Arguments structure in the arguments' space since
802 // it's not controlled by GC.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000803 const int kApiStackSpace = 4;
804
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000805 FrameScope frame_scope(masm, StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000806 __ EnterExitFrame(false, kApiStackSpace);
807
808 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
809 // struct from the function (which is currently the case). This means we pass
810 // the first argument in a1 instead of a0. TryCallApiFunctionAndReturn
811 // will handle setting up a0.
812
813 // a1 = v8::Arguments&
814 // Arguments is built at sp + 1 (sp is a reserved spot for ra).
815 __ Addu(a1, sp, kPointerSize);
816
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000817 // v8::Arguments::implicit_args_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000818 __ sw(a2, MemOperand(a1, 0 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000819 // v8::Arguments::values_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000820 __ Addu(t0, a2, Operand(argc * kPointerSize));
821 __ sw(t0, MemOperand(a1, 1 * kPointerSize));
822 // v8::Arguments::length_ = argc
823 __ li(t0, Operand(argc));
824 __ sw(t0, MemOperand(a1, 2 * kPointerSize));
825 // v8::Arguments::is_construct_call = 0
826 __ sw(zero_reg, MemOperand(a1, 3 * kPointerSize));
827
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000828 const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000829 Address function_address = v8::ToCData<Address>(api_call_info->callback());
830 ApiFunction fun(function_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000831 ExternalReference ref =
832 ExternalReference(&fun,
833 ExternalReference::DIRECT_API_CALL,
834 masm->isolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000835 AllowExternalCallThatCantCauseGC scope(masm);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000836 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000837}
838
lrn@chromium.org7516f052011-03-30 08:52:27 +0000839class CallInterceptorCompiler BASE_EMBEDDED {
840 public:
841 CallInterceptorCompiler(StubCompiler* stub_compiler,
842 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000843 Register name,
844 Code::ExtraICState extra_ic_state)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000845 : stub_compiler_(stub_compiler),
846 arguments_(arguments),
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000847 name_(name),
848 extra_ic_state_(extra_ic_state) {}
lrn@chromium.org7516f052011-03-30 08:52:27 +0000849
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000850 void Compile(MacroAssembler* masm,
851 Handle<JSObject> object,
852 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000853 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000854 LookupResult* lookup,
855 Register receiver,
856 Register scratch1,
857 Register scratch2,
858 Register scratch3,
859 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000860 ASSERT(holder->HasNamedInterceptor());
861 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
862
863 // Check that the receiver isn't a smi.
864 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000865 CallOptimization optimization(lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000866 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000867 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
868 holder, lookup, name, optimization, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000869 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000870 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
871 name, holder, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000872 }
873 }
874
875 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000876 void CompileCacheable(MacroAssembler* masm,
877 Handle<JSObject> object,
878 Register receiver,
879 Register scratch1,
880 Register scratch2,
881 Register scratch3,
882 Handle<JSObject> interceptor_holder,
883 LookupResult* lookup,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000884 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000885 const CallOptimization& optimization,
886 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000887 ASSERT(optimization.is_constant_call());
888 ASSERT(!lookup->holder()->IsGlobalObject());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000889 Counters* counters = masm->isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000890 int depth1 = kInvalidProtoDepth;
891 int depth2 = kInvalidProtoDepth;
892 bool can_do_fast_api_call = false;
893 if (optimization.is_simple_api_call() &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000894 !lookup->holder()->IsGlobalObject()) {
895 depth1 = optimization.GetPrototypeDepthOfExpectedType(
896 object, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000897 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000898 depth2 = optimization.GetPrototypeDepthOfExpectedType(
899 interceptor_holder, Handle<JSObject>(lookup->holder()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000900 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000901 can_do_fast_api_call =
902 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000903 }
904
905 __ IncrementCounter(counters->call_const_interceptor(), 1,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000906 scratch1, scratch2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000907
908 if (can_do_fast_api_call) {
909 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
910 scratch1, scratch2);
911 ReserveSpaceForFastApiCall(masm, scratch1);
912 }
913
914 // Check that the maps from receiver to interceptor's holder
915 // haven't changed and thus we can invoke interceptor.
916 Label miss_cleanup;
917 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
918 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000919 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
920 scratch1, scratch2, scratch3,
921 name, depth1, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000922
923 // Invoke an interceptor and if it provides a value,
924 // branch to |regular_invoke|.
925 Label regular_invoke;
926 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
927 &regular_invoke);
928
929 // Interceptor returned nothing for this property. Try to use cached
930 // constant function.
931
932 // Check that the maps from interceptor's holder to constant function's
933 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000934 if (*interceptor_holder != lookup->holder()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000935 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000936 Handle<JSObject>(lookup->holder()),
937 scratch1, scratch2, scratch3,
938 name, depth2, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000939 } else {
940 // CheckPrototypes has a side effect of fetching a 'holder'
941 // for API (object which is instanceof for the signature). It's
942 // safe to omit it here, as if present, it should be fetched
943 // by the previous CheckPrototypes.
944 ASSERT(depth2 == kInvalidProtoDepth);
945 }
946
947 // Invoke function.
948 if (can_do_fast_api_call) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000949 GenerateFastApiDirectCall(masm, optimization, arguments_.immediate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000950 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000951 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
952 ? CALL_AS_FUNCTION
953 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000954 Handle<JSFunction> function = optimization.constant_function();
955 ParameterCount expected(function);
956 __ InvokeFunction(function, expected, arguments_,
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000957 JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000958 }
959
960 // Deferred code for fast API call case---clean preallocated space.
961 if (can_do_fast_api_call) {
962 __ bind(&miss_cleanup);
963 FreeSpaceForFastApiCall(masm);
964 __ Branch(miss_label);
965 }
966
967 // Invoke a regular function.
968 __ bind(&regular_invoke);
969 if (can_do_fast_api_call) {
970 FreeSpaceForFastApiCall(masm);
971 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000972 }
973
974 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000975 Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000976 Register receiver,
977 Register scratch1,
978 Register scratch2,
979 Register scratch3,
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000980 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000981 Handle<JSObject> interceptor_holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000982 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000983 Register holder =
984 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000985 scratch1, scratch2, scratch3,
986 name, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000987
988 // Call a runtime function to load the interceptor property.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000989 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000990 // Save the name_ register across the call.
991 __ push(name_);
992
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000993 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000994
995 __ CallExternalReference(
996 ExternalReference(
997 IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
998 masm->isolate()),
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000999 6);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001000 // Restore the name_ register.
1001 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001002 // Leave the internal frame.
lrn@chromium.org7516f052011-03-30 08:52:27 +00001003 }
1004
1005 void LoadWithInterceptor(MacroAssembler* masm,
1006 Register receiver,
1007 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001008 Handle<JSObject> holder_obj,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001009 Register scratch,
1010 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001011 {
1012 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001013
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001014 __ Push(holder, name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001015 CompileCallLoadPropertyWithInterceptor(masm,
1016 receiver,
1017 holder,
1018 name_,
1019 holder_obj);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001020 __ pop(name_); // Restore the name.
1021 __ pop(receiver); // Restore the holder.
1022 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001023 // If interceptor returns no-result sentinel, call the constant function.
1024 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
1025 __ Branch(interceptor_succeeded, ne, v0, Operand(scratch));
lrn@chromium.org7516f052011-03-30 08:52:27 +00001026 }
1027
1028 StubCompiler* stub_compiler_;
1029 const ParameterCount& arguments_;
1030 Register name_;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001031 Code::ExtraICState extra_ic_state_;
lrn@chromium.org7516f052011-03-30 08:52:27 +00001032};
1033
1034
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001035// Calls GenerateCheckPropertyCell for each global object in the prototype chain
1036// from object to (but not including) holder.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001037static void GenerateCheckPropertyCells(MacroAssembler* masm,
1038 Handle<JSObject> object,
1039 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001040 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001041 Register scratch,
1042 Label* miss) {
1043 Handle<JSObject> current = object;
1044 while (!current.is_identical_to(holder)) {
1045 if (current->IsGlobalObject()) {
1046 GenerateCheckPropertyCell(masm,
1047 Handle<GlobalObject>::cast(current),
1048 name,
1049 scratch,
1050 miss);
1051 }
1052 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
1053 }
1054}
1055
1056
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001057// Convert and store int passed in register ival to IEEE 754 single precision
1058// floating point value at memory location (dst + 4 * wordoffset)
1059// If FPU is available use it for conversion.
1060static void StoreIntAsFloat(MacroAssembler* masm,
1061 Register dst,
1062 Register wordoffset,
1063 Register ival,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001064 Register scratch1) {
1065 __ mtc1(ival, f0);
1066 __ cvt_s_w(f0, f0);
1067 __ sll(scratch1, wordoffset, 2);
1068 __ addu(scratch1, dst, scratch1);
1069 __ swc1(f0, MemOperand(scratch1, 0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001070}
1071
1072
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001073void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001074 __ Jump(code, RelocInfo::CODE_TARGET);
1075}
1076
1077
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001078#undef __
1079#define __ ACCESS_MASM(masm())
1080
1081
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001082Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
1083 Register object_reg,
1084 Handle<JSObject> holder,
1085 Register holder_reg,
1086 Register scratch1,
1087 Register scratch2,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001088 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001089 int save_at_depth,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001090 Label* miss,
1091 PrototypeCheckType check) {
1092 Handle<JSObject> first = object;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001093 // Make sure there's no overlap between holder and object registers.
1094 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1095 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1096 && !scratch2.is(scratch1));
1097
1098 // Keep track of the current object in register reg.
1099 Register reg = object_reg;
1100 int depth = 0;
1101
1102 if (save_at_depth == depth) {
1103 __ sw(reg, MemOperand(sp));
1104 }
1105
1106 // Check the maps in the prototype chain.
1107 // Traverse the prototype chain from the object and do map checks.
1108 Handle<JSObject> current = object;
1109 while (!current.is_identical_to(holder)) {
1110 ++depth;
1111
1112 // Only global objects and objects that do not require access
1113 // checks are allowed in stubs.
1114 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1115
1116 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
1117 if (!current->HasFastProperties() &&
1118 !current->IsJSGlobalObject() &&
1119 !current->IsJSGlobalProxy()) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001120 if (!name->IsUniqueName()) {
1121 ASSERT(name->IsString());
1122 name = factory()->InternalizeString(Handle<String>::cast(name));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001123 }
1124 ASSERT(current->property_dictionary()->FindEntry(*name) ==
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001125 NameDictionary::kNotFound);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001126
1127 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1128 scratch1, scratch2);
1129
1130 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1131 reg = holder_reg; // From now on the object will be in holder_reg.
1132 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1133 } else {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001134 Register map_reg = scratch1;
1135 if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) {
1136 Handle<Map> current_map(current->map());
1137 // CheckMap implicitly loads the map of |reg| into |map_reg|.
1138 __ CheckMap(reg, map_reg, current_map, miss, DONT_DO_SMI_CHECK,
1139 ALLOW_ELEMENT_TRANSITION_MAPS);
1140 } else {
1141 __ lw(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
1142 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001143 // Check access rights to the global object. This has to happen after
1144 // the map check so that we know that the object is actually a global
1145 // object.
1146 if (current->IsJSGlobalProxy()) {
1147 __ CheckAccessGlobalProxy(reg, scratch2, miss);
1148 }
1149 reg = holder_reg; // From now on the object will be in holder_reg.
1150
1151 if (heap()->InNewSpace(*prototype)) {
1152 // The prototype is in new space; we cannot store a reference to it
1153 // in the code. Load it from the map.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001154 __ lw(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001155 } else {
1156 // The prototype is in old space; load it directly.
1157 __ li(reg, Operand(prototype));
1158 }
1159 }
1160
1161 if (save_at_depth == depth) {
1162 __ sw(reg, MemOperand(sp));
1163 }
1164
1165 // Go to the next object in the prototype chain.
1166 current = prototype;
1167 }
1168
1169 // Log the check depth.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001170 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001171
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001172 if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) {
1173 // Check the holder map.
1174 __ CheckMap(reg, scratch1, Handle<Map>(holder->map()), miss,
1175 DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
1176 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001177
1178 // Perform security check for access to the global object.
1179 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1180 if (holder->IsJSGlobalProxy()) {
1181 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1182 }
1183
1184 // If we've skipped any global objects, it's not enough to verify that
1185 // their maps haven't changed. We also need to check that the property
1186 // cell for the property is still empty.
1187 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1188
1189 // Return the register containing the holder.
1190 return reg;
1191}
1192
1193
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001194void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success,
1195 Label* miss) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001196 if (!miss->is_unused()) {
1197 __ Branch(success);
1198 __ bind(miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001199 TailCallBuiltin(masm(), MissBuiltin(kind()));
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001200 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001201}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001202
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001203
1204Register BaseLoadStubCompiler::CallbackHandlerFrontend(
1205 Handle<JSObject> object,
1206 Register object_reg,
1207 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001208 Handle<Name> name,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001209 Label* success,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001210 Handle<ExecutableAccessorInfo> callback) {
1211 Label miss;
1212
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001213 Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001214
1215 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
1216 ASSERT(!reg.is(scratch2()));
1217 ASSERT(!reg.is(scratch3()));
1218 ASSERT(!reg.is(scratch4()));
1219
1220 // Load the properties dictionary.
1221 Register dictionary = scratch4();
1222 __ lw(dictionary, FieldMemOperand(reg, JSObject::kPropertiesOffset));
1223
1224 // Probe the dictionary.
1225 Label probe_done;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001226 NameDictionaryLookupStub::GeneratePositiveLookup(masm(),
1227 &miss,
1228 &probe_done,
1229 dictionary,
1230 this->name(),
1231 scratch2(),
1232 scratch3());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001233 __ bind(&probe_done);
1234
1235 // If probing finds an entry in the dictionary, scratch3 contains the
1236 // pointer into the dictionary. Check that the value is the callback.
1237 Register pointer = scratch3();
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001238 const int kElementsStartOffset = NameDictionary::kHeaderSize +
1239 NameDictionary::kElementsStartIndex * kPointerSize;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001240 const int kValueOffset = kElementsStartOffset + kPointerSize;
1241 __ lw(scratch2(), FieldMemOperand(pointer, kValueOffset));
1242 __ Branch(&miss, ne, scratch2(), Operand(callback));
1243 }
1244
1245 HandlerFrontendFooter(success, &miss);
1246 return reg;
1247}
1248
1249
1250void BaseLoadStubCompiler::NonexistentHandlerFrontend(
1251 Handle<JSObject> object,
1252 Handle<JSObject> last,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001253 Handle<Name> name,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001254 Label* success,
1255 Handle<GlobalObject> global) {
1256 Label miss;
1257
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001258 HandlerFrontendHeader(object, receiver(), last, name, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001259
1260 // If the last object in the prototype chain is a global object,
1261 // check that the global property cell is empty.
1262 if (!global.is_null()) {
1263 GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
1264 }
1265
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001266 HandlerFrontendFooter(success, &miss);
1267}
1268
1269
1270void BaseLoadStubCompiler::GenerateLoadField(Register reg,
1271 Handle<JSObject> holder,
1272 PropertyIndex index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001273 GenerateFastPropertyLoad(masm(), v0, reg, holder, index);
1274 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001275}
1276
1277
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001278void BaseLoadStubCompiler::GenerateLoadConstant(Handle<JSFunction> value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001279 // Return the constant value.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001280 __ LoadHeapObject(v0, value);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001281 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001282}
1283
1284
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001285void BaseLoadStubCompiler::GenerateLoadCallback(
1286 Register reg,
1287 Handle<ExecutableAccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001288 // Build AccessorInfo::args_ list on the stack and push property name below
1289 // the exit frame to make GC aware of them and store pointers to them.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001290 __ push(receiver());
1291 __ mov(scratch2(), sp); // scratch2 = AccessorInfo::args_
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001292 if (heap()->InNewSpace(callback->data())) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001293 __ li(scratch3(), callback);
1294 __ lw(scratch3(), FieldMemOperand(scratch3(),
1295 ExecutableAccessorInfo::kDataOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001296 } else {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001297 __ li(scratch3(), Handle<Object>(callback->data(), isolate()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001298 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001299 __ Subu(sp, sp, 4 * kPointerSize);
1300 __ sw(reg, MemOperand(sp, 3 * kPointerSize));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001301 __ sw(scratch3(), MemOperand(sp, 2 * kPointerSize));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001302 __ li(scratch3(),
1303 Operand(ExternalReference::isolate_address(isolate())));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001304 __ sw(scratch3(), MemOperand(sp, 1 * kPointerSize));
1305 __ sw(name(), MemOperand(sp, 0 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001306
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001307 __ mov(a2, scratch2()); // Saved in case scratch2 == a1.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001308 __ mov(a1, sp); // a1 (first argument - see note below) = Handle<Name>
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001309
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001310 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
1311 // struct from the function (which is currently the case). This means we pass
1312 // the arguments in a1-a2 instead of a0-a1. TryCallApiFunctionAndReturn
1313 // will handle setting up a0.
1314
1315 const int kApiStackSpace = 1;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001316 FrameScope frame_scope(masm(), StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001317 __ EnterExitFrame(false, kApiStackSpace);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001318
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001319 // Create AccessorInfo instance on the stack above the exit frame with
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001320 // scratch2 (internal::Object** args_) as the data.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001321 __ sw(a2, MemOperand(sp, kPointerSize));
1322 // a2 (second argument - see note above) = AccessorInfo&
1323 __ Addu(a2, sp, kPointerSize);
1324
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001325 const int kStackUnwindSpace = 5;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001326 Address getter_address = v8::ToCData<Address>(callback->getter());
1327 ApiFunction fun(getter_address);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001328 ExternalReference ref = ExternalReference(
1329 &fun, ExternalReference::DIRECT_GETTER_CALL, isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001330 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
ager@chromium.org5c838252010-02-19 08:53:10 +00001331}
1332
1333
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001334void BaseLoadStubCompiler::GenerateLoadInterceptor(
1335 Register holder_reg,
1336 Handle<JSObject> object,
1337 Handle<JSObject> interceptor_holder,
1338 LookupResult* lookup,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001339 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001340 ASSERT(interceptor_holder->HasNamedInterceptor());
1341 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1342
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001343 // So far the most popular follow ups for interceptor loads are FIELD
1344 // and CALLBACKS, so inline only them, other cases may be added
1345 // later.
1346 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001347 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001348 if (lookup->IsField()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001349 compile_followup_inline = true;
1350 } else if (lookup->type() == CALLBACKS &&
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001351 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
1352 ExecutableAccessorInfo* callback =
1353 ExecutableAccessorInfo::cast(lookup->GetCallbackObject());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001354 compile_followup_inline = callback->getter() != NULL &&
1355 callback->IsCompatibleReceiver(*object);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001356 }
1357 }
1358
1359 if (compile_followup_inline) {
1360 // Compile the interceptor call, followed by inline code to load the
1361 // property from further up the prototype chain if the call fails.
1362 // Check that the maps haven't changed.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001363 ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001364
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001365 // Preserve the receiver register explicitly whenever it is different from
1366 // the holder and it is needed should the interceptor return without any
1367 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1368 // the FIELD case might cause a miss during the prototype check.
1369 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001370 bool must_preserve_receiver_reg = !receiver().is(holder_reg) &&
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001371 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1372
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001373 // Save necessary data before invoking an interceptor.
1374 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001375 {
1376 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001377 if (must_preserve_receiver_reg) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001378 __ Push(receiver(), holder_reg, this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001379 } else {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001380 __ Push(holder_reg, this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001381 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001382 // Invoke an interceptor. Note: map checks from receiver to
1383 // interceptor's holder has been compiled before (see a caller
1384 // of this method).
1385 CompileCallLoadPropertyWithInterceptor(masm(),
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001386 receiver(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001387 holder_reg,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001388 this->name(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001389 interceptor_holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001390 // Check if interceptor provided a value for property. If it's
1391 // the case, return immediately.
1392 Label interceptor_failed;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001393 __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
1394 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001395 frame_scope.GenerateLeaveFrame();
1396 __ Ret();
1397
1398 __ bind(&interceptor_failed);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001399 __ pop(this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001400 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001401 if (must_preserve_receiver_reg) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001402 __ pop(receiver());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001403 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001404 // Leave the internal frame.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001405 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001406 GenerateLoadPostInterceptor(holder_reg, interceptor_holder, name, lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001407 } else { // !compile_followup_inline
1408 // Call the runtime system to load the interceptor.
1409 // Check that the maps haven't changed.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001410 PushInterceptorArguments(masm(), receiver(), holder_reg,
1411 this->name(), interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001412
1413 ExternalReference ref = ExternalReference(
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001414 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001415 __ TailCallExternalReference(ref, 6, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001416 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001417}
1418
1419
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001420void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001421 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001422 __ Branch(miss, ne, a2, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001423 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001424}
1425
1426
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001427void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1428 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001429 Handle<Name> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001430 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001431 ASSERT(holder->IsGlobalObject());
1432
1433 // Get the number of arguments.
1434 const int argc = arguments().immediate();
1435
1436 // Get the receiver from the stack.
1437 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1438
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001439 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001440 __ JumpIfSmi(a0, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001441 CheckPrototypes(object, a0, holder, a3, a1, t0, name, miss);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001442}
1443
1444
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001445void CallStubCompiler::GenerateLoadFunctionFromCell(
1446 Handle<JSGlobalPropertyCell> cell,
1447 Handle<JSFunction> function,
1448 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001449 // Get the value from the cell.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001450 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001451 __ lw(a1, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
1452
1453 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001454 if (heap()->InNewSpace(*function)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001455 // We can't embed a pointer to a function in new space so we have
1456 // to verify that the shared function info is unchanged. This has
1457 // the nice side effect that multiple closures based on the same
1458 // function can all use this call IC. Before we load through the
1459 // function, we have to verify that it still is a function.
1460 __ JumpIfSmi(a1, miss);
1461 __ GetObjectType(a1, a3, a3);
1462 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
1463
1464 // Check the shared function info. Make sure it hasn't changed.
1465 __ li(a3, Handle<SharedFunctionInfo>(function->shared()));
1466 __ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
1467 __ Branch(miss, ne, t0, Operand(a3));
1468 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001469 __ Branch(miss, ne, a1, Operand(function));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001470 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001471}
1472
1473
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001474void CallStubCompiler::GenerateMissBranch() {
1475 Handle<Code> code =
danno@chromium.org40cb8782011-05-25 07:58:50 +00001476 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1477 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001478 extra_state_);
1479 __ Jump(code, RelocInfo::CODE_TARGET);
1480}
1481
1482
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001483Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1484 Handle<JSObject> holder,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001485 PropertyIndex index,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001486 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001487 // ----------- S t a t e -------------
1488 // -- a2 : name
1489 // -- ra : return address
1490 // -----------------------------------
1491 Label miss;
1492
1493 GenerateNameCheck(name, &miss);
1494
1495 const int argc = arguments().immediate();
1496
1497 // Get the receiver of the function from the stack into a0.
1498 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1499 // Check that the receiver isn't a smi.
1500 __ JumpIfSmi(a0, &miss, t0);
1501
1502 // Do the right check and compute the holder register.
1503 Register reg = CheckPrototypes(object, a0, holder, a1, a3, t0, name, &miss);
1504 GenerateFastPropertyLoad(masm(), a1, reg, holder, index);
1505
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001506 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001507
1508 // Handle call cache miss.
1509 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001510 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001511
1512 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001513 return GetCode(Code::FIELD, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001514}
1515
1516
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001517Handle<Code> CallStubCompiler::CompileArrayPushCall(
1518 Handle<Object> object,
1519 Handle<JSObject> holder,
1520 Handle<JSGlobalPropertyCell> cell,
1521 Handle<JSFunction> function,
1522 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001523 // ----------- S t a t e -------------
1524 // -- a2 : name
1525 // -- ra : return address
1526 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1527 // -- ...
1528 // -- sp[argc * 4] : receiver
1529 // -----------------------------------
1530
1531 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001532 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001533
1534 Label miss;
1535
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001536 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001537
1538 Register receiver = a1;
1539
1540 // Get the receiver from the stack.
1541 const int argc = arguments().immediate();
1542 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1543
1544 // Check that the receiver isn't a smi.
1545 __ JumpIfSmi(receiver, &miss);
1546
1547 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001548 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, a3, v0, t0,
1549 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001550
1551 if (argc == 0) {
1552 // Nothing to do, just return the length.
1553 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1554 __ Drop(argc + 1);
1555 __ Ret();
1556 } else {
1557 Label call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001558 if (argc == 1) { // Otherwise fall through to call the builtin.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001559 Label attempt_to_grow_elements, with_write_barrier, check_double;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001560
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001561 Register elements = t2;
1562 Register end_elements = t1;
1563 // Get the elements array of the object.
1564 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1565
1566 // Check that the elements are in fast mode and writable.
1567 __ CheckMap(elements,
1568 v0,
1569 Heap::kFixedArrayMapRootIndex,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001570 &check_double,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001571 DONT_DO_SMI_CHECK);
1572
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001573 // Get the array's length into v0 and calculate new length.
1574 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1575 STATIC_ASSERT(kSmiTagSize == 1);
1576 STATIC_ASSERT(kSmiTag == 0);
1577 __ Addu(v0, v0, Operand(Smi::FromInt(argc)));
1578
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001579 // Get the elements' length.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001580 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1581
1582 // Check if we could survive without allocation.
1583 __ Branch(&attempt_to_grow_elements, gt, v0, Operand(t0));
1584
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001585 // Check if value is a smi.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001586 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1587 __ JumpIfNotSmi(t0, &with_write_barrier);
1588
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001589 // Save new length.
1590 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1591
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001592 // Store the value.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001593 // We may need a register containing the address end_elements below,
1594 // so write back the value in end_elements.
1595 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1596 __ Addu(end_elements, elements, end_elements);
1597 const int kEndElementsOffset =
1598 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001599 __ Addu(end_elements, end_elements, kEndElementsOffset);
1600 __ sw(t0, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001601
1602 // Check for a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001603 __ Drop(argc + 1);
1604 __ Ret();
1605
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001606 __ bind(&check_double);
1607
1608 // Check that the elements are in fast mode and writable.
1609 __ CheckMap(elements,
1610 a0,
1611 Heap::kFixedDoubleArrayMapRootIndex,
1612 &call_builtin,
1613 DONT_DO_SMI_CHECK);
1614
1615 // Get the array's length into r0 and calculate new length.
1616 __ lw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1617 STATIC_ASSERT(kSmiTagSize == 1);
1618 STATIC_ASSERT(kSmiTag == 0);
1619 __ Addu(a0, a0, Operand(Smi::FromInt(argc)));
1620
1621 // Get the elements' length.
1622 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1623
1624 // Check if we could survive without allocation.
1625 __ Branch(&call_builtin, gt, a0, Operand(t0));
1626
1627 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1628 __ StoreNumberToDoubleElements(
1629 t0, a0, elements, a3, t1, a2, t5,
1630 &call_builtin, argc * kDoubleSize);
1631
1632 // Save new length.
1633 __ sw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1634
1635 // Check for a smi.
1636 __ Drop(argc + 1);
1637 __ Ret();
1638
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001639 __ bind(&with_write_barrier);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001640
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001641 __ lw(a3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1642
1643 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
1644 Label fast_object, not_fast_object;
1645 __ CheckFastObjectElements(a3, t3, &not_fast_object);
1646 __ jmp(&fast_object);
1647 // In case of fast smi-only, convert to fast object, otherwise bail out.
1648 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001649 __ CheckFastSmiElements(a3, t3, &call_builtin);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001650
1651 __ lw(t3, FieldMemOperand(t0, HeapObject::kMapOffset));
1652 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
1653 __ Branch(&call_builtin, eq, t3, Operand(at));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001654 // edx: receiver
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001655 // a3: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001656 Label try_holey_map;
1657 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001658 FAST_ELEMENTS,
1659 a3,
1660 t3,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001661 &try_holey_map);
1662 __ mov(a2, receiver);
1663 ElementsTransitionGenerator::
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001664 GenerateMapChangeElementsTransition(masm(),
1665 DONT_TRACK_ALLOCATION_SITE,
1666 NULL);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001667 __ jmp(&fast_object);
1668
1669 __ bind(&try_holey_map);
1670 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1671 FAST_HOLEY_ELEMENTS,
1672 a3,
1673 t3,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001674 &call_builtin);
1675 __ mov(a2, receiver);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001676 ElementsTransitionGenerator::
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001677 GenerateMapChangeElementsTransition(masm(),
1678 DONT_TRACK_ALLOCATION_SITE,
1679 NULL);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001680 __ bind(&fast_object);
1681 } else {
1682 __ CheckFastObjectElements(a3, a3, &call_builtin);
1683 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001684
1685 // Save new length.
1686 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1687
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001688 // Store the value.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001689 // We may need a register containing the address end_elements below,
1690 // so write back the value in end_elements.
1691 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1692 __ Addu(end_elements, elements, end_elements);
1693 __ Addu(end_elements, end_elements, kEndElementsOffset);
1694 __ sw(t0, MemOperand(end_elements));
1695
1696 __ RecordWrite(elements,
1697 end_elements,
1698 t0,
1699 kRAHasNotBeenSaved,
1700 kDontSaveFPRegs,
1701 EMIT_REMEMBERED_SET,
1702 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001703 __ Drop(argc + 1);
1704 __ Ret();
1705
1706 __ bind(&attempt_to_grow_elements);
1707 // v0: array's length + 1.
1708 // t0: elements' length.
1709
1710 if (!FLAG_inline_new) {
1711 __ Branch(&call_builtin);
1712 }
1713
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001714 __ lw(a2, MemOperand(sp, (argc - 1) * kPointerSize));
1715 // Growing elements that are SMI-only requires special handling in case
1716 // the new element is non-Smi. For now, delegate to the builtin.
1717 Label no_fast_elements_check;
1718 __ JumpIfSmi(a2, &no_fast_elements_check);
1719 __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1720 __ CheckFastObjectElements(t3, t3, &call_builtin);
1721 __ bind(&no_fast_elements_check);
1722
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001723 ExternalReference new_space_allocation_top =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001724 ExternalReference::new_space_allocation_top_address(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001725 ExternalReference new_space_allocation_limit =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001726 ExternalReference::new_space_allocation_limit_address(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001727
1728 const int kAllocationDelta = 4;
1729 // Load top and check if it is the end of elements.
1730 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1731 __ Addu(end_elements, elements, end_elements);
1732 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset));
1733 __ li(t3, Operand(new_space_allocation_top));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001734 __ lw(a3, MemOperand(t3));
1735 __ Branch(&call_builtin, ne, end_elements, Operand(a3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001736
1737 __ li(t5, Operand(new_space_allocation_limit));
1738 __ lw(t5, MemOperand(t5));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001739 __ Addu(a3, a3, Operand(kAllocationDelta * kPointerSize));
1740 __ Branch(&call_builtin, hi, a3, Operand(t5));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001741
1742 // We fit and could grow elements.
1743 // Update new_space_allocation_top.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001744 __ sw(a3, MemOperand(t3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001745 // Push the argument.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001746 __ sw(a2, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001747 // Fill the rest with holes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001748 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001749 for (int i = 1; i < kAllocationDelta; i++) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001750 __ sw(a3, MemOperand(end_elements, i * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001751 }
1752
1753 // Update elements' and array's sizes.
1754 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1755 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta)));
1756 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1757
1758 // Elements are in new space, so write barrier is not required.
1759 __ Drop(argc + 1);
1760 __ Ret();
1761 }
1762 __ bind(&call_builtin);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001763 __ TailCallExternalReference(
1764 ExternalReference(Builtins::c_ArrayPush, isolate()), argc + 1, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001765 }
1766
1767 // Handle call cache miss.
1768 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001769 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001770
1771 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001772 return GetCode(function);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001773}
1774
1775
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001776Handle<Code> CallStubCompiler::CompileArrayPopCall(
1777 Handle<Object> object,
1778 Handle<JSObject> holder,
1779 Handle<JSGlobalPropertyCell> cell,
1780 Handle<JSFunction> function,
1781 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001782 // ----------- S t a t e -------------
1783 // -- a2 : name
1784 // -- ra : return address
1785 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1786 // -- ...
1787 // -- sp[argc * 4] : receiver
1788 // -----------------------------------
1789
1790 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001791 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001792
1793 Label miss, return_undefined, call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001794 Register receiver = a1;
1795 Register elements = a3;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001796 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001797
1798 // Get the receiver from the stack.
1799 const int argc = arguments().immediate();
1800 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001801 // Check that the receiver isn't a smi.
1802 __ JumpIfSmi(receiver, &miss);
1803
1804 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001805 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, elements,
1806 t0, v0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001807
1808 // Get the elements array of the object.
1809 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1810
1811 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001812 __ CheckMap(elements,
1813 v0,
1814 Heap::kFixedArrayMapRootIndex,
1815 &call_builtin,
1816 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001817
1818 // Get the array's length into t0 and calculate new length.
1819 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1820 __ Subu(t0, t0, Operand(Smi::FromInt(1)));
1821 __ Branch(&return_undefined, lt, t0, Operand(zero_reg));
1822
1823 // Get the last element.
1824 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1825 STATIC_ASSERT(kSmiTagSize == 1);
1826 STATIC_ASSERT(kSmiTag == 0);
1827 // We can't address the last element in one operation. Compute the more
1828 // expensive shift first, and use an offset later on.
1829 __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize);
1830 __ Addu(elements, elements, t1);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001831 __ lw(v0, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001832 __ Branch(&call_builtin, eq, v0, Operand(t2));
1833
1834 // Set the array's length.
1835 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1836
1837 // Fill with the hole.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001838 __ sw(t2, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001839 __ Drop(argc + 1);
1840 __ Ret();
1841
1842 __ bind(&return_undefined);
1843 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
1844 __ Drop(argc + 1);
1845 __ Ret();
1846
1847 __ bind(&call_builtin);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001848 __ TailCallExternalReference(
1849 ExternalReference(Builtins::c_ArrayPop, isolate()), argc + 1, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001850
1851 // Handle call cache miss.
1852 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001853 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001854
1855 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001856 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001857}
1858
1859
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001860Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1861 Handle<Object> object,
1862 Handle<JSObject> holder,
1863 Handle<JSGlobalPropertyCell> cell,
1864 Handle<JSFunction> function,
1865 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001866 // ----------- S t a t e -------------
1867 // -- a2 : function name
1868 // -- ra : return address
1869 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1870 // -- ...
1871 // -- sp[argc * 4] : receiver
1872 // -----------------------------------
1873
1874 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001875 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001876
1877 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001878 Label miss;
1879 Label name_miss;
1880 Label index_out_of_range;
1881
1882 Label* index_out_of_range_label = &index_out_of_range;
1883
danno@chromium.org40cb8782011-05-25 07:58:50 +00001884 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001885 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001886 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001887 index_out_of_range_label = &miss;
1888 }
1889
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001890 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001891
1892 // Check that the maps starting from the prototype haven't changed.
1893 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1894 Context::STRING_FUNCTION_INDEX,
1895 v0,
1896 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001897 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001898 CheckPrototypes(
1899 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
1900 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001901
1902 Register receiver = a1;
1903 Register index = t1;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001904 Register result = v0;
1905 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1906 if (argc > 0) {
1907 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1908 } else {
1909 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1910 }
1911
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001912 StringCharCodeAtGenerator generator(receiver,
1913 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001914 result,
1915 &miss, // When not a string.
1916 &miss, // When not a number.
1917 index_out_of_range_label,
1918 STRING_INDEX_IS_NUMBER);
1919 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001920 __ Drop(argc + 1);
1921 __ Ret();
1922
1923 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001924 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001925
1926 if (index_out_of_range.is_linked()) {
1927 __ bind(&index_out_of_range);
1928 __ LoadRoot(v0, Heap::kNanValueRootIndex);
1929 __ Drop(argc + 1);
1930 __ Ret();
1931 }
1932
1933 __ bind(&miss);
1934 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001935 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001936 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001937 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001938
1939 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001940 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001941}
1942
1943
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001944Handle<Code> CallStubCompiler::CompileStringCharAtCall(
1945 Handle<Object> object,
1946 Handle<JSObject> holder,
1947 Handle<JSGlobalPropertyCell> cell,
1948 Handle<JSFunction> function,
1949 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001950 // ----------- S t a t e -------------
1951 // -- a2 : function name
1952 // -- ra : return address
1953 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1954 // -- ...
1955 // -- sp[argc * 4] : receiver
1956 // -----------------------------------
1957
1958 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001959 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001960
1961 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001962 Label miss;
1963 Label name_miss;
1964 Label index_out_of_range;
1965 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00001966 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001967 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001968 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001969 index_out_of_range_label = &miss;
1970 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001971 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001972
1973 // Check that the maps starting from the prototype haven't changed.
1974 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1975 Context::STRING_FUNCTION_INDEX,
1976 v0,
1977 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001978 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001979 CheckPrototypes(
1980 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
1981 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001982
1983 Register receiver = v0;
1984 Register index = t1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001985 Register scratch = a3;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001986 Register result = v0;
1987 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1988 if (argc > 0) {
1989 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1990 } else {
1991 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1992 }
1993
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001994 StringCharAtGenerator generator(receiver,
1995 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00001996 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001997 result,
1998 &miss, // When not a string.
1999 &miss, // When not a number.
2000 index_out_of_range_label,
2001 STRING_INDEX_IS_NUMBER);
2002 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002003 __ Drop(argc + 1);
2004 __ Ret();
2005
2006 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002007 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002008
2009 if (index_out_of_range.is_linked()) {
2010 __ bind(&index_out_of_range);
ulan@chromium.org750145a2013-03-07 15:14:13 +00002011 __ LoadRoot(v0, Heap::kempty_stringRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002012 __ Drop(argc + 1);
2013 __ Ret();
2014 }
2015
2016 __ bind(&miss);
2017 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002018 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002019 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002020 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002021
2022 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002023 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002024}
2025
2026
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002027Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
2028 Handle<Object> object,
2029 Handle<JSObject> holder,
2030 Handle<JSGlobalPropertyCell> cell,
2031 Handle<JSFunction> function,
2032 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002033 // ----------- S t a t e -------------
2034 // -- a2 : function name
2035 // -- ra : return address
2036 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2037 // -- ...
2038 // -- sp[argc * 4] : receiver
2039 // -----------------------------------
2040
2041 const int argc = arguments().immediate();
2042
2043 // If the object is not a JSObject or we got an unexpected number of
2044 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002045 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002046
2047 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002048 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002049
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002050 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002051 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
2052
2053 STATIC_ASSERT(kSmiTag == 0);
2054 __ JumpIfSmi(a1, &miss);
2055
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002056 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2057 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002058 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002059 ASSERT(cell->value() == *function);
2060 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2061 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002062 GenerateLoadFunctionFromCell(cell, function, &miss);
2063 }
2064
2065 // Load the char code argument.
2066 Register code = a1;
2067 __ lw(code, MemOperand(sp, 0 * kPointerSize));
2068
2069 // Check the code is a smi.
2070 Label slow;
2071 STATIC_ASSERT(kSmiTag == 0);
2072 __ JumpIfNotSmi(code, &slow);
2073
2074 // Convert the smi code to uint16.
2075 __ And(code, code, Operand(Smi::FromInt(0xffff)));
2076
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002077 StringCharFromCodeGenerator generator(code, v0);
2078 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002079 __ Drop(argc + 1);
2080 __ Ret();
2081
2082 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002083 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002084
2085 // Tail call the full function. We do not have to patch the receiver
2086 // because the function makes no use of it.
2087 __ bind(&slow);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002088 ParameterCount expected(function);
2089 __ InvokeFunction(function, expected, arguments(),
2090 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002091
2092 __ bind(&miss);
2093 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002094 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002095
2096 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002097 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002098}
2099
2100
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002101Handle<Code> CallStubCompiler::CompileMathFloorCall(
2102 Handle<Object> object,
2103 Handle<JSObject> holder,
2104 Handle<JSGlobalPropertyCell> cell,
2105 Handle<JSFunction> function,
2106 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002107 // ----------- S t a t e -------------
2108 // -- a2 : function name
2109 // -- ra : return address
2110 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2111 // -- ...
2112 // -- sp[argc * 4] : receiver
2113 // -----------------------------------
2114
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002115
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002116 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002117 // If the object is not a JSObject or we got an unexpected number of
2118 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002119 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002120
2121 Label miss, slow;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002122 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002123
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002124 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002125 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002126 STATIC_ASSERT(kSmiTag == 0);
2127 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002128 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2129 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002130 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002131 ASSERT(cell->value() == *function);
2132 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2133 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002134 GenerateLoadFunctionFromCell(cell, function, &miss);
2135 }
2136
2137 // Load the (only) argument into v0.
2138 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2139
2140 // If the argument is a smi, just return.
2141 STATIC_ASSERT(kSmiTag == 0);
2142 __ And(t0, v0, Operand(kSmiTagMask));
2143 __ Drop(argc + 1, eq, t0, Operand(zero_reg));
2144 __ Ret(eq, t0, Operand(zero_reg));
2145
danno@chromium.org40cb8782011-05-25 07:58:50 +00002146 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002147
2148 Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return;
2149
2150 // If fpu is enabled, we use the floor instruction.
2151
2152 // Load the HeapNumber value.
2153 __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2154
2155 // Backup FCSR.
2156 __ cfc1(a3, FCSR);
2157 // Clearing FCSR clears the exception mask with no side-effects.
2158 __ ctc1(zero_reg, FCSR);
2159 // Convert the argument to an integer.
2160 __ floor_w_d(f0, f0);
2161
2162 // Start checking for special cases.
2163 // Get the argument exponent and clear the sign bit.
2164 __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize));
2165 __ And(t2, t1, Operand(~HeapNumber::kSignMask));
2166 __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord);
2167
2168 // Retrieve FCSR and check for fpu errors.
2169 __ cfc1(t5, FCSR);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002170 __ And(t5, t5, Operand(kFCSRExceptionFlagMask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002171 __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));
2172
2173 // Check for NaN, Infinity, and -Infinity.
2174 // They are invariant through a Math.Floor call, so just
2175 // return the original argument.
2176 __ Subu(t3, t2, Operand(HeapNumber::kExponentMask
2177 >> HeapNumber::kMantissaBitsInTopWord));
2178 __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg));
2179 // We had an overflow or underflow in the conversion. Check if we
2180 // have a big exponent.
2181 // If greater or equal, the argument is already round and in v0.
2182 __ Branch(&restore_fcsr_and_return, ge, t3,
2183 Operand(HeapNumber::kMantissaBits));
2184 __ Branch(&wont_fit_smi);
2185
2186 __ bind(&no_fpu_error);
2187 // Move the result back to v0.
2188 __ mfc1(v0, f0);
2189 // Check if the result fits into a smi.
2190 __ Addu(a1, v0, Operand(0x40000000));
2191 __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg));
2192 // Tag the result.
2193 STATIC_ASSERT(kSmiTag == 0);
2194 __ sll(v0, v0, kSmiTagSize);
2195
2196 // Check for -0.
2197 __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg));
2198 // t1 already holds the HeapNumber exponent.
2199 __ And(t0, t1, Operand(HeapNumber::kSignMask));
2200 // If our HeapNumber is negative it was -0, so load its address and return.
2201 // Else v0 is loaded with 0, so we can also just return.
2202 __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg));
2203 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2204
2205 __ bind(&restore_fcsr_and_return);
2206 // Restore FCSR and return.
2207 __ ctc1(a3, FCSR);
2208
2209 __ Drop(argc + 1);
2210 __ Ret();
2211
2212 __ bind(&wont_fit_smi);
2213 // Restore FCSR and fall to slow case.
2214 __ ctc1(a3, FCSR);
2215
2216 __ bind(&slow);
2217 // Tail call the full function. We do not have to patch the receiver
2218 // because the function makes no use of it.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002219 ParameterCount expected(function);
2220 __ InvokeFunction(function, expected, arguments(),
2221 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002222
2223 __ bind(&miss);
2224 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002225 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002226
2227 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002228 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002229}
2230
2231
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002232Handle<Code> CallStubCompiler::CompileMathAbsCall(
2233 Handle<Object> object,
2234 Handle<JSObject> holder,
2235 Handle<JSGlobalPropertyCell> cell,
2236 Handle<JSFunction> function,
2237 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002238 // ----------- S t a t e -------------
2239 // -- a2 : function name
2240 // -- ra : return address
2241 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2242 // -- ...
2243 // -- sp[argc * 4] : receiver
2244 // -----------------------------------
2245
2246 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002247 // If the object is not a JSObject or we got an unexpected number of
2248 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002249 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002250
2251 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002252
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002253 GenerateNameCheck(name, &miss);
2254 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002255 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002256 STATIC_ASSERT(kSmiTag == 0);
2257 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002258 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2259 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002260 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002261 ASSERT(cell->value() == *function);
2262 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2263 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002264 GenerateLoadFunctionFromCell(cell, function, &miss);
2265 }
2266
2267 // Load the (only) argument into v0.
2268 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2269
2270 // Check if the argument is a smi.
2271 Label not_smi;
2272 STATIC_ASSERT(kSmiTag == 0);
2273 __ JumpIfNotSmi(v0, &not_smi);
2274
2275 // Do bitwise not or do nothing depending on the sign of the
2276 // argument.
2277 __ sra(t0, v0, kBitsPerInt - 1);
2278 __ Xor(a1, v0, t0);
2279
2280 // Add 1 or do nothing depending on the sign of the argument.
2281 __ Subu(v0, a1, t0);
2282
2283 // If the result is still negative, go to the slow case.
2284 // This only happens for the most negative smi.
2285 Label slow;
2286 __ Branch(&slow, lt, v0, Operand(zero_reg));
2287
2288 // Smi case done.
2289 __ Drop(argc + 1);
2290 __ Ret();
2291
2292 // Check if the argument is a heap number and load its exponent and
2293 // sign.
2294 __ bind(&not_smi);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002295 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002296 __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2297
2298 // Check the sign of the argument. If the argument is positive,
2299 // just return it.
2300 Label negative_sign;
2301 __ And(t0, a1, Operand(HeapNumber::kSignMask));
2302 __ Branch(&negative_sign, ne, t0, Operand(zero_reg));
2303 __ Drop(argc + 1);
2304 __ Ret();
2305
2306 // If the argument is negative, clear the sign, and return a new
2307 // number.
2308 __ bind(&negative_sign);
2309 __ Xor(a1, a1, Operand(HeapNumber::kSignMask));
2310 __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2311 __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
2312 __ AllocateHeapNumber(v0, t0, t1, t2, &slow);
2313 __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2314 __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2315 __ Drop(argc + 1);
2316 __ Ret();
2317
2318 // Tail call the full function. We do not have to patch the receiver
2319 // because the function makes no use of it.
2320 __ bind(&slow);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002321 ParameterCount expected(function);
2322 __ InvokeFunction(function, expected, arguments(),
2323 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002324
2325 __ bind(&miss);
2326 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002327 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002328
2329 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002330 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002331}
2332
2333
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002334Handle<Code> CallStubCompiler::CompileFastApiCall(
lrn@chromium.org7516f052011-03-30 08:52:27 +00002335 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002336 Handle<Object> object,
2337 Handle<JSObject> holder,
2338 Handle<JSGlobalPropertyCell> cell,
2339 Handle<JSFunction> function,
2340 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002341
danno@chromium.org40cb8782011-05-25 07:58:50 +00002342 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002343
2344 ASSERT(optimization.is_simple_api_call());
2345 // Bail out if object is a global object as we don't want to
2346 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002347 if (object->IsGlobalObject()) return Handle<Code>::null();
2348 if (!cell.is_null()) return Handle<Code>::null();
2349 if (!object->IsJSObject()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002350 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002351 Handle<JSObject>::cast(object), holder);
2352 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002353
2354 Label miss, miss_before_stack_reserved;
2355
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002356 GenerateNameCheck(name, &miss_before_stack_reserved);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002357
2358 // Get the receiver from the stack.
2359 const int argc = arguments().immediate();
2360 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2361
2362 // Check that the receiver isn't a smi.
2363 __ JumpIfSmi(a1, &miss_before_stack_reserved);
2364
2365 __ IncrementCounter(counters->call_const(), 1, a0, a3);
2366 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2367
2368 ReserveSpaceForFastApiCall(masm(), a0);
2369
2370 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002371 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002372 depth, &miss);
2373
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002374 GenerateFastApiDirectCall(masm(), optimization, argc);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002375
2376 __ bind(&miss);
2377 FreeSpaceForFastApiCall(masm());
2378
2379 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002380 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002381
2382 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002383 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002384}
2385
2386
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002387void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
2388 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002389 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002390 CheckType check,
2391 Label* success) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002392 // ----------- S t a t e -------------
2393 // -- a2 : name
2394 // -- ra : return address
2395 // -----------------------------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002396 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002397 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002398
2399 // Get the receiver from the stack.
2400 const int argc = arguments().immediate();
2401 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2402
2403 // Check that the receiver isn't a smi.
2404 if (check != NUMBER_CHECK) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002405 __ JumpIfSmi(a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002406 }
2407
2408 // Make sure that it's okay not to patch the on stack receiver
2409 // unless we're doing a receiver map check.
2410 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002411 switch (check) {
2412 case RECEIVER_MAP_CHECK:
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002413 __ IncrementCounter(isolate()->counters()->call_const(), 1, a0, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002414
2415 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002416 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2417 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002418
2419 // Patch the receiver on the stack with the global proxy if
2420 // necessary.
2421 if (object->IsGlobalObject()) {
2422 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2423 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2424 }
2425 break;
2426
2427 case STRING_CHECK:
ulan@chromium.org750145a2013-03-07 15:14:13 +00002428 // Check that the object is a string.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002429 __ GetObjectType(a1, a3, a3);
2430 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2431 // Check that the maps starting from the prototype haven't changed.
2432 GenerateDirectLoadGlobalFunctionPrototype(
2433 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
2434 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002435 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002436 a0, holder, a3, a1, t0, name, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002437 break;
2438
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002439 case SYMBOL_CHECK:
2440 // Check that the object is a symbol.
2441 __ GetObjectType(a1, a1, a3);
2442 __ Branch(&miss, ne, a3, Operand(SYMBOL_TYPE));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002443 // Check that the maps starting from the prototype haven't changed.
2444 GenerateDirectLoadGlobalFunctionPrototype(
2445 masm(), Context::SYMBOL_FUNCTION_INDEX, a0, &miss);
2446 CheckPrototypes(
2447 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2448 a0, holder, a3, a1, t0, name, &miss);
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002449 break;
2450
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002451 case NUMBER_CHECK: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002452 Label fast;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002453 // Check that the object is a smi or a heap number.
2454 __ JumpIfSmi(a1, &fast);
2455 __ GetObjectType(a1, a0, a0);
2456 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
2457 __ bind(&fast);
2458 // Check that the maps starting from the prototype haven't changed.
2459 GenerateDirectLoadGlobalFunctionPrototype(
2460 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
2461 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002462 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002463 a0, holder, a3, a1, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002464 break;
2465 }
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002466 case BOOLEAN_CHECK: {
2467 Label fast;
2468 // Check that the object is a boolean.
2469 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
2470 __ Branch(&fast, eq, a1, Operand(t0));
2471 __ LoadRoot(t0, Heap::kFalseValueRootIndex);
2472 __ Branch(&miss, ne, a1, Operand(t0));
2473 __ bind(&fast);
2474 // Check that the maps starting from the prototype haven't changed.
2475 GenerateDirectLoadGlobalFunctionPrototype(
2476 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
2477 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002478 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002479 a0, holder, a3, a1, t0, name, &miss);
2480 break;
2481 }
2482 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002483
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002484 __ jmp(success);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002485
2486 // Handle call cache miss.
2487 __ bind(&miss);
2488
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002489 GenerateMissBranch();
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002490}
2491
2492
2493void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) {
2494 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
2495 ? CALL_AS_FUNCTION
2496 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002497 ParameterCount expected(function);
2498 __ InvokeFunction(function, expected, arguments(),
2499 JUMP_FUNCTION, NullCallWrapper(), call_kind);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002500}
2501
2502
2503Handle<Code> CallStubCompiler::CompileCallConstant(
2504 Handle<Object> object,
2505 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002506 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002507 CheckType check,
2508 Handle<JSFunction> function) {
2509 if (HasCustomCallGenerator(function)) {
2510 Handle<Code> code = CompileCustomCall(object, holder,
2511 Handle<JSGlobalPropertyCell>::null(),
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002512 function, Handle<String>::cast(name));
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002513 // A null handle means bail out to the regular compiler code below.
2514 if (!code.is_null()) return code;
2515 }
2516
2517 Label success;
2518
2519 CompileHandlerFrontend(object, holder, name, check, &success);
2520 __ bind(&success);
2521 CompileHandlerBackend(function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002522
2523 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002524 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002525}
2526
2527
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002528Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2529 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002530 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002531 // ----------- S t a t e -------------
2532 // -- a2 : name
2533 // -- ra : return address
2534 // -----------------------------------
2535
2536 Label miss;
2537
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002538 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002539
2540 // Get the number of arguments.
2541 const int argc = arguments().immediate();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002542 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002543 LookupPostInterceptor(holder, name, &lookup);
2544
2545 // Get the receiver from the stack.
2546 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2547
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002548 CallInterceptorCompiler compiler(this, arguments(), a2, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002549 compiler.Compile(masm(), object, holder, name, &lookup, a1, a3, t0, a0,
2550 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002551
2552 // Move returned value, the function to call, to a1.
2553 __ mov(a1, v0);
2554 // Restore receiver.
2555 __ lw(a0, MemOperand(sp, argc * kPointerSize));
2556
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002557 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002558
2559 // Handle call cache miss.
2560 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002561 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002562
2563 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002564 return GetCode(Code::INTERCEPTOR, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002565}
2566
2567
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002568Handle<Code> CallStubCompiler::CompileCallGlobal(
2569 Handle<JSObject> object,
2570 Handle<GlobalObject> holder,
2571 Handle<JSGlobalPropertyCell> cell,
2572 Handle<JSFunction> function,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002573 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002574 // ----------- S t a t e -------------
2575 // -- a2 : name
2576 // -- ra : return address
2577 // -----------------------------------
2578
2579 if (HasCustomCallGenerator(function)) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002580 Handle<Code> code = CompileCustomCall(
2581 object, holder, cell, function, Handle<String>::cast(name));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002582 // A null handle means bail out to the regular compiler code below.
2583 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002584 }
2585
2586 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002587 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002588
2589 // Get the number of arguments.
2590 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002591 GenerateGlobalReceiverCheck(object, holder, name, &miss);
2592 GenerateLoadFunctionFromCell(cell, function, &miss);
2593
2594 // Patch the receiver on the stack with the global proxy if
2595 // necessary.
2596 if (object->IsGlobalObject()) {
2597 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
2598 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2599 }
2600
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002601 // Set up the context (function already in r1).
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002602 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
2603
2604 // Jump to the cached code (tail call).
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002605 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002606 __ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002607 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002608 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002609 ? CALL_AS_FUNCTION
2610 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002611 // We call indirectly through the code field in the function to
2612 // allow recompilation to take effect without changing any of the
2613 // call sites.
2614 __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
2615 __ InvokeCode(a3, expected, arguments(), JUMP_FUNCTION,
2616 NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002617
2618 // Handle call cache miss.
2619 __ bind(&miss);
2620 __ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002621 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002622
2623 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002624 return GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002625}
2626
2627
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002628Handle<Code> StoreStubCompiler::CompileStoreCallback(
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002629 Handle<Name> name,
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002630 Handle<JSObject> object,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002631 Handle<JSObject> holder,
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002632 Handle<ExecutableAccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002633 Label miss;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002634 // Check that the maps haven't changed.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002635 __ JumpIfSmi(receiver(), &miss);
2636 CheckPrototypes(object, receiver(), holder,
2637 scratch1(), scratch2(), scratch3(), name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002638
2639 // Stub never generated for non-global objects that require access
2640 // checks.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002641 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002642
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002643 __ push(receiver()); // Receiver.
2644 __ li(at, Operand(callback)); // Callback info.
2645 __ Push(at, this->name(), value());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002646
2647 // Do tail-call to the runtime system.
2648 ExternalReference store_callback_property =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002649 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002650 __ TailCallExternalReference(store_callback_property, 4, 1);
2651
2652 // Handle store cache miss.
2653 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002654 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002655
2656 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002657 return GetICCode(kind(), Code::CALLBACKS, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002658}
2659
2660
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002661#undef __
2662#define __ ACCESS_MASM(masm)
2663
2664
2665void StoreStubCompiler::GenerateStoreViaSetter(
2666 MacroAssembler* masm,
2667 Handle<JSFunction> setter) {
2668 // ----------- S t a t e -------------
2669 // -- a0 : value
2670 // -- a1 : receiver
2671 // -- a2 : name
2672 // -- ra : return address
2673 // -----------------------------------
2674 {
2675 FrameScope scope(masm, StackFrame::INTERNAL);
2676
2677 // Save value register, so we can restore it later.
2678 __ push(a0);
2679
2680 if (!setter.is_null()) {
2681 // Call the JavaScript setter with receiver and value on the stack.
2682 __ push(a1);
2683 __ push(a0);
2684 ParameterCount actual(1);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002685 ParameterCount expected(setter);
2686 __ InvokeFunction(setter, expected, actual,
2687 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002688 } else {
2689 // If we generate a global code snippet for deoptimization only, remember
2690 // the place to continue after deoptimization.
2691 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2692 }
2693
2694 // We have to return the passed value, not the return value of the setter.
2695 __ pop(v0);
2696
2697 // Restore context register.
2698 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2699 }
2700 __ Ret();
2701}
2702
2703
2704#undef __
2705#define __ ACCESS_MASM(masm())
2706
2707
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002708Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002709 Handle<JSObject> object,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002710 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002711 Label miss;
2712
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002713 // Check that the map of the object hasn't changed.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002714 __ CheckMap(receiver(), scratch1(), Handle<Map>(object->map()), &miss,
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002715 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002716
2717 // Perform global security token check if needed.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002718 if (object->IsJSGlobalProxy()) {
2719 __ CheckAccessGlobalProxy(receiver(), scratch1(), &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002720 }
2721
2722 // Stub is never generated for non-global objects that require access
2723 // checks.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002724 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002725
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002726 __ Push(receiver(), this->name(), value());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002727
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002728 __ li(scratch1(), Operand(Smi::FromInt(strict_mode())));
2729 __ push(scratch1()); // strict mode
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002730
2731 // Do tail-call to the runtime system.
2732 ExternalReference store_ic_property =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002733 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002734 __ TailCallExternalReference(store_ic_property, 4, 1);
2735
2736 // Handle store cache miss.
2737 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002738 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002739
2740 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002741 return GetICCode(kind(), Code::INTERCEPTOR, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002742}
2743
2744
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002745Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2746 Handle<GlobalObject> object,
2747 Handle<JSGlobalPropertyCell> cell,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002748 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002749 Label miss;
2750
2751 // Check that the map of the global has not changed.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002752 __ lw(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset));
2753 __ Branch(&miss, ne, scratch1(), Operand(Handle<Map>(object->map())));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002754
2755 // Check that the value in the cell is not the hole. If it is, this
2756 // cell could have been deleted and reintroducing the global needs
2757 // to update the property details in the property dictionary of the
2758 // global object. We bail out to the runtime system to do that.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002759 __ li(scratch1(), Operand(cell));
2760 __ LoadRoot(scratch2(), Heap::kTheHoleValueRootIndex);
2761 __ lw(scratch3(),
2762 FieldMemOperand(scratch1(), JSGlobalPropertyCell::kValueOffset));
2763 __ Branch(&miss, eq, scratch3(), Operand(scratch2()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002764
2765 // Store the value in the cell.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002766 __ sw(value(),
2767 FieldMemOperand(scratch1(), JSGlobalPropertyCell::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002768 __ mov(v0, a0); // Stored value must be returned in v0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002769 // Cells are always rescanned, so no write barrier here.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002770
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002771 Counters* counters = isolate()->counters();
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002772 __ IncrementCounter(
2773 counters->named_store_global_inline(), 1, scratch1(), scratch2());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002774 __ Ret();
2775
2776 // Handle store cache miss.
2777 __ bind(&miss);
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002778 __ IncrementCounter(
2779 counters->named_store_global_inline_miss(), 1, scratch1(), scratch2());
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002780 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002781
2782 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002783 return GetICCode(kind(), Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002784}
2785
2786
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002787Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
2788 Handle<JSObject> object,
2789 Handle<JSObject> last,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002790 Handle<Name> name,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002791 Handle<GlobalObject> global) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002792 Label success;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002793
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002794 NonexistentHandlerFrontend(object, last, name, &success, global);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002795
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002796 __ bind(&success);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002797 // Return undefined if maps of the full prototype chain is still the same.
2798 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2799 __ Ret();
2800
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002801 // Return the generated code.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002802 return GetCode(kind(), Code::NONEXISTENT, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002803}
2804
2805
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002806Register* LoadStubCompiler::registers() {
2807 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2808 static Register registers[] = { a0, a2, a3, a1, t0, t1 };
2809 return registers;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002810}
2811
2812
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002813Register* KeyedLoadStubCompiler::registers() {
2814 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2815 static Register registers[] = { a1, a0, a2, a3, t0, t1 };
2816 return registers;
2817}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002818
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002819
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002820Register* StoreStubCompiler::registers() {
2821 // receiver, name, value, scratch1, scratch2, scratch3.
2822 static Register registers[] = { a1, a2, a0, a3, t0, t1 };
2823 return registers;
2824}
2825
2826
2827Register* KeyedStoreStubCompiler::registers() {
2828 // receiver, name, value, scratch1, scratch2, scratch3.
2829 static Register registers[] = { a2, a1, a0, a3, t0, t1 };
2830 return registers;
2831}
2832
2833
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002834void KeyedLoadStubCompiler::GenerateNameCheck(Handle<Name> name,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002835 Register name_reg,
2836 Label* miss) {
2837 __ Branch(miss, ne, name_reg, Operand(name));
lrn@chromium.org7516f052011-03-30 08:52:27 +00002838}
2839
2840
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002841void KeyedStoreStubCompiler::GenerateNameCheck(Handle<Name> name,
2842 Register name_reg,
2843 Label* miss) {
2844 __ Branch(miss, ne, name_reg, Operand(name));
2845}
2846
2847
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002848#undef __
2849#define __ ACCESS_MASM(masm)
2850
2851
2852void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
2853 Handle<JSFunction> getter) {
2854 // ----------- S t a t e -------------
2855 // -- a0 : receiver
2856 // -- a2 : name
2857 // -- ra : return address
2858 // -----------------------------------
2859 {
2860 FrameScope scope(masm, StackFrame::INTERNAL);
2861
2862 if (!getter.is_null()) {
2863 // Call the JavaScript getter with the receiver on the stack.
2864 __ push(a0);
2865 ParameterCount actual(0);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002866 ParameterCount expected(getter);
2867 __ InvokeFunction(getter, expected, actual,
2868 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002869 } else {
2870 // If we generate a global code snippet for deoptimization only, remember
2871 // the place to continue after deoptimization.
2872 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
2873 }
2874
2875 // Restore context register.
2876 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2877 }
2878 __ Ret();
2879}
2880
2881
2882#undef __
2883#define __ ACCESS_MASM(masm())
2884
2885
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002886Handle<Code> LoadStubCompiler::CompileLoadGlobal(
2887 Handle<JSObject> object,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002888 Handle<GlobalObject> global,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002889 Handle<JSGlobalPropertyCell> cell,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002890 Handle<Name> name,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002891 bool is_dont_delete) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002892 Label success, miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002893
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002894 __ CheckMap(
2895 receiver(), scratch1(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
2896 HandlerFrontendHeader(
2897 object, receiver(), Handle<JSObject>::cast(global), name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002898
2899 // Get the value from the cell.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002900 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002901 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
2902
2903 // Check for deleted property if property can actually be deleted.
2904 if (!is_dont_delete) {
2905 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
2906 __ Branch(&miss, eq, t0, Operand(at));
2907 }
2908
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002909 HandlerFrontendFooter(&success, &miss);
2910 __ bind(&success);
2911
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002912 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002913 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002914 __ mov(v0, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002915 __ Ret();
2916
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002917 // Return the generated code.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002918 return GetICCode(kind(), Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002919}
2920
2921
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002922Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002923 MapHandleList* receiver_maps,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002924 CodeHandleList* handlers,
2925 Handle<Name> name,
2926 Code::StubType type,
2927 IcCheckType check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002928 Label miss;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002929
2930 if (check == PROPERTY) {
2931 GenerateNameCheck(name, this->name(), &miss);
2932 }
2933
2934 __ JumpIfSmi(receiver(), &miss);
2935 Register map_reg = scratch1();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002936
danno@chromium.org40cb8782011-05-25 07:58:50 +00002937 int receiver_count = receiver_maps->length();
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002938 __ lw(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00002939 for (int current = 0; current < receiver_count; ++current) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002940 __ Jump(handlers->at(current), RelocInfo::CODE_TARGET,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002941 eq, map_reg, Operand(receiver_maps->at(current)));
danno@chromium.org40cb8782011-05-25 07:58:50 +00002942 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002943
2944 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002945 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002946
2947 // Return the generated code.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002948 InlineCacheState state =
2949 receiver_maps->length() > 1 ? POLYMORPHIC : MONOMORPHIC;
2950 return GetICCode(kind(), type, name, state);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002951}
2952
2953
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002954Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
2955 MapHandleList* receiver_maps,
2956 CodeHandleList* handler_stubs,
2957 MapHandleList* transitioned_maps) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00002958 Label miss;
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002959 __ JumpIfSmi(receiver(), &miss);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002960
2961 int receiver_count = receiver_maps->length();
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002962 __ lw(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002963 for (int i = 0; i < receiver_count; ++i) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002964 if (transitioned_maps->at(i).is_null()) {
2965 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq,
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002966 scratch1(), Operand(receiver_maps->at(i)));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002967 } else {
2968 Label next_map;
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002969 __ Branch(&next_map, ne, scratch1(), Operand(receiver_maps->at(i)));
2970 __ li(transition_map(), Operand(transitioned_maps->at(i)));
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002971 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002972 __ bind(&next_map);
2973 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00002974 }
2975
2976 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002977 TailCallBuiltin(masm(), MissBuiltin(kind()));
danno@chromium.org40cb8782011-05-25 07:58:50 +00002978
2979 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002980 return GetICCode(
2981 kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002982}
2983
2984
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002985Handle<Code> ConstructStubCompiler::CompileConstructStub(
2986 Handle<JSFunction> function) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002987 // a0 : argc
2988 // a1 : constructor
2989 // ra : return address
2990 // [sp] : last argument
2991 Label generic_stub_call;
2992
2993 // Use t7 for holding undefined which is used in several places below.
2994 __ LoadRoot(t7, Heap::kUndefinedValueRootIndex);
2995
2996#ifdef ENABLE_DEBUGGER_SUPPORT
2997 // Check to see whether there are any break points in the function code. If
2998 // there are jump to the generic constructor stub which calls the actual
2999 // code for the function thereby hitting the break points.
3000 __ lw(t5, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3001 __ lw(a2, FieldMemOperand(t5, SharedFunctionInfo::kDebugInfoOffset));
3002 __ Branch(&generic_stub_call, ne, a2, Operand(t7));
3003#endif
3004
3005 // Load the initial map and verify that it is in fact a map.
3006 // a1: constructor function
3007 // t7: undefined
3008 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003009 __ JumpIfSmi(a2, &generic_stub_call);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003010 __ GetObjectType(a2, a3, t0);
3011 __ Branch(&generic_stub_call, ne, t0, Operand(MAP_TYPE));
3012
3013#ifdef DEBUG
3014 // Cannot construct functions this way.
3015 // a0: argc
3016 // a1: constructor function
3017 // a2: initial map
3018 // t7: undefined
3019 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
3020 __ Check(ne, "Function constructed by construct stub.",
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003021 a3, Operand(JS_FUNCTION_TYPE));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003022#endif
3023
3024 // Now allocate the JSObject in new space.
3025 // a0: argc
3026 // a1: constructor function
3027 // a2: initial map
3028 // t7: undefined
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003029 ASSERT(function->has_initial_map());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003030 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003031#ifdef DEBUG
3032 int instance_size = function->initial_map()->instance_size();
3033 __ Check(eq, "Instance size of initial map changed.",
3034 a3, Operand(instance_size >> kPointerSizeLog2));
3035#endif
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003036 __ Allocate(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003037
3038 // Allocated the JSObject, now initialize the fields. Map is set to initial
3039 // map and properties and elements are set to empty fixed array.
3040 // a0: argc
3041 // a1: constructor function
3042 // a2: initial map
3043 // a3: object size (in words)
3044 // t4: JSObject (not tagged)
3045 // t7: undefined
3046 __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex);
3047 __ mov(t5, t4);
3048 __ sw(a2, MemOperand(t5, JSObject::kMapOffset));
3049 __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset));
3050 __ sw(t6, MemOperand(t5, JSObject::kElementsOffset));
3051 __ Addu(t5, t5, Operand(3 * kPointerSize));
3052 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
3053 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
3054 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
3055
3056
3057 // Calculate the location of the first argument. The stack contains only the
3058 // argc arguments.
3059 __ sll(a1, a0, kPointerSizeLog2);
3060 __ Addu(a1, a1, sp);
3061
3062 // Fill all the in-object properties with undefined.
3063 // a0: argc
3064 // a1: first argument
3065 // a3: object size (in words)
3066 // t4: JSObject (not tagged)
3067 // t5: First in-object property of JSObject (not tagged)
3068 // t7: undefined
3069 // Fill the initialized properties with a constant value or a passed argument
3070 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003071 Handle<SharedFunctionInfo> shared(function->shared());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003072 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3073 if (shared->IsThisPropertyAssignmentArgument(i)) {
3074 Label not_passed, next;
3075 // Check if the argument assigned to the property is actually passed.
3076 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3077 __ Branch(&not_passed, less_equal, a0, Operand(arg_number));
3078 // Argument passed - find it on the stack.
3079 __ lw(a2, MemOperand(a1, (arg_number + 1) * -kPointerSize));
3080 __ sw(a2, MemOperand(t5));
3081 __ Addu(t5, t5, kPointerSize);
3082 __ jmp(&next);
3083 __ bind(&not_passed);
3084 // Set the property to undefined.
3085 __ sw(t7, MemOperand(t5));
3086 __ Addu(t5, t5, Operand(kPointerSize));
3087 __ bind(&next);
3088 } else {
3089 // Set the property to the constant value.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003090 Handle<Object> constant(
3091 shared->GetThisPropertyAssignmentConstant(i), isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003092 __ li(a2, Operand(constant));
3093 __ sw(a2, MemOperand(t5));
3094 __ Addu(t5, t5, kPointerSize);
3095 }
3096 }
3097
3098 // Fill the unused in-object property fields with undefined.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003099 for (int i = shared->this_property_assignments_count();
3100 i < function->initial_map()->inobject_properties();
3101 i++) {
3102 __ sw(t7, MemOperand(t5));
3103 __ Addu(t5, t5, kPointerSize);
3104 }
3105
3106 // a0: argc
3107 // t4: JSObject (not tagged)
3108 // Move argc to a1 and the JSObject to return to v0 and tag it.
3109 __ mov(a1, a0);
3110 __ mov(v0, t4);
3111 __ Or(v0, v0, Operand(kHeapObjectTag));
3112
3113 // v0: JSObject
3114 // a1: argc
3115 // Remove caller arguments and receiver from the stack and return.
3116 __ sll(t0, a1, kPointerSizeLog2);
3117 __ Addu(sp, sp, t0);
3118 __ Addu(sp, sp, Operand(kPointerSize));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003119 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003120 __ IncrementCounter(counters->constructed_objects(), 1, a1, a2);
3121 __ IncrementCounter(counters->constructed_objects_stub(), 1, a1, a2);
3122 __ Ret();
3123
3124 // Jump to the generic stub in case the specialized code cannot handle the
3125 // construction.
3126 __ bind(&generic_stub_call);
3127 Handle<Code> generic_construct_stub =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003128 isolate()->builtins()->JSConstructStubGeneric();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003129 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
3130
3131 // Return the generated code.
3132 return GetCode();
3133}
3134
3135
danno@chromium.org40cb8782011-05-25 07:58:50 +00003136#undef __
3137#define __ ACCESS_MASM(masm)
3138
3139
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003140void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3141 MacroAssembler* masm) {
3142 // ---------- S t a t e --------------
3143 // -- ra : return address
3144 // -- a0 : key
3145 // -- a1 : receiver
3146 // -----------------------------------
3147 Label slow, miss_force_generic;
3148
3149 Register key = a0;
3150 Register receiver = a1;
3151
3152 __ JumpIfNotSmi(key, &miss_force_generic);
3153 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
3154 __ sra(a2, a0, kSmiTagSize);
3155 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
3156 __ Ret();
3157
3158 // Slow case, key and receiver still in a0 and a1.
3159 __ bind(&slow);
3160 __ IncrementCounter(
3161 masm->isolate()->counters()->keyed_load_external_array_slow(),
3162 1, a2, a3);
3163 // Entry registers are intact.
3164 // ---------- S t a t e --------------
3165 // -- ra : return address
3166 // -- a0 : key
3167 // -- a1 : receiver
3168 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003169 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003170
3171 // Miss case, call the runtime.
3172 __ bind(&miss_force_generic);
3173
3174 // ---------- S t a t e --------------
3175 // -- ra : return address
3176 // -- a0 : key
3177 // -- a1 : receiver
3178 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003179 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_MissForceGeneric);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003180}
3181
3182
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003183static void GenerateSmiKeyCheck(MacroAssembler* masm,
3184 Register key,
3185 Register scratch0,
3186 Register scratch1,
3187 FPURegister double_scratch0,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003188 FPURegister double_scratch1,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003189 Label* fail) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003190 Label key_ok;
3191 // Check for smi or a smi inside a heap number. We convert the heap
3192 // number and check if the conversion is exact and fits into the smi
3193 // range.
3194 __ JumpIfSmi(key, &key_ok);
3195 __ CheckMap(key,
3196 scratch0,
3197 Heap::kHeapNumberMapRootIndex,
3198 fail,
3199 DONT_DO_SMI_CHECK);
3200 __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
3201 __ EmitFPUTruncate(kRoundToZero,
3202 scratch0,
3203 double_scratch0,
3204 at,
3205 double_scratch1,
3206 scratch1,
3207 kCheckForInexactConversion);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003208
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003209 __ Branch(fail, ne, scratch1, Operand(zero_reg));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003210
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003211 __ SmiTagCheckOverflow(key, scratch0, scratch1);
3212 __ BranchOnOverflow(fail, scratch1);
3213 __ bind(&key_ok);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003214}
3215
3216
danno@chromium.org40cb8782011-05-25 07:58:50 +00003217void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3218 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003219 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003220 // ---------- S t a t e --------------
3221 // -- a0 : value
3222 // -- a1 : key
3223 // -- a2 : receiver
3224 // -- ra : return address
3225 // -----------------------------------
3226
danno@chromium.org40cb8782011-05-25 07:58:50 +00003227 Label slow, check_heap_number, miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003228
3229 // Register usage.
3230 Register value = a0;
3231 Register key = a1;
3232 Register receiver = a2;
3233 // a3 mostly holds the elements array or the destination external array.
3234
danno@chromium.org40cb8782011-05-25 07:58:50 +00003235 // This stub is meant to be tail-jumped to, the receiver must already
3236 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003237
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003238 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003239 GenerateSmiKeyCheck(masm, key, t0, t1, f2, f4, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003240
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003241 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3242
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003243 // Check that the index is in range.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003244 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3245 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003246 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003247
3248 // Handle both smis and HeapNumbers in the fast path. Go to the
3249 // runtime for all other kinds of values.
3250 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003251
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003252 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003253 // Double to pixel conversion is only implemented in the runtime for now.
3254 __ JumpIfNotSmi(value, &slow);
3255 } else {
3256 __ JumpIfNotSmi(value, &check_heap_number);
3257 }
3258 __ SmiUntag(t1, value);
3259 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3260
3261 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003262 // t1: value (integer).
3263
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003264 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003265 case EXTERNAL_PIXEL_ELEMENTS: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003266 // Clamp the value to [0..255].
3267 // v0 is used as a scratch register here.
3268 Label done;
3269 __ li(v0, Operand(255));
3270 // Normal branch: nop in delay slot.
3271 __ Branch(&done, gt, t1, Operand(v0));
3272 // Use delay slot in this branch.
3273 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg));
3274 __ mov(v0, zero_reg); // In delay slot.
3275 __ mov(v0, t1); // Value is in range 0..255.
3276 __ bind(&done);
3277 __ mov(t1, v0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003278
3279 __ srl(t8, key, 1);
3280 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003281 __ sb(t1, MemOperand(t8, 0));
3282 }
3283 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003284 case EXTERNAL_BYTE_ELEMENTS:
3285 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003286 __ srl(t8, key, 1);
3287 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003288 __ sb(t1, MemOperand(t8, 0));
3289 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003290 case EXTERNAL_SHORT_ELEMENTS:
3291 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003292 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003293 __ sh(t1, MemOperand(t8, 0));
3294 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003295 case EXTERNAL_INT_ELEMENTS:
3296 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003297 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003298 __ addu(t8, a3, t8);
3299 __ sw(t1, MemOperand(t8, 0));
3300 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003301 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003302 // Perform int-to-float conversion and store to memory.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003303 __ SmiUntag(t0, key);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003304 StoreIntAsFloat(masm, a3, t0, t1, t2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003305 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003306 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003307 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003308 __ addu(a3, a3, t8);
3309 // a3: effective address of the double element
3310 FloatingPointHelper::Destination destination;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003311 destination = FloatingPointHelper::kFPURegisters;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003312 FloatingPointHelper::ConvertIntToDouble(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003313 masm, t1, destination,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003314 f0, t2, t3, // These are: double_dst, dst_mantissa, dst_exponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003315 t0, f2); // These are: scratch2, single_scratch.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003316 __ sdc1(f0, MemOperand(a3, 0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003317 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003318 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003319 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003320 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003321 case FAST_HOLEY_ELEMENTS:
3322 case FAST_HOLEY_SMI_ELEMENTS:
3323 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003324 case DICTIONARY_ELEMENTS:
3325 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003326 UNREACHABLE();
3327 break;
3328 }
3329
3330 // Entry registers are intact, a0 holds the value which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003331 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003332 __ Ret();
3333
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003334 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003335 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003336 __ bind(&check_heap_number);
3337 __ GetObjectType(value, t1, t2);
3338 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE));
3339
3340 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3341
3342 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003343
3344 // The WebGL specification leaves the behavior of storing NaN and
3345 // +/-Infinity into integer arrays basically undefined. For more
3346 // reproducible behavior, convert these to zero.
3347
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003348
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003349 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003350
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003351 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
3352 __ cvt_s_d(f0, f0);
3353 __ sll(t8, key, 1);
3354 __ addu(t8, a3, t8);
3355 __ swc1(f0, MemOperand(t8, 0));
3356 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
3357 __ sll(t8, key, 2);
3358 __ addu(t8, a3, t8);
3359 __ sdc1(f0, MemOperand(t8, 0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003360 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003361 __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003362
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003363 switch (elements_kind) {
3364 case EXTERNAL_BYTE_ELEMENTS:
3365 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3366 __ srl(t8, key, 1);
3367 __ addu(t8, a3, t8);
3368 __ sb(t3, MemOperand(t8, 0));
3369 break;
3370 case EXTERNAL_SHORT_ELEMENTS:
3371 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3372 __ addu(t8, a3, key);
3373 __ sh(t3, MemOperand(t8, 0));
3374 break;
3375 case EXTERNAL_INT_ELEMENTS:
3376 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3377 __ sll(t8, key, 1);
3378 __ addu(t8, a3, t8);
3379 __ sw(t3, MemOperand(t8, 0));
3380 break;
3381 case EXTERNAL_PIXEL_ELEMENTS:
3382 case EXTERNAL_FLOAT_ELEMENTS:
3383 case EXTERNAL_DOUBLE_ELEMENTS:
3384 case FAST_ELEMENTS:
3385 case FAST_SMI_ELEMENTS:
3386 case FAST_DOUBLE_ELEMENTS:
3387 case FAST_HOLEY_ELEMENTS:
3388 case FAST_HOLEY_SMI_ELEMENTS:
3389 case FAST_HOLEY_DOUBLE_ELEMENTS:
3390 case DICTIONARY_ELEMENTS:
3391 case NON_STRICT_ARGUMENTS_ELEMENTS:
3392 UNREACHABLE();
3393 break;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003394 }
3395 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003396
3397 // Entry registers are intact, a0 holds the value
3398 // which is the return value.
3399 __ mov(v0, a0);
3400 __ Ret();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003401 }
3402
danno@chromium.org40cb8782011-05-25 07:58:50 +00003403 // Slow case, key and receiver still in a0 and a1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003404 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003405 __ IncrementCounter(
3406 masm->isolate()->counters()->keyed_load_external_array_slow(),
3407 1, a2, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003408 // Entry registers are intact.
3409 // ---------- S t a t e --------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003410 // -- ra : return address
danno@chromium.org40cb8782011-05-25 07:58:50 +00003411 // -- a0 : key
3412 // -- a1 : receiver
3413 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003414 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003415
3416 // Miss case, call the runtime.
3417 __ bind(&miss_force_generic);
3418
3419 // ---------- S t a t e --------------
3420 // -- ra : return address
3421 // -- a0 : key
3422 // -- a1 : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003423 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003424 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003425}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003426
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003427
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003428void KeyedStoreStubCompiler::GenerateStoreFastElement(
3429 MacroAssembler* masm,
3430 bool is_js_array,
yangguo@chromium.org56454712012-02-16 15:33:53 +00003431 ElementsKind elements_kind,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003432 KeyedAccessStoreMode store_mode) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003433 // ----------- S t a t e -------------
3434 // -- a0 : value
3435 // -- a1 : key
3436 // -- a2 : receiver
3437 // -- ra : return address
3438 // -- a3 : scratch
3439 // -- a4 : scratch (elements)
3440 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00003441 Label miss_force_generic, transition_elements_kind, grow, slow;
3442 Label finish_store, check_capacity;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003443
3444 Register value_reg = a0;
3445 Register key_reg = a1;
3446 Register receiver_reg = a2;
yangguo@chromium.org56454712012-02-16 15:33:53 +00003447 Register scratch = t0;
3448 Register elements_reg = a3;
3449 Register length_reg = t1;
3450 Register scratch2 = t2;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003451
3452 // This stub is meant to be tail-jumped to, the receiver must already
3453 // have been verified by the caller to not be a smi.
3454
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003455 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003456 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003457
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003458 if (IsFastSmiElementsKind(elements_kind)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003459 __ JumpIfNotSmi(value_reg, &transition_elements_kind);
3460 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003461
3462 // Check that the key is within bounds.
yangguo@chromium.org56454712012-02-16 15:33:53 +00003463 __ lw(elements_reg,
3464 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003465 if (is_js_array) {
3466 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3467 } else {
3468 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3469 }
3470 // Compare smis.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003471 if (is_js_array && IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003472 __ Branch(&grow, hs, key_reg, Operand(scratch));
3473 } else {
3474 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
3475 }
3476
3477 // Make sure elements is a fast element array, not 'cow'.
3478 __ CheckMap(elements_reg,
3479 scratch,
3480 Heap::kFixedArrayMapRootIndex,
3481 &miss_force_generic,
3482 DONT_DO_SMI_CHECK);
3483
3484 __ bind(&finish_store);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003485
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003486 if (IsFastSmiElementsKind(elements_kind)) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003487 __ Addu(scratch,
3488 elements_reg,
3489 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3490 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
3491 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
3492 __ Addu(scratch, scratch, scratch2);
3493 __ sw(value_reg, MemOperand(scratch));
3494 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003495 ASSERT(IsFastObjectElementsKind(elements_kind));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003496 __ Addu(scratch,
3497 elements_reg,
3498 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3499 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
3500 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
3501 __ Addu(scratch, scratch, scratch2);
3502 __ sw(value_reg, MemOperand(scratch));
3503 __ mov(receiver_reg, value_reg);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003504 __ RecordWrite(elements_reg, // Object.
3505 scratch, // Address.
3506 receiver_reg, // Value.
3507 kRAHasNotBeenSaved,
3508 kDontSaveFPRegs);
3509 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003510 // value_reg (a0) is preserved.
3511 // Done.
3512 __ Ret();
3513
3514 __ bind(&miss_force_generic);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003515 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003516
3517 __ bind(&transition_elements_kind);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003518 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003519
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003520 if (is_js_array && IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003521 // Grow the array by a single element if possible.
3522 __ bind(&grow);
3523
3524 // Make sure the array is only growing by a single element, anything else
3525 // must be handled by the runtime.
3526 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch));
3527
3528 // Check for the empty array, and preallocate a small backing store if
3529 // possible.
3530 __ lw(length_reg,
3531 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3532 __ lw(elements_reg,
3533 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3534 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
3535 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
3536
3537 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003538 __ Allocate(size, elements_reg, scratch, scratch2, &slow, TAG_OBJECT);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003539
3540 __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex);
3541 __ sw(scratch, FieldMemOperand(elements_reg, JSObject::kMapOffset));
3542 __ li(scratch, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
3543 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3544 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
3545 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
3546 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::SizeFor(i)));
3547 }
3548
3549 // Store the element at index zero.
3550 __ sw(value_reg, FieldMemOperand(elements_reg, FixedArray::SizeFor(0)));
3551
3552 // Install the new backing store in the JSArray.
3553 __ sw(elements_reg,
3554 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3555 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
3556 scratch, kRAHasNotBeenSaved, kDontSaveFPRegs,
3557 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3558
3559 // Increment the length of the array.
3560 __ li(length_reg, Operand(Smi::FromInt(1)));
3561 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3562 __ Ret();
3563
3564 __ bind(&check_capacity);
3565 // Check for cow elements, in general they are not handled by this stub
3566 __ CheckMap(elements_reg,
3567 scratch,
3568 Heap::kFixedCOWArrayMapRootIndex,
3569 &miss_force_generic,
3570 DONT_DO_SMI_CHECK);
3571
3572 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3573 __ Branch(&slow, hs, length_reg, Operand(scratch));
3574
3575 // Grow the array and finish the store.
3576 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
3577 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3578 __ jmp(&finish_store);
3579
3580 __ bind(&slow);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003581 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003582 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003583}
3584
3585
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003586void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
3587 MacroAssembler* masm,
yangguo@chromium.org56454712012-02-16 15:33:53 +00003588 bool is_js_array,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003589 KeyedAccessStoreMode store_mode) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003590 // ----------- S t a t e -------------
3591 // -- a0 : value
3592 // -- a1 : key
3593 // -- a2 : receiver
3594 // -- ra : return address
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003595 // -- a3 : scratch (elements backing store)
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003596 // -- t0 : scratch (elements_reg)
3597 // -- t1 : scratch (mantissa_reg)
3598 // -- t2 : scratch (exponent_reg)
3599 // -- t3 : scratch4
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003600 // -- t4 : scratch
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003601 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00003602 Label miss_force_generic, transition_elements_kind, grow, slow;
3603 Label finish_store, check_capacity;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003604
3605 Register value_reg = a0;
3606 Register key_reg = a1;
3607 Register receiver_reg = a2;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003608 Register elements_reg = a3;
3609 Register scratch1 = t0;
3610 Register scratch2 = t1;
3611 Register scratch3 = t2;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003612 Register scratch4 = t3;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003613 Register scratch5 = t4;
yangguo@chromium.org56454712012-02-16 15:33:53 +00003614 Register length_reg = t3;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003615
3616 // This stub is meant to be tail-jumped to, the receiver must already
3617 // have been verified by the caller to not be a smi.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003618
3619 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003620 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003621
3622 __ lw(elements_reg,
3623 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3624
3625 // Check that the key is within bounds.
3626 if (is_js_array) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003627 __ lw(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003628 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003629 __ lw(scratch1,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003630 FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3631 }
3632 // Compare smis, unsigned compare catches both negative and out-of-bound
3633 // indexes.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003634 if (IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003635 __ Branch(&grow, hs, key_reg, Operand(scratch1));
3636 } else {
3637 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch1));
3638 }
3639
3640 __ bind(&finish_store);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003641
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003642 __ StoreNumberToDoubleElements(value_reg,
3643 key_reg,
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00003644 // All registers after this are overwritten.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003645 elements_reg,
3646 scratch1,
3647 scratch2,
3648 scratch3,
3649 scratch4,
3650 &transition_elements_kind);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003651
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003652 __ Ret(USE_DELAY_SLOT);
3653 __ mov(v0, value_reg); // In delay slot.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003654
3655 // Handle store cache miss, replacing the ic with the generic stub.
3656 __ bind(&miss_force_generic);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003657 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003658
3659 __ bind(&transition_elements_kind);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003660 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003661
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003662 if (is_js_array && IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003663 // Grow the array by a single element if possible.
3664 __ bind(&grow);
3665
3666 // Make sure the array is only growing by a single element, anything else
3667 // must be handled by the runtime.
3668 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch1));
3669
3670 // Transition on values that can't be stored in a FixedDoubleArray.
3671 Label value_is_smi;
3672 __ JumpIfSmi(value_reg, &value_is_smi);
3673 __ lw(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
3674 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
3675 __ Branch(&transition_elements_kind, ne, scratch1, Operand(at));
3676 __ bind(&value_is_smi);
3677
3678 // Check for the empty array, and preallocate a small backing store if
3679 // possible.
3680 __ lw(length_reg,
3681 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3682 __ lw(elements_reg,
3683 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3684 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
3685 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
3686
3687 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003688 __ Allocate(size, elements_reg, scratch1, scratch2, &slow, TAG_OBJECT);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003689
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003690 // Initialize the new FixedDoubleArray.
yangguo@chromium.org56454712012-02-16 15:33:53 +00003691 __ LoadRoot(scratch1, Heap::kFixedDoubleArrayMapRootIndex);
3692 __ sw(scratch1, FieldMemOperand(elements_reg, JSObject::kMapOffset));
3693 __ li(scratch1, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
3694 __ sw(scratch1,
3695 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
3696
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003697 __ mov(scratch1, elements_reg);
3698 __ StoreNumberToDoubleElements(value_reg,
3699 key_reg,
3700 // All registers after this are overwritten.
3701 scratch1,
3702 scratch2,
3703 scratch3,
3704 scratch4,
3705 scratch5,
3706 &transition_elements_kind);
3707
3708 __ li(scratch1, Operand(kHoleNanLower32));
3709 __ li(scratch2, Operand(kHoleNanUpper32));
3710 for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) {
3711 int offset = FixedDoubleArray::OffsetOfElementAt(i);
3712 __ sw(scratch1, FieldMemOperand(elements_reg, offset));
3713 __ sw(scratch2, FieldMemOperand(elements_reg, offset + kPointerSize));
3714 }
3715
yangguo@chromium.org56454712012-02-16 15:33:53 +00003716 // Install the new backing store in the JSArray.
3717 __ sw(elements_reg,
3718 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3719 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
3720 scratch1, kRAHasNotBeenSaved, kDontSaveFPRegs,
3721 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3722
3723 // Increment the length of the array.
3724 __ li(length_reg, Operand(Smi::FromInt(1)));
3725 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
danno@chromium.org00379b82012-05-04 09:16:29 +00003726 __ lw(elements_reg,
3727 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003728 __ Ret();
yangguo@chromium.org56454712012-02-16 15:33:53 +00003729
3730 __ bind(&check_capacity);
3731 // Make sure that the backing store can hold additional elements.
3732 __ lw(scratch1,
3733 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
3734 __ Branch(&slow, hs, length_reg, Operand(scratch1));
3735
3736 // Grow the array and finish the store.
3737 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
3738 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3739 __ jmp(&finish_store);
3740
3741 __ bind(&slow);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003742 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003743 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003744}
3745
3746
ager@chromium.org5c838252010-02-19 08:53:10 +00003747#undef __
3748
3749} } // namespace v8::internal
3750
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003751#endif // V8_TARGET_ARCH_MIPS