blob: 5b36cc2fb30faf66ddd986a942999ff60cdc7af3 [file] [log] [blame]
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001// Copyright 2012 the V8 project authors. All rights reserved.
ager@chromium.org5c838252010-02-19 08:53:10 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000030#if defined(V8_TARGET_ARCH_MIPS)
31
ager@chromium.org5c838252010-02-19 08:53:10 +000032#include "ic-inl.h"
karlklose@chromium.org83a47282011-05-11 11:54:09 +000033#include "codegen.h"
ager@chromium.org5c838252010-02-19 08:53:10 +000034#include "stub-cache.h"
35
36namespace v8 {
37namespace internal {
38
39#define __ ACCESS_MASM(masm)
40
41
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000042static void ProbeTable(Isolate* isolate,
43 MacroAssembler* masm,
44 Code::Flags flags,
45 StubCache::Table table,
fschneider@chromium.org35814e52012-03-01 15:43:35 +000046 Register receiver,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000047 Register name,
fschneider@chromium.org35814e52012-03-01 15:43:35 +000048 // Number of the cache entry, not scaled.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000049 Register offset,
50 Register scratch,
fschneider@chromium.org35814e52012-03-01 15:43:35 +000051 Register scratch2,
52 Register offset_scratch) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000053 ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
54 ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
fschneider@chromium.org35814e52012-03-01 15:43:35 +000055 ExternalReference map_offset(isolate->stub_cache()->map_reference(table));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000056
57 uint32_t key_off_addr = reinterpret_cast<uint32_t>(key_offset.address());
58 uint32_t value_off_addr = reinterpret_cast<uint32_t>(value_offset.address());
fschneider@chromium.org35814e52012-03-01 15:43:35 +000059 uint32_t map_off_addr = reinterpret_cast<uint32_t>(map_offset.address());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000060
61 // Check the relative positions of the address fields.
62 ASSERT(value_off_addr > key_off_addr);
63 ASSERT((value_off_addr - key_off_addr) % 4 == 0);
64 ASSERT((value_off_addr - key_off_addr) < (256 * 4));
fschneider@chromium.org35814e52012-03-01 15:43:35 +000065 ASSERT(map_off_addr > key_off_addr);
66 ASSERT((map_off_addr - key_off_addr) % 4 == 0);
67 ASSERT((map_off_addr - key_off_addr) < (256 * 4));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000068
69 Label miss;
fschneider@chromium.org35814e52012-03-01 15:43:35 +000070 Register base_addr = scratch;
71 scratch = no_reg;
72
73 // Multiply by 3 because there are 3 fields per entry (name, code, map).
74 __ sll(offset_scratch, offset, 1);
75 __ Addu(offset_scratch, offset_scratch, offset);
76
77 // Calculate the base address of the entry.
78 __ li(base_addr, Operand(key_offset));
79 __ sll(at, offset_scratch, kPointerSizeLog2);
80 __ Addu(base_addr, base_addr, at);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000081
82 // Check that the key in the entry matches the name.
fschneider@chromium.org35814e52012-03-01 15:43:35 +000083 __ lw(at, MemOperand(base_addr, 0));
84 __ Branch(&miss, ne, name, Operand(at));
85
86 // Check the map matches.
87 __ lw(at, MemOperand(base_addr, map_off_addr - key_off_addr));
88 __ lw(scratch2, FieldMemOperand(receiver, HeapObject::kMapOffset));
89 __ Branch(&miss, ne, at, Operand(scratch2));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000090
91 // Get the code entry from the cache.
fschneider@chromium.org35814e52012-03-01 15:43:35 +000092 Register code = scratch2;
93 scratch2 = no_reg;
94 __ lw(code, MemOperand(base_addr, value_off_addr - key_off_addr));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000095
96 // Check that the flags match what we're looking for.
fschneider@chromium.org35814e52012-03-01 15:43:35 +000097 Register flags_reg = base_addr;
98 base_addr = no_reg;
99 __ lw(flags_reg, FieldMemOperand(code, Code::kFlagsOffset));
100 __ And(flags_reg, flags_reg, Operand(~Code::kFlagsNotUsedInLookup));
101 __ Branch(&miss, ne, flags_reg, Operand(flags));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000102
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000103#ifdef DEBUG
104 if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
105 __ jmp(&miss);
106 } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
107 __ jmp(&miss);
108 }
109#endif
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000110
111 // Jump to the first instruction in the code stub.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000112 __ Addu(at, code, Operand(Code::kHeaderSize - kHeapObjectTag));
113 __ Jump(at);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000114
115 // Miss: fall through.
116 __ bind(&miss);
117}
118
119
120// Helper function used to check that the dictionary doesn't contain
121// the property. This function may return false negatives, so miss_label
122// must always call a backup property check that is complete.
123// This function is safe to call if the receiver has fast properties.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000124// Name must be unique and receiver must be a heap object.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000125static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
126 Label* miss_label,
127 Register receiver,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000128 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000129 Register scratch0,
130 Register scratch1) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000131 ASSERT(name->IsUniqueName());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000132 Counters* counters = masm->isolate()->counters();
133 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
134 __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
135
136 Label done;
137
138 const int kInterceptorOrAccessCheckNeededMask =
139 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
140
141 // Bail out if the receiver has a named interceptor or requires access checks.
142 Register map = scratch1;
143 __ lw(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
144 __ lbu(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
145 __ And(scratch0, scratch0, Operand(kInterceptorOrAccessCheckNeededMask));
146 __ Branch(miss_label, ne, scratch0, Operand(zero_reg));
147
148 // Check that receiver is a JSObject.
149 __ lbu(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
150 __ Branch(miss_label, lt, scratch0, Operand(FIRST_SPEC_OBJECT_TYPE));
151
152 // Load properties array.
153 Register properties = scratch0;
154 __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
155 // Check that the properties array is a dictionary.
156 __ lw(map, FieldMemOperand(properties, HeapObject::kMapOffset));
157 Register tmp = properties;
158 __ LoadRoot(tmp, Heap::kHashTableMapRootIndex);
159 __ Branch(miss_label, ne, map, Operand(tmp));
160
161 // Restore the temporarily used register.
162 __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
163
164
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000165 NameDictionaryLookupStub::GenerateNegativeLookup(masm,
166 miss_label,
167 &done,
168 receiver,
169 properties,
170 name,
171 scratch1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000172 __ bind(&done);
173 __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
174}
175
176
ager@chromium.org5c838252010-02-19 08:53:10 +0000177void StubCache::GenerateProbe(MacroAssembler* masm,
178 Code::Flags flags,
179 Register receiver,
180 Register name,
181 Register scratch,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000182 Register extra,
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000183 Register extra2,
184 Register extra3) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000185 Isolate* isolate = masm->isolate();
186 Label miss;
187
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000188 // Make sure that code is valid. The multiplying code relies on the
189 // entry size being 12.
190 ASSERT(sizeof(Entry) == 12);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000191
192 // Make sure the flags does not name a specific type.
193 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
194
195 // Make sure that there are no register conflicts.
196 ASSERT(!scratch.is(receiver));
197 ASSERT(!scratch.is(name));
198 ASSERT(!extra.is(receiver));
199 ASSERT(!extra.is(name));
200 ASSERT(!extra.is(scratch));
201 ASSERT(!extra2.is(receiver));
202 ASSERT(!extra2.is(name));
203 ASSERT(!extra2.is(scratch));
204 ASSERT(!extra2.is(extra));
205
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000206 // Check register validity.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000207 ASSERT(!scratch.is(no_reg));
208 ASSERT(!extra.is(no_reg));
209 ASSERT(!extra2.is(no_reg));
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000210 ASSERT(!extra3.is(no_reg));
211
212 Counters* counters = masm->isolate()->counters();
213 __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1,
214 extra2, extra3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000215
216 // Check that the receiver isn't a smi.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000217 __ JumpIfSmi(receiver, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000218
219 // Get the map of the receiver and compute the hash.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000220 __ lw(scratch, FieldMemOperand(name, Name::kHashFieldOffset));
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000221 __ lw(at, FieldMemOperand(receiver, HeapObject::kMapOffset));
222 __ Addu(scratch, scratch, at);
223 uint32_t mask = kPrimaryTableSize - 1;
224 // We shift out the last two bits because they are not part of the hash and
225 // they are always 01 for maps.
226 __ srl(scratch, scratch, kHeapObjectTagSize);
227 __ Xor(scratch, scratch, Operand((flags >> kHeapObjectTagSize) & mask));
228 __ And(scratch, scratch, Operand(mask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000229
230 // Probe the primary table.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000231 ProbeTable(isolate,
232 masm,
233 flags,
234 kPrimary,
235 receiver,
236 name,
237 scratch,
238 extra,
239 extra2,
240 extra3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000241
242 // Primary miss: Compute hash for secondary probe.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000243 __ srl(at, name, kHeapObjectTagSize);
244 __ Subu(scratch, scratch, at);
245 uint32_t mask2 = kSecondaryTableSize - 1;
246 __ Addu(scratch, scratch, Operand((flags >> kHeapObjectTagSize) & mask2));
247 __ And(scratch, scratch, Operand(mask2));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000248
249 // Probe the secondary table.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000250 ProbeTable(isolate,
251 masm,
252 flags,
253 kSecondary,
254 receiver,
255 name,
256 scratch,
257 extra,
258 extra2,
259 extra3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000260
261 // Cache miss: Fall-through and let caller handle the miss by
262 // entering the runtime system.
263 __ bind(&miss);
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000264 __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1,
265 extra2, extra3);
ager@chromium.org5c838252010-02-19 08:53:10 +0000266}
267
268
269void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
270 int index,
271 Register prototype) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000272 // Load the global or builtins object from the current context.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000273 __ lw(prototype,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000274 MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
275 // Load the native context from the global or builtins object.
276 __ lw(prototype,
277 FieldMemOperand(prototype, GlobalObject::kNativeContextOffset));
278 // Load the function from the native context.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000279 __ lw(prototype, MemOperand(prototype, Context::SlotOffset(index)));
280 // Load the initial map. The global functions all have initial maps.
281 __ lw(prototype,
282 FieldMemOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
283 // Load the prototype from the initial map.
284 __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000285}
286
287
lrn@chromium.org7516f052011-03-30 08:52:27 +0000288void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000289 MacroAssembler* masm,
290 int index,
291 Register prototype,
292 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000293 Isolate* isolate = masm->isolate();
294 // Check we're still in the same context.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000295 __ lw(prototype,
296 MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000297 ASSERT(!prototype.is(at));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000298 __ li(at, isolate->global_object());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000299 __ Branch(miss, ne, prototype, Operand(at));
300 // Get the global function with the given index.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000301 Handle<JSFunction> function(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000302 JSFunction::cast(isolate->native_context()->get(index)));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000303 // Load its initial map. The global functions all have initial maps.
304 __ li(prototype, Handle<Map>(function->initial_map()));
305 // Load the prototype from the initial map.
306 __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000307}
308
309
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000310void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
311 Register dst,
312 Register src,
313 bool inobject,
314 int index,
315 Representation representation) {
316 ASSERT(!FLAG_track_double_fields || !representation.IsDouble());
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000317 int offset = index * kPointerSize;
318 if (!inobject) {
319 // Calculate the offset into the properties array.
320 offset = offset + FixedArray::kHeaderSize;
321 __ lw(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
322 src = dst;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000323 }
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000324 __ lw(dst, FieldMemOperand(src, offset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000325}
326
327
328void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
329 Register receiver,
330 Register scratch,
331 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000332 // Check that the receiver isn't a smi.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000333 __ JumpIfSmi(receiver, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000334
335 // Check that the object is a JS array.
336 __ GetObjectType(receiver, scratch, scratch);
337 __ Branch(miss_label, ne, scratch, Operand(JS_ARRAY_TYPE));
338
339 // Load length directly from the JS array.
340 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
341 __ Ret();
342}
343
344
345// Generate code to check if an object is a string. If the object is a
346// heap object, its map's instance type is left in the scratch1 register.
347// If this is not needed, scratch1 and scratch2 may be the same register.
348static void GenerateStringCheck(MacroAssembler* masm,
349 Register receiver,
350 Register scratch1,
351 Register scratch2,
352 Label* smi,
353 Label* non_string_object) {
354 // Check that the receiver isn't a smi.
355 __ JumpIfSmi(receiver, smi, t0);
356
357 // Check that the object is a string.
358 __ lw(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
359 __ lbu(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
360 __ And(scratch2, scratch1, Operand(kIsNotStringMask));
361 // The cast is to resolve the overload for the argument of 0x0.
362 __ Branch(non_string_object,
363 ne,
364 scratch2,
365 Operand(static_cast<int32_t>(kStringTag)));
ager@chromium.org5c838252010-02-19 08:53:10 +0000366}
367
368
lrn@chromium.org7516f052011-03-30 08:52:27 +0000369// Generate code to load the length from a string object and return the length.
370// If the receiver object is not a string or a wrapped string object the
371// execution continues at the miss label. The register containing the
372// receiver is potentially clobbered.
373void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
374 Register receiver,
375 Register scratch1,
376 Register scratch2,
377 Label* miss,
378 bool support_wrappers) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000379 Label check_wrapper;
380
381 // Check if the object is a string leaving the instance type in the
382 // scratch1 register.
383 GenerateStringCheck(masm, receiver, scratch1, scratch2, miss,
384 support_wrappers ? &check_wrapper : miss);
385
386 // Load length directly from the string.
387 __ lw(v0, FieldMemOperand(receiver, String::kLengthOffset));
388 __ Ret();
389
390 if (support_wrappers) {
391 // Check if the object is a JSValue wrapper.
392 __ bind(&check_wrapper);
393 __ Branch(miss, ne, scratch1, Operand(JS_VALUE_TYPE));
394
395 // Unwrap the value and check if the wrapped value is a string.
396 __ lw(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
397 GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
398 __ lw(v0, FieldMemOperand(scratch1, String::kLengthOffset));
399 __ Ret();
400 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000401}
402
403
ager@chromium.org5c838252010-02-19 08:53:10 +0000404void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
405 Register receiver,
406 Register scratch1,
407 Register scratch2,
408 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000409 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
410 __ mov(v0, scratch1);
411 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000412}
413
414
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000415// Generate code to check that a global property cell is empty. Create
416// the property cell at compilation time if no cell exists for the
417// property.
418static void GenerateCheckPropertyCell(MacroAssembler* masm,
419 Handle<GlobalObject> global,
420 Handle<Name> name,
421 Register scratch,
422 Label* miss) {
423 Handle<JSGlobalPropertyCell> cell =
424 GlobalObject::EnsurePropertyCell(global, name);
425 ASSERT(cell->value()->IsTheHole());
426 __ li(scratch, Operand(cell));
427 __ lw(scratch,
428 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
429 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
430 __ Branch(miss, ne, scratch, Operand(at));
431}
432
433
434// Generate StoreTransition code, value is passed in a0 register.
ager@chromium.org5c838252010-02-19 08:53:10 +0000435// After executing generated code, the receiver_reg and name_reg
436// may be clobbered.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000437void StubCompiler::GenerateStoreTransition(MacroAssembler* masm,
438 Handle<JSObject> object,
439 LookupResult* lookup,
440 Handle<Map> transition,
441 Handle<Name> name,
442 Register receiver_reg,
443 Register name_reg,
444 Register value_reg,
445 Register scratch1,
446 Register scratch2,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000447 Register scratch3,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000448 Label* miss_label,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000449 Label* miss_restore_name,
450 Label* slow) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000451 // a0 : value.
452 Label exit;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000453
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000454 // Check that the map of the object hasn't changed.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000455 __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000456 DO_SMI_CHECK, REQUIRE_EXACT_MAP);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000457
458 // Perform global security token check if needed.
459 if (object->IsJSGlobalProxy()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000460 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
461 }
462
danno@chromium.orgf005df62013-04-30 16:36:45 +0000463 int descriptor = transition->LastAdded();
464 DescriptorArray* descriptors = transition->instance_descriptors();
465 PropertyDetails details = descriptors->GetDetails(descriptor);
466 Representation representation = details.representation();
467 ASSERT(!representation.IsNone());
468
469 // Ensure no transitions to deprecated maps are followed.
470 __ CheckMapDeprecated(transition, scratch1, miss_label);
471
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000472 // Check that we are allowed to write this.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000473 if (object->GetPrototype()->IsJSObject()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000474 JSObject* holder;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000475 // holder == object indicates that no property was found.
476 if (lookup->holder() != *object) {
477 holder = lookup->holder();
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000478 } else {
479 // Find the top object.
480 holder = *object;
481 do {
482 holder = JSObject::cast(holder->GetPrototype());
483 } while (holder->GetPrototype()->IsJSObject());
484 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000485 Register holder_reg = CheckPrototypes(
486 object, receiver_reg, Handle<JSObject>(holder), name_reg,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000487 scratch1, scratch2, name, miss_restore_name, SKIP_RECEIVER);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000488 // If no property was found, and the holder (the last object in the
489 // prototype chain) is in slow mode, we need to do a negative lookup on the
490 // holder.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000491 if (lookup->holder() == *object) {
492 if (holder->IsJSGlobalObject()) {
493 GenerateCheckPropertyCell(
494 masm,
495 Handle<GlobalObject>(GlobalObject::cast(holder)),
496 name,
497 scratch1,
498 miss_restore_name);
499 } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
500 GenerateDictionaryNegativeLookup(
501 masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
502 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000503 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000504 }
505
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000506 Register storage_reg = name_reg;
507
508 if (FLAG_track_fields && representation.IsSmi()) {
509 __ JumpIfNotSmi(value_reg, miss_restore_name);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +0000510 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
511 __ JumpIfSmi(value_reg, miss_restore_name);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000512 } else if (FLAG_track_double_fields && representation.IsDouble()) {
513 Label do_store, heap_number;
514 __ LoadRoot(scratch3, Heap::kHeapNumberMapRootIndex);
515 __ AllocateHeapNumber(storage_reg, scratch1, scratch2, scratch3, slow);
516
517 __ JumpIfNotSmi(value_reg, &heap_number);
518 __ SmiUntag(scratch1, value_reg);
519 __ mtc1(scratch1, f6);
520 __ cvt_d_w(f4, f6);
521 __ jmp(&do_store);
522
523 __ bind(&heap_number);
524 __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex,
525 miss_restore_name, DONT_DO_SMI_CHECK);
526 __ ldc1(f4, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
527
528 __ bind(&do_store);
529 __ sdc1(f4, FieldMemOperand(storage_reg, HeapNumber::kValueOffset));
530 }
531
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000532 // Stub never generated for non-global objects that require access
533 // checks.
534 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
535
536 // Perform map transition for the receiver if necessary.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000537 if (object->map()->unused_property_fields() == 0) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000538 // The properties must be extended before we can store the value.
539 // We jump to a runtime call that extends the properties array.
540 __ push(receiver_reg);
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000541 __ li(a2, Operand(transition));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000542 __ Push(a2, a0);
543 __ TailCallExternalReference(
544 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
545 masm->isolate()),
546 3, 1);
547 return;
548 }
549
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000550 // Update the map of the object.
551 __ li(scratch1, Operand(transition));
552 __ sw(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
verwaest@chromium.org37141392012-05-31 13:27:02 +0000553
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000554 // Update the write barrier for the map field and pass the now unused
555 // name_reg as scratch register.
556 __ RecordWriteField(receiver_reg,
557 HeapObject::kMapOffset,
558 scratch1,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000559 scratch2,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000560 kRAHasNotBeenSaved,
561 kDontSaveFPRegs,
562 OMIT_REMEMBERED_SET,
563 OMIT_SMI_CHECK);
564
565 int index = transition->instance_descriptors()->GetFieldIndex(
566 transition->LastAdded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000567
568 // Adjust for the number of properties stored in the object. Even in the
569 // face of a transition we can use the old map here because the size of the
570 // object and the number of in-object properties is not going to change.
571 index -= object->map()->inobject_properties();
572
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000573 // TODO(verwaest): Share this code as a code stub.
574 if (index < 0) {
575 // Set the property straight into the object.
576 int offset = object->map()->instance_size() + (index * kPointerSize);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000577 if (FLAG_track_double_fields && representation.IsDouble()) {
578 __ sw(storage_reg, FieldMemOperand(receiver_reg, offset));
579 } else {
580 __ sw(value_reg, FieldMemOperand(receiver_reg, offset));
581 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000582
danno@chromium.orgf005df62013-04-30 16:36:45 +0000583 if (!FLAG_track_fields || !representation.IsSmi()) {
584 // Skip updating write barrier if storing a smi.
585 __ JumpIfSmi(value_reg, &exit);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000586
danno@chromium.orgf005df62013-04-30 16:36:45 +0000587 // Update the write barrier for the array address.
588 // Pass the now unused name_reg as a scratch register.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000589 if (!FLAG_track_double_fields || !representation.IsDouble()) {
590 __ mov(name_reg, value_reg);
591 } else {
592 ASSERT(storage_reg.is(name_reg));
593 }
danno@chromium.orgf005df62013-04-30 16:36:45 +0000594 __ RecordWriteField(receiver_reg,
595 offset,
596 name_reg,
597 scratch1,
598 kRAHasNotBeenSaved,
599 kDontSaveFPRegs);
600 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000601 } else {
602 // Write to the properties array.
603 int offset = index * kPointerSize + FixedArray::kHeaderSize;
604 // Get the properties array
605 __ lw(scratch1,
606 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000607 if (FLAG_track_double_fields && representation.IsDouble()) {
608 __ sw(storage_reg, FieldMemOperand(scratch1, offset));
609 } else {
610 __ sw(value_reg, FieldMemOperand(scratch1, offset));
611 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000612
danno@chromium.orgf005df62013-04-30 16:36:45 +0000613 if (!FLAG_track_fields || !representation.IsSmi()) {
614 // Skip updating write barrier if storing a smi.
615 __ JumpIfSmi(value_reg, &exit);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000616
danno@chromium.orgf005df62013-04-30 16:36:45 +0000617 // Update the write barrier for the array address.
618 // Ok to clobber receiver_reg and name_reg, since we return.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000619 if (!FLAG_track_double_fields || !representation.IsDouble()) {
620 __ mov(name_reg, value_reg);
621 } else {
622 ASSERT(storage_reg.is(name_reg));
623 }
danno@chromium.orgf005df62013-04-30 16:36:45 +0000624 __ mov(name_reg, value_reg);
625 __ RecordWriteField(scratch1,
626 offset,
627 name_reg,
628 receiver_reg,
629 kRAHasNotBeenSaved,
630 kDontSaveFPRegs);
631 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000632 }
633
634 // Return the value (register v0).
635 ASSERT(value_reg.is(a0));
636 __ bind(&exit);
637 __ mov(v0, a0);
638 __ Ret();
639}
640
641
642// Generate StoreField code, value is passed in a0 register.
643// When leaving generated code after success, the receiver_reg and name_reg
644// may be clobbered. Upon branch to miss_label, the receiver and name
645// registers have their original values.
646void StubCompiler::GenerateStoreField(MacroAssembler* masm,
647 Handle<JSObject> object,
648 LookupResult* lookup,
649 Register receiver_reg,
650 Register name_reg,
651 Register value_reg,
652 Register scratch1,
653 Register scratch2,
654 Label* miss_label) {
655 // a0 : value
656 Label exit;
657
658 // Check that the map of the object hasn't changed.
659 __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
660 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
661
662 // Perform global security token check if needed.
663 if (object->IsJSGlobalProxy()) {
664 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
665 }
666
667 // Stub never generated for non-global objects that require access
668 // checks.
669 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
670
671 int index = lookup->GetFieldIndex().field_index();
672
673 // Adjust for the number of properties stored in the object. Even in the
674 // face of a transition we can use the old map here because the size of the
675 // object and the number of in-object properties is not going to change.
676 index -= object->map()->inobject_properties();
677
danno@chromium.orgf005df62013-04-30 16:36:45 +0000678 Representation representation = lookup->representation();
679 ASSERT(!representation.IsNone());
680 if (FLAG_track_fields && representation.IsSmi()) {
681 __ JumpIfNotSmi(value_reg, miss_label);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +0000682 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
683 __ JumpIfSmi(value_reg, miss_label);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000684 } else if (FLAG_track_double_fields && representation.IsDouble()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000685 // Load the double storage.
686 if (index < 0) {
687 int offset = object->map()->instance_size() + (index * kPointerSize);
688 __ lw(scratch1, FieldMemOperand(receiver_reg, offset));
689 } else {
690 __ lw(scratch1,
691 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
692 int offset = index * kPointerSize + FixedArray::kHeaderSize;
693 __ lw(scratch1, FieldMemOperand(scratch1, offset));
694 }
695
696 // Store the value into the storage.
697 Label do_store, heap_number;
698 __ JumpIfNotSmi(value_reg, &heap_number);
699 __ SmiUntag(scratch2, value_reg);
700 __ mtc1(scratch2, f6);
701 __ cvt_d_w(f4, f6);
702 __ jmp(&do_store);
703
704 __ bind(&heap_number);
705 __ CheckMap(value_reg, scratch2, Heap::kHeapNumberMapRootIndex,
danno@chromium.orgf005df62013-04-30 16:36:45 +0000706 miss_label, DONT_DO_SMI_CHECK);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000707 __ ldc1(f4, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
708
danno@chromium.orgf005df62013-04-30 16:36:45 +0000709 __ bind(&do_store);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000710 __ sdc1(f4, FieldMemOperand(scratch1, HeapNumber::kValueOffset));
711 // Return the value (register v0).
712 ASSERT(value_reg.is(a0));
713 __ mov(v0, a0);
714 __ Ret();
715 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +0000716 }
717
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000718 // TODO(verwaest): Share this code as a code stub.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000719 if (index < 0) {
720 // Set the property straight into the object.
721 int offset = object->map()->instance_size() + (index * kPointerSize);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000722 __ sw(value_reg, FieldMemOperand(receiver_reg, offset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000723
danno@chromium.orgf005df62013-04-30 16:36:45 +0000724 if (!FLAG_track_fields || !representation.IsSmi()) {
725 // Skip updating write barrier if storing a smi.
726 __ JumpIfSmi(value_reg, &exit);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000727
danno@chromium.orgf005df62013-04-30 16:36:45 +0000728 // Update the write barrier for the array address.
729 // Pass the now unused name_reg as a scratch register.
730 __ mov(name_reg, value_reg);
731 __ RecordWriteField(receiver_reg,
732 offset,
733 name_reg,
734 scratch1,
735 kRAHasNotBeenSaved,
736 kDontSaveFPRegs);
737 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000738 } else {
739 // Write to the properties array.
740 int offset = index * kPointerSize + FixedArray::kHeaderSize;
741 // Get the properties array.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000742 __ lw(scratch1,
743 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000744 __ sw(value_reg, FieldMemOperand(scratch1, offset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000745
danno@chromium.orgf005df62013-04-30 16:36:45 +0000746 if (!FLAG_track_fields || !representation.IsSmi()) {
747 // Skip updating write barrier if storing a smi.
748 __ JumpIfSmi(value_reg, &exit);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000749
danno@chromium.orgf005df62013-04-30 16:36:45 +0000750 // Update the write barrier for the array address.
751 // Ok to clobber receiver_reg and name_reg, since we return.
752 __ mov(name_reg, value_reg);
753 __ RecordWriteField(scratch1,
754 offset,
755 name_reg,
756 receiver_reg,
757 kRAHasNotBeenSaved,
758 kDontSaveFPRegs);
759 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000760 }
761
762 // Return the value (register v0).
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000763 ASSERT(value_reg.is(a0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000764 __ bind(&exit);
765 __ mov(v0, a0);
766 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000767}
768
769
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000770void BaseStoreStubCompiler::GenerateRestoreName(MacroAssembler* masm,
771 Label* label,
772 Handle<Name> name) {
773 if (!label->is_unused()) {
774 __ bind(label);
775 __ li(this->name(), Operand(name));
776 }
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000777}
778
779
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000780static void GenerateCallFunction(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000781 Handle<Object> object,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000782 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000783 Label* miss,
784 Code::ExtraICState extra_ic_state) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000785 // ----------- S t a t e -------------
786 // -- a0: receiver
787 // -- a1: function to call
788 // -----------------------------------
789 // Check that the function really is a function.
790 __ JumpIfSmi(a1, miss);
791 __ GetObjectType(a1, a3, a3);
792 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
793
794 // Patch the receiver on the stack with the global proxy if
795 // necessary.
796 if (object->IsGlobalObject()) {
797 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
798 __ sw(a3, MemOperand(sp, arguments.immediate() * kPointerSize));
799 }
800
801 // Invoke the function.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000802 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
803 ? CALL_AS_FUNCTION
804 : CALL_AS_METHOD;
805 __ InvokeFunction(a1, arguments, JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000806}
807
808
809static void PushInterceptorArguments(MacroAssembler* masm,
810 Register receiver,
811 Register holder,
812 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000813 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000814 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000815 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
816 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000817 Register scratch = name;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000818 __ li(scratch, Operand(interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000819 __ Push(scratch, receiver, holder);
820 __ lw(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
821 __ push(scratch);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000822 __ li(scratch, Operand(ExternalReference::isolate_address(masm->isolate())));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000823 __ push(scratch);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000824}
825
826
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000827static void CompileCallLoadPropertyWithInterceptor(
828 MacroAssembler* masm,
829 Register receiver,
830 Register holder,
831 Register name,
832 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000833 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
834
835 ExternalReference ref =
836 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
837 masm->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000838 __ PrepareCEntryArgs(6);
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000839 __ PrepareCEntryFunction(ref);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000840
841 CEntryStub stub(1);
842 __ CallStub(&stub);
843}
844
845
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000846static const int kFastApiCallArguments = 4;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000847
848
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000849// Reserves space for the extra arguments to API function in the
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000850// caller's frame.
851//
852// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
853static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
854 Register scratch) {
855 ASSERT(Smi::FromInt(0) == 0);
856 for (int i = 0; i < kFastApiCallArguments; i++) {
857 __ push(zero_reg);
858 }
859}
860
861
862// Undoes the effects of ReserveSpaceForFastApiCall.
863static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
864 __ Drop(kFastApiCallArguments);
865}
866
867
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000868static void GenerateFastApiDirectCall(MacroAssembler* masm,
869 const CallOptimization& optimization,
870 int argc) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000871 // ----------- S t a t e -------------
872 // -- sp[0] : holder (set by CheckPrototypes)
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000873 // -- sp[4] : callee JS function
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000874 // -- sp[8] : call data
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000875 // -- sp[12] : isolate
876 // -- sp[16] : last JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000877 // -- ...
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000878 // -- sp[(argc + 3) * 4] : first JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000879 // -- sp[(argc + 4) * 4] : receiver
880 // -----------------------------------
881 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000882 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000883 __ LoadHeapObject(t1, function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000884 __ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset));
885
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000886 // Pass the additional arguments.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000887 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000888 Handle<Object> call_data(api_call_info->data(), masm->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000889 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
890 __ li(a0, api_call_info);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000891 __ lw(t2, FieldMemOperand(a0, CallHandlerInfo::kDataOffset));
892 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000893 __ li(t2, call_data);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000894 }
895
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000896 __ li(t3, Operand(ExternalReference::isolate_address(masm->isolate())));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000897 // Store JS function, call data and isolate.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000898 __ sw(t1, MemOperand(sp, 1 * kPointerSize));
899 __ sw(t2, MemOperand(sp, 2 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000900 __ sw(t3, MemOperand(sp, 3 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000901
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000902 // Prepare arguments.
903 __ Addu(a2, sp, Operand(3 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000904
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000905 // Allocate the v8::Arguments structure in the arguments' space since
906 // it's not controlled by GC.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000907 const int kApiStackSpace = 4;
908
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000909 FrameScope frame_scope(masm, StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000910 __ EnterExitFrame(false, kApiStackSpace);
911
912 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
913 // struct from the function (which is currently the case). This means we pass
914 // the first argument in a1 instead of a0. TryCallApiFunctionAndReturn
915 // will handle setting up a0.
916
917 // a1 = v8::Arguments&
918 // Arguments is built at sp + 1 (sp is a reserved spot for ra).
919 __ Addu(a1, sp, kPointerSize);
920
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000921 // v8::Arguments::implicit_args_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000922 __ sw(a2, MemOperand(a1, 0 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000923 // v8::Arguments::values_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000924 __ Addu(t0, a2, Operand(argc * kPointerSize));
925 __ sw(t0, MemOperand(a1, 1 * kPointerSize));
926 // v8::Arguments::length_ = argc
927 __ li(t0, Operand(argc));
928 __ sw(t0, MemOperand(a1, 2 * kPointerSize));
929 // v8::Arguments::is_construct_call = 0
930 __ sw(zero_reg, MemOperand(a1, 3 * kPointerSize));
931
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000932 const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000933 Address function_address = v8::ToCData<Address>(api_call_info->callback());
934 ApiFunction fun(function_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000935 ExternalReference ref =
936 ExternalReference(&fun,
937 ExternalReference::DIRECT_API_CALL,
938 masm->isolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000939 AllowExternalCallThatCantCauseGC scope(masm);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000940 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000941}
942
lrn@chromium.org7516f052011-03-30 08:52:27 +0000943class CallInterceptorCompiler BASE_EMBEDDED {
944 public:
945 CallInterceptorCompiler(StubCompiler* stub_compiler,
946 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000947 Register name,
948 Code::ExtraICState extra_ic_state)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000949 : stub_compiler_(stub_compiler),
950 arguments_(arguments),
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000951 name_(name),
952 extra_ic_state_(extra_ic_state) {}
lrn@chromium.org7516f052011-03-30 08:52:27 +0000953
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000954 void Compile(MacroAssembler* masm,
955 Handle<JSObject> object,
956 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000957 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000958 LookupResult* lookup,
959 Register receiver,
960 Register scratch1,
961 Register scratch2,
962 Register scratch3,
963 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000964 ASSERT(holder->HasNamedInterceptor());
965 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
966
967 // Check that the receiver isn't a smi.
968 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000969 CallOptimization optimization(lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000970 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000971 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
972 holder, lookup, name, optimization, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000973 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000974 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
975 name, holder, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000976 }
977 }
978
979 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000980 void CompileCacheable(MacroAssembler* masm,
981 Handle<JSObject> object,
982 Register receiver,
983 Register scratch1,
984 Register scratch2,
985 Register scratch3,
986 Handle<JSObject> interceptor_holder,
987 LookupResult* lookup,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000988 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000989 const CallOptimization& optimization,
990 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000991 ASSERT(optimization.is_constant_call());
992 ASSERT(!lookup->holder()->IsGlobalObject());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000993 Counters* counters = masm->isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000994 int depth1 = kInvalidProtoDepth;
995 int depth2 = kInvalidProtoDepth;
996 bool can_do_fast_api_call = false;
997 if (optimization.is_simple_api_call() &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000998 !lookup->holder()->IsGlobalObject()) {
999 depth1 = optimization.GetPrototypeDepthOfExpectedType(
1000 object, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001001 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001002 depth2 = optimization.GetPrototypeDepthOfExpectedType(
1003 interceptor_holder, Handle<JSObject>(lookup->holder()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001004 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001005 can_do_fast_api_call =
1006 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001007 }
1008
1009 __ IncrementCounter(counters->call_const_interceptor(), 1,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001010 scratch1, scratch2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001011
1012 if (can_do_fast_api_call) {
1013 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
1014 scratch1, scratch2);
1015 ReserveSpaceForFastApiCall(masm, scratch1);
1016 }
1017
1018 // Check that the maps from receiver to interceptor's holder
1019 // haven't changed and thus we can invoke interceptor.
1020 Label miss_cleanup;
1021 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
1022 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001023 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
1024 scratch1, scratch2, scratch3,
1025 name, depth1, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001026
1027 // Invoke an interceptor and if it provides a value,
1028 // branch to |regular_invoke|.
1029 Label regular_invoke;
1030 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
1031 &regular_invoke);
1032
1033 // Interceptor returned nothing for this property. Try to use cached
1034 // constant function.
1035
1036 // Check that the maps from interceptor's holder to constant function's
1037 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001038 if (*interceptor_holder != lookup->holder()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001039 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001040 Handle<JSObject>(lookup->holder()),
1041 scratch1, scratch2, scratch3,
1042 name, depth2, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001043 } else {
1044 // CheckPrototypes has a side effect of fetching a 'holder'
1045 // for API (object which is instanceof for the signature). It's
1046 // safe to omit it here, as if present, it should be fetched
1047 // by the previous CheckPrototypes.
1048 ASSERT(depth2 == kInvalidProtoDepth);
1049 }
1050
1051 // Invoke function.
1052 if (can_do_fast_api_call) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001053 GenerateFastApiDirectCall(masm, optimization, arguments_.immediate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001054 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001055 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
1056 ? CALL_AS_FUNCTION
1057 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001058 Handle<JSFunction> function = optimization.constant_function();
1059 ParameterCount expected(function);
1060 __ InvokeFunction(function, expected, arguments_,
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001061 JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001062 }
1063
1064 // Deferred code for fast API call case---clean preallocated space.
1065 if (can_do_fast_api_call) {
1066 __ bind(&miss_cleanup);
1067 FreeSpaceForFastApiCall(masm);
1068 __ Branch(miss_label);
1069 }
1070
1071 // Invoke a regular function.
1072 __ bind(&regular_invoke);
1073 if (can_do_fast_api_call) {
1074 FreeSpaceForFastApiCall(masm);
1075 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00001076 }
1077
1078 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001079 Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001080 Register receiver,
1081 Register scratch1,
1082 Register scratch2,
1083 Register scratch3,
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001084 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001085 Handle<JSObject> interceptor_holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001086 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001087 Register holder =
1088 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001089 scratch1, scratch2, scratch3,
1090 name, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001091
1092 // Call a runtime function to load the interceptor property.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001093 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001094 // Save the name_ register across the call.
1095 __ push(name_);
1096
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001097 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001098
1099 __ CallExternalReference(
1100 ExternalReference(
1101 IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
1102 masm->isolate()),
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001103 6);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001104 // Restore the name_ register.
1105 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001106 // Leave the internal frame.
lrn@chromium.org7516f052011-03-30 08:52:27 +00001107 }
1108
1109 void LoadWithInterceptor(MacroAssembler* masm,
1110 Register receiver,
1111 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001112 Handle<JSObject> holder_obj,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001113 Register scratch,
1114 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001115 {
1116 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001117
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001118 __ Push(holder, name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001119 CompileCallLoadPropertyWithInterceptor(masm,
1120 receiver,
1121 holder,
1122 name_,
1123 holder_obj);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001124 __ pop(name_); // Restore the name.
1125 __ pop(receiver); // Restore the holder.
1126 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001127 // If interceptor returns no-result sentinel, call the constant function.
1128 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
1129 __ Branch(interceptor_succeeded, ne, v0, Operand(scratch));
lrn@chromium.org7516f052011-03-30 08:52:27 +00001130 }
1131
1132 StubCompiler* stub_compiler_;
1133 const ParameterCount& arguments_;
1134 Register name_;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001135 Code::ExtraICState extra_ic_state_;
lrn@chromium.org7516f052011-03-30 08:52:27 +00001136};
1137
1138
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001139// Calls GenerateCheckPropertyCell for each global object in the prototype chain
1140// from object to (but not including) holder.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001141static void GenerateCheckPropertyCells(MacroAssembler* masm,
1142 Handle<JSObject> object,
1143 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001144 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001145 Register scratch,
1146 Label* miss) {
1147 Handle<JSObject> current = object;
1148 while (!current.is_identical_to(holder)) {
1149 if (current->IsGlobalObject()) {
1150 GenerateCheckPropertyCell(masm,
1151 Handle<GlobalObject>::cast(current),
1152 name,
1153 scratch,
1154 miss);
1155 }
1156 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
1157 }
1158}
1159
1160
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001161// Convert and store int passed in register ival to IEEE 754 single precision
1162// floating point value at memory location (dst + 4 * wordoffset)
1163// If FPU is available use it for conversion.
1164static void StoreIntAsFloat(MacroAssembler* masm,
1165 Register dst,
1166 Register wordoffset,
1167 Register ival,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001168 Register scratch1) {
1169 __ mtc1(ival, f0);
1170 __ cvt_s_w(f0, f0);
1171 __ sll(scratch1, wordoffset, 2);
1172 __ addu(scratch1, dst, scratch1);
1173 __ swc1(f0, MemOperand(scratch1, 0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001174}
1175
1176
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001177void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001178 __ Jump(code, RelocInfo::CODE_TARGET);
1179}
1180
1181
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001182#undef __
1183#define __ ACCESS_MASM(masm())
1184
1185
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001186Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
1187 Register object_reg,
1188 Handle<JSObject> holder,
1189 Register holder_reg,
1190 Register scratch1,
1191 Register scratch2,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001192 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001193 int save_at_depth,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001194 Label* miss,
1195 PrototypeCheckType check) {
1196 Handle<JSObject> first = object;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001197 // Make sure there's no overlap between holder and object registers.
1198 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1199 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1200 && !scratch2.is(scratch1));
1201
1202 // Keep track of the current object in register reg.
1203 Register reg = object_reg;
1204 int depth = 0;
1205
1206 if (save_at_depth == depth) {
1207 __ sw(reg, MemOperand(sp));
1208 }
1209
1210 // Check the maps in the prototype chain.
1211 // Traverse the prototype chain from the object and do map checks.
1212 Handle<JSObject> current = object;
1213 while (!current.is_identical_to(holder)) {
1214 ++depth;
1215
1216 // Only global objects and objects that do not require access
1217 // checks are allowed in stubs.
1218 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1219
1220 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
1221 if (!current->HasFastProperties() &&
1222 !current->IsJSGlobalObject() &&
1223 !current->IsJSGlobalProxy()) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001224 if (!name->IsUniqueName()) {
1225 ASSERT(name->IsString());
1226 name = factory()->InternalizeString(Handle<String>::cast(name));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001227 }
1228 ASSERT(current->property_dictionary()->FindEntry(*name) ==
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001229 NameDictionary::kNotFound);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001230
1231 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1232 scratch1, scratch2);
1233
1234 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1235 reg = holder_reg; // From now on the object will be in holder_reg.
1236 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1237 } else {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001238 Register map_reg = scratch1;
1239 if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) {
1240 Handle<Map> current_map(current->map());
1241 // CheckMap implicitly loads the map of |reg| into |map_reg|.
1242 __ CheckMap(reg, map_reg, current_map, miss, DONT_DO_SMI_CHECK,
1243 ALLOW_ELEMENT_TRANSITION_MAPS);
1244 } else {
1245 __ lw(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
1246 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001247 // Check access rights to the global object. This has to happen after
1248 // the map check so that we know that the object is actually a global
1249 // object.
1250 if (current->IsJSGlobalProxy()) {
1251 __ CheckAccessGlobalProxy(reg, scratch2, miss);
1252 }
1253 reg = holder_reg; // From now on the object will be in holder_reg.
1254
1255 if (heap()->InNewSpace(*prototype)) {
1256 // The prototype is in new space; we cannot store a reference to it
1257 // in the code. Load it from the map.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001258 __ lw(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001259 } else {
1260 // The prototype is in old space; load it directly.
1261 __ li(reg, Operand(prototype));
1262 }
1263 }
1264
1265 if (save_at_depth == depth) {
1266 __ sw(reg, MemOperand(sp));
1267 }
1268
1269 // Go to the next object in the prototype chain.
1270 current = prototype;
1271 }
1272
1273 // Log the check depth.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001274 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001275
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001276 if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) {
1277 // Check the holder map.
1278 __ CheckMap(reg, scratch1, Handle<Map>(holder->map()), miss,
1279 DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
1280 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001281
1282 // Perform security check for access to the global object.
1283 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1284 if (holder->IsJSGlobalProxy()) {
1285 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1286 }
1287
1288 // If we've skipped any global objects, it's not enough to verify that
1289 // their maps haven't changed. We also need to check that the property
1290 // cell for the property is still empty.
1291 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1292
1293 // Return the register containing the holder.
1294 return reg;
1295}
1296
1297
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001298void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success,
1299 Label* miss) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001300 if (!miss->is_unused()) {
1301 __ Branch(success);
1302 __ bind(miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001303 TailCallBuiltin(masm(), MissBuiltin(kind()));
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001304 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001305}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001306
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001307
1308Register BaseLoadStubCompiler::CallbackHandlerFrontend(
1309 Handle<JSObject> object,
1310 Register object_reg,
1311 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001312 Handle<Name> name,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001313 Label* success,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001314 Handle<ExecutableAccessorInfo> callback) {
1315 Label miss;
1316
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001317 Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001318
1319 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
1320 ASSERT(!reg.is(scratch2()));
1321 ASSERT(!reg.is(scratch3()));
1322 ASSERT(!reg.is(scratch4()));
1323
1324 // Load the properties dictionary.
1325 Register dictionary = scratch4();
1326 __ lw(dictionary, FieldMemOperand(reg, JSObject::kPropertiesOffset));
1327
1328 // Probe the dictionary.
1329 Label probe_done;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001330 NameDictionaryLookupStub::GeneratePositiveLookup(masm(),
1331 &miss,
1332 &probe_done,
1333 dictionary,
1334 this->name(),
1335 scratch2(),
1336 scratch3());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001337 __ bind(&probe_done);
1338
1339 // If probing finds an entry in the dictionary, scratch3 contains the
1340 // pointer into the dictionary. Check that the value is the callback.
1341 Register pointer = scratch3();
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001342 const int kElementsStartOffset = NameDictionary::kHeaderSize +
1343 NameDictionary::kElementsStartIndex * kPointerSize;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001344 const int kValueOffset = kElementsStartOffset + kPointerSize;
1345 __ lw(scratch2(), FieldMemOperand(pointer, kValueOffset));
1346 __ Branch(&miss, ne, scratch2(), Operand(callback));
1347 }
1348
1349 HandlerFrontendFooter(success, &miss);
1350 return reg;
1351}
1352
1353
1354void BaseLoadStubCompiler::NonexistentHandlerFrontend(
1355 Handle<JSObject> object,
1356 Handle<JSObject> last,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001357 Handle<Name> name,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001358 Label* success,
1359 Handle<GlobalObject> global) {
1360 Label miss;
1361
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001362 HandlerFrontendHeader(object, receiver(), last, name, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001363
1364 // If the last object in the prototype chain is a global object,
1365 // check that the global property cell is empty.
1366 if (!global.is_null()) {
1367 GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
1368 }
1369
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001370 HandlerFrontendFooter(success, &miss);
1371}
1372
1373
1374void BaseLoadStubCompiler::GenerateLoadField(Register reg,
1375 Handle<JSObject> holder,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001376 PropertyIndex field,
1377 Representation representation) {
1378 if (!reg.is(receiver())) __ mov(receiver(), reg);
1379 if (kind() == Code::LOAD_IC) {
1380 LoadFieldStub stub(field.is_inobject(holder),
1381 field.translate(holder),
1382 representation);
1383 GenerateTailCall(masm(), stub.GetCode(isolate()));
1384 } else {
1385 KeyedLoadFieldStub stub(field.is_inobject(holder),
1386 field.translate(holder),
1387 representation);
1388 GenerateTailCall(masm(), stub.GetCode(isolate()));
1389 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001390}
1391
1392
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001393void BaseLoadStubCompiler::GenerateLoadConstant(Handle<JSFunction> value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001394 // Return the constant value.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001395 __ LoadHeapObject(v0, value);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001396 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001397}
1398
1399
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001400void BaseLoadStubCompiler::GenerateLoadCallback(
1401 Register reg,
1402 Handle<ExecutableAccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001403 // Build AccessorInfo::args_ list on the stack and push property name below
1404 // the exit frame to make GC aware of them and store pointers to them.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001405 __ push(receiver());
1406 __ mov(scratch2(), sp); // scratch2 = AccessorInfo::args_
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001407 if (heap()->InNewSpace(callback->data())) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001408 __ li(scratch3(), callback);
1409 __ lw(scratch3(), FieldMemOperand(scratch3(),
1410 ExecutableAccessorInfo::kDataOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001411 } else {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001412 __ li(scratch3(), Handle<Object>(callback->data(), isolate()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001413 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001414 __ Subu(sp, sp, 4 * kPointerSize);
1415 __ sw(reg, MemOperand(sp, 3 * kPointerSize));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001416 __ sw(scratch3(), MemOperand(sp, 2 * kPointerSize));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001417 __ li(scratch3(),
1418 Operand(ExternalReference::isolate_address(isolate())));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001419 __ sw(scratch3(), MemOperand(sp, 1 * kPointerSize));
1420 __ sw(name(), MemOperand(sp, 0 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001421
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001422 __ mov(a2, scratch2()); // Saved in case scratch2 == a1.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001423 __ mov(a1, sp); // a1 (first argument - see note below) = Handle<Name>
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001424
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001425 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
1426 // struct from the function (which is currently the case). This means we pass
1427 // the arguments in a1-a2 instead of a0-a1. TryCallApiFunctionAndReturn
1428 // will handle setting up a0.
1429
1430 const int kApiStackSpace = 1;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001431 FrameScope frame_scope(masm(), StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001432 __ EnterExitFrame(false, kApiStackSpace);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001433
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001434 // Create AccessorInfo instance on the stack above the exit frame with
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001435 // scratch2 (internal::Object** args_) as the data.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001436 __ sw(a2, MemOperand(sp, kPointerSize));
1437 // a2 (second argument - see note above) = AccessorInfo&
1438 __ Addu(a2, sp, kPointerSize);
1439
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001440 const int kStackUnwindSpace = 5;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001441 Address getter_address = v8::ToCData<Address>(callback->getter());
1442 ApiFunction fun(getter_address);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001443 ExternalReference ref = ExternalReference(
1444 &fun, ExternalReference::DIRECT_GETTER_CALL, isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001445 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
ager@chromium.org5c838252010-02-19 08:53:10 +00001446}
1447
1448
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001449void BaseLoadStubCompiler::GenerateLoadInterceptor(
1450 Register holder_reg,
1451 Handle<JSObject> object,
1452 Handle<JSObject> interceptor_holder,
1453 LookupResult* lookup,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001454 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001455 ASSERT(interceptor_holder->HasNamedInterceptor());
1456 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1457
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001458 // So far the most popular follow ups for interceptor loads are FIELD
1459 // and CALLBACKS, so inline only them, other cases may be added
1460 // later.
1461 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001462 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001463 if (lookup->IsField()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001464 compile_followup_inline = true;
1465 } else if (lookup->type() == CALLBACKS &&
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001466 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
1467 ExecutableAccessorInfo* callback =
1468 ExecutableAccessorInfo::cast(lookup->GetCallbackObject());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001469 compile_followup_inline = callback->getter() != NULL &&
1470 callback->IsCompatibleReceiver(*object);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001471 }
1472 }
1473
1474 if (compile_followup_inline) {
1475 // Compile the interceptor call, followed by inline code to load the
1476 // property from further up the prototype chain if the call fails.
1477 // Check that the maps haven't changed.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001478 ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001479
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001480 // Preserve the receiver register explicitly whenever it is different from
1481 // the holder and it is needed should the interceptor return without any
1482 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1483 // the FIELD case might cause a miss during the prototype check.
1484 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001485 bool must_preserve_receiver_reg = !receiver().is(holder_reg) &&
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001486 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1487
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001488 // Save necessary data before invoking an interceptor.
1489 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001490 {
1491 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001492 if (must_preserve_receiver_reg) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001493 __ Push(receiver(), holder_reg, this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001494 } else {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001495 __ Push(holder_reg, this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001496 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001497 // Invoke an interceptor. Note: map checks from receiver to
1498 // interceptor's holder has been compiled before (see a caller
1499 // of this method).
1500 CompileCallLoadPropertyWithInterceptor(masm(),
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001501 receiver(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001502 holder_reg,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001503 this->name(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001504 interceptor_holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001505 // Check if interceptor provided a value for property. If it's
1506 // the case, return immediately.
1507 Label interceptor_failed;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001508 __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
1509 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001510 frame_scope.GenerateLeaveFrame();
1511 __ Ret();
1512
1513 __ bind(&interceptor_failed);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001514 __ pop(this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001515 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001516 if (must_preserve_receiver_reg) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001517 __ pop(receiver());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001518 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001519 // Leave the internal frame.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001520 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001521 GenerateLoadPostInterceptor(holder_reg, interceptor_holder, name, lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001522 } else { // !compile_followup_inline
1523 // Call the runtime system to load the interceptor.
1524 // Check that the maps haven't changed.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001525 PushInterceptorArguments(masm(), receiver(), holder_reg,
1526 this->name(), interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001527
1528 ExternalReference ref = ExternalReference(
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001529 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001530 __ TailCallExternalReference(ref, 6, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001531 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001532}
1533
1534
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001535void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001536 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001537 __ Branch(miss, ne, a2, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001538 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001539}
1540
1541
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001542void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1543 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001544 Handle<Name> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001545 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001546 ASSERT(holder->IsGlobalObject());
1547
1548 // Get the number of arguments.
1549 const int argc = arguments().immediate();
1550
1551 // Get the receiver from the stack.
1552 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1553
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001554 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001555 __ JumpIfSmi(a0, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001556 CheckPrototypes(object, a0, holder, a3, a1, t0, name, miss);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001557}
1558
1559
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001560void CallStubCompiler::GenerateLoadFunctionFromCell(
1561 Handle<JSGlobalPropertyCell> cell,
1562 Handle<JSFunction> function,
1563 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001564 // Get the value from the cell.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001565 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001566 __ lw(a1, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
1567
1568 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001569 if (heap()->InNewSpace(*function)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001570 // We can't embed a pointer to a function in new space so we have
1571 // to verify that the shared function info is unchanged. This has
1572 // the nice side effect that multiple closures based on the same
1573 // function can all use this call IC. Before we load through the
1574 // function, we have to verify that it still is a function.
1575 __ JumpIfSmi(a1, miss);
1576 __ GetObjectType(a1, a3, a3);
1577 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
1578
1579 // Check the shared function info. Make sure it hasn't changed.
1580 __ li(a3, Handle<SharedFunctionInfo>(function->shared()));
1581 __ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
1582 __ Branch(miss, ne, t0, Operand(a3));
1583 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001584 __ Branch(miss, ne, a1, Operand(function));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001585 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001586}
1587
1588
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001589void CallStubCompiler::GenerateMissBranch() {
1590 Handle<Code> code =
danno@chromium.org40cb8782011-05-25 07:58:50 +00001591 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1592 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001593 extra_state_);
1594 __ Jump(code, RelocInfo::CODE_TARGET);
1595}
1596
1597
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001598Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1599 Handle<JSObject> holder,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001600 PropertyIndex index,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001601 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001602 // ----------- S t a t e -------------
1603 // -- a2 : name
1604 // -- ra : return address
1605 // -----------------------------------
1606 Label miss;
1607
1608 GenerateNameCheck(name, &miss);
1609
1610 const int argc = arguments().immediate();
1611
1612 // Get the receiver of the function from the stack into a0.
1613 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1614 // Check that the receiver isn't a smi.
1615 __ JumpIfSmi(a0, &miss, t0);
1616
1617 // Do the right check and compute the holder register.
1618 Register reg = CheckPrototypes(object, a0, holder, a1, a3, t0, name, &miss);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001619 GenerateFastPropertyLoad(masm(), a1, reg, index.is_inobject(holder),
1620 index.translate(holder), Representation::Tagged());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001621
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001622 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001623
1624 // Handle call cache miss.
1625 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001626 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001627
1628 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001629 return GetCode(Code::FIELD, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001630}
1631
1632
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001633Handle<Code> CallStubCompiler::CompileArrayPushCall(
1634 Handle<Object> object,
1635 Handle<JSObject> holder,
1636 Handle<JSGlobalPropertyCell> cell,
1637 Handle<JSFunction> function,
1638 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001639 // ----------- S t a t e -------------
1640 // -- a2 : name
1641 // -- ra : return address
1642 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1643 // -- ...
1644 // -- sp[argc * 4] : receiver
1645 // -----------------------------------
1646
1647 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001648 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001649
1650 Label miss;
1651
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001652 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001653
1654 Register receiver = a1;
1655
1656 // Get the receiver from the stack.
1657 const int argc = arguments().immediate();
1658 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1659
1660 // Check that the receiver isn't a smi.
1661 __ JumpIfSmi(receiver, &miss);
1662
1663 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001664 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, a3, v0, t0,
1665 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001666
1667 if (argc == 0) {
1668 // Nothing to do, just return the length.
1669 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1670 __ Drop(argc + 1);
1671 __ Ret();
1672 } else {
1673 Label call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001674 if (argc == 1) { // Otherwise fall through to call the builtin.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001675 Label attempt_to_grow_elements, with_write_barrier, check_double;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001676
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001677 Register elements = t2;
1678 Register end_elements = t1;
1679 // Get the elements array of the object.
1680 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1681
1682 // Check that the elements are in fast mode and writable.
1683 __ CheckMap(elements,
1684 v0,
1685 Heap::kFixedArrayMapRootIndex,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001686 &check_double,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001687 DONT_DO_SMI_CHECK);
1688
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001689 // Get the array's length into v0 and calculate new length.
1690 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1691 STATIC_ASSERT(kSmiTagSize == 1);
1692 STATIC_ASSERT(kSmiTag == 0);
1693 __ Addu(v0, v0, Operand(Smi::FromInt(argc)));
1694
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001695 // Get the elements' length.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001696 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1697
1698 // Check if we could survive without allocation.
1699 __ Branch(&attempt_to_grow_elements, gt, v0, Operand(t0));
1700
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001701 // Check if value is a smi.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001702 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1703 __ JumpIfNotSmi(t0, &with_write_barrier);
1704
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001705 // Save new length.
1706 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1707
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001708 // Store the value.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001709 // We may need a register containing the address end_elements below,
1710 // so write back the value in end_elements.
1711 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1712 __ Addu(end_elements, elements, end_elements);
1713 const int kEndElementsOffset =
1714 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001715 __ Addu(end_elements, end_elements, kEndElementsOffset);
1716 __ sw(t0, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001717
1718 // Check for a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001719 __ Drop(argc + 1);
1720 __ Ret();
1721
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001722 __ bind(&check_double);
1723
1724 // Check that the elements are in fast mode and writable.
1725 __ CheckMap(elements,
1726 a0,
1727 Heap::kFixedDoubleArrayMapRootIndex,
1728 &call_builtin,
1729 DONT_DO_SMI_CHECK);
1730
1731 // Get the array's length into r0 and calculate new length.
1732 __ lw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1733 STATIC_ASSERT(kSmiTagSize == 1);
1734 STATIC_ASSERT(kSmiTag == 0);
1735 __ Addu(a0, a0, Operand(Smi::FromInt(argc)));
1736
1737 // Get the elements' length.
1738 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1739
1740 // Check if we could survive without allocation.
1741 __ Branch(&call_builtin, gt, a0, Operand(t0));
1742
1743 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1744 __ StoreNumberToDoubleElements(
1745 t0, a0, elements, a3, t1, a2, t5,
1746 &call_builtin, argc * kDoubleSize);
1747
1748 // Save new length.
1749 __ sw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1750
1751 // Check for a smi.
1752 __ Drop(argc + 1);
1753 __ Ret();
1754
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001755 __ bind(&with_write_barrier);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001756
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001757 __ lw(a3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1758
1759 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
1760 Label fast_object, not_fast_object;
1761 __ CheckFastObjectElements(a3, t3, &not_fast_object);
1762 __ jmp(&fast_object);
1763 // In case of fast smi-only, convert to fast object, otherwise bail out.
1764 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001765 __ CheckFastSmiElements(a3, t3, &call_builtin);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001766
1767 __ lw(t3, FieldMemOperand(t0, HeapObject::kMapOffset));
1768 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
1769 __ Branch(&call_builtin, eq, t3, Operand(at));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001770 // edx: receiver
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001771 // a3: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001772 Label try_holey_map;
1773 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001774 FAST_ELEMENTS,
1775 a3,
1776 t3,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001777 &try_holey_map);
1778 __ mov(a2, receiver);
1779 ElementsTransitionGenerator::
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001780 GenerateMapChangeElementsTransition(masm(),
1781 DONT_TRACK_ALLOCATION_SITE,
1782 NULL);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001783 __ jmp(&fast_object);
1784
1785 __ bind(&try_holey_map);
1786 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1787 FAST_HOLEY_ELEMENTS,
1788 a3,
1789 t3,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001790 &call_builtin);
1791 __ mov(a2, receiver);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001792 ElementsTransitionGenerator::
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001793 GenerateMapChangeElementsTransition(masm(),
1794 DONT_TRACK_ALLOCATION_SITE,
1795 NULL);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001796 __ bind(&fast_object);
1797 } else {
1798 __ CheckFastObjectElements(a3, a3, &call_builtin);
1799 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001800
1801 // Save new length.
1802 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1803
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001804 // Store the value.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001805 // We may need a register containing the address end_elements below,
1806 // so write back the value in end_elements.
1807 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1808 __ Addu(end_elements, elements, end_elements);
1809 __ Addu(end_elements, end_elements, kEndElementsOffset);
1810 __ sw(t0, MemOperand(end_elements));
1811
1812 __ RecordWrite(elements,
1813 end_elements,
1814 t0,
1815 kRAHasNotBeenSaved,
1816 kDontSaveFPRegs,
1817 EMIT_REMEMBERED_SET,
1818 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001819 __ Drop(argc + 1);
1820 __ Ret();
1821
1822 __ bind(&attempt_to_grow_elements);
1823 // v0: array's length + 1.
1824 // t0: elements' length.
1825
1826 if (!FLAG_inline_new) {
1827 __ Branch(&call_builtin);
1828 }
1829
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001830 __ lw(a2, MemOperand(sp, (argc - 1) * kPointerSize));
1831 // Growing elements that are SMI-only requires special handling in case
1832 // the new element is non-Smi. For now, delegate to the builtin.
1833 Label no_fast_elements_check;
1834 __ JumpIfSmi(a2, &no_fast_elements_check);
1835 __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1836 __ CheckFastObjectElements(t3, t3, &call_builtin);
1837 __ bind(&no_fast_elements_check);
1838
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001839 ExternalReference new_space_allocation_top =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001840 ExternalReference::new_space_allocation_top_address(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001841 ExternalReference new_space_allocation_limit =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001842 ExternalReference::new_space_allocation_limit_address(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001843
1844 const int kAllocationDelta = 4;
1845 // Load top and check if it is the end of elements.
1846 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1847 __ Addu(end_elements, elements, end_elements);
1848 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset));
1849 __ li(t3, Operand(new_space_allocation_top));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001850 __ lw(a3, MemOperand(t3));
1851 __ Branch(&call_builtin, ne, end_elements, Operand(a3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001852
1853 __ li(t5, Operand(new_space_allocation_limit));
1854 __ lw(t5, MemOperand(t5));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001855 __ Addu(a3, a3, Operand(kAllocationDelta * kPointerSize));
1856 __ Branch(&call_builtin, hi, a3, Operand(t5));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001857
1858 // We fit and could grow elements.
1859 // Update new_space_allocation_top.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001860 __ sw(a3, MemOperand(t3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001861 // Push the argument.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001862 __ sw(a2, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001863 // Fill the rest with holes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001864 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001865 for (int i = 1; i < kAllocationDelta; i++) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001866 __ sw(a3, MemOperand(end_elements, i * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001867 }
1868
1869 // Update elements' and array's sizes.
1870 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1871 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta)));
1872 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1873
1874 // Elements are in new space, so write barrier is not required.
1875 __ Drop(argc + 1);
1876 __ Ret();
1877 }
1878 __ bind(&call_builtin);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001879 __ TailCallExternalReference(
1880 ExternalReference(Builtins::c_ArrayPush, isolate()), argc + 1, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001881 }
1882
1883 // Handle call cache miss.
1884 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001885 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001886
1887 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001888 return GetCode(function);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001889}
1890
1891
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001892Handle<Code> CallStubCompiler::CompileArrayPopCall(
1893 Handle<Object> object,
1894 Handle<JSObject> holder,
1895 Handle<JSGlobalPropertyCell> cell,
1896 Handle<JSFunction> function,
1897 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001898 // ----------- S t a t e -------------
1899 // -- a2 : name
1900 // -- ra : return address
1901 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1902 // -- ...
1903 // -- sp[argc * 4] : receiver
1904 // -----------------------------------
1905
1906 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001907 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001908
1909 Label miss, return_undefined, call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001910 Register receiver = a1;
1911 Register elements = a3;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001912 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001913
1914 // Get the receiver from the stack.
1915 const int argc = arguments().immediate();
1916 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001917 // Check that the receiver isn't a smi.
1918 __ JumpIfSmi(receiver, &miss);
1919
1920 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001921 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, elements,
1922 t0, v0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001923
1924 // Get the elements array of the object.
1925 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1926
1927 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001928 __ CheckMap(elements,
1929 v0,
1930 Heap::kFixedArrayMapRootIndex,
1931 &call_builtin,
1932 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001933
1934 // Get the array's length into t0 and calculate new length.
1935 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1936 __ Subu(t0, t0, Operand(Smi::FromInt(1)));
1937 __ Branch(&return_undefined, lt, t0, Operand(zero_reg));
1938
1939 // Get the last element.
1940 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1941 STATIC_ASSERT(kSmiTagSize == 1);
1942 STATIC_ASSERT(kSmiTag == 0);
1943 // We can't address the last element in one operation. Compute the more
1944 // expensive shift first, and use an offset later on.
1945 __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize);
1946 __ Addu(elements, elements, t1);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001947 __ lw(v0, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001948 __ Branch(&call_builtin, eq, v0, Operand(t2));
1949
1950 // Set the array's length.
1951 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1952
1953 // Fill with the hole.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001954 __ sw(t2, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001955 __ Drop(argc + 1);
1956 __ Ret();
1957
1958 __ bind(&return_undefined);
1959 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
1960 __ Drop(argc + 1);
1961 __ Ret();
1962
1963 __ bind(&call_builtin);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001964 __ TailCallExternalReference(
1965 ExternalReference(Builtins::c_ArrayPop, isolate()), argc + 1, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001966
1967 // Handle call cache miss.
1968 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001969 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001970
1971 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001972 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001973}
1974
1975
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001976Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1977 Handle<Object> object,
1978 Handle<JSObject> holder,
1979 Handle<JSGlobalPropertyCell> cell,
1980 Handle<JSFunction> function,
1981 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001982 // ----------- S t a t e -------------
1983 // -- a2 : function name
1984 // -- ra : return address
1985 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1986 // -- ...
1987 // -- sp[argc * 4] : receiver
1988 // -----------------------------------
1989
1990 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001991 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001992
1993 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001994 Label miss;
1995 Label name_miss;
1996 Label index_out_of_range;
1997
1998 Label* index_out_of_range_label = &index_out_of_range;
1999
danno@chromium.org40cb8782011-05-25 07:58:50 +00002000 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002001 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002002 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002003 index_out_of_range_label = &miss;
2004 }
2005
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002006 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002007
2008 // Check that the maps starting from the prototype haven't changed.
2009 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2010 Context::STRING_FUNCTION_INDEX,
2011 v0,
2012 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002013 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002014 CheckPrototypes(
2015 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2016 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002017
2018 Register receiver = a1;
2019 Register index = t1;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002020 Register result = v0;
2021 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
2022 if (argc > 0) {
2023 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
2024 } else {
2025 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
2026 }
2027
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002028 StringCharCodeAtGenerator generator(receiver,
2029 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002030 result,
2031 &miss, // When not a string.
2032 &miss, // When not a number.
2033 index_out_of_range_label,
2034 STRING_INDEX_IS_NUMBER);
2035 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002036 __ Drop(argc + 1);
2037 __ Ret();
2038
2039 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002040 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002041
2042 if (index_out_of_range.is_linked()) {
2043 __ bind(&index_out_of_range);
2044 __ LoadRoot(v0, Heap::kNanValueRootIndex);
2045 __ Drop(argc + 1);
2046 __ Ret();
2047 }
2048
2049 __ bind(&miss);
2050 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002051 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002052 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002053 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002054
2055 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002056 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002057}
2058
2059
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002060Handle<Code> CallStubCompiler::CompileStringCharAtCall(
2061 Handle<Object> object,
2062 Handle<JSObject> holder,
2063 Handle<JSGlobalPropertyCell> cell,
2064 Handle<JSFunction> function,
2065 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002066 // ----------- S t a t e -------------
2067 // -- a2 : function name
2068 // -- ra : return address
2069 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2070 // -- ...
2071 // -- sp[argc * 4] : receiver
2072 // -----------------------------------
2073
2074 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002075 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002076
2077 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002078 Label miss;
2079 Label name_miss;
2080 Label index_out_of_range;
2081 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00002082 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002083 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002084 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002085 index_out_of_range_label = &miss;
2086 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002087 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002088
2089 // Check that the maps starting from the prototype haven't changed.
2090 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2091 Context::STRING_FUNCTION_INDEX,
2092 v0,
2093 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002094 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002095 CheckPrototypes(
2096 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2097 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002098
2099 Register receiver = v0;
2100 Register index = t1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00002101 Register scratch = a3;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002102 Register result = v0;
2103 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
2104 if (argc > 0) {
2105 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
2106 } else {
2107 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
2108 }
2109
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002110 StringCharAtGenerator generator(receiver,
2111 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00002112 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002113 result,
2114 &miss, // When not a string.
2115 &miss, // When not a number.
2116 index_out_of_range_label,
2117 STRING_INDEX_IS_NUMBER);
2118 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002119 __ Drop(argc + 1);
2120 __ Ret();
2121
2122 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002123 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002124
2125 if (index_out_of_range.is_linked()) {
2126 __ bind(&index_out_of_range);
ulan@chromium.org750145a2013-03-07 15:14:13 +00002127 __ LoadRoot(v0, Heap::kempty_stringRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002128 __ Drop(argc + 1);
2129 __ Ret();
2130 }
2131
2132 __ bind(&miss);
2133 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002134 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002135 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002136 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002137
2138 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002139 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002140}
2141
2142
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002143Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
2144 Handle<Object> object,
2145 Handle<JSObject> holder,
2146 Handle<JSGlobalPropertyCell> cell,
2147 Handle<JSFunction> function,
2148 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002149 // ----------- S t a t e -------------
2150 // -- a2 : function name
2151 // -- ra : return address
2152 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2153 // -- ...
2154 // -- sp[argc * 4] : receiver
2155 // -----------------------------------
2156
2157 const int argc = arguments().immediate();
2158
2159 // If the object is not a JSObject or we got an unexpected number of
2160 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002161 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002162
2163 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002164 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002165
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002166 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002167 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
2168
2169 STATIC_ASSERT(kSmiTag == 0);
2170 __ JumpIfSmi(a1, &miss);
2171
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002172 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2173 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002174 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002175 ASSERT(cell->value() == *function);
2176 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2177 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002178 GenerateLoadFunctionFromCell(cell, function, &miss);
2179 }
2180
2181 // Load the char code argument.
2182 Register code = a1;
2183 __ lw(code, MemOperand(sp, 0 * kPointerSize));
2184
2185 // Check the code is a smi.
2186 Label slow;
2187 STATIC_ASSERT(kSmiTag == 0);
2188 __ JumpIfNotSmi(code, &slow);
2189
2190 // Convert the smi code to uint16.
2191 __ And(code, code, Operand(Smi::FromInt(0xffff)));
2192
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002193 StringCharFromCodeGenerator generator(code, v0);
2194 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002195 __ Drop(argc + 1);
2196 __ Ret();
2197
2198 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002199 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002200
2201 // Tail call the full function. We do not have to patch the receiver
2202 // because the function makes no use of it.
2203 __ bind(&slow);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002204 ParameterCount expected(function);
2205 __ InvokeFunction(function, expected, arguments(),
2206 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002207
2208 __ bind(&miss);
2209 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002210 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002211
2212 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002213 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002214}
2215
2216
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002217Handle<Code> CallStubCompiler::CompileMathFloorCall(
2218 Handle<Object> object,
2219 Handle<JSObject> holder,
2220 Handle<JSGlobalPropertyCell> cell,
2221 Handle<JSFunction> function,
2222 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002223 // ----------- S t a t e -------------
2224 // -- a2 : function name
2225 // -- ra : return address
2226 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2227 // -- ...
2228 // -- sp[argc * 4] : receiver
2229 // -----------------------------------
2230
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002231
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002232 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002233 // If the object is not a JSObject or we got an unexpected number of
2234 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002235 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002236
2237 Label miss, slow;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002238 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002239
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002240 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002241 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002242 STATIC_ASSERT(kSmiTag == 0);
2243 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002244 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2245 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002246 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002247 ASSERT(cell->value() == *function);
2248 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2249 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002250 GenerateLoadFunctionFromCell(cell, function, &miss);
2251 }
2252
2253 // Load the (only) argument into v0.
2254 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2255
2256 // If the argument is a smi, just return.
2257 STATIC_ASSERT(kSmiTag == 0);
2258 __ And(t0, v0, Operand(kSmiTagMask));
2259 __ Drop(argc + 1, eq, t0, Operand(zero_reg));
2260 __ Ret(eq, t0, Operand(zero_reg));
2261
danno@chromium.org40cb8782011-05-25 07:58:50 +00002262 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002263
2264 Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return;
2265
2266 // If fpu is enabled, we use the floor instruction.
2267
2268 // Load the HeapNumber value.
2269 __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2270
2271 // Backup FCSR.
2272 __ cfc1(a3, FCSR);
2273 // Clearing FCSR clears the exception mask with no side-effects.
2274 __ ctc1(zero_reg, FCSR);
2275 // Convert the argument to an integer.
2276 __ floor_w_d(f0, f0);
2277
2278 // Start checking for special cases.
2279 // Get the argument exponent and clear the sign bit.
2280 __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize));
2281 __ And(t2, t1, Operand(~HeapNumber::kSignMask));
2282 __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord);
2283
2284 // Retrieve FCSR and check for fpu errors.
2285 __ cfc1(t5, FCSR);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002286 __ And(t5, t5, Operand(kFCSRExceptionFlagMask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002287 __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));
2288
2289 // Check for NaN, Infinity, and -Infinity.
2290 // They are invariant through a Math.Floor call, so just
2291 // return the original argument.
2292 __ Subu(t3, t2, Operand(HeapNumber::kExponentMask
2293 >> HeapNumber::kMantissaBitsInTopWord));
2294 __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg));
2295 // We had an overflow or underflow in the conversion. Check if we
2296 // have a big exponent.
2297 // If greater or equal, the argument is already round and in v0.
2298 __ Branch(&restore_fcsr_and_return, ge, t3,
2299 Operand(HeapNumber::kMantissaBits));
2300 __ Branch(&wont_fit_smi);
2301
2302 __ bind(&no_fpu_error);
2303 // Move the result back to v0.
2304 __ mfc1(v0, f0);
2305 // Check if the result fits into a smi.
2306 __ Addu(a1, v0, Operand(0x40000000));
2307 __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg));
2308 // Tag the result.
2309 STATIC_ASSERT(kSmiTag == 0);
2310 __ sll(v0, v0, kSmiTagSize);
2311
2312 // Check for -0.
2313 __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg));
2314 // t1 already holds the HeapNumber exponent.
2315 __ And(t0, t1, Operand(HeapNumber::kSignMask));
2316 // If our HeapNumber is negative it was -0, so load its address and return.
2317 // Else v0 is loaded with 0, so we can also just return.
2318 __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg));
2319 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2320
2321 __ bind(&restore_fcsr_and_return);
2322 // Restore FCSR and return.
2323 __ ctc1(a3, FCSR);
2324
2325 __ Drop(argc + 1);
2326 __ Ret();
2327
2328 __ bind(&wont_fit_smi);
2329 // Restore FCSR and fall to slow case.
2330 __ ctc1(a3, FCSR);
2331
2332 __ bind(&slow);
2333 // Tail call the full function. We do not have to patch the receiver
2334 // because the function makes no use of it.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002335 ParameterCount expected(function);
2336 __ InvokeFunction(function, expected, arguments(),
2337 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002338
2339 __ bind(&miss);
2340 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002341 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002342
2343 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002344 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002345}
2346
2347
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002348Handle<Code> CallStubCompiler::CompileMathAbsCall(
2349 Handle<Object> object,
2350 Handle<JSObject> holder,
2351 Handle<JSGlobalPropertyCell> cell,
2352 Handle<JSFunction> function,
2353 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002354 // ----------- S t a t e -------------
2355 // -- a2 : function name
2356 // -- ra : return address
2357 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2358 // -- ...
2359 // -- sp[argc * 4] : receiver
2360 // -----------------------------------
2361
2362 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002363 // If the object is not a JSObject or we got an unexpected number of
2364 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002365 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002366
2367 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002368
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002369 GenerateNameCheck(name, &miss);
2370 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002371 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002372 STATIC_ASSERT(kSmiTag == 0);
2373 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002374 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2375 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002376 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002377 ASSERT(cell->value() == *function);
2378 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2379 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002380 GenerateLoadFunctionFromCell(cell, function, &miss);
2381 }
2382
2383 // Load the (only) argument into v0.
2384 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2385
2386 // Check if the argument is a smi.
2387 Label not_smi;
2388 STATIC_ASSERT(kSmiTag == 0);
2389 __ JumpIfNotSmi(v0, &not_smi);
2390
2391 // Do bitwise not or do nothing depending on the sign of the
2392 // argument.
2393 __ sra(t0, v0, kBitsPerInt - 1);
2394 __ Xor(a1, v0, t0);
2395
2396 // Add 1 or do nothing depending on the sign of the argument.
2397 __ Subu(v0, a1, t0);
2398
2399 // If the result is still negative, go to the slow case.
2400 // This only happens for the most negative smi.
2401 Label slow;
2402 __ Branch(&slow, lt, v0, Operand(zero_reg));
2403
2404 // Smi case done.
2405 __ Drop(argc + 1);
2406 __ Ret();
2407
2408 // Check if the argument is a heap number and load its exponent and
2409 // sign.
2410 __ bind(&not_smi);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002411 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002412 __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2413
2414 // Check the sign of the argument. If the argument is positive,
2415 // just return it.
2416 Label negative_sign;
2417 __ And(t0, a1, Operand(HeapNumber::kSignMask));
2418 __ Branch(&negative_sign, ne, t0, Operand(zero_reg));
2419 __ Drop(argc + 1);
2420 __ Ret();
2421
2422 // If the argument is negative, clear the sign, and return a new
2423 // number.
2424 __ bind(&negative_sign);
2425 __ Xor(a1, a1, Operand(HeapNumber::kSignMask));
2426 __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2427 __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
2428 __ AllocateHeapNumber(v0, t0, t1, t2, &slow);
2429 __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2430 __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2431 __ Drop(argc + 1);
2432 __ Ret();
2433
2434 // Tail call the full function. We do not have to patch the receiver
2435 // because the function makes no use of it.
2436 __ bind(&slow);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002437 ParameterCount expected(function);
2438 __ InvokeFunction(function, expected, arguments(),
2439 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002440
2441 __ bind(&miss);
2442 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002443 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002444
2445 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002446 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002447}
2448
2449
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002450Handle<Code> CallStubCompiler::CompileFastApiCall(
lrn@chromium.org7516f052011-03-30 08:52:27 +00002451 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002452 Handle<Object> object,
2453 Handle<JSObject> holder,
2454 Handle<JSGlobalPropertyCell> cell,
2455 Handle<JSFunction> function,
2456 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002457
danno@chromium.org40cb8782011-05-25 07:58:50 +00002458 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002459
2460 ASSERT(optimization.is_simple_api_call());
2461 // Bail out if object is a global object as we don't want to
2462 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002463 if (object->IsGlobalObject()) return Handle<Code>::null();
2464 if (!cell.is_null()) return Handle<Code>::null();
2465 if (!object->IsJSObject()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002466 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002467 Handle<JSObject>::cast(object), holder);
2468 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002469
2470 Label miss, miss_before_stack_reserved;
2471
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002472 GenerateNameCheck(name, &miss_before_stack_reserved);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002473
2474 // Get the receiver from the stack.
2475 const int argc = arguments().immediate();
2476 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2477
2478 // Check that the receiver isn't a smi.
2479 __ JumpIfSmi(a1, &miss_before_stack_reserved);
2480
2481 __ IncrementCounter(counters->call_const(), 1, a0, a3);
2482 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2483
2484 ReserveSpaceForFastApiCall(masm(), a0);
2485
2486 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002487 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002488 depth, &miss);
2489
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002490 GenerateFastApiDirectCall(masm(), optimization, argc);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002491
2492 __ bind(&miss);
2493 FreeSpaceForFastApiCall(masm());
2494
2495 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002496 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002497
2498 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002499 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002500}
2501
2502
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002503void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
2504 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002505 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002506 CheckType check,
2507 Label* success) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002508 // ----------- S t a t e -------------
2509 // -- a2 : name
2510 // -- ra : return address
2511 // -----------------------------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002512 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002513 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002514
2515 // Get the receiver from the stack.
2516 const int argc = arguments().immediate();
2517 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2518
2519 // Check that the receiver isn't a smi.
2520 if (check != NUMBER_CHECK) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002521 __ JumpIfSmi(a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002522 }
2523
2524 // Make sure that it's okay not to patch the on stack receiver
2525 // unless we're doing a receiver map check.
2526 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002527 switch (check) {
2528 case RECEIVER_MAP_CHECK:
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002529 __ IncrementCounter(isolate()->counters()->call_const(), 1, a0, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002530
2531 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002532 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2533 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002534
2535 // Patch the receiver on the stack with the global proxy if
2536 // necessary.
2537 if (object->IsGlobalObject()) {
2538 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2539 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2540 }
2541 break;
2542
2543 case STRING_CHECK:
ulan@chromium.org750145a2013-03-07 15:14:13 +00002544 // Check that the object is a string.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002545 __ GetObjectType(a1, a3, a3);
2546 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2547 // Check that the maps starting from the prototype haven't changed.
2548 GenerateDirectLoadGlobalFunctionPrototype(
2549 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
2550 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002551 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002552 a0, holder, a3, a1, t0, name, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002553 break;
2554
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002555 case SYMBOL_CHECK:
2556 // Check that the object is a symbol.
2557 __ GetObjectType(a1, a1, a3);
2558 __ Branch(&miss, ne, a3, Operand(SYMBOL_TYPE));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002559 // Check that the maps starting from the prototype haven't changed.
2560 GenerateDirectLoadGlobalFunctionPrototype(
2561 masm(), Context::SYMBOL_FUNCTION_INDEX, a0, &miss);
2562 CheckPrototypes(
2563 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2564 a0, holder, a3, a1, t0, name, &miss);
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002565 break;
2566
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002567 case NUMBER_CHECK: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002568 Label fast;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002569 // Check that the object is a smi or a heap number.
2570 __ JumpIfSmi(a1, &fast);
2571 __ GetObjectType(a1, a0, a0);
2572 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
2573 __ bind(&fast);
2574 // Check that the maps starting from the prototype haven't changed.
2575 GenerateDirectLoadGlobalFunctionPrototype(
2576 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
2577 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002578 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002579 a0, holder, a3, a1, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002580 break;
2581 }
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002582 case BOOLEAN_CHECK: {
2583 Label fast;
2584 // Check that the object is a boolean.
2585 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
2586 __ Branch(&fast, eq, a1, Operand(t0));
2587 __ LoadRoot(t0, Heap::kFalseValueRootIndex);
2588 __ Branch(&miss, ne, a1, Operand(t0));
2589 __ bind(&fast);
2590 // Check that the maps starting from the prototype haven't changed.
2591 GenerateDirectLoadGlobalFunctionPrototype(
2592 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
2593 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002594 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002595 a0, holder, a3, a1, t0, name, &miss);
2596 break;
2597 }
2598 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002599
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002600 __ jmp(success);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002601
2602 // Handle call cache miss.
2603 __ bind(&miss);
2604
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002605 GenerateMissBranch();
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002606}
2607
2608
2609void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) {
2610 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
2611 ? CALL_AS_FUNCTION
2612 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002613 ParameterCount expected(function);
2614 __ InvokeFunction(function, expected, arguments(),
2615 JUMP_FUNCTION, NullCallWrapper(), call_kind);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002616}
2617
2618
2619Handle<Code> CallStubCompiler::CompileCallConstant(
2620 Handle<Object> object,
2621 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002622 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002623 CheckType check,
2624 Handle<JSFunction> function) {
2625 if (HasCustomCallGenerator(function)) {
2626 Handle<Code> code = CompileCustomCall(object, holder,
2627 Handle<JSGlobalPropertyCell>::null(),
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002628 function, Handle<String>::cast(name));
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002629 // A null handle means bail out to the regular compiler code below.
2630 if (!code.is_null()) return code;
2631 }
2632
2633 Label success;
2634
2635 CompileHandlerFrontend(object, holder, name, check, &success);
2636 __ bind(&success);
2637 CompileHandlerBackend(function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002638
2639 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002640 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002641}
2642
2643
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002644Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2645 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002646 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002647 // ----------- S t a t e -------------
2648 // -- a2 : name
2649 // -- ra : return address
2650 // -----------------------------------
2651
2652 Label miss;
2653
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002654 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002655
2656 // Get the number of arguments.
2657 const int argc = arguments().immediate();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002658 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002659 LookupPostInterceptor(holder, name, &lookup);
2660
2661 // Get the receiver from the stack.
2662 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2663
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002664 CallInterceptorCompiler compiler(this, arguments(), a2, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002665 compiler.Compile(masm(), object, holder, name, &lookup, a1, a3, t0, a0,
2666 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002667
2668 // Move returned value, the function to call, to a1.
2669 __ mov(a1, v0);
2670 // Restore receiver.
2671 __ lw(a0, MemOperand(sp, argc * kPointerSize));
2672
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002673 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002674
2675 // Handle call cache miss.
2676 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002677 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002678
2679 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002680 return GetCode(Code::INTERCEPTOR, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002681}
2682
2683
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002684Handle<Code> CallStubCompiler::CompileCallGlobal(
2685 Handle<JSObject> object,
2686 Handle<GlobalObject> holder,
2687 Handle<JSGlobalPropertyCell> cell,
2688 Handle<JSFunction> function,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002689 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002690 // ----------- S t a t e -------------
2691 // -- a2 : name
2692 // -- ra : return address
2693 // -----------------------------------
2694
2695 if (HasCustomCallGenerator(function)) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002696 Handle<Code> code = CompileCustomCall(
2697 object, holder, cell, function, Handle<String>::cast(name));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002698 // A null handle means bail out to the regular compiler code below.
2699 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002700 }
2701
2702 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002703 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002704
2705 // Get the number of arguments.
2706 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002707 GenerateGlobalReceiverCheck(object, holder, name, &miss);
2708 GenerateLoadFunctionFromCell(cell, function, &miss);
2709
2710 // Patch the receiver on the stack with the global proxy if
2711 // necessary.
2712 if (object->IsGlobalObject()) {
2713 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
2714 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2715 }
2716
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002717 // Set up the context (function already in r1).
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002718 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
2719
2720 // Jump to the cached code (tail call).
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002721 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002722 __ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002723 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002724 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002725 ? CALL_AS_FUNCTION
2726 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002727 // We call indirectly through the code field in the function to
2728 // allow recompilation to take effect without changing any of the
2729 // call sites.
2730 __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
2731 __ InvokeCode(a3, expected, arguments(), JUMP_FUNCTION,
2732 NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002733
2734 // Handle call cache miss.
2735 __ bind(&miss);
2736 __ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002737 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002738
2739 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002740 return GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002741}
2742
2743
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002744Handle<Code> StoreStubCompiler::CompileStoreCallback(
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002745 Handle<Name> name,
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002746 Handle<JSObject> object,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002747 Handle<JSObject> holder,
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002748 Handle<ExecutableAccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002749 Label miss;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002750 // Check that the maps haven't changed.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002751 __ JumpIfSmi(receiver(), &miss);
2752 CheckPrototypes(object, receiver(), holder,
2753 scratch1(), scratch2(), scratch3(), name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002754
2755 // Stub never generated for non-global objects that require access
2756 // checks.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002757 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002758
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002759 __ push(receiver()); // Receiver.
2760 __ li(at, Operand(callback)); // Callback info.
2761 __ Push(at, this->name(), value());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002762
2763 // Do tail-call to the runtime system.
2764 ExternalReference store_callback_property =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002765 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002766 __ TailCallExternalReference(store_callback_property, 4, 1);
2767
2768 // Handle store cache miss.
2769 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002770 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002771
2772 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002773 return GetICCode(kind(), Code::CALLBACKS, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002774}
2775
2776
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002777#undef __
2778#define __ ACCESS_MASM(masm)
2779
2780
2781void StoreStubCompiler::GenerateStoreViaSetter(
2782 MacroAssembler* masm,
2783 Handle<JSFunction> setter) {
2784 // ----------- S t a t e -------------
2785 // -- a0 : value
2786 // -- a1 : receiver
2787 // -- a2 : name
2788 // -- ra : return address
2789 // -----------------------------------
2790 {
2791 FrameScope scope(masm, StackFrame::INTERNAL);
2792
2793 // Save value register, so we can restore it later.
2794 __ push(a0);
2795
2796 if (!setter.is_null()) {
2797 // Call the JavaScript setter with receiver and value on the stack.
2798 __ push(a1);
2799 __ push(a0);
2800 ParameterCount actual(1);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002801 ParameterCount expected(setter);
2802 __ InvokeFunction(setter, expected, actual,
2803 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002804 } else {
2805 // If we generate a global code snippet for deoptimization only, remember
2806 // the place to continue after deoptimization.
2807 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2808 }
2809
2810 // We have to return the passed value, not the return value of the setter.
2811 __ pop(v0);
2812
2813 // Restore context register.
2814 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2815 }
2816 __ Ret();
2817}
2818
2819
2820#undef __
2821#define __ ACCESS_MASM(masm())
2822
2823
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002824Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002825 Handle<JSObject> object,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002826 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002827 Label miss;
2828
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002829 // Check that the map of the object hasn't changed.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002830 __ CheckMap(receiver(), scratch1(), Handle<Map>(object->map()), &miss,
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002831 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002832
2833 // Perform global security token check if needed.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002834 if (object->IsJSGlobalProxy()) {
2835 __ CheckAccessGlobalProxy(receiver(), scratch1(), &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002836 }
2837
2838 // Stub is never generated for non-global objects that require access
2839 // checks.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002840 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002841
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002842 __ Push(receiver(), this->name(), value());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002843
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002844 __ li(scratch1(), Operand(Smi::FromInt(strict_mode())));
2845 __ push(scratch1()); // strict mode
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002846
2847 // Do tail-call to the runtime system.
2848 ExternalReference store_ic_property =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002849 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002850 __ TailCallExternalReference(store_ic_property, 4, 1);
2851
2852 // Handle store cache miss.
2853 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002854 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002855
2856 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002857 return GetICCode(kind(), Code::INTERCEPTOR, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002858}
2859
2860
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002861Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2862 Handle<GlobalObject> object,
2863 Handle<JSGlobalPropertyCell> cell,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002864 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002865 Label miss;
2866
2867 // Check that the map of the global has not changed.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002868 __ lw(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset));
2869 __ Branch(&miss, ne, scratch1(), Operand(Handle<Map>(object->map())));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002870
2871 // Check that the value in the cell is not the hole. If it is, this
2872 // cell could have been deleted and reintroducing the global needs
2873 // to update the property details in the property dictionary of the
2874 // global object. We bail out to the runtime system to do that.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002875 __ li(scratch1(), Operand(cell));
2876 __ LoadRoot(scratch2(), Heap::kTheHoleValueRootIndex);
2877 __ lw(scratch3(),
2878 FieldMemOperand(scratch1(), JSGlobalPropertyCell::kValueOffset));
2879 __ Branch(&miss, eq, scratch3(), Operand(scratch2()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002880
2881 // Store the value in the cell.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002882 __ sw(value(),
2883 FieldMemOperand(scratch1(), JSGlobalPropertyCell::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002884 __ mov(v0, a0); // Stored value must be returned in v0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002885 // Cells are always rescanned, so no write barrier here.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002886
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002887 Counters* counters = isolate()->counters();
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002888 __ IncrementCounter(
2889 counters->named_store_global_inline(), 1, scratch1(), scratch2());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002890 __ Ret();
2891
2892 // Handle store cache miss.
2893 __ bind(&miss);
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002894 __ IncrementCounter(
2895 counters->named_store_global_inline_miss(), 1, scratch1(), scratch2());
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002896 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002897
2898 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002899 return GetICCode(kind(), Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002900}
2901
2902
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002903Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
2904 Handle<JSObject> object,
2905 Handle<JSObject> last,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002906 Handle<Name> name,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002907 Handle<GlobalObject> global) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002908 Label success;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002909
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002910 NonexistentHandlerFrontend(object, last, name, &success, global);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002911
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002912 __ bind(&success);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002913 // Return undefined if maps of the full prototype chain is still the same.
2914 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2915 __ 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 GetCode(kind(), Code::NONEXISTENT, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002919}
2920
2921
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002922Register* LoadStubCompiler::registers() {
2923 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2924 static Register registers[] = { a0, a2, a3, a1, t0, t1 };
2925 return registers;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002926}
2927
2928
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002929Register* KeyedLoadStubCompiler::registers() {
2930 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2931 static Register registers[] = { a1, a0, a2, a3, t0, t1 };
2932 return registers;
2933}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002934
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002935
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002936Register* StoreStubCompiler::registers() {
2937 // receiver, name, value, scratch1, scratch2, scratch3.
2938 static Register registers[] = { a1, a2, a0, a3, t0, t1 };
2939 return registers;
2940}
2941
2942
2943Register* KeyedStoreStubCompiler::registers() {
2944 // receiver, name, value, scratch1, scratch2, scratch3.
2945 static Register registers[] = { a2, a1, a0, a3, t0, t1 };
2946 return registers;
2947}
2948
2949
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002950void KeyedLoadStubCompiler::GenerateNameCheck(Handle<Name> name,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002951 Register name_reg,
2952 Label* miss) {
2953 __ Branch(miss, ne, name_reg, Operand(name));
lrn@chromium.org7516f052011-03-30 08:52:27 +00002954}
2955
2956
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002957void KeyedStoreStubCompiler::GenerateNameCheck(Handle<Name> name,
2958 Register name_reg,
2959 Label* miss) {
2960 __ Branch(miss, ne, name_reg, Operand(name));
2961}
2962
2963
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002964#undef __
2965#define __ ACCESS_MASM(masm)
2966
2967
2968void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
2969 Handle<JSFunction> getter) {
2970 // ----------- S t a t e -------------
2971 // -- a0 : receiver
2972 // -- a2 : name
2973 // -- ra : return address
2974 // -----------------------------------
2975 {
2976 FrameScope scope(masm, StackFrame::INTERNAL);
2977
2978 if (!getter.is_null()) {
2979 // Call the JavaScript getter with the receiver on the stack.
2980 __ push(a0);
2981 ParameterCount actual(0);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002982 ParameterCount expected(getter);
2983 __ InvokeFunction(getter, expected, actual,
2984 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002985 } else {
2986 // If we generate a global code snippet for deoptimization only, remember
2987 // the place to continue after deoptimization.
2988 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
2989 }
2990
2991 // Restore context register.
2992 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2993 }
2994 __ Ret();
2995}
2996
2997
2998#undef __
2999#define __ ACCESS_MASM(masm())
3000
3001
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003002Handle<Code> LoadStubCompiler::CompileLoadGlobal(
3003 Handle<JSObject> object,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003004 Handle<GlobalObject> global,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003005 Handle<JSGlobalPropertyCell> cell,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003006 Handle<Name> name,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003007 bool is_dont_delete) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003008 Label success, miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003009
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003010 __ CheckMap(
3011 receiver(), scratch1(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
3012 HandlerFrontendHeader(
3013 object, receiver(), Handle<JSObject>::cast(global), name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003014
3015 // Get the value from the cell.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003016 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003017 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
3018
3019 // Check for deleted property if property can actually be deleted.
3020 if (!is_dont_delete) {
3021 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
3022 __ Branch(&miss, eq, t0, Operand(at));
3023 }
3024
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003025 HandlerFrontendFooter(&success, &miss);
3026 __ bind(&success);
3027
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003028 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003029 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003030 __ mov(v0, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003031 __ Ret();
3032
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003033 // Return the generated code.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003034 return GetICCode(kind(), Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003035}
3036
3037
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003038Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003039 MapHandleList* receiver_maps,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003040 CodeHandleList* handlers,
3041 Handle<Name> name,
3042 Code::StubType type,
3043 IcCheckType check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003044 Label miss;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003045
3046 if (check == PROPERTY) {
3047 GenerateNameCheck(name, this->name(), &miss);
3048 }
3049
3050 __ JumpIfSmi(receiver(), &miss);
3051 Register map_reg = scratch1();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003052
danno@chromium.org40cb8782011-05-25 07:58:50 +00003053 int receiver_count = receiver_maps->length();
danno@chromium.orgf005df62013-04-30 16:36:45 +00003054 int number_of_handled_maps = 0;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003055 __ lw(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003056 for (int current = 0; current < receiver_count; ++current) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00003057 Handle<Map> map = receiver_maps->at(current);
3058 if (!map->is_deprecated()) {
3059 number_of_handled_maps++;
3060 __ Jump(handlers->at(current), RelocInfo::CODE_TARGET,
3061 eq, map_reg, Operand(receiver_maps->at(current)));
3062 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003063 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00003064 ASSERT(number_of_handled_maps != 0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003065
3066 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003067 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003068
3069 // Return the generated code.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003070 InlineCacheState state =
danno@chromium.orgf005df62013-04-30 16:36:45 +00003071 number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003072 return GetICCode(kind(), type, name, state);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003073}
3074
3075
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003076Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
3077 MapHandleList* receiver_maps,
3078 CodeHandleList* handler_stubs,
3079 MapHandleList* transitioned_maps) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003080 Label miss;
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003081 __ JumpIfSmi(receiver(), &miss);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003082
3083 int receiver_count = receiver_maps->length();
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003084 __ lw(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003085 for (int i = 0; i < receiver_count; ++i) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003086 if (transitioned_maps->at(i).is_null()) {
3087 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq,
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003088 scratch1(), Operand(receiver_maps->at(i)));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003089 } else {
3090 Label next_map;
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003091 __ Branch(&next_map, ne, scratch1(), Operand(receiver_maps->at(i)));
3092 __ li(transition_map(), Operand(transitioned_maps->at(i)));
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003093 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003094 __ bind(&next_map);
3095 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003096 }
3097
3098 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003099 TailCallBuiltin(masm(), MissBuiltin(kind()));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003100
3101 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003102 return GetICCode(
3103 kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003104}
3105
3106
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003107Handle<Code> ConstructStubCompiler::CompileConstructStub(
3108 Handle<JSFunction> function) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003109 // a0 : argc
3110 // a1 : constructor
3111 // ra : return address
3112 // [sp] : last argument
3113 Label generic_stub_call;
3114
3115 // Use t7 for holding undefined which is used in several places below.
3116 __ LoadRoot(t7, Heap::kUndefinedValueRootIndex);
3117
3118#ifdef ENABLE_DEBUGGER_SUPPORT
3119 // Check to see whether there are any break points in the function code. If
3120 // there are jump to the generic constructor stub which calls the actual
3121 // code for the function thereby hitting the break points.
3122 __ lw(t5, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3123 __ lw(a2, FieldMemOperand(t5, SharedFunctionInfo::kDebugInfoOffset));
3124 __ Branch(&generic_stub_call, ne, a2, Operand(t7));
3125#endif
3126
3127 // Load the initial map and verify that it is in fact a map.
3128 // a1: constructor function
3129 // t7: undefined
3130 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003131 __ JumpIfSmi(a2, &generic_stub_call);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003132 __ GetObjectType(a2, a3, t0);
3133 __ Branch(&generic_stub_call, ne, t0, Operand(MAP_TYPE));
3134
3135#ifdef DEBUG
3136 // Cannot construct functions this way.
3137 // a0: argc
3138 // a1: constructor function
3139 // a2: initial map
3140 // t7: undefined
3141 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
3142 __ Check(ne, "Function constructed by construct stub.",
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003143 a3, Operand(JS_FUNCTION_TYPE));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003144#endif
3145
3146 // Now allocate the JSObject in new space.
3147 // a0: argc
3148 // a1: constructor function
3149 // a2: initial map
3150 // t7: undefined
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003151 ASSERT(function->has_initial_map());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003152 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003153#ifdef DEBUG
3154 int instance_size = function->initial_map()->instance_size();
3155 __ Check(eq, "Instance size of initial map changed.",
3156 a3, Operand(instance_size >> kPointerSizeLog2));
3157#endif
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003158 __ Allocate(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003159
3160 // Allocated the JSObject, now initialize the fields. Map is set to initial
3161 // map and properties and elements are set to empty fixed array.
3162 // a0: argc
3163 // a1: constructor function
3164 // a2: initial map
3165 // a3: object size (in words)
3166 // t4: JSObject (not tagged)
3167 // t7: undefined
3168 __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex);
3169 __ mov(t5, t4);
3170 __ sw(a2, MemOperand(t5, JSObject::kMapOffset));
3171 __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset));
3172 __ sw(t6, MemOperand(t5, JSObject::kElementsOffset));
3173 __ Addu(t5, t5, Operand(3 * kPointerSize));
3174 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
3175 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
3176 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
3177
3178
3179 // Calculate the location of the first argument. The stack contains only the
3180 // argc arguments.
3181 __ sll(a1, a0, kPointerSizeLog2);
3182 __ Addu(a1, a1, sp);
3183
3184 // Fill all the in-object properties with undefined.
3185 // a0: argc
3186 // a1: first argument
3187 // a3: object size (in words)
3188 // t4: JSObject (not tagged)
3189 // t5: First in-object property of JSObject (not tagged)
3190 // t7: undefined
3191 // Fill the initialized properties with a constant value or a passed argument
3192 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003193 Handle<SharedFunctionInfo> shared(function->shared());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003194 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3195 if (shared->IsThisPropertyAssignmentArgument(i)) {
3196 Label not_passed, next;
3197 // Check if the argument assigned to the property is actually passed.
3198 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3199 __ Branch(&not_passed, less_equal, a0, Operand(arg_number));
3200 // Argument passed - find it on the stack.
3201 __ lw(a2, MemOperand(a1, (arg_number + 1) * -kPointerSize));
3202 __ sw(a2, MemOperand(t5));
3203 __ Addu(t5, t5, kPointerSize);
3204 __ jmp(&next);
3205 __ bind(&not_passed);
3206 // Set the property to undefined.
3207 __ sw(t7, MemOperand(t5));
3208 __ Addu(t5, t5, Operand(kPointerSize));
3209 __ bind(&next);
3210 } else {
3211 // Set the property to the constant value.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003212 Handle<Object> constant(
3213 shared->GetThisPropertyAssignmentConstant(i), isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003214 __ li(a2, Operand(constant));
3215 __ sw(a2, MemOperand(t5));
3216 __ Addu(t5, t5, kPointerSize);
3217 }
3218 }
3219
3220 // Fill the unused in-object property fields with undefined.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003221 for (int i = shared->this_property_assignments_count();
3222 i < function->initial_map()->inobject_properties();
3223 i++) {
3224 __ sw(t7, MemOperand(t5));
3225 __ Addu(t5, t5, kPointerSize);
3226 }
3227
3228 // a0: argc
3229 // t4: JSObject (not tagged)
3230 // Move argc to a1 and the JSObject to return to v0 and tag it.
3231 __ mov(a1, a0);
3232 __ mov(v0, t4);
3233 __ Or(v0, v0, Operand(kHeapObjectTag));
3234
3235 // v0: JSObject
3236 // a1: argc
3237 // Remove caller arguments and receiver from the stack and return.
3238 __ sll(t0, a1, kPointerSizeLog2);
3239 __ Addu(sp, sp, t0);
3240 __ Addu(sp, sp, Operand(kPointerSize));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003241 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003242 __ IncrementCounter(counters->constructed_objects(), 1, a1, a2);
3243 __ IncrementCounter(counters->constructed_objects_stub(), 1, a1, a2);
3244 __ Ret();
3245
3246 // Jump to the generic stub in case the specialized code cannot handle the
3247 // construction.
3248 __ bind(&generic_stub_call);
3249 Handle<Code> generic_construct_stub =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003250 isolate()->builtins()->JSConstructStubGeneric();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003251 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
3252
3253 // Return the generated code.
3254 return GetCode();
3255}
3256
3257
danno@chromium.org40cb8782011-05-25 07:58:50 +00003258#undef __
3259#define __ ACCESS_MASM(masm)
3260
3261
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003262void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3263 MacroAssembler* masm) {
3264 // ---------- S t a t e --------------
3265 // -- ra : return address
3266 // -- a0 : key
3267 // -- a1 : receiver
3268 // -----------------------------------
3269 Label slow, miss_force_generic;
3270
3271 Register key = a0;
3272 Register receiver = a1;
3273
3274 __ JumpIfNotSmi(key, &miss_force_generic);
3275 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
3276 __ sra(a2, a0, kSmiTagSize);
3277 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
3278 __ Ret();
3279
3280 // Slow case, key and receiver still in a0 and a1.
3281 __ bind(&slow);
3282 __ IncrementCounter(
3283 masm->isolate()->counters()->keyed_load_external_array_slow(),
3284 1, a2, a3);
3285 // Entry registers are intact.
3286 // ---------- S t a t e --------------
3287 // -- ra : return address
3288 // -- a0 : key
3289 // -- a1 : receiver
3290 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003291 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003292
3293 // Miss case, call the runtime.
3294 __ bind(&miss_force_generic);
3295
3296 // ---------- S t a t e --------------
3297 // -- ra : return address
3298 // -- a0 : key
3299 // -- a1 : receiver
3300 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003301 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_MissForceGeneric);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003302}
3303
3304
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003305static void GenerateSmiKeyCheck(MacroAssembler* masm,
3306 Register key,
3307 Register scratch0,
3308 Register scratch1,
3309 FPURegister double_scratch0,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003310 FPURegister double_scratch1,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003311 Label* fail) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003312 Label key_ok;
3313 // Check for smi or a smi inside a heap number. We convert the heap
3314 // number and check if the conversion is exact and fits into the smi
3315 // range.
3316 __ JumpIfSmi(key, &key_ok);
3317 __ CheckMap(key,
3318 scratch0,
3319 Heap::kHeapNumberMapRootIndex,
3320 fail,
3321 DONT_DO_SMI_CHECK);
3322 __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
3323 __ EmitFPUTruncate(kRoundToZero,
3324 scratch0,
3325 double_scratch0,
3326 at,
3327 double_scratch1,
3328 scratch1,
3329 kCheckForInexactConversion);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003330
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003331 __ Branch(fail, ne, scratch1, Operand(zero_reg));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003332
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003333 __ SmiTagCheckOverflow(key, scratch0, scratch1);
3334 __ BranchOnOverflow(fail, scratch1);
3335 __ bind(&key_ok);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003336}
3337
3338
danno@chromium.org40cb8782011-05-25 07:58:50 +00003339void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3340 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003341 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003342 // ---------- S t a t e --------------
3343 // -- a0 : value
3344 // -- a1 : key
3345 // -- a2 : receiver
3346 // -- ra : return address
3347 // -----------------------------------
3348
danno@chromium.org40cb8782011-05-25 07:58:50 +00003349 Label slow, check_heap_number, miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003350
3351 // Register usage.
3352 Register value = a0;
3353 Register key = a1;
3354 Register receiver = a2;
3355 // a3 mostly holds the elements array or the destination external array.
3356
danno@chromium.org40cb8782011-05-25 07:58:50 +00003357 // This stub is meant to be tail-jumped to, the receiver must already
3358 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003359
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003360 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003361 GenerateSmiKeyCheck(masm, key, t0, t1, f2, f4, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003362
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003363 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3364
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003365 // Check that the index is in range.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003366 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3367 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003368 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003369
3370 // Handle both smis and HeapNumbers in the fast path. Go to the
3371 // runtime for all other kinds of values.
3372 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003373
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003374 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003375 // Double to pixel conversion is only implemented in the runtime for now.
3376 __ JumpIfNotSmi(value, &slow);
3377 } else {
3378 __ JumpIfNotSmi(value, &check_heap_number);
3379 }
3380 __ SmiUntag(t1, value);
3381 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3382
3383 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003384 // t1: value (integer).
3385
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003386 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003387 case EXTERNAL_PIXEL_ELEMENTS: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003388 // Clamp the value to [0..255].
3389 // v0 is used as a scratch register here.
3390 Label done;
3391 __ li(v0, Operand(255));
3392 // Normal branch: nop in delay slot.
3393 __ Branch(&done, gt, t1, Operand(v0));
3394 // Use delay slot in this branch.
3395 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg));
3396 __ mov(v0, zero_reg); // In delay slot.
3397 __ mov(v0, t1); // Value is in range 0..255.
3398 __ bind(&done);
3399 __ mov(t1, v0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003400
3401 __ srl(t8, key, 1);
3402 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003403 __ sb(t1, MemOperand(t8, 0));
3404 }
3405 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003406 case EXTERNAL_BYTE_ELEMENTS:
3407 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003408 __ srl(t8, key, 1);
3409 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003410 __ sb(t1, MemOperand(t8, 0));
3411 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003412 case EXTERNAL_SHORT_ELEMENTS:
3413 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003414 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003415 __ sh(t1, MemOperand(t8, 0));
3416 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003417 case EXTERNAL_INT_ELEMENTS:
3418 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003419 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003420 __ addu(t8, a3, t8);
3421 __ sw(t1, MemOperand(t8, 0));
3422 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003423 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003424 // Perform int-to-float conversion and store to memory.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003425 __ SmiUntag(t0, key);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003426 StoreIntAsFloat(masm, a3, t0, t1, t2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003427 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003428 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003429 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003430 __ addu(a3, a3, t8);
3431 // a3: effective address of the double element
3432 FloatingPointHelper::Destination destination;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003433 destination = FloatingPointHelper::kFPURegisters;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003434 FloatingPointHelper::ConvertIntToDouble(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003435 masm, t1, destination,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003436 f0, t2, t3, // These are: double_dst, dst_mantissa, dst_exponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003437 t0, f2); // These are: scratch2, single_scratch.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003438 __ sdc1(f0, MemOperand(a3, 0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003439 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003440 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003441 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003442 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003443 case FAST_HOLEY_ELEMENTS:
3444 case FAST_HOLEY_SMI_ELEMENTS:
3445 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003446 case DICTIONARY_ELEMENTS:
3447 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003448 UNREACHABLE();
3449 break;
3450 }
3451
3452 // Entry registers are intact, a0 holds the value which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003453 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003454 __ Ret();
3455
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003456 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003457 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003458 __ bind(&check_heap_number);
3459 __ GetObjectType(value, t1, t2);
3460 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE));
3461
3462 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3463
3464 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003465
3466 // The WebGL specification leaves the behavior of storing NaN and
3467 // +/-Infinity into integer arrays basically undefined. For more
3468 // reproducible behavior, convert these to zero.
3469
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003470
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003471 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003472
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003473 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
3474 __ cvt_s_d(f0, f0);
3475 __ sll(t8, key, 1);
3476 __ addu(t8, a3, t8);
3477 __ swc1(f0, MemOperand(t8, 0));
3478 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
3479 __ sll(t8, key, 2);
3480 __ addu(t8, a3, t8);
3481 __ sdc1(f0, MemOperand(t8, 0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003482 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003483 __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003484
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003485 switch (elements_kind) {
3486 case EXTERNAL_BYTE_ELEMENTS:
3487 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3488 __ srl(t8, key, 1);
3489 __ addu(t8, a3, t8);
3490 __ sb(t3, MemOperand(t8, 0));
3491 break;
3492 case EXTERNAL_SHORT_ELEMENTS:
3493 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3494 __ addu(t8, a3, key);
3495 __ sh(t3, MemOperand(t8, 0));
3496 break;
3497 case EXTERNAL_INT_ELEMENTS:
3498 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3499 __ sll(t8, key, 1);
3500 __ addu(t8, a3, t8);
3501 __ sw(t3, MemOperand(t8, 0));
3502 break;
3503 case EXTERNAL_PIXEL_ELEMENTS:
3504 case EXTERNAL_FLOAT_ELEMENTS:
3505 case EXTERNAL_DOUBLE_ELEMENTS:
3506 case FAST_ELEMENTS:
3507 case FAST_SMI_ELEMENTS:
3508 case FAST_DOUBLE_ELEMENTS:
3509 case FAST_HOLEY_ELEMENTS:
3510 case FAST_HOLEY_SMI_ELEMENTS:
3511 case FAST_HOLEY_DOUBLE_ELEMENTS:
3512 case DICTIONARY_ELEMENTS:
3513 case NON_STRICT_ARGUMENTS_ELEMENTS:
3514 UNREACHABLE();
3515 break;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003516 }
3517 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003518
3519 // Entry registers are intact, a0 holds the value
3520 // which is the return value.
3521 __ mov(v0, a0);
3522 __ Ret();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003523 }
3524
danno@chromium.org40cb8782011-05-25 07:58:50 +00003525 // Slow case, key and receiver still in a0 and a1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003526 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003527 __ IncrementCounter(
3528 masm->isolate()->counters()->keyed_load_external_array_slow(),
3529 1, a2, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003530 // Entry registers are intact.
3531 // ---------- S t a t e --------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003532 // -- ra : return address
danno@chromium.org40cb8782011-05-25 07:58:50 +00003533 // -- a0 : key
3534 // -- a1 : receiver
3535 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003536 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003537
3538 // Miss case, call the runtime.
3539 __ bind(&miss_force_generic);
3540
3541 // ---------- S t a t e --------------
3542 // -- ra : return address
3543 // -- a0 : key
3544 // -- a1 : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003545 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003546 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003547}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003548
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003549
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003550void KeyedStoreStubCompiler::GenerateStoreFastElement(
3551 MacroAssembler* masm,
3552 bool is_js_array,
yangguo@chromium.org56454712012-02-16 15:33:53 +00003553 ElementsKind elements_kind,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003554 KeyedAccessStoreMode store_mode) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003555 // ----------- S t a t e -------------
3556 // -- a0 : value
3557 // -- a1 : key
3558 // -- a2 : receiver
3559 // -- ra : return address
3560 // -- a3 : scratch
3561 // -- a4 : scratch (elements)
3562 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00003563 Label miss_force_generic, transition_elements_kind, grow, slow;
3564 Label finish_store, check_capacity;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003565
3566 Register value_reg = a0;
3567 Register key_reg = a1;
3568 Register receiver_reg = a2;
yangguo@chromium.org56454712012-02-16 15:33:53 +00003569 Register scratch = t0;
3570 Register elements_reg = a3;
3571 Register length_reg = t1;
3572 Register scratch2 = t2;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003573
3574 // This stub is meant to be tail-jumped to, the receiver must already
3575 // have been verified by the caller to not be a smi.
3576
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003577 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003578 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003579
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003580 if (IsFastSmiElementsKind(elements_kind)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003581 __ JumpIfNotSmi(value_reg, &transition_elements_kind);
3582 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003583
3584 // Check that the key is within bounds.
yangguo@chromium.org56454712012-02-16 15:33:53 +00003585 __ lw(elements_reg,
3586 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003587 if (is_js_array) {
3588 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3589 } else {
3590 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3591 }
3592 // Compare smis.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003593 if (is_js_array && IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003594 __ Branch(&grow, hs, key_reg, Operand(scratch));
3595 } else {
3596 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
3597 }
3598
3599 // Make sure elements is a fast element array, not 'cow'.
3600 __ CheckMap(elements_reg,
3601 scratch,
3602 Heap::kFixedArrayMapRootIndex,
3603 &miss_force_generic,
3604 DONT_DO_SMI_CHECK);
3605
3606 __ bind(&finish_store);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003607
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003608 if (IsFastSmiElementsKind(elements_kind)) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003609 __ Addu(scratch,
3610 elements_reg,
3611 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3612 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
3613 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
3614 __ Addu(scratch, scratch, scratch2);
3615 __ sw(value_reg, MemOperand(scratch));
3616 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003617 ASSERT(IsFastObjectElementsKind(elements_kind));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003618 __ Addu(scratch,
3619 elements_reg,
3620 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3621 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
3622 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
3623 __ Addu(scratch, scratch, scratch2);
3624 __ sw(value_reg, MemOperand(scratch));
3625 __ mov(receiver_reg, value_reg);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003626 __ RecordWrite(elements_reg, // Object.
3627 scratch, // Address.
3628 receiver_reg, // Value.
3629 kRAHasNotBeenSaved,
3630 kDontSaveFPRegs);
3631 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003632 // value_reg (a0) is preserved.
3633 // Done.
3634 __ Ret();
3635
3636 __ bind(&miss_force_generic);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003637 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003638
3639 __ bind(&transition_elements_kind);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003640 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003641
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003642 if (is_js_array && IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003643 // Grow the array by a single element if possible.
3644 __ bind(&grow);
3645
3646 // Make sure the array is only growing by a single element, anything else
3647 // must be handled by the runtime.
3648 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch));
3649
3650 // Check for the empty array, and preallocate a small backing store if
3651 // possible.
3652 __ lw(length_reg,
3653 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3654 __ lw(elements_reg,
3655 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3656 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
3657 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
3658
3659 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003660 __ Allocate(size, elements_reg, scratch, scratch2, &slow, TAG_OBJECT);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003661
3662 __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex);
3663 __ sw(scratch, FieldMemOperand(elements_reg, JSObject::kMapOffset));
3664 __ li(scratch, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
3665 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3666 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
3667 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
3668 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::SizeFor(i)));
3669 }
3670
3671 // Store the element at index zero.
3672 __ sw(value_reg, FieldMemOperand(elements_reg, FixedArray::SizeFor(0)));
3673
3674 // Install the new backing store in the JSArray.
3675 __ sw(elements_reg,
3676 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3677 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
3678 scratch, kRAHasNotBeenSaved, kDontSaveFPRegs,
3679 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3680
3681 // Increment the length of the array.
3682 __ li(length_reg, Operand(Smi::FromInt(1)));
3683 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3684 __ Ret();
3685
3686 __ bind(&check_capacity);
3687 // Check for cow elements, in general they are not handled by this stub
3688 __ CheckMap(elements_reg,
3689 scratch,
3690 Heap::kFixedCOWArrayMapRootIndex,
3691 &miss_force_generic,
3692 DONT_DO_SMI_CHECK);
3693
3694 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3695 __ Branch(&slow, hs, length_reg, Operand(scratch));
3696
3697 // Grow the array and finish the store.
3698 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
3699 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3700 __ jmp(&finish_store);
3701
3702 __ bind(&slow);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003703 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003704 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003705}
3706
3707
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003708void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
3709 MacroAssembler* masm,
yangguo@chromium.org56454712012-02-16 15:33:53 +00003710 bool is_js_array,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003711 KeyedAccessStoreMode store_mode) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003712 // ----------- S t a t e -------------
3713 // -- a0 : value
3714 // -- a1 : key
3715 // -- a2 : receiver
3716 // -- ra : return address
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003717 // -- a3 : scratch (elements backing store)
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003718 // -- t0 : scratch (elements_reg)
3719 // -- t1 : scratch (mantissa_reg)
3720 // -- t2 : scratch (exponent_reg)
3721 // -- t3 : scratch4
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003722 // -- t4 : scratch
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003723 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00003724 Label miss_force_generic, transition_elements_kind, grow, slow;
3725 Label finish_store, check_capacity;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003726
3727 Register value_reg = a0;
3728 Register key_reg = a1;
3729 Register receiver_reg = a2;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003730 Register elements_reg = a3;
3731 Register scratch1 = t0;
3732 Register scratch2 = t1;
3733 Register scratch3 = t2;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003734 Register scratch4 = t3;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003735 Register scratch5 = t4;
yangguo@chromium.org56454712012-02-16 15:33:53 +00003736 Register length_reg = t3;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003737
3738 // This stub is meant to be tail-jumped to, the receiver must already
3739 // have been verified by the caller to not be a smi.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003740
3741 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003742 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003743
3744 __ lw(elements_reg,
3745 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3746
3747 // Check that the key is within bounds.
3748 if (is_js_array) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003749 __ lw(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003750 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003751 __ lw(scratch1,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003752 FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3753 }
3754 // Compare smis, unsigned compare catches both negative and out-of-bound
3755 // indexes.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003756 if (IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003757 __ Branch(&grow, hs, key_reg, Operand(scratch1));
3758 } else {
3759 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch1));
3760 }
3761
3762 __ bind(&finish_store);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003763
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003764 __ StoreNumberToDoubleElements(value_reg,
3765 key_reg,
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00003766 // All registers after this are overwritten.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003767 elements_reg,
3768 scratch1,
3769 scratch2,
3770 scratch3,
3771 scratch4,
3772 &transition_elements_kind);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003773
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003774 __ Ret(USE_DELAY_SLOT);
3775 __ mov(v0, value_reg); // In delay slot.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003776
3777 // Handle store cache miss, replacing the ic with the generic stub.
3778 __ bind(&miss_force_generic);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003779 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003780
3781 __ bind(&transition_elements_kind);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003782 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003783
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003784 if (is_js_array && IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003785 // Grow the array by a single element if possible.
3786 __ bind(&grow);
3787
3788 // Make sure the array is only growing by a single element, anything else
3789 // must be handled by the runtime.
3790 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch1));
3791
3792 // Transition on values that can't be stored in a FixedDoubleArray.
3793 Label value_is_smi;
3794 __ JumpIfSmi(value_reg, &value_is_smi);
3795 __ lw(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
3796 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
3797 __ Branch(&transition_elements_kind, ne, scratch1, Operand(at));
3798 __ bind(&value_is_smi);
3799
3800 // Check for the empty array, and preallocate a small backing store if
3801 // possible.
3802 __ lw(length_reg,
3803 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3804 __ lw(elements_reg,
3805 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3806 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
3807 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
3808
3809 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003810 __ Allocate(size, elements_reg, scratch1, scratch2, &slow, TAG_OBJECT);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003811
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003812 // Initialize the new FixedDoubleArray.
yangguo@chromium.org56454712012-02-16 15:33:53 +00003813 __ LoadRoot(scratch1, Heap::kFixedDoubleArrayMapRootIndex);
3814 __ sw(scratch1, FieldMemOperand(elements_reg, JSObject::kMapOffset));
3815 __ li(scratch1, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
3816 __ sw(scratch1,
3817 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
3818
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003819 __ mov(scratch1, elements_reg);
3820 __ StoreNumberToDoubleElements(value_reg,
3821 key_reg,
3822 // All registers after this are overwritten.
3823 scratch1,
3824 scratch2,
3825 scratch3,
3826 scratch4,
3827 scratch5,
3828 &transition_elements_kind);
3829
3830 __ li(scratch1, Operand(kHoleNanLower32));
3831 __ li(scratch2, Operand(kHoleNanUpper32));
3832 for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) {
3833 int offset = FixedDoubleArray::OffsetOfElementAt(i);
3834 __ sw(scratch1, FieldMemOperand(elements_reg, offset));
3835 __ sw(scratch2, FieldMemOperand(elements_reg, offset + kPointerSize));
3836 }
3837
yangguo@chromium.org56454712012-02-16 15:33:53 +00003838 // Install the new backing store in the JSArray.
3839 __ sw(elements_reg,
3840 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3841 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
3842 scratch1, kRAHasNotBeenSaved, kDontSaveFPRegs,
3843 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3844
3845 // Increment the length of the array.
3846 __ li(length_reg, Operand(Smi::FromInt(1)));
3847 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
danno@chromium.org00379b82012-05-04 09:16:29 +00003848 __ lw(elements_reg,
3849 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003850 __ Ret();
yangguo@chromium.org56454712012-02-16 15:33:53 +00003851
3852 __ bind(&check_capacity);
3853 // Make sure that the backing store can hold additional elements.
3854 __ lw(scratch1,
3855 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
3856 __ Branch(&slow, hs, length_reg, Operand(scratch1));
3857
3858 // Grow the array and finish the store.
3859 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
3860 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3861 __ jmp(&finish_store);
3862
3863 __ bind(&slow);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003864 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003865 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003866}
3867
3868
ager@chromium.org5c838252010-02-19 08:53:10 +00003869#undef __
3870
3871} } // namespace v8::internal
3872
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003873#endif // V8_TARGET_ARCH_MIPS