blob: 80ab31a5e46124d236573fe2f325d52571214e95 [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);
510 } else if (FLAG_track_double_fields && representation.IsDouble()) {
511 Label do_store, heap_number;
512 __ LoadRoot(scratch3, Heap::kHeapNumberMapRootIndex);
513 __ AllocateHeapNumber(storage_reg, scratch1, scratch2, scratch3, slow);
514
515 __ JumpIfNotSmi(value_reg, &heap_number);
516 __ SmiUntag(scratch1, value_reg);
517 __ mtc1(scratch1, f6);
518 __ cvt_d_w(f4, f6);
519 __ jmp(&do_store);
520
521 __ bind(&heap_number);
522 __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex,
523 miss_restore_name, DONT_DO_SMI_CHECK);
524 __ ldc1(f4, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
525
526 __ bind(&do_store);
527 __ sdc1(f4, FieldMemOperand(storage_reg, HeapNumber::kValueOffset));
528 }
529
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000530 // Stub never generated for non-global objects that require access
531 // checks.
532 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
533
534 // Perform map transition for the receiver if necessary.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000535 if (object->map()->unused_property_fields() == 0) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000536 // The properties must be extended before we can store the value.
537 // We jump to a runtime call that extends the properties array.
538 __ push(receiver_reg);
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000539 __ li(a2, Operand(transition));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000540 __ Push(a2, a0);
541 __ TailCallExternalReference(
542 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
543 masm->isolate()),
544 3, 1);
545 return;
546 }
547
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000548 // Update the map of the object.
549 __ li(scratch1, Operand(transition));
550 __ sw(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
verwaest@chromium.org37141392012-05-31 13:27:02 +0000551
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000552 // Update the write barrier for the map field and pass the now unused
553 // name_reg as scratch register.
554 __ RecordWriteField(receiver_reg,
555 HeapObject::kMapOffset,
556 scratch1,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000557 scratch2,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000558 kRAHasNotBeenSaved,
559 kDontSaveFPRegs,
560 OMIT_REMEMBERED_SET,
561 OMIT_SMI_CHECK);
562
563 int index = transition->instance_descriptors()->GetFieldIndex(
564 transition->LastAdded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000565
566 // Adjust for the number of properties stored in the object. Even in the
567 // face of a transition we can use the old map here because the size of the
568 // object and the number of in-object properties is not going to change.
569 index -= object->map()->inobject_properties();
570
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000571 // TODO(verwaest): Share this code as a code stub.
572 if (index < 0) {
573 // Set the property straight into the object.
574 int offset = object->map()->instance_size() + (index * kPointerSize);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000575 if (FLAG_track_double_fields && representation.IsDouble()) {
576 __ sw(storage_reg, FieldMemOperand(receiver_reg, offset));
577 } else {
578 __ sw(value_reg, FieldMemOperand(receiver_reg, offset));
579 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000580
danno@chromium.orgf005df62013-04-30 16:36:45 +0000581 if (!FLAG_track_fields || !representation.IsSmi()) {
582 // Skip updating write barrier if storing a smi.
583 __ JumpIfSmi(value_reg, &exit);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000584
danno@chromium.orgf005df62013-04-30 16:36:45 +0000585 // Update the write barrier for the array address.
586 // Pass the now unused name_reg as a scratch register.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000587 if (!FLAG_track_double_fields || !representation.IsDouble()) {
588 __ mov(name_reg, value_reg);
589 } else {
590 ASSERT(storage_reg.is(name_reg));
591 }
danno@chromium.orgf005df62013-04-30 16:36:45 +0000592 __ RecordWriteField(receiver_reg,
593 offset,
594 name_reg,
595 scratch1,
596 kRAHasNotBeenSaved,
597 kDontSaveFPRegs);
598 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000599 } else {
600 // Write to the properties array.
601 int offset = index * kPointerSize + FixedArray::kHeaderSize;
602 // Get the properties array
603 __ lw(scratch1,
604 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000605 if (FLAG_track_double_fields && representation.IsDouble()) {
606 __ sw(storage_reg, FieldMemOperand(scratch1, offset));
607 } else {
608 __ sw(value_reg, FieldMemOperand(scratch1, offset));
609 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000610
danno@chromium.orgf005df62013-04-30 16:36:45 +0000611 if (!FLAG_track_fields || !representation.IsSmi()) {
612 // Skip updating write barrier if storing a smi.
613 __ JumpIfSmi(value_reg, &exit);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000614
danno@chromium.orgf005df62013-04-30 16:36:45 +0000615 // Update the write barrier for the array address.
616 // Ok to clobber receiver_reg and name_reg, since we return.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000617 if (!FLAG_track_double_fields || !representation.IsDouble()) {
618 __ mov(name_reg, value_reg);
619 } else {
620 ASSERT(storage_reg.is(name_reg));
621 }
danno@chromium.orgf005df62013-04-30 16:36:45 +0000622 __ mov(name_reg, value_reg);
623 __ RecordWriteField(scratch1,
624 offset,
625 name_reg,
626 receiver_reg,
627 kRAHasNotBeenSaved,
628 kDontSaveFPRegs);
629 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000630 }
631
632 // Return the value (register v0).
633 ASSERT(value_reg.is(a0));
634 __ bind(&exit);
635 __ mov(v0, a0);
636 __ Ret();
637}
638
639
640// Generate StoreField code, value is passed in a0 register.
641// When leaving generated code after success, the receiver_reg and name_reg
642// may be clobbered. Upon branch to miss_label, the receiver and name
643// registers have their original values.
644void StubCompiler::GenerateStoreField(MacroAssembler* masm,
645 Handle<JSObject> object,
646 LookupResult* lookup,
647 Register receiver_reg,
648 Register name_reg,
649 Register value_reg,
650 Register scratch1,
651 Register scratch2,
652 Label* miss_label) {
653 // a0 : value
654 Label exit;
655
656 // Check that the map of the object hasn't changed.
657 __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
658 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
659
660 // Perform global security token check if needed.
661 if (object->IsJSGlobalProxy()) {
662 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
663 }
664
665 // Stub never generated for non-global objects that require access
666 // checks.
667 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
668
669 int index = lookup->GetFieldIndex().field_index();
670
671 // Adjust for the number of properties stored in the object. Even in the
672 // face of a transition we can use the old map here because the size of the
673 // object and the number of in-object properties is not going to change.
674 index -= object->map()->inobject_properties();
675
danno@chromium.orgf005df62013-04-30 16:36:45 +0000676 Representation representation = lookup->representation();
677 ASSERT(!representation.IsNone());
678 if (FLAG_track_fields && representation.IsSmi()) {
679 __ JumpIfNotSmi(value_reg, miss_label);
680 } else if (FLAG_track_double_fields && representation.IsDouble()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000681 // Load the double storage.
682 if (index < 0) {
683 int offset = object->map()->instance_size() + (index * kPointerSize);
684 __ lw(scratch1, FieldMemOperand(receiver_reg, offset));
685 } else {
686 __ lw(scratch1,
687 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
688 int offset = index * kPointerSize + FixedArray::kHeaderSize;
689 __ lw(scratch1, FieldMemOperand(scratch1, offset));
690 }
691
692 // Store the value into the storage.
693 Label do_store, heap_number;
694 __ JumpIfNotSmi(value_reg, &heap_number);
695 __ SmiUntag(scratch2, value_reg);
696 __ mtc1(scratch2, f6);
697 __ cvt_d_w(f4, f6);
698 __ jmp(&do_store);
699
700 __ bind(&heap_number);
701 __ CheckMap(value_reg, scratch2, Heap::kHeapNumberMapRootIndex,
danno@chromium.orgf005df62013-04-30 16:36:45 +0000702 miss_label, DONT_DO_SMI_CHECK);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000703 __ ldc1(f4, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
704
danno@chromium.orgf005df62013-04-30 16:36:45 +0000705 __ bind(&do_store);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000706 __ sdc1(f4, FieldMemOperand(scratch1, HeapNumber::kValueOffset));
707 // Return the value (register v0).
708 ASSERT(value_reg.is(a0));
709 __ mov(v0, a0);
710 __ Ret();
711 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +0000712 }
713
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000714 // TODO(verwaest): Share this code as a code stub.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000715 if (index < 0) {
716 // Set the property straight into the object.
717 int offset = object->map()->instance_size() + (index * kPointerSize);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000718 __ sw(value_reg, FieldMemOperand(receiver_reg, offset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000719
danno@chromium.orgf005df62013-04-30 16:36:45 +0000720 if (!FLAG_track_fields || !representation.IsSmi()) {
721 // Skip updating write barrier if storing a smi.
722 __ JumpIfSmi(value_reg, &exit);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000723
danno@chromium.orgf005df62013-04-30 16:36:45 +0000724 // Update the write barrier for the array address.
725 // Pass the now unused name_reg as a scratch register.
726 __ mov(name_reg, value_reg);
727 __ RecordWriteField(receiver_reg,
728 offset,
729 name_reg,
730 scratch1,
731 kRAHasNotBeenSaved,
732 kDontSaveFPRegs);
733 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000734 } else {
735 // Write to the properties array.
736 int offset = index * kPointerSize + FixedArray::kHeaderSize;
737 // Get the properties array.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000738 __ lw(scratch1,
739 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000740 __ sw(value_reg, FieldMemOperand(scratch1, offset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000741
danno@chromium.orgf005df62013-04-30 16:36:45 +0000742 if (!FLAG_track_fields || !representation.IsSmi()) {
743 // Skip updating write barrier if storing a smi.
744 __ JumpIfSmi(value_reg, &exit);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000745
danno@chromium.orgf005df62013-04-30 16:36:45 +0000746 // Update the write barrier for the array address.
747 // Ok to clobber receiver_reg and name_reg, since we return.
748 __ mov(name_reg, value_reg);
749 __ RecordWriteField(scratch1,
750 offset,
751 name_reg,
752 receiver_reg,
753 kRAHasNotBeenSaved,
754 kDontSaveFPRegs);
755 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000756 }
757
758 // Return the value (register v0).
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000759 ASSERT(value_reg.is(a0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000760 __ bind(&exit);
761 __ mov(v0, a0);
762 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000763}
764
765
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000766void BaseStoreStubCompiler::GenerateRestoreName(MacroAssembler* masm,
767 Label* label,
768 Handle<Name> name) {
769 if (!label->is_unused()) {
770 __ bind(label);
771 __ li(this->name(), Operand(name));
772 }
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000773}
774
775
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000776static void GenerateCallFunction(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000777 Handle<Object> object,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000778 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000779 Label* miss,
780 Code::ExtraICState extra_ic_state) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000781 // ----------- S t a t e -------------
782 // -- a0: receiver
783 // -- a1: function to call
784 // -----------------------------------
785 // Check that the function really is a function.
786 __ JumpIfSmi(a1, miss);
787 __ GetObjectType(a1, a3, a3);
788 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
789
790 // Patch the receiver on the stack with the global proxy if
791 // necessary.
792 if (object->IsGlobalObject()) {
793 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
794 __ sw(a3, MemOperand(sp, arguments.immediate() * kPointerSize));
795 }
796
797 // Invoke the function.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000798 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
799 ? CALL_AS_FUNCTION
800 : CALL_AS_METHOD;
801 __ InvokeFunction(a1, arguments, JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000802}
803
804
805static void PushInterceptorArguments(MacroAssembler* masm,
806 Register receiver,
807 Register holder,
808 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000809 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000810 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000811 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
812 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000813 Register scratch = name;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000814 __ li(scratch, Operand(interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000815 __ Push(scratch, receiver, holder);
816 __ lw(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
817 __ push(scratch);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000818 __ li(scratch, Operand(ExternalReference::isolate_address(masm->isolate())));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000819 __ push(scratch);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000820}
821
822
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000823static void CompileCallLoadPropertyWithInterceptor(
824 MacroAssembler* masm,
825 Register receiver,
826 Register holder,
827 Register name,
828 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000829 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
830
831 ExternalReference ref =
832 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
833 masm->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000834 __ PrepareCEntryArgs(6);
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000835 __ PrepareCEntryFunction(ref);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000836
837 CEntryStub stub(1);
838 __ CallStub(&stub);
839}
840
841
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000842static const int kFastApiCallArguments = 4;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000843
844
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000845// Reserves space for the extra arguments to API function in the
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000846// caller's frame.
847//
848// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
849static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
850 Register scratch) {
851 ASSERT(Smi::FromInt(0) == 0);
852 for (int i = 0; i < kFastApiCallArguments; i++) {
853 __ push(zero_reg);
854 }
855}
856
857
858// Undoes the effects of ReserveSpaceForFastApiCall.
859static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
860 __ Drop(kFastApiCallArguments);
861}
862
863
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000864static void GenerateFastApiDirectCall(MacroAssembler* masm,
865 const CallOptimization& optimization,
866 int argc) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000867 // ----------- S t a t e -------------
868 // -- sp[0] : holder (set by CheckPrototypes)
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000869 // -- sp[4] : callee JS function
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000870 // -- sp[8] : call data
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000871 // -- sp[12] : isolate
872 // -- sp[16] : last JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000873 // -- ...
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000874 // -- sp[(argc + 3) * 4] : first JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000875 // -- sp[(argc + 4) * 4] : receiver
876 // -----------------------------------
877 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000878 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000879 __ LoadHeapObject(t1, function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000880 __ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset));
881
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000882 // Pass the additional arguments.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000883 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000884 Handle<Object> call_data(api_call_info->data(), masm->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000885 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
886 __ li(a0, api_call_info);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000887 __ lw(t2, FieldMemOperand(a0, CallHandlerInfo::kDataOffset));
888 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000889 __ li(t2, call_data);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000890 }
891
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000892 __ li(t3, Operand(ExternalReference::isolate_address(masm->isolate())));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000893 // Store JS function, call data and isolate.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000894 __ sw(t1, MemOperand(sp, 1 * kPointerSize));
895 __ sw(t2, MemOperand(sp, 2 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000896 __ sw(t3, MemOperand(sp, 3 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000897
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000898 // Prepare arguments.
899 __ Addu(a2, sp, Operand(3 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000900
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000901 // Allocate the v8::Arguments structure in the arguments' space since
902 // it's not controlled by GC.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000903 const int kApiStackSpace = 4;
904
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000905 FrameScope frame_scope(masm, StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000906 __ EnterExitFrame(false, kApiStackSpace);
907
908 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
909 // struct from the function (which is currently the case). This means we pass
910 // the first argument in a1 instead of a0. TryCallApiFunctionAndReturn
911 // will handle setting up a0.
912
913 // a1 = v8::Arguments&
914 // Arguments is built at sp + 1 (sp is a reserved spot for ra).
915 __ Addu(a1, sp, kPointerSize);
916
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000917 // v8::Arguments::implicit_args_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000918 __ sw(a2, MemOperand(a1, 0 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000919 // v8::Arguments::values_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000920 __ Addu(t0, a2, Operand(argc * kPointerSize));
921 __ sw(t0, MemOperand(a1, 1 * kPointerSize));
922 // v8::Arguments::length_ = argc
923 __ li(t0, Operand(argc));
924 __ sw(t0, MemOperand(a1, 2 * kPointerSize));
925 // v8::Arguments::is_construct_call = 0
926 __ sw(zero_reg, MemOperand(a1, 3 * kPointerSize));
927
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000928 const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000929 Address function_address = v8::ToCData<Address>(api_call_info->callback());
930 ApiFunction fun(function_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000931 ExternalReference ref =
932 ExternalReference(&fun,
933 ExternalReference::DIRECT_API_CALL,
934 masm->isolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000935 AllowExternalCallThatCantCauseGC scope(masm);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000936 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000937}
938
lrn@chromium.org7516f052011-03-30 08:52:27 +0000939class CallInterceptorCompiler BASE_EMBEDDED {
940 public:
941 CallInterceptorCompiler(StubCompiler* stub_compiler,
942 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000943 Register name,
944 Code::ExtraICState extra_ic_state)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000945 : stub_compiler_(stub_compiler),
946 arguments_(arguments),
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000947 name_(name),
948 extra_ic_state_(extra_ic_state) {}
lrn@chromium.org7516f052011-03-30 08:52:27 +0000949
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000950 void Compile(MacroAssembler* masm,
951 Handle<JSObject> object,
952 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000953 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000954 LookupResult* lookup,
955 Register receiver,
956 Register scratch1,
957 Register scratch2,
958 Register scratch3,
959 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000960 ASSERT(holder->HasNamedInterceptor());
961 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
962
963 // Check that the receiver isn't a smi.
964 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000965 CallOptimization optimization(lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000966 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000967 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
968 holder, lookup, name, optimization, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000969 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000970 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
971 name, holder, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000972 }
973 }
974
975 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000976 void CompileCacheable(MacroAssembler* masm,
977 Handle<JSObject> object,
978 Register receiver,
979 Register scratch1,
980 Register scratch2,
981 Register scratch3,
982 Handle<JSObject> interceptor_holder,
983 LookupResult* lookup,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000984 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000985 const CallOptimization& optimization,
986 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000987 ASSERT(optimization.is_constant_call());
988 ASSERT(!lookup->holder()->IsGlobalObject());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000989 Counters* counters = masm->isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000990 int depth1 = kInvalidProtoDepth;
991 int depth2 = kInvalidProtoDepth;
992 bool can_do_fast_api_call = false;
993 if (optimization.is_simple_api_call() &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000994 !lookup->holder()->IsGlobalObject()) {
995 depth1 = optimization.GetPrototypeDepthOfExpectedType(
996 object, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000997 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000998 depth2 = optimization.GetPrototypeDepthOfExpectedType(
999 interceptor_holder, Handle<JSObject>(lookup->holder()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001000 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001001 can_do_fast_api_call =
1002 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001003 }
1004
1005 __ IncrementCounter(counters->call_const_interceptor(), 1,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001006 scratch1, scratch2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001007
1008 if (can_do_fast_api_call) {
1009 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
1010 scratch1, scratch2);
1011 ReserveSpaceForFastApiCall(masm, scratch1);
1012 }
1013
1014 // Check that the maps from receiver to interceptor's holder
1015 // haven't changed and thus we can invoke interceptor.
1016 Label miss_cleanup;
1017 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
1018 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001019 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
1020 scratch1, scratch2, scratch3,
1021 name, depth1, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001022
1023 // Invoke an interceptor and if it provides a value,
1024 // branch to |regular_invoke|.
1025 Label regular_invoke;
1026 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
1027 &regular_invoke);
1028
1029 // Interceptor returned nothing for this property. Try to use cached
1030 // constant function.
1031
1032 // Check that the maps from interceptor's holder to constant function's
1033 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001034 if (*interceptor_holder != lookup->holder()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001035 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001036 Handle<JSObject>(lookup->holder()),
1037 scratch1, scratch2, scratch3,
1038 name, depth2, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001039 } else {
1040 // CheckPrototypes has a side effect of fetching a 'holder'
1041 // for API (object which is instanceof for the signature). It's
1042 // safe to omit it here, as if present, it should be fetched
1043 // by the previous CheckPrototypes.
1044 ASSERT(depth2 == kInvalidProtoDepth);
1045 }
1046
1047 // Invoke function.
1048 if (can_do_fast_api_call) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001049 GenerateFastApiDirectCall(masm, optimization, arguments_.immediate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001050 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001051 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
1052 ? CALL_AS_FUNCTION
1053 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001054 Handle<JSFunction> function = optimization.constant_function();
1055 ParameterCount expected(function);
1056 __ InvokeFunction(function, expected, arguments_,
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001057 JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001058 }
1059
1060 // Deferred code for fast API call case---clean preallocated space.
1061 if (can_do_fast_api_call) {
1062 __ bind(&miss_cleanup);
1063 FreeSpaceForFastApiCall(masm);
1064 __ Branch(miss_label);
1065 }
1066
1067 // Invoke a regular function.
1068 __ bind(&regular_invoke);
1069 if (can_do_fast_api_call) {
1070 FreeSpaceForFastApiCall(masm);
1071 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00001072 }
1073
1074 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001075 Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001076 Register receiver,
1077 Register scratch1,
1078 Register scratch2,
1079 Register scratch3,
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001080 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001081 Handle<JSObject> interceptor_holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001082 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001083 Register holder =
1084 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001085 scratch1, scratch2, scratch3,
1086 name, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001087
1088 // Call a runtime function to load the interceptor property.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001089 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001090 // Save the name_ register across the call.
1091 __ push(name_);
1092
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001093 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001094
1095 __ CallExternalReference(
1096 ExternalReference(
1097 IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
1098 masm->isolate()),
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001099 6);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001100 // Restore the name_ register.
1101 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001102 // Leave the internal frame.
lrn@chromium.org7516f052011-03-30 08:52:27 +00001103 }
1104
1105 void LoadWithInterceptor(MacroAssembler* masm,
1106 Register receiver,
1107 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001108 Handle<JSObject> holder_obj,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001109 Register scratch,
1110 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001111 {
1112 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001113
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001114 __ Push(holder, name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001115 CompileCallLoadPropertyWithInterceptor(masm,
1116 receiver,
1117 holder,
1118 name_,
1119 holder_obj);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001120 __ pop(name_); // Restore the name.
1121 __ pop(receiver); // Restore the holder.
1122 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001123 // If interceptor returns no-result sentinel, call the constant function.
1124 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
1125 __ Branch(interceptor_succeeded, ne, v0, Operand(scratch));
lrn@chromium.org7516f052011-03-30 08:52:27 +00001126 }
1127
1128 StubCompiler* stub_compiler_;
1129 const ParameterCount& arguments_;
1130 Register name_;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001131 Code::ExtraICState extra_ic_state_;
lrn@chromium.org7516f052011-03-30 08:52:27 +00001132};
1133
1134
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001135// Calls GenerateCheckPropertyCell for each global object in the prototype chain
1136// from object to (but not including) holder.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001137static void GenerateCheckPropertyCells(MacroAssembler* masm,
1138 Handle<JSObject> object,
1139 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001140 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001141 Register scratch,
1142 Label* miss) {
1143 Handle<JSObject> current = object;
1144 while (!current.is_identical_to(holder)) {
1145 if (current->IsGlobalObject()) {
1146 GenerateCheckPropertyCell(masm,
1147 Handle<GlobalObject>::cast(current),
1148 name,
1149 scratch,
1150 miss);
1151 }
1152 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
1153 }
1154}
1155
1156
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001157// Convert and store int passed in register ival to IEEE 754 single precision
1158// floating point value at memory location (dst + 4 * wordoffset)
1159// If FPU is available use it for conversion.
1160static void StoreIntAsFloat(MacroAssembler* masm,
1161 Register dst,
1162 Register wordoffset,
1163 Register ival,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001164 Register scratch1) {
1165 __ mtc1(ival, f0);
1166 __ cvt_s_w(f0, f0);
1167 __ sll(scratch1, wordoffset, 2);
1168 __ addu(scratch1, dst, scratch1);
1169 __ swc1(f0, MemOperand(scratch1, 0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001170}
1171
1172
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001173void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001174 __ Jump(code, RelocInfo::CODE_TARGET);
1175}
1176
1177
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001178#undef __
1179#define __ ACCESS_MASM(masm())
1180
1181
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001182Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
1183 Register object_reg,
1184 Handle<JSObject> holder,
1185 Register holder_reg,
1186 Register scratch1,
1187 Register scratch2,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001188 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001189 int save_at_depth,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001190 Label* miss,
1191 PrototypeCheckType check) {
1192 Handle<JSObject> first = object;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001193 // Make sure there's no overlap between holder and object registers.
1194 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1195 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1196 && !scratch2.is(scratch1));
1197
1198 // Keep track of the current object in register reg.
1199 Register reg = object_reg;
1200 int depth = 0;
1201
1202 if (save_at_depth == depth) {
1203 __ sw(reg, MemOperand(sp));
1204 }
1205
1206 // Check the maps in the prototype chain.
1207 // Traverse the prototype chain from the object and do map checks.
1208 Handle<JSObject> current = object;
1209 while (!current.is_identical_to(holder)) {
1210 ++depth;
1211
1212 // Only global objects and objects that do not require access
1213 // checks are allowed in stubs.
1214 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1215
1216 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
1217 if (!current->HasFastProperties() &&
1218 !current->IsJSGlobalObject() &&
1219 !current->IsJSGlobalProxy()) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001220 if (!name->IsUniqueName()) {
1221 ASSERT(name->IsString());
1222 name = factory()->InternalizeString(Handle<String>::cast(name));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001223 }
1224 ASSERT(current->property_dictionary()->FindEntry(*name) ==
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001225 NameDictionary::kNotFound);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001226
1227 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1228 scratch1, scratch2);
1229
1230 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1231 reg = holder_reg; // From now on the object will be in holder_reg.
1232 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1233 } else {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001234 Register map_reg = scratch1;
1235 if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) {
1236 Handle<Map> current_map(current->map());
1237 // CheckMap implicitly loads the map of |reg| into |map_reg|.
1238 __ CheckMap(reg, map_reg, current_map, miss, DONT_DO_SMI_CHECK,
1239 ALLOW_ELEMENT_TRANSITION_MAPS);
1240 } else {
1241 __ lw(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
1242 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001243 // Check access rights to the global object. This has to happen after
1244 // the map check so that we know that the object is actually a global
1245 // object.
1246 if (current->IsJSGlobalProxy()) {
1247 __ CheckAccessGlobalProxy(reg, scratch2, miss);
1248 }
1249 reg = holder_reg; // From now on the object will be in holder_reg.
1250
1251 if (heap()->InNewSpace(*prototype)) {
1252 // The prototype is in new space; we cannot store a reference to it
1253 // in the code. Load it from the map.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001254 __ lw(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001255 } else {
1256 // The prototype is in old space; load it directly.
1257 __ li(reg, Operand(prototype));
1258 }
1259 }
1260
1261 if (save_at_depth == depth) {
1262 __ sw(reg, MemOperand(sp));
1263 }
1264
1265 // Go to the next object in the prototype chain.
1266 current = prototype;
1267 }
1268
1269 // Log the check depth.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001270 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001271
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001272 if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) {
1273 // Check the holder map.
1274 __ CheckMap(reg, scratch1, Handle<Map>(holder->map()), miss,
1275 DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
1276 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001277
1278 // Perform security check for access to the global object.
1279 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1280 if (holder->IsJSGlobalProxy()) {
1281 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1282 }
1283
1284 // If we've skipped any global objects, it's not enough to verify that
1285 // their maps haven't changed. We also need to check that the property
1286 // cell for the property is still empty.
1287 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1288
1289 // Return the register containing the holder.
1290 return reg;
1291}
1292
1293
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001294void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success,
1295 Label* miss) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001296 if (!miss->is_unused()) {
1297 __ Branch(success);
1298 __ bind(miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001299 TailCallBuiltin(masm(), MissBuiltin(kind()));
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001300 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001301}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001302
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001303
1304Register BaseLoadStubCompiler::CallbackHandlerFrontend(
1305 Handle<JSObject> object,
1306 Register object_reg,
1307 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001308 Handle<Name> name,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001309 Label* success,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001310 Handle<ExecutableAccessorInfo> callback) {
1311 Label miss;
1312
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001313 Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001314
1315 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
1316 ASSERT(!reg.is(scratch2()));
1317 ASSERT(!reg.is(scratch3()));
1318 ASSERT(!reg.is(scratch4()));
1319
1320 // Load the properties dictionary.
1321 Register dictionary = scratch4();
1322 __ lw(dictionary, FieldMemOperand(reg, JSObject::kPropertiesOffset));
1323
1324 // Probe the dictionary.
1325 Label probe_done;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001326 NameDictionaryLookupStub::GeneratePositiveLookup(masm(),
1327 &miss,
1328 &probe_done,
1329 dictionary,
1330 this->name(),
1331 scratch2(),
1332 scratch3());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001333 __ bind(&probe_done);
1334
1335 // If probing finds an entry in the dictionary, scratch3 contains the
1336 // pointer into the dictionary. Check that the value is the callback.
1337 Register pointer = scratch3();
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001338 const int kElementsStartOffset = NameDictionary::kHeaderSize +
1339 NameDictionary::kElementsStartIndex * kPointerSize;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001340 const int kValueOffset = kElementsStartOffset + kPointerSize;
1341 __ lw(scratch2(), FieldMemOperand(pointer, kValueOffset));
1342 __ Branch(&miss, ne, scratch2(), Operand(callback));
1343 }
1344
1345 HandlerFrontendFooter(success, &miss);
1346 return reg;
1347}
1348
1349
1350void BaseLoadStubCompiler::NonexistentHandlerFrontend(
1351 Handle<JSObject> object,
1352 Handle<JSObject> last,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001353 Handle<Name> name,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001354 Label* success,
1355 Handle<GlobalObject> global) {
1356 Label miss;
1357
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001358 HandlerFrontendHeader(object, receiver(), last, name, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001359
1360 // If the last object in the prototype chain is a global object,
1361 // check that the global property cell is empty.
1362 if (!global.is_null()) {
1363 GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
1364 }
1365
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001366 HandlerFrontendFooter(success, &miss);
1367}
1368
1369
1370void BaseLoadStubCompiler::GenerateLoadField(Register reg,
1371 Handle<JSObject> holder,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001372 PropertyIndex field,
1373 Representation representation) {
1374 if (!reg.is(receiver())) __ mov(receiver(), reg);
1375 if (kind() == Code::LOAD_IC) {
1376 LoadFieldStub stub(field.is_inobject(holder),
1377 field.translate(holder),
1378 representation);
1379 GenerateTailCall(masm(), stub.GetCode(isolate()));
1380 } else {
1381 KeyedLoadFieldStub stub(field.is_inobject(holder),
1382 field.translate(holder),
1383 representation);
1384 GenerateTailCall(masm(), stub.GetCode(isolate()));
1385 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001386}
1387
1388
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001389void BaseLoadStubCompiler::GenerateLoadConstant(Handle<JSFunction> value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001390 // Return the constant value.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001391 __ LoadHeapObject(v0, value);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001392 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001393}
1394
1395
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001396void BaseLoadStubCompiler::GenerateLoadCallback(
1397 Register reg,
1398 Handle<ExecutableAccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001399 // Build AccessorInfo::args_ list on the stack and push property name below
1400 // the exit frame to make GC aware of them and store pointers to them.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001401 __ push(receiver());
1402 __ mov(scratch2(), sp); // scratch2 = AccessorInfo::args_
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001403 if (heap()->InNewSpace(callback->data())) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001404 __ li(scratch3(), callback);
1405 __ lw(scratch3(), FieldMemOperand(scratch3(),
1406 ExecutableAccessorInfo::kDataOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001407 } else {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001408 __ li(scratch3(), Handle<Object>(callback->data(), isolate()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001409 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001410 __ Subu(sp, sp, 4 * kPointerSize);
1411 __ sw(reg, MemOperand(sp, 3 * kPointerSize));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001412 __ sw(scratch3(), MemOperand(sp, 2 * kPointerSize));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001413 __ li(scratch3(),
1414 Operand(ExternalReference::isolate_address(isolate())));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001415 __ sw(scratch3(), MemOperand(sp, 1 * kPointerSize));
1416 __ sw(name(), MemOperand(sp, 0 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001417
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001418 __ mov(a2, scratch2()); // Saved in case scratch2 == a1.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001419 __ mov(a1, sp); // a1 (first argument - see note below) = Handle<Name>
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001420
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001421 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
1422 // struct from the function (which is currently the case). This means we pass
1423 // the arguments in a1-a2 instead of a0-a1. TryCallApiFunctionAndReturn
1424 // will handle setting up a0.
1425
1426 const int kApiStackSpace = 1;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001427 FrameScope frame_scope(masm(), StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001428 __ EnterExitFrame(false, kApiStackSpace);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001429
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001430 // Create AccessorInfo instance on the stack above the exit frame with
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001431 // scratch2 (internal::Object** args_) as the data.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001432 __ sw(a2, MemOperand(sp, kPointerSize));
1433 // a2 (second argument - see note above) = AccessorInfo&
1434 __ Addu(a2, sp, kPointerSize);
1435
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001436 const int kStackUnwindSpace = 5;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001437 Address getter_address = v8::ToCData<Address>(callback->getter());
1438 ApiFunction fun(getter_address);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001439 ExternalReference ref = ExternalReference(
1440 &fun, ExternalReference::DIRECT_GETTER_CALL, isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001441 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
ager@chromium.org5c838252010-02-19 08:53:10 +00001442}
1443
1444
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001445void BaseLoadStubCompiler::GenerateLoadInterceptor(
1446 Register holder_reg,
1447 Handle<JSObject> object,
1448 Handle<JSObject> interceptor_holder,
1449 LookupResult* lookup,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001450 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001451 ASSERT(interceptor_holder->HasNamedInterceptor());
1452 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1453
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001454 // So far the most popular follow ups for interceptor loads are FIELD
1455 // and CALLBACKS, so inline only them, other cases may be added
1456 // later.
1457 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001458 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001459 if (lookup->IsField()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001460 compile_followup_inline = true;
1461 } else if (lookup->type() == CALLBACKS &&
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001462 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
1463 ExecutableAccessorInfo* callback =
1464 ExecutableAccessorInfo::cast(lookup->GetCallbackObject());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001465 compile_followup_inline = callback->getter() != NULL &&
1466 callback->IsCompatibleReceiver(*object);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001467 }
1468 }
1469
1470 if (compile_followup_inline) {
1471 // Compile the interceptor call, followed by inline code to load the
1472 // property from further up the prototype chain if the call fails.
1473 // Check that the maps haven't changed.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001474 ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001475
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001476 // Preserve the receiver register explicitly whenever it is different from
1477 // the holder and it is needed should the interceptor return without any
1478 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1479 // the FIELD case might cause a miss during the prototype check.
1480 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001481 bool must_preserve_receiver_reg = !receiver().is(holder_reg) &&
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001482 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1483
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001484 // Save necessary data before invoking an interceptor.
1485 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001486 {
1487 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001488 if (must_preserve_receiver_reg) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001489 __ Push(receiver(), holder_reg, this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001490 } else {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001491 __ Push(holder_reg, this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001492 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001493 // Invoke an interceptor. Note: map checks from receiver to
1494 // interceptor's holder has been compiled before (see a caller
1495 // of this method).
1496 CompileCallLoadPropertyWithInterceptor(masm(),
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001497 receiver(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001498 holder_reg,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001499 this->name(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001500 interceptor_holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001501 // Check if interceptor provided a value for property. If it's
1502 // the case, return immediately.
1503 Label interceptor_failed;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001504 __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
1505 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001506 frame_scope.GenerateLeaveFrame();
1507 __ Ret();
1508
1509 __ bind(&interceptor_failed);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001510 __ pop(this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001511 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001512 if (must_preserve_receiver_reg) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001513 __ pop(receiver());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001514 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001515 // Leave the internal frame.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001516 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001517 GenerateLoadPostInterceptor(holder_reg, interceptor_holder, name, lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001518 } else { // !compile_followup_inline
1519 // Call the runtime system to load the interceptor.
1520 // Check that the maps haven't changed.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001521 PushInterceptorArguments(masm(), receiver(), holder_reg,
1522 this->name(), interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001523
1524 ExternalReference ref = ExternalReference(
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001525 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001526 __ TailCallExternalReference(ref, 6, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001527 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001528}
1529
1530
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001531void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001532 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001533 __ Branch(miss, ne, a2, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001534 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001535}
1536
1537
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001538void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1539 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001540 Handle<Name> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001541 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001542 ASSERT(holder->IsGlobalObject());
1543
1544 // Get the number of arguments.
1545 const int argc = arguments().immediate();
1546
1547 // Get the receiver from the stack.
1548 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1549
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001550 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001551 __ JumpIfSmi(a0, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001552 CheckPrototypes(object, a0, holder, a3, a1, t0, name, miss);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001553}
1554
1555
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001556void CallStubCompiler::GenerateLoadFunctionFromCell(
1557 Handle<JSGlobalPropertyCell> cell,
1558 Handle<JSFunction> function,
1559 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001560 // Get the value from the cell.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001561 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001562 __ lw(a1, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
1563
1564 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001565 if (heap()->InNewSpace(*function)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001566 // We can't embed a pointer to a function in new space so we have
1567 // to verify that the shared function info is unchanged. This has
1568 // the nice side effect that multiple closures based on the same
1569 // function can all use this call IC. Before we load through the
1570 // function, we have to verify that it still is a function.
1571 __ JumpIfSmi(a1, miss);
1572 __ GetObjectType(a1, a3, a3);
1573 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
1574
1575 // Check the shared function info. Make sure it hasn't changed.
1576 __ li(a3, Handle<SharedFunctionInfo>(function->shared()));
1577 __ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
1578 __ Branch(miss, ne, t0, Operand(a3));
1579 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001580 __ Branch(miss, ne, a1, Operand(function));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001581 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001582}
1583
1584
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001585void CallStubCompiler::GenerateMissBranch() {
1586 Handle<Code> code =
danno@chromium.org40cb8782011-05-25 07:58:50 +00001587 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1588 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001589 extra_state_);
1590 __ Jump(code, RelocInfo::CODE_TARGET);
1591}
1592
1593
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001594Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1595 Handle<JSObject> holder,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001596 PropertyIndex index,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001597 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001598 // ----------- S t a t e -------------
1599 // -- a2 : name
1600 // -- ra : return address
1601 // -----------------------------------
1602 Label miss;
1603
1604 GenerateNameCheck(name, &miss);
1605
1606 const int argc = arguments().immediate();
1607
1608 // Get the receiver of the function from the stack into a0.
1609 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1610 // Check that the receiver isn't a smi.
1611 __ JumpIfSmi(a0, &miss, t0);
1612
1613 // Do the right check and compute the holder register.
1614 Register reg = CheckPrototypes(object, a0, holder, a1, a3, t0, name, &miss);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001615 GenerateFastPropertyLoad(masm(), a1, reg, index.is_inobject(holder),
1616 index.translate(holder), Representation::Tagged());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001617
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001618 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001619
1620 // Handle call cache miss.
1621 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001622 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001623
1624 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001625 return GetCode(Code::FIELD, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001626}
1627
1628
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001629Handle<Code> CallStubCompiler::CompileArrayPushCall(
1630 Handle<Object> object,
1631 Handle<JSObject> holder,
1632 Handle<JSGlobalPropertyCell> cell,
1633 Handle<JSFunction> function,
1634 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001635 // ----------- S t a t e -------------
1636 // -- a2 : name
1637 // -- ra : return address
1638 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1639 // -- ...
1640 // -- sp[argc * 4] : receiver
1641 // -----------------------------------
1642
1643 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001644 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001645
1646 Label miss;
1647
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001648 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001649
1650 Register receiver = a1;
1651
1652 // Get the receiver from the stack.
1653 const int argc = arguments().immediate();
1654 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1655
1656 // Check that the receiver isn't a smi.
1657 __ JumpIfSmi(receiver, &miss);
1658
1659 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001660 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, a3, v0, t0,
1661 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001662
1663 if (argc == 0) {
1664 // Nothing to do, just return the length.
1665 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1666 __ Drop(argc + 1);
1667 __ Ret();
1668 } else {
1669 Label call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001670 if (argc == 1) { // Otherwise fall through to call the builtin.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001671 Label attempt_to_grow_elements, with_write_barrier, check_double;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001672
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001673 Register elements = t2;
1674 Register end_elements = t1;
1675 // Get the elements array of the object.
1676 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1677
1678 // Check that the elements are in fast mode and writable.
1679 __ CheckMap(elements,
1680 v0,
1681 Heap::kFixedArrayMapRootIndex,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001682 &check_double,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001683 DONT_DO_SMI_CHECK);
1684
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001685 // Get the array's length into v0 and calculate new length.
1686 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1687 STATIC_ASSERT(kSmiTagSize == 1);
1688 STATIC_ASSERT(kSmiTag == 0);
1689 __ Addu(v0, v0, Operand(Smi::FromInt(argc)));
1690
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001691 // Get the elements' length.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001692 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1693
1694 // Check if we could survive without allocation.
1695 __ Branch(&attempt_to_grow_elements, gt, v0, Operand(t0));
1696
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001697 // Check if value is a smi.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001698 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1699 __ JumpIfNotSmi(t0, &with_write_barrier);
1700
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001701 // Save new length.
1702 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1703
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001704 // Store the value.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001705 // We may need a register containing the address end_elements below,
1706 // so write back the value in end_elements.
1707 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1708 __ Addu(end_elements, elements, end_elements);
1709 const int kEndElementsOffset =
1710 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001711 __ Addu(end_elements, end_elements, kEndElementsOffset);
1712 __ sw(t0, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001713
1714 // Check for a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001715 __ Drop(argc + 1);
1716 __ Ret();
1717
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001718 __ bind(&check_double);
1719
1720 // Check that the elements are in fast mode and writable.
1721 __ CheckMap(elements,
1722 a0,
1723 Heap::kFixedDoubleArrayMapRootIndex,
1724 &call_builtin,
1725 DONT_DO_SMI_CHECK);
1726
1727 // Get the array's length into r0 and calculate new length.
1728 __ lw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1729 STATIC_ASSERT(kSmiTagSize == 1);
1730 STATIC_ASSERT(kSmiTag == 0);
1731 __ Addu(a0, a0, Operand(Smi::FromInt(argc)));
1732
1733 // Get the elements' length.
1734 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1735
1736 // Check if we could survive without allocation.
1737 __ Branch(&call_builtin, gt, a0, Operand(t0));
1738
1739 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1740 __ StoreNumberToDoubleElements(
1741 t0, a0, elements, a3, t1, a2, t5,
1742 &call_builtin, argc * kDoubleSize);
1743
1744 // Save new length.
1745 __ sw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1746
1747 // Check for a smi.
1748 __ Drop(argc + 1);
1749 __ Ret();
1750
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001751 __ bind(&with_write_barrier);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001752
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001753 __ lw(a3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1754
1755 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
1756 Label fast_object, not_fast_object;
1757 __ CheckFastObjectElements(a3, t3, &not_fast_object);
1758 __ jmp(&fast_object);
1759 // In case of fast smi-only, convert to fast object, otherwise bail out.
1760 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001761 __ CheckFastSmiElements(a3, t3, &call_builtin);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001762
1763 __ lw(t3, FieldMemOperand(t0, HeapObject::kMapOffset));
1764 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
1765 __ Branch(&call_builtin, eq, t3, Operand(at));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001766 // edx: receiver
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001767 // a3: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001768 Label try_holey_map;
1769 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001770 FAST_ELEMENTS,
1771 a3,
1772 t3,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001773 &try_holey_map);
1774 __ mov(a2, receiver);
1775 ElementsTransitionGenerator::
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001776 GenerateMapChangeElementsTransition(masm(),
1777 DONT_TRACK_ALLOCATION_SITE,
1778 NULL);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001779 __ jmp(&fast_object);
1780
1781 __ bind(&try_holey_map);
1782 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1783 FAST_HOLEY_ELEMENTS,
1784 a3,
1785 t3,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001786 &call_builtin);
1787 __ mov(a2, receiver);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001788 ElementsTransitionGenerator::
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001789 GenerateMapChangeElementsTransition(masm(),
1790 DONT_TRACK_ALLOCATION_SITE,
1791 NULL);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001792 __ bind(&fast_object);
1793 } else {
1794 __ CheckFastObjectElements(a3, a3, &call_builtin);
1795 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001796
1797 // Save new length.
1798 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1799
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001800 // Store the value.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001801 // We may need a register containing the address end_elements below,
1802 // so write back the value in end_elements.
1803 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1804 __ Addu(end_elements, elements, end_elements);
1805 __ Addu(end_elements, end_elements, kEndElementsOffset);
1806 __ sw(t0, MemOperand(end_elements));
1807
1808 __ RecordWrite(elements,
1809 end_elements,
1810 t0,
1811 kRAHasNotBeenSaved,
1812 kDontSaveFPRegs,
1813 EMIT_REMEMBERED_SET,
1814 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001815 __ Drop(argc + 1);
1816 __ Ret();
1817
1818 __ bind(&attempt_to_grow_elements);
1819 // v0: array's length + 1.
1820 // t0: elements' length.
1821
1822 if (!FLAG_inline_new) {
1823 __ Branch(&call_builtin);
1824 }
1825
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001826 __ lw(a2, MemOperand(sp, (argc - 1) * kPointerSize));
1827 // Growing elements that are SMI-only requires special handling in case
1828 // the new element is non-Smi. For now, delegate to the builtin.
1829 Label no_fast_elements_check;
1830 __ JumpIfSmi(a2, &no_fast_elements_check);
1831 __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1832 __ CheckFastObjectElements(t3, t3, &call_builtin);
1833 __ bind(&no_fast_elements_check);
1834
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001835 ExternalReference new_space_allocation_top =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001836 ExternalReference::new_space_allocation_top_address(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001837 ExternalReference new_space_allocation_limit =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001838 ExternalReference::new_space_allocation_limit_address(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001839
1840 const int kAllocationDelta = 4;
1841 // Load top and check if it is the end of elements.
1842 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1843 __ Addu(end_elements, elements, end_elements);
1844 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset));
1845 __ li(t3, Operand(new_space_allocation_top));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001846 __ lw(a3, MemOperand(t3));
1847 __ Branch(&call_builtin, ne, end_elements, Operand(a3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001848
1849 __ li(t5, Operand(new_space_allocation_limit));
1850 __ lw(t5, MemOperand(t5));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001851 __ Addu(a3, a3, Operand(kAllocationDelta * kPointerSize));
1852 __ Branch(&call_builtin, hi, a3, Operand(t5));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001853
1854 // We fit and could grow elements.
1855 // Update new_space_allocation_top.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001856 __ sw(a3, MemOperand(t3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001857 // Push the argument.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001858 __ sw(a2, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001859 // Fill the rest with holes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001860 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001861 for (int i = 1; i < kAllocationDelta; i++) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001862 __ sw(a3, MemOperand(end_elements, i * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001863 }
1864
1865 // Update elements' and array's sizes.
1866 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1867 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta)));
1868 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1869
1870 // Elements are in new space, so write barrier is not required.
1871 __ Drop(argc + 1);
1872 __ Ret();
1873 }
1874 __ bind(&call_builtin);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001875 __ TailCallExternalReference(
1876 ExternalReference(Builtins::c_ArrayPush, isolate()), argc + 1, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001877 }
1878
1879 // Handle call cache miss.
1880 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001881 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001882
1883 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001884 return GetCode(function);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001885}
1886
1887
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001888Handle<Code> CallStubCompiler::CompileArrayPopCall(
1889 Handle<Object> object,
1890 Handle<JSObject> holder,
1891 Handle<JSGlobalPropertyCell> cell,
1892 Handle<JSFunction> function,
1893 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001894 // ----------- S t a t e -------------
1895 // -- a2 : name
1896 // -- ra : return address
1897 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1898 // -- ...
1899 // -- sp[argc * 4] : receiver
1900 // -----------------------------------
1901
1902 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001903 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001904
1905 Label miss, return_undefined, call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001906 Register receiver = a1;
1907 Register elements = a3;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001908 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001909
1910 // Get the receiver from the stack.
1911 const int argc = arguments().immediate();
1912 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001913 // Check that the receiver isn't a smi.
1914 __ JumpIfSmi(receiver, &miss);
1915
1916 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001917 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, elements,
1918 t0, v0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001919
1920 // Get the elements array of the object.
1921 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1922
1923 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001924 __ CheckMap(elements,
1925 v0,
1926 Heap::kFixedArrayMapRootIndex,
1927 &call_builtin,
1928 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001929
1930 // Get the array's length into t0 and calculate new length.
1931 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1932 __ Subu(t0, t0, Operand(Smi::FromInt(1)));
1933 __ Branch(&return_undefined, lt, t0, Operand(zero_reg));
1934
1935 // Get the last element.
1936 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1937 STATIC_ASSERT(kSmiTagSize == 1);
1938 STATIC_ASSERT(kSmiTag == 0);
1939 // We can't address the last element in one operation. Compute the more
1940 // expensive shift first, and use an offset later on.
1941 __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize);
1942 __ Addu(elements, elements, t1);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001943 __ lw(v0, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001944 __ Branch(&call_builtin, eq, v0, Operand(t2));
1945
1946 // Set the array's length.
1947 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1948
1949 // Fill with the hole.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001950 __ sw(t2, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001951 __ Drop(argc + 1);
1952 __ Ret();
1953
1954 __ bind(&return_undefined);
1955 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
1956 __ Drop(argc + 1);
1957 __ Ret();
1958
1959 __ bind(&call_builtin);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001960 __ TailCallExternalReference(
1961 ExternalReference(Builtins::c_ArrayPop, isolate()), argc + 1, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001962
1963 // Handle call cache miss.
1964 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001965 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001966
1967 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001968 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001969}
1970
1971
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001972Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1973 Handle<Object> object,
1974 Handle<JSObject> holder,
1975 Handle<JSGlobalPropertyCell> cell,
1976 Handle<JSFunction> function,
1977 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001978 // ----------- S t a t e -------------
1979 // -- a2 : function name
1980 // -- ra : return address
1981 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1982 // -- ...
1983 // -- sp[argc * 4] : receiver
1984 // -----------------------------------
1985
1986 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001987 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001988
1989 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001990 Label miss;
1991 Label name_miss;
1992 Label index_out_of_range;
1993
1994 Label* index_out_of_range_label = &index_out_of_range;
1995
danno@chromium.org40cb8782011-05-25 07:58:50 +00001996 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001997 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001998 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001999 index_out_of_range_label = &miss;
2000 }
2001
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002002 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002003
2004 // Check that the maps starting from the prototype haven't changed.
2005 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2006 Context::STRING_FUNCTION_INDEX,
2007 v0,
2008 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002009 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002010 CheckPrototypes(
2011 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2012 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002013
2014 Register receiver = a1;
2015 Register index = t1;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002016 Register result = v0;
2017 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
2018 if (argc > 0) {
2019 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
2020 } else {
2021 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
2022 }
2023
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002024 StringCharCodeAtGenerator generator(receiver,
2025 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002026 result,
2027 &miss, // When not a string.
2028 &miss, // When not a number.
2029 index_out_of_range_label,
2030 STRING_INDEX_IS_NUMBER);
2031 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002032 __ Drop(argc + 1);
2033 __ Ret();
2034
2035 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002036 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002037
2038 if (index_out_of_range.is_linked()) {
2039 __ bind(&index_out_of_range);
2040 __ LoadRoot(v0, Heap::kNanValueRootIndex);
2041 __ Drop(argc + 1);
2042 __ Ret();
2043 }
2044
2045 __ bind(&miss);
2046 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002047 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002048 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002049 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002050
2051 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002052 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002053}
2054
2055
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002056Handle<Code> CallStubCompiler::CompileStringCharAtCall(
2057 Handle<Object> object,
2058 Handle<JSObject> holder,
2059 Handle<JSGlobalPropertyCell> cell,
2060 Handle<JSFunction> function,
2061 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002062 // ----------- S t a t e -------------
2063 // -- a2 : function name
2064 // -- ra : return address
2065 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2066 // -- ...
2067 // -- sp[argc * 4] : receiver
2068 // -----------------------------------
2069
2070 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002071 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002072
2073 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002074 Label miss;
2075 Label name_miss;
2076 Label index_out_of_range;
2077 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00002078 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002079 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002080 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002081 index_out_of_range_label = &miss;
2082 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002083 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002084
2085 // Check that the maps starting from the prototype haven't changed.
2086 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2087 Context::STRING_FUNCTION_INDEX,
2088 v0,
2089 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002090 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002091 CheckPrototypes(
2092 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2093 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002094
2095 Register receiver = v0;
2096 Register index = t1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00002097 Register scratch = a3;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002098 Register result = v0;
2099 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
2100 if (argc > 0) {
2101 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
2102 } else {
2103 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
2104 }
2105
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002106 StringCharAtGenerator generator(receiver,
2107 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00002108 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002109 result,
2110 &miss, // When not a string.
2111 &miss, // When not a number.
2112 index_out_of_range_label,
2113 STRING_INDEX_IS_NUMBER);
2114 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002115 __ Drop(argc + 1);
2116 __ Ret();
2117
2118 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002119 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002120
2121 if (index_out_of_range.is_linked()) {
2122 __ bind(&index_out_of_range);
ulan@chromium.org750145a2013-03-07 15:14:13 +00002123 __ LoadRoot(v0, Heap::kempty_stringRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002124 __ Drop(argc + 1);
2125 __ Ret();
2126 }
2127
2128 __ bind(&miss);
2129 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002130 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002131 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002132 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002133
2134 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002135 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002136}
2137
2138
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002139Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
2140 Handle<Object> object,
2141 Handle<JSObject> holder,
2142 Handle<JSGlobalPropertyCell> cell,
2143 Handle<JSFunction> function,
2144 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002145 // ----------- S t a t e -------------
2146 // -- a2 : function name
2147 // -- ra : return address
2148 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2149 // -- ...
2150 // -- sp[argc * 4] : receiver
2151 // -----------------------------------
2152
2153 const int argc = arguments().immediate();
2154
2155 // If the object is not a JSObject or we got an unexpected number of
2156 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002157 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002158
2159 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002160 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002161
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002162 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002163 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
2164
2165 STATIC_ASSERT(kSmiTag == 0);
2166 __ JumpIfSmi(a1, &miss);
2167
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002168 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2169 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002170 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002171 ASSERT(cell->value() == *function);
2172 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2173 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002174 GenerateLoadFunctionFromCell(cell, function, &miss);
2175 }
2176
2177 // Load the char code argument.
2178 Register code = a1;
2179 __ lw(code, MemOperand(sp, 0 * kPointerSize));
2180
2181 // Check the code is a smi.
2182 Label slow;
2183 STATIC_ASSERT(kSmiTag == 0);
2184 __ JumpIfNotSmi(code, &slow);
2185
2186 // Convert the smi code to uint16.
2187 __ And(code, code, Operand(Smi::FromInt(0xffff)));
2188
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002189 StringCharFromCodeGenerator generator(code, v0);
2190 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002191 __ Drop(argc + 1);
2192 __ Ret();
2193
2194 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002195 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002196
2197 // Tail call the full function. We do not have to patch the receiver
2198 // because the function makes no use of it.
2199 __ bind(&slow);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002200 ParameterCount expected(function);
2201 __ InvokeFunction(function, expected, arguments(),
2202 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002203
2204 __ bind(&miss);
2205 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002206 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002207
2208 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002209 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002210}
2211
2212
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002213Handle<Code> CallStubCompiler::CompileMathFloorCall(
2214 Handle<Object> object,
2215 Handle<JSObject> holder,
2216 Handle<JSGlobalPropertyCell> cell,
2217 Handle<JSFunction> function,
2218 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002219 // ----------- S t a t e -------------
2220 // -- a2 : function name
2221 // -- ra : return address
2222 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2223 // -- ...
2224 // -- sp[argc * 4] : receiver
2225 // -----------------------------------
2226
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002227
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002228 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002229 // If the object is not a JSObject or we got an unexpected number of
2230 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002231 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002232
2233 Label miss, slow;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002234 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002235
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002236 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002237 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002238 STATIC_ASSERT(kSmiTag == 0);
2239 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002240 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2241 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002242 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002243 ASSERT(cell->value() == *function);
2244 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2245 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002246 GenerateLoadFunctionFromCell(cell, function, &miss);
2247 }
2248
2249 // Load the (only) argument into v0.
2250 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2251
2252 // If the argument is a smi, just return.
2253 STATIC_ASSERT(kSmiTag == 0);
2254 __ And(t0, v0, Operand(kSmiTagMask));
2255 __ Drop(argc + 1, eq, t0, Operand(zero_reg));
2256 __ Ret(eq, t0, Operand(zero_reg));
2257
danno@chromium.org40cb8782011-05-25 07:58:50 +00002258 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002259
2260 Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return;
2261
2262 // If fpu is enabled, we use the floor instruction.
2263
2264 // Load the HeapNumber value.
2265 __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2266
2267 // Backup FCSR.
2268 __ cfc1(a3, FCSR);
2269 // Clearing FCSR clears the exception mask with no side-effects.
2270 __ ctc1(zero_reg, FCSR);
2271 // Convert the argument to an integer.
2272 __ floor_w_d(f0, f0);
2273
2274 // Start checking for special cases.
2275 // Get the argument exponent and clear the sign bit.
2276 __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize));
2277 __ And(t2, t1, Operand(~HeapNumber::kSignMask));
2278 __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord);
2279
2280 // Retrieve FCSR and check for fpu errors.
2281 __ cfc1(t5, FCSR);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002282 __ And(t5, t5, Operand(kFCSRExceptionFlagMask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002283 __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));
2284
2285 // Check for NaN, Infinity, and -Infinity.
2286 // They are invariant through a Math.Floor call, so just
2287 // return the original argument.
2288 __ Subu(t3, t2, Operand(HeapNumber::kExponentMask
2289 >> HeapNumber::kMantissaBitsInTopWord));
2290 __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg));
2291 // We had an overflow or underflow in the conversion. Check if we
2292 // have a big exponent.
2293 // If greater or equal, the argument is already round and in v0.
2294 __ Branch(&restore_fcsr_and_return, ge, t3,
2295 Operand(HeapNumber::kMantissaBits));
2296 __ Branch(&wont_fit_smi);
2297
2298 __ bind(&no_fpu_error);
2299 // Move the result back to v0.
2300 __ mfc1(v0, f0);
2301 // Check if the result fits into a smi.
2302 __ Addu(a1, v0, Operand(0x40000000));
2303 __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg));
2304 // Tag the result.
2305 STATIC_ASSERT(kSmiTag == 0);
2306 __ sll(v0, v0, kSmiTagSize);
2307
2308 // Check for -0.
2309 __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg));
2310 // t1 already holds the HeapNumber exponent.
2311 __ And(t0, t1, Operand(HeapNumber::kSignMask));
2312 // If our HeapNumber is negative it was -0, so load its address and return.
2313 // Else v0 is loaded with 0, so we can also just return.
2314 __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg));
2315 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2316
2317 __ bind(&restore_fcsr_and_return);
2318 // Restore FCSR and return.
2319 __ ctc1(a3, FCSR);
2320
2321 __ Drop(argc + 1);
2322 __ Ret();
2323
2324 __ bind(&wont_fit_smi);
2325 // Restore FCSR and fall to slow case.
2326 __ ctc1(a3, FCSR);
2327
2328 __ bind(&slow);
2329 // Tail call the full function. We do not have to patch the receiver
2330 // because the function makes no use of it.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002331 ParameterCount expected(function);
2332 __ InvokeFunction(function, expected, arguments(),
2333 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002334
2335 __ bind(&miss);
2336 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002337 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002338
2339 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002340 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002341}
2342
2343
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002344Handle<Code> CallStubCompiler::CompileMathAbsCall(
2345 Handle<Object> object,
2346 Handle<JSObject> holder,
2347 Handle<JSGlobalPropertyCell> cell,
2348 Handle<JSFunction> function,
2349 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002350 // ----------- S t a t e -------------
2351 // -- a2 : function name
2352 // -- ra : return address
2353 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2354 // -- ...
2355 // -- sp[argc * 4] : receiver
2356 // -----------------------------------
2357
2358 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002359 // If the object is not a JSObject or we got an unexpected number of
2360 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002361 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002362
2363 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002364
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002365 GenerateNameCheck(name, &miss);
2366 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002367 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002368 STATIC_ASSERT(kSmiTag == 0);
2369 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002370 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2371 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002372 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002373 ASSERT(cell->value() == *function);
2374 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2375 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002376 GenerateLoadFunctionFromCell(cell, function, &miss);
2377 }
2378
2379 // Load the (only) argument into v0.
2380 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2381
2382 // Check if the argument is a smi.
2383 Label not_smi;
2384 STATIC_ASSERT(kSmiTag == 0);
2385 __ JumpIfNotSmi(v0, &not_smi);
2386
2387 // Do bitwise not or do nothing depending on the sign of the
2388 // argument.
2389 __ sra(t0, v0, kBitsPerInt - 1);
2390 __ Xor(a1, v0, t0);
2391
2392 // Add 1 or do nothing depending on the sign of the argument.
2393 __ Subu(v0, a1, t0);
2394
2395 // If the result is still negative, go to the slow case.
2396 // This only happens for the most negative smi.
2397 Label slow;
2398 __ Branch(&slow, lt, v0, Operand(zero_reg));
2399
2400 // Smi case done.
2401 __ Drop(argc + 1);
2402 __ Ret();
2403
2404 // Check if the argument is a heap number and load its exponent and
2405 // sign.
2406 __ bind(&not_smi);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002407 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002408 __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2409
2410 // Check the sign of the argument. If the argument is positive,
2411 // just return it.
2412 Label negative_sign;
2413 __ And(t0, a1, Operand(HeapNumber::kSignMask));
2414 __ Branch(&negative_sign, ne, t0, Operand(zero_reg));
2415 __ Drop(argc + 1);
2416 __ Ret();
2417
2418 // If the argument is negative, clear the sign, and return a new
2419 // number.
2420 __ bind(&negative_sign);
2421 __ Xor(a1, a1, Operand(HeapNumber::kSignMask));
2422 __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2423 __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
2424 __ AllocateHeapNumber(v0, t0, t1, t2, &slow);
2425 __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2426 __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2427 __ Drop(argc + 1);
2428 __ Ret();
2429
2430 // Tail call the full function. We do not have to patch the receiver
2431 // because the function makes no use of it.
2432 __ bind(&slow);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002433 ParameterCount expected(function);
2434 __ InvokeFunction(function, expected, arguments(),
2435 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002436
2437 __ bind(&miss);
2438 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002439 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002440
2441 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002442 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002443}
2444
2445
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002446Handle<Code> CallStubCompiler::CompileFastApiCall(
lrn@chromium.org7516f052011-03-30 08:52:27 +00002447 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002448 Handle<Object> object,
2449 Handle<JSObject> holder,
2450 Handle<JSGlobalPropertyCell> cell,
2451 Handle<JSFunction> function,
2452 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002453
danno@chromium.org40cb8782011-05-25 07:58:50 +00002454 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002455
2456 ASSERT(optimization.is_simple_api_call());
2457 // Bail out if object is a global object as we don't want to
2458 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002459 if (object->IsGlobalObject()) return Handle<Code>::null();
2460 if (!cell.is_null()) return Handle<Code>::null();
2461 if (!object->IsJSObject()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002462 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002463 Handle<JSObject>::cast(object), holder);
2464 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002465
2466 Label miss, miss_before_stack_reserved;
2467
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002468 GenerateNameCheck(name, &miss_before_stack_reserved);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002469
2470 // Get the receiver from the stack.
2471 const int argc = arguments().immediate();
2472 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2473
2474 // Check that the receiver isn't a smi.
2475 __ JumpIfSmi(a1, &miss_before_stack_reserved);
2476
2477 __ IncrementCounter(counters->call_const(), 1, a0, a3);
2478 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2479
2480 ReserveSpaceForFastApiCall(masm(), a0);
2481
2482 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002483 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002484 depth, &miss);
2485
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002486 GenerateFastApiDirectCall(masm(), optimization, argc);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002487
2488 __ bind(&miss);
2489 FreeSpaceForFastApiCall(masm());
2490
2491 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002492 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002493
2494 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002495 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002496}
2497
2498
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002499void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
2500 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002501 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002502 CheckType check,
2503 Label* success) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002504 // ----------- S t a t e -------------
2505 // -- a2 : name
2506 // -- ra : return address
2507 // -----------------------------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002508 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002509 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002510
2511 // Get the receiver from the stack.
2512 const int argc = arguments().immediate();
2513 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2514
2515 // Check that the receiver isn't a smi.
2516 if (check != NUMBER_CHECK) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002517 __ JumpIfSmi(a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002518 }
2519
2520 // Make sure that it's okay not to patch the on stack receiver
2521 // unless we're doing a receiver map check.
2522 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002523 switch (check) {
2524 case RECEIVER_MAP_CHECK:
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002525 __ IncrementCounter(isolate()->counters()->call_const(), 1, a0, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002526
2527 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002528 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2529 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002530
2531 // Patch the receiver on the stack with the global proxy if
2532 // necessary.
2533 if (object->IsGlobalObject()) {
2534 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2535 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2536 }
2537 break;
2538
2539 case STRING_CHECK:
ulan@chromium.org750145a2013-03-07 15:14:13 +00002540 // Check that the object is a string.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002541 __ GetObjectType(a1, a3, a3);
2542 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2543 // Check that the maps starting from the prototype haven't changed.
2544 GenerateDirectLoadGlobalFunctionPrototype(
2545 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
2546 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002547 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002548 a0, holder, a3, a1, t0, name, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002549 break;
2550
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002551 case SYMBOL_CHECK:
2552 // Check that the object is a symbol.
2553 __ GetObjectType(a1, a1, a3);
2554 __ Branch(&miss, ne, a3, Operand(SYMBOL_TYPE));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002555 // Check that the maps starting from the prototype haven't changed.
2556 GenerateDirectLoadGlobalFunctionPrototype(
2557 masm(), Context::SYMBOL_FUNCTION_INDEX, a0, &miss);
2558 CheckPrototypes(
2559 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2560 a0, holder, a3, a1, t0, name, &miss);
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002561 break;
2562
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002563 case NUMBER_CHECK: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002564 Label fast;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002565 // Check that the object is a smi or a heap number.
2566 __ JumpIfSmi(a1, &fast);
2567 __ GetObjectType(a1, a0, a0);
2568 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
2569 __ bind(&fast);
2570 // Check that the maps starting from the prototype haven't changed.
2571 GenerateDirectLoadGlobalFunctionPrototype(
2572 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
2573 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002574 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002575 a0, holder, a3, a1, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002576 break;
2577 }
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002578 case BOOLEAN_CHECK: {
2579 Label fast;
2580 // Check that the object is a boolean.
2581 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
2582 __ Branch(&fast, eq, a1, Operand(t0));
2583 __ LoadRoot(t0, Heap::kFalseValueRootIndex);
2584 __ Branch(&miss, ne, a1, Operand(t0));
2585 __ bind(&fast);
2586 // Check that the maps starting from the prototype haven't changed.
2587 GenerateDirectLoadGlobalFunctionPrototype(
2588 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
2589 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002590 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002591 a0, holder, a3, a1, t0, name, &miss);
2592 break;
2593 }
2594 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002595
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002596 __ jmp(success);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002597
2598 // Handle call cache miss.
2599 __ bind(&miss);
2600
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002601 GenerateMissBranch();
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002602}
2603
2604
2605void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) {
2606 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
2607 ? CALL_AS_FUNCTION
2608 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002609 ParameterCount expected(function);
2610 __ InvokeFunction(function, expected, arguments(),
2611 JUMP_FUNCTION, NullCallWrapper(), call_kind);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002612}
2613
2614
2615Handle<Code> CallStubCompiler::CompileCallConstant(
2616 Handle<Object> object,
2617 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002618 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002619 CheckType check,
2620 Handle<JSFunction> function) {
2621 if (HasCustomCallGenerator(function)) {
2622 Handle<Code> code = CompileCustomCall(object, holder,
2623 Handle<JSGlobalPropertyCell>::null(),
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002624 function, Handle<String>::cast(name));
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002625 // A null handle means bail out to the regular compiler code below.
2626 if (!code.is_null()) return code;
2627 }
2628
2629 Label success;
2630
2631 CompileHandlerFrontend(object, holder, name, check, &success);
2632 __ bind(&success);
2633 CompileHandlerBackend(function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002634
2635 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002636 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002637}
2638
2639
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002640Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2641 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002642 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002643 // ----------- S t a t e -------------
2644 // -- a2 : name
2645 // -- ra : return address
2646 // -----------------------------------
2647
2648 Label miss;
2649
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002650 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002651
2652 // Get the number of arguments.
2653 const int argc = arguments().immediate();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002654 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002655 LookupPostInterceptor(holder, name, &lookup);
2656
2657 // Get the receiver from the stack.
2658 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2659
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002660 CallInterceptorCompiler compiler(this, arguments(), a2, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002661 compiler.Compile(masm(), object, holder, name, &lookup, a1, a3, t0, a0,
2662 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002663
2664 // Move returned value, the function to call, to a1.
2665 __ mov(a1, v0);
2666 // Restore receiver.
2667 __ lw(a0, MemOperand(sp, argc * kPointerSize));
2668
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002669 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002670
2671 // Handle call cache miss.
2672 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002673 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002674
2675 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002676 return GetCode(Code::INTERCEPTOR, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002677}
2678
2679
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002680Handle<Code> CallStubCompiler::CompileCallGlobal(
2681 Handle<JSObject> object,
2682 Handle<GlobalObject> holder,
2683 Handle<JSGlobalPropertyCell> cell,
2684 Handle<JSFunction> function,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002685 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002686 // ----------- S t a t e -------------
2687 // -- a2 : name
2688 // -- ra : return address
2689 // -----------------------------------
2690
2691 if (HasCustomCallGenerator(function)) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002692 Handle<Code> code = CompileCustomCall(
2693 object, holder, cell, function, Handle<String>::cast(name));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002694 // A null handle means bail out to the regular compiler code below.
2695 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002696 }
2697
2698 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002699 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002700
2701 // Get the number of arguments.
2702 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002703 GenerateGlobalReceiverCheck(object, holder, name, &miss);
2704 GenerateLoadFunctionFromCell(cell, function, &miss);
2705
2706 // Patch the receiver on the stack with the global proxy if
2707 // necessary.
2708 if (object->IsGlobalObject()) {
2709 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
2710 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2711 }
2712
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002713 // Set up the context (function already in r1).
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002714 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
2715
2716 // Jump to the cached code (tail call).
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002717 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002718 __ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002719 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002720 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002721 ? CALL_AS_FUNCTION
2722 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002723 // We call indirectly through the code field in the function to
2724 // allow recompilation to take effect without changing any of the
2725 // call sites.
2726 __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
2727 __ InvokeCode(a3, expected, arguments(), JUMP_FUNCTION,
2728 NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002729
2730 // Handle call cache miss.
2731 __ bind(&miss);
2732 __ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002733 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002734
2735 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002736 return GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002737}
2738
2739
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002740Handle<Code> StoreStubCompiler::CompileStoreCallback(
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002741 Handle<Name> name,
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002742 Handle<JSObject> object,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002743 Handle<JSObject> holder,
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002744 Handle<ExecutableAccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002745 Label miss;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002746 // Check that the maps haven't changed.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002747 __ JumpIfSmi(receiver(), &miss);
2748 CheckPrototypes(object, receiver(), holder,
2749 scratch1(), scratch2(), scratch3(), name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002750
2751 // Stub never generated for non-global objects that require access
2752 // checks.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002753 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002754
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002755 __ push(receiver()); // Receiver.
2756 __ li(at, Operand(callback)); // Callback info.
2757 __ Push(at, this->name(), value());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002758
2759 // Do tail-call to the runtime system.
2760 ExternalReference store_callback_property =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002761 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002762 __ TailCallExternalReference(store_callback_property, 4, 1);
2763
2764 // Handle store cache miss.
2765 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002766 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002767
2768 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002769 return GetICCode(kind(), Code::CALLBACKS, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002770}
2771
2772
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002773#undef __
2774#define __ ACCESS_MASM(masm)
2775
2776
2777void StoreStubCompiler::GenerateStoreViaSetter(
2778 MacroAssembler* masm,
2779 Handle<JSFunction> setter) {
2780 // ----------- S t a t e -------------
2781 // -- a0 : value
2782 // -- a1 : receiver
2783 // -- a2 : name
2784 // -- ra : return address
2785 // -----------------------------------
2786 {
2787 FrameScope scope(masm, StackFrame::INTERNAL);
2788
2789 // Save value register, so we can restore it later.
2790 __ push(a0);
2791
2792 if (!setter.is_null()) {
2793 // Call the JavaScript setter with receiver and value on the stack.
2794 __ push(a1);
2795 __ push(a0);
2796 ParameterCount actual(1);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002797 ParameterCount expected(setter);
2798 __ InvokeFunction(setter, expected, actual,
2799 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002800 } else {
2801 // If we generate a global code snippet for deoptimization only, remember
2802 // the place to continue after deoptimization.
2803 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2804 }
2805
2806 // We have to return the passed value, not the return value of the setter.
2807 __ pop(v0);
2808
2809 // Restore context register.
2810 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2811 }
2812 __ Ret();
2813}
2814
2815
2816#undef __
2817#define __ ACCESS_MASM(masm())
2818
2819
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002820Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002821 Handle<JSObject> object,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002822 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002823 Label miss;
2824
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002825 // Check that the map of the object hasn't changed.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002826 __ CheckMap(receiver(), scratch1(), Handle<Map>(object->map()), &miss,
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002827 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002828
2829 // Perform global security token check if needed.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002830 if (object->IsJSGlobalProxy()) {
2831 __ CheckAccessGlobalProxy(receiver(), scratch1(), &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002832 }
2833
2834 // Stub is never generated for non-global objects that require access
2835 // checks.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002836 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002837
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002838 __ Push(receiver(), this->name(), value());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002839
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002840 __ li(scratch1(), Operand(Smi::FromInt(strict_mode())));
2841 __ push(scratch1()); // strict mode
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002842
2843 // Do tail-call to the runtime system.
2844 ExternalReference store_ic_property =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002845 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002846 __ TailCallExternalReference(store_ic_property, 4, 1);
2847
2848 // Handle store cache miss.
2849 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002850 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002851
2852 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002853 return GetICCode(kind(), Code::INTERCEPTOR, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002854}
2855
2856
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002857Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2858 Handle<GlobalObject> object,
2859 Handle<JSGlobalPropertyCell> cell,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002860 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002861 Label miss;
2862
2863 // Check that the map of the global has not changed.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002864 __ lw(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset));
2865 __ Branch(&miss, ne, scratch1(), Operand(Handle<Map>(object->map())));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002866
2867 // Check that the value in the cell is not the hole. If it is, this
2868 // cell could have been deleted and reintroducing the global needs
2869 // to update the property details in the property dictionary of the
2870 // global object. We bail out to the runtime system to do that.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002871 __ li(scratch1(), Operand(cell));
2872 __ LoadRoot(scratch2(), Heap::kTheHoleValueRootIndex);
2873 __ lw(scratch3(),
2874 FieldMemOperand(scratch1(), JSGlobalPropertyCell::kValueOffset));
2875 __ Branch(&miss, eq, scratch3(), Operand(scratch2()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002876
2877 // Store the value in the cell.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002878 __ sw(value(),
2879 FieldMemOperand(scratch1(), JSGlobalPropertyCell::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002880 __ mov(v0, a0); // Stored value must be returned in v0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002881 // Cells are always rescanned, so no write barrier here.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002882
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002883 Counters* counters = isolate()->counters();
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002884 __ IncrementCounter(
2885 counters->named_store_global_inline(), 1, scratch1(), scratch2());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002886 __ Ret();
2887
2888 // Handle store cache miss.
2889 __ bind(&miss);
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002890 __ IncrementCounter(
2891 counters->named_store_global_inline_miss(), 1, scratch1(), scratch2());
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002892 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002893
2894 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002895 return GetICCode(kind(), Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002896}
2897
2898
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002899Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
2900 Handle<JSObject> object,
2901 Handle<JSObject> last,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002902 Handle<Name> name,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002903 Handle<GlobalObject> global) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002904 Label success;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002905
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002906 NonexistentHandlerFrontend(object, last, name, &success, global);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002907
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002908 __ bind(&success);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002909 // Return undefined if maps of the full prototype chain is still the same.
2910 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2911 __ Ret();
2912
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002913 // Return the generated code.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002914 return GetCode(kind(), Code::NONEXISTENT, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002915}
2916
2917
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002918Register* LoadStubCompiler::registers() {
2919 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2920 static Register registers[] = { a0, a2, a3, a1, t0, t1 };
2921 return registers;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002922}
2923
2924
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002925Register* KeyedLoadStubCompiler::registers() {
2926 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2927 static Register registers[] = { a1, a0, a2, a3, t0, t1 };
2928 return registers;
2929}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002930
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002931
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002932Register* StoreStubCompiler::registers() {
2933 // receiver, name, value, scratch1, scratch2, scratch3.
2934 static Register registers[] = { a1, a2, a0, a3, t0, t1 };
2935 return registers;
2936}
2937
2938
2939Register* KeyedStoreStubCompiler::registers() {
2940 // receiver, name, value, scratch1, scratch2, scratch3.
2941 static Register registers[] = { a2, a1, a0, a3, t0, t1 };
2942 return registers;
2943}
2944
2945
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002946void KeyedLoadStubCompiler::GenerateNameCheck(Handle<Name> name,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002947 Register name_reg,
2948 Label* miss) {
2949 __ Branch(miss, ne, name_reg, Operand(name));
lrn@chromium.org7516f052011-03-30 08:52:27 +00002950}
2951
2952
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002953void KeyedStoreStubCompiler::GenerateNameCheck(Handle<Name> name,
2954 Register name_reg,
2955 Label* miss) {
2956 __ Branch(miss, ne, name_reg, Operand(name));
2957}
2958
2959
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002960#undef __
2961#define __ ACCESS_MASM(masm)
2962
2963
2964void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
2965 Handle<JSFunction> getter) {
2966 // ----------- S t a t e -------------
2967 // -- a0 : receiver
2968 // -- a2 : name
2969 // -- ra : return address
2970 // -----------------------------------
2971 {
2972 FrameScope scope(masm, StackFrame::INTERNAL);
2973
2974 if (!getter.is_null()) {
2975 // Call the JavaScript getter with the receiver on the stack.
2976 __ push(a0);
2977 ParameterCount actual(0);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002978 ParameterCount expected(getter);
2979 __ InvokeFunction(getter, expected, actual,
2980 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002981 } else {
2982 // If we generate a global code snippet for deoptimization only, remember
2983 // the place to continue after deoptimization.
2984 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
2985 }
2986
2987 // Restore context register.
2988 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2989 }
2990 __ Ret();
2991}
2992
2993
2994#undef __
2995#define __ ACCESS_MASM(masm())
2996
2997
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002998Handle<Code> LoadStubCompiler::CompileLoadGlobal(
2999 Handle<JSObject> object,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003000 Handle<GlobalObject> global,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003001 Handle<JSGlobalPropertyCell> cell,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003002 Handle<Name> name,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003003 bool is_dont_delete) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003004 Label success, miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003005
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003006 __ CheckMap(
3007 receiver(), scratch1(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
3008 HandlerFrontendHeader(
3009 object, receiver(), Handle<JSObject>::cast(global), name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003010
3011 // Get the value from the cell.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003012 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003013 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
3014
3015 // Check for deleted property if property can actually be deleted.
3016 if (!is_dont_delete) {
3017 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
3018 __ Branch(&miss, eq, t0, Operand(at));
3019 }
3020
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003021 HandlerFrontendFooter(&success, &miss);
3022 __ bind(&success);
3023
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003024 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003025 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003026 __ mov(v0, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003027 __ Ret();
3028
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003029 // Return the generated code.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003030 return GetICCode(kind(), Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003031}
3032
3033
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003034Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003035 MapHandleList* receiver_maps,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003036 CodeHandleList* handlers,
3037 Handle<Name> name,
3038 Code::StubType type,
3039 IcCheckType check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003040 Label miss;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003041
3042 if (check == PROPERTY) {
3043 GenerateNameCheck(name, this->name(), &miss);
3044 }
3045
3046 __ JumpIfSmi(receiver(), &miss);
3047 Register map_reg = scratch1();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003048
danno@chromium.org40cb8782011-05-25 07:58:50 +00003049 int receiver_count = receiver_maps->length();
danno@chromium.orgf005df62013-04-30 16:36:45 +00003050 int number_of_handled_maps = 0;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003051 __ lw(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003052 for (int current = 0; current < receiver_count; ++current) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00003053 Handle<Map> map = receiver_maps->at(current);
3054 if (!map->is_deprecated()) {
3055 number_of_handled_maps++;
3056 __ Jump(handlers->at(current), RelocInfo::CODE_TARGET,
3057 eq, map_reg, Operand(receiver_maps->at(current)));
3058 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003059 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00003060 ASSERT(number_of_handled_maps != 0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003061
3062 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003063 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003064
3065 // Return the generated code.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003066 InlineCacheState state =
danno@chromium.orgf005df62013-04-30 16:36:45 +00003067 number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003068 return GetICCode(kind(), type, name, state);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003069}
3070
3071
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003072Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
3073 MapHandleList* receiver_maps,
3074 CodeHandleList* handler_stubs,
3075 MapHandleList* transitioned_maps) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003076 Label miss;
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003077 __ JumpIfSmi(receiver(), &miss);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003078
3079 int receiver_count = receiver_maps->length();
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003080 __ lw(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003081 for (int i = 0; i < receiver_count; ++i) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003082 if (transitioned_maps->at(i).is_null()) {
3083 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq,
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003084 scratch1(), Operand(receiver_maps->at(i)));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003085 } else {
3086 Label next_map;
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003087 __ Branch(&next_map, ne, scratch1(), Operand(receiver_maps->at(i)));
3088 __ li(transition_map(), Operand(transitioned_maps->at(i)));
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003089 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003090 __ bind(&next_map);
3091 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003092 }
3093
3094 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003095 TailCallBuiltin(masm(), MissBuiltin(kind()));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003096
3097 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003098 return GetICCode(
3099 kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003100}
3101
3102
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003103Handle<Code> ConstructStubCompiler::CompileConstructStub(
3104 Handle<JSFunction> function) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003105 // a0 : argc
3106 // a1 : constructor
3107 // ra : return address
3108 // [sp] : last argument
3109 Label generic_stub_call;
3110
3111 // Use t7 for holding undefined which is used in several places below.
3112 __ LoadRoot(t7, Heap::kUndefinedValueRootIndex);
3113
3114#ifdef ENABLE_DEBUGGER_SUPPORT
3115 // Check to see whether there are any break points in the function code. If
3116 // there are jump to the generic constructor stub which calls the actual
3117 // code for the function thereby hitting the break points.
3118 __ lw(t5, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3119 __ lw(a2, FieldMemOperand(t5, SharedFunctionInfo::kDebugInfoOffset));
3120 __ Branch(&generic_stub_call, ne, a2, Operand(t7));
3121#endif
3122
3123 // Load the initial map and verify that it is in fact a map.
3124 // a1: constructor function
3125 // t7: undefined
3126 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003127 __ JumpIfSmi(a2, &generic_stub_call);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003128 __ GetObjectType(a2, a3, t0);
3129 __ Branch(&generic_stub_call, ne, t0, Operand(MAP_TYPE));
3130
3131#ifdef DEBUG
3132 // Cannot construct functions this way.
3133 // a0: argc
3134 // a1: constructor function
3135 // a2: initial map
3136 // t7: undefined
3137 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
3138 __ Check(ne, "Function constructed by construct stub.",
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003139 a3, Operand(JS_FUNCTION_TYPE));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003140#endif
3141
3142 // Now allocate the JSObject in new space.
3143 // a0: argc
3144 // a1: constructor function
3145 // a2: initial map
3146 // t7: undefined
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003147 ASSERT(function->has_initial_map());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003148 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003149#ifdef DEBUG
3150 int instance_size = function->initial_map()->instance_size();
3151 __ Check(eq, "Instance size of initial map changed.",
3152 a3, Operand(instance_size >> kPointerSizeLog2));
3153#endif
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003154 __ Allocate(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003155
3156 // Allocated the JSObject, now initialize the fields. Map is set to initial
3157 // map and properties and elements are set to empty fixed array.
3158 // a0: argc
3159 // a1: constructor function
3160 // a2: initial map
3161 // a3: object size (in words)
3162 // t4: JSObject (not tagged)
3163 // t7: undefined
3164 __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex);
3165 __ mov(t5, t4);
3166 __ sw(a2, MemOperand(t5, JSObject::kMapOffset));
3167 __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset));
3168 __ sw(t6, MemOperand(t5, JSObject::kElementsOffset));
3169 __ Addu(t5, t5, Operand(3 * kPointerSize));
3170 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
3171 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
3172 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
3173
3174
3175 // Calculate the location of the first argument. The stack contains only the
3176 // argc arguments.
3177 __ sll(a1, a0, kPointerSizeLog2);
3178 __ Addu(a1, a1, sp);
3179
3180 // Fill all the in-object properties with undefined.
3181 // a0: argc
3182 // a1: first argument
3183 // a3: object size (in words)
3184 // t4: JSObject (not tagged)
3185 // t5: First in-object property of JSObject (not tagged)
3186 // t7: undefined
3187 // Fill the initialized properties with a constant value or a passed argument
3188 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003189 Handle<SharedFunctionInfo> shared(function->shared());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003190 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3191 if (shared->IsThisPropertyAssignmentArgument(i)) {
3192 Label not_passed, next;
3193 // Check if the argument assigned to the property is actually passed.
3194 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3195 __ Branch(&not_passed, less_equal, a0, Operand(arg_number));
3196 // Argument passed - find it on the stack.
3197 __ lw(a2, MemOperand(a1, (arg_number + 1) * -kPointerSize));
3198 __ sw(a2, MemOperand(t5));
3199 __ Addu(t5, t5, kPointerSize);
3200 __ jmp(&next);
3201 __ bind(&not_passed);
3202 // Set the property to undefined.
3203 __ sw(t7, MemOperand(t5));
3204 __ Addu(t5, t5, Operand(kPointerSize));
3205 __ bind(&next);
3206 } else {
3207 // Set the property to the constant value.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003208 Handle<Object> constant(
3209 shared->GetThisPropertyAssignmentConstant(i), isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003210 __ li(a2, Operand(constant));
3211 __ sw(a2, MemOperand(t5));
3212 __ Addu(t5, t5, kPointerSize);
3213 }
3214 }
3215
3216 // Fill the unused in-object property fields with undefined.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003217 for (int i = shared->this_property_assignments_count();
3218 i < function->initial_map()->inobject_properties();
3219 i++) {
3220 __ sw(t7, MemOperand(t5));
3221 __ Addu(t5, t5, kPointerSize);
3222 }
3223
3224 // a0: argc
3225 // t4: JSObject (not tagged)
3226 // Move argc to a1 and the JSObject to return to v0 and tag it.
3227 __ mov(a1, a0);
3228 __ mov(v0, t4);
3229 __ Or(v0, v0, Operand(kHeapObjectTag));
3230
3231 // v0: JSObject
3232 // a1: argc
3233 // Remove caller arguments and receiver from the stack and return.
3234 __ sll(t0, a1, kPointerSizeLog2);
3235 __ Addu(sp, sp, t0);
3236 __ Addu(sp, sp, Operand(kPointerSize));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003237 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003238 __ IncrementCounter(counters->constructed_objects(), 1, a1, a2);
3239 __ IncrementCounter(counters->constructed_objects_stub(), 1, a1, a2);
3240 __ Ret();
3241
3242 // Jump to the generic stub in case the specialized code cannot handle the
3243 // construction.
3244 __ bind(&generic_stub_call);
3245 Handle<Code> generic_construct_stub =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003246 isolate()->builtins()->JSConstructStubGeneric();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003247 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
3248
3249 // Return the generated code.
3250 return GetCode();
3251}
3252
3253
danno@chromium.org40cb8782011-05-25 07:58:50 +00003254#undef __
3255#define __ ACCESS_MASM(masm)
3256
3257
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003258void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3259 MacroAssembler* masm) {
3260 // ---------- S t a t e --------------
3261 // -- ra : return address
3262 // -- a0 : key
3263 // -- a1 : receiver
3264 // -----------------------------------
3265 Label slow, miss_force_generic;
3266
3267 Register key = a0;
3268 Register receiver = a1;
3269
3270 __ JumpIfNotSmi(key, &miss_force_generic);
3271 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
3272 __ sra(a2, a0, kSmiTagSize);
3273 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
3274 __ Ret();
3275
3276 // Slow case, key and receiver still in a0 and a1.
3277 __ bind(&slow);
3278 __ IncrementCounter(
3279 masm->isolate()->counters()->keyed_load_external_array_slow(),
3280 1, a2, a3);
3281 // Entry registers are intact.
3282 // ---------- S t a t e --------------
3283 // -- ra : return address
3284 // -- a0 : key
3285 // -- a1 : receiver
3286 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003287 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003288
3289 // Miss case, call the runtime.
3290 __ bind(&miss_force_generic);
3291
3292 // ---------- S t a t e --------------
3293 // -- ra : return address
3294 // -- a0 : key
3295 // -- a1 : receiver
3296 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003297 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_MissForceGeneric);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003298}
3299
3300
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003301static void GenerateSmiKeyCheck(MacroAssembler* masm,
3302 Register key,
3303 Register scratch0,
3304 Register scratch1,
3305 FPURegister double_scratch0,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003306 FPURegister double_scratch1,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003307 Label* fail) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003308 Label key_ok;
3309 // Check for smi or a smi inside a heap number. We convert the heap
3310 // number and check if the conversion is exact and fits into the smi
3311 // range.
3312 __ JumpIfSmi(key, &key_ok);
3313 __ CheckMap(key,
3314 scratch0,
3315 Heap::kHeapNumberMapRootIndex,
3316 fail,
3317 DONT_DO_SMI_CHECK);
3318 __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
3319 __ EmitFPUTruncate(kRoundToZero,
3320 scratch0,
3321 double_scratch0,
3322 at,
3323 double_scratch1,
3324 scratch1,
3325 kCheckForInexactConversion);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003326
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003327 __ Branch(fail, ne, scratch1, Operand(zero_reg));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003328
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003329 __ SmiTagCheckOverflow(key, scratch0, scratch1);
3330 __ BranchOnOverflow(fail, scratch1);
3331 __ bind(&key_ok);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003332}
3333
3334
danno@chromium.org40cb8782011-05-25 07:58:50 +00003335void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3336 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003337 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003338 // ---------- S t a t e --------------
3339 // -- a0 : value
3340 // -- a1 : key
3341 // -- a2 : receiver
3342 // -- ra : return address
3343 // -----------------------------------
3344
danno@chromium.org40cb8782011-05-25 07:58:50 +00003345 Label slow, check_heap_number, miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003346
3347 // Register usage.
3348 Register value = a0;
3349 Register key = a1;
3350 Register receiver = a2;
3351 // a3 mostly holds the elements array or the destination external array.
3352
danno@chromium.org40cb8782011-05-25 07:58:50 +00003353 // This stub is meant to be tail-jumped to, the receiver must already
3354 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003355
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003356 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003357 GenerateSmiKeyCheck(masm, key, t0, t1, f2, f4, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003358
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003359 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3360
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003361 // Check that the index is in range.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003362 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3363 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003364 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003365
3366 // Handle both smis and HeapNumbers in the fast path. Go to the
3367 // runtime for all other kinds of values.
3368 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003369
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003370 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003371 // Double to pixel conversion is only implemented in the runtime for now.
3372 __ JumpIfNotSmi(value, &slow);
3373 } else {
3374 __ JumpIfNotSmi(value, &check_heap_number);
3375 }
3376 __ SmiUntag(t1, value);
3377 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3378
3379 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003380 // t1: value (integer).
3381
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003382 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003383 case EXTERNAL_PIXEL_ELEMENTS: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003384 // Clamp the value to [0..255].
3385 // v0 is used as a scratch register here.
3386 Label done;
3387 __ li(v0, Operand(255));
3388 // Normal branch: nop in delay slot.
3389 __ Branch(&done, gt, t1, Operand(v0));
3390 // Use delay slot in this branch.
3391 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg));
3392 __ mov(v0, zero_reg); // In delay slot.
3393 __ mov(v0, t1); // Value is in range 0..255.
3394 __ bind(&done);
3395 __ mov(t1, v0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003396
3397 __ srl(t8, key, 1);
3398 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003399 __ sb(t1, MemOperand(t8, 0));
3400 }
3401 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003402 case EXTERNAL_BYTE_ELEMENTS:
3403 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003404 __ srl(t8, key, 1);
3405 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003406 __ sb(t1, MemOperand(t8, 0));
3407 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003408 case EXTERNAL_SHORT_ELEMENTS:
3409 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003410 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003411 __ sh(t1, MemOperand(t8, 0));
3412 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003413 case EXTERNAL_INT_ELEMENTS:
3414 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003415 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003416 __ addu(t8, a3, t8);
3417 __ sw(t1, MemOperand(t8, 0));
3418 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003419 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003420 // Perform int-to-float conversion and store to memory.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003421 __ SmiUntag(t0, key);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003422 StoreIntAsFloat(masm, a3, t0, t1, t2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003423 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003424 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003425 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003426 __ addu(a3, a3, t8);
3427 // a3: effective address of the double element
3428 FloatingPointHelper::Destination destination;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003429 destination = FloatingPointHelper::kFPURegisters;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003430 FloatingPointHelper::ConvertIntToDouble(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003431 masm, t1, destination,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003432 f0, t2, t3, // These are: double_dst, dst_mantissa, dst_exponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003433 t0, f2); // These are: scratch2, single_scratch.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003434 __ sdc1(f0, MemOperand(a3, 0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003435 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003436 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003437 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003438 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003439 case FAST_HOLEY_ELEMENTS:
3440 case FAST_HOLEY_SMI_ELEMENTS:
3441 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003442 case DICTIONARY_ELEMENTS:
3443 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003444 UNREACHABLE();
3445 break;
3446 }
3447
3448 // Entry registers are intact, a0 holds the value which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003449 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003450 __ Ret();
3451
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003452 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003453 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003454 __ bind(&check_heap_number);
3455 __ GetObjectType(value, t1, t2);
3456 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE));
3457
3458 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3459
3460 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003461
3462 // The WebGL specification leaves the behavior of storing NaN and
3463 // +/-Infinity into integer arrays basically undefined. For more
3464 // reproducible behavior, convert these to zero.
3465
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003466
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003467 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003468
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003469 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
3470 __ cvt_s_d(f0, f0);
3471 __ sll(t8, key, 1);
3472 __ addu(t8, a3, t8);
3473 __ swc1(f0, MemOperand(t8, 0));
3474 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
3475 __ sll(t8, key, 2);
3476 __ addu(t8, a3, t8);
3477 __ sdc1(f0, MemOperand(t8, 0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003478 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003479 __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003480
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003481 switch (elements_kind) {
3482 case EXTERNAL_BYTE_ELEMENTS:
3483 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3484 __ srl(t8, key, 1);
3485 __ addu(t8, a3, t8);
3486 __ sb(t3, MemOperand(t8, 0));
3487 break;
3488 case EXTERNAL_SHORT_ELEMENTS:
3489 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3490 __ addu(t8, a3, key);
3491 __ sh(t3, MemOperand(t8, 0));
3492 break;
3493 case EXTERNAL_INT_ELEMENTS:
3494 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3495 __ sll(t8, key, 1);
3496 __ addu(t8, a3, t8);
3497 __ sw(t3, MemOperand(t8, 0));
3498 break;
3499 case EXTERNAL_PIXEL_ELEMENTS:
3500 case EXTERNAL_FLOAT_ELEMENTS:
3501 case EXTERNAL_DOUBLE_ELEMENTS:
3502 case FAST_ELEMENTS:
3503 case FAST_SMI_ELEMENTS:
3504 case FAST_DOUBLE_ELEMENTS:
3505 case FAST_HOLEY_ELEMENTS:
3506 case FAST_HOLEY_SMI_ELEMENTS:
3507 case FAST_HOLEY_DOUBLE_ELEMENTS:
3508 case DICTIONARY_ELEMENTS:
3509 case NON_STRICT_ARGUMENTS_ELEMENTS:
3510 UNREACHABLE();
3511 break;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003512 }
3513 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003514
3515 // Entry registers are intact, a0 holds the value
3516 // which is the return value.
3517 __ mov(v0, a0);
3518 __ Ret();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003519 }
3520
danno@chromium.org40cb8782011-05-25 07:58:50 +00003521 // Slow case, key and receiver still in a0 and a1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003522 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003523 __ IncrementCounter(
3524 masm->isolate()->counters()->keyed_load_external_array_slow(),
3525 1, a2, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003526 // Entry registers are intact.
3527 // ---------- S t a t e --------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003528 // -- ra : return address
danno@chromium.org40cb8782011-05-25 07:58:50 +00003529 // -- a0 : key
3530 // -- a1 : receiver
3531 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003532 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003533
3534 // Miss case, call the runtime.
3535 __ bind(&miss_force_generic);
3536
3537 // ---------- S t a t e --------------
3538 // -- ra : return address
3539 // -- a0 : key
3540 // -- a1 : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003541 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003542 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003543}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003544
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003545
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003546void KeyedStoreStubCompiler::GenerateStoreFastElement(
3547 MacroAssembler* masm,
3548 bool is_js_array,
yangguo@chromium.org56454712012-02-16 15:33:53 +00003549 ElementsKind elements_kind,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003550 KeyedAccessStoreMode store_mode) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003551 // ----------- S t a t e -------------
3552 // -- a0 : value
3553 // -- a1 : key
3554 // -- a2 : receiver
3555 // -- ra : return address
3556 // -- a3 : scratch
3557 // -- a4 : scratch (elements)
3558 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00003559 Label miss_force_generic, transition_elements_kind, grow, slow;
3560 Label finish_store, check_capacity;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003561
3562 Register value_reg = a0;
3563 Register key_reg = a1;
3564 Register receiver_reg = a2;
yangguo@chromium.org56454712012-02-16 15:33:53 +00003565 Register scratch = t0;
3566 Register elements_reg = a3;
3567 Register length_reg = t1;
3568 Register scratch2 = t2;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003569
3570 // This stub is meant to be tail-jumped to, the receiver must already
3571 // have been verified by the caller to not be a smi.
3572
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003573 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003574 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003575
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003576 if (IsFastSmiElementsKind(elements_kind)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003577 __ JumpIfNotSmi(value_reg, &transition_elements_kind);
3578 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003579
3580 // Check that the key is within bounds.
yangguo@chromium.org56454712012-02-16 15:33:53 +00003581 __ lw(elements_reg,
3582 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003583 if (is_js_array) {
3584 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3585 } else {
3586 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3587 }
3588 // Compare smis.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003589 if (is_js_array && IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003590 __ Branch(&grow, hs, key_reg, Operand(scratch));
3591 } else {
3592 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
3593 }
3594
3595 // Make sure elements is a fast element array, not 'cow'.
3596 __ CheckMap(elements_reg,
3597 scratch,
3598 Heap::kFixedArrayMapRootIndex,
3599 &miss_force_generic,
3600 DONT_DO_SMI_CHECK);
3601
3602 __ bind(&finish_store);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003603
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003604 if (IsFastSmiElementsKind(elements_kind)) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003605 __ Addu(scratch,
3606 elements_reg,
3607 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3608 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
3609 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
3610 __ Addu(scratch, scratch, scratch2);
3611 __ sw(value_reg, MemOperand(scratch));
3612 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003613 ASSERT(IsFastObjectElementsKind(elements_kind));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003614 __ Addu(scratch,
3615 elements_reg,
3616 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3617 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
3618 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
3619 __ Addu(scratch, scratch, scratch2);
3620 __ sw(value_reg, MemOperand(scratch));
3621 __ mov(receiver_reg, value_reg);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003622 __ RecordWrite(elements_reg, // Object.
3623 scratch, // Address.
3624 receiver_reg, // Value.
3625 kRAHasNotBeenSaved,
3626 kDontSaveFPRegs);
3627 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003628 // value_reg (a0) is preserved.
3629 // Done.
3630 __ Ret();
3631
3632 __ bind(&miss_force_generic);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003633 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003634
3635 __ bind(&transition_elements_kind);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003636 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003637
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003638 if (is_js_array && IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003639 // Grow the array by a single element if possible.
3640 __ bind(&grow);
3641
3642 // Make sure the array is only growing by a single element, anything else
3643 // must be handled by the runtime.
3644 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch));
3645
3646 // Check for the empty array, and preallocate a small backing store if
3647 // possible.
3648 __ lw(length_reg,
3649 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3650 __ lw(elements_reg,
3651 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3652 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
3653 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
3654
3655 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003656 __ Allocate(size, elements_reg, scratch, scratch2, &slow, TAG_OBJECT);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003657
3658 __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex);
3659 __ sw(scratch, FieldMemOperand(elements_reg, JSObject::kMapOffset));
3660 __ li(scratch, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
3661 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3662 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
3663 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
3664 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::SizeFor(i)));
3665 }
3666
3667 // Store the element at index zero.
3668 __ sw(value_reg, FieldMemOperand(elements_reg, FixedArray::SizeFor(0)));
3669
3670 // Install the new backing store in the JSArray.
3671 __ sw(elements_reg,
3672 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3673 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
3674 scratch, kRAHasNotBeenSaved, kDontSaveFPRegs,
3675 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3676
3677 // Increment the length of the array.
3678 __ li(length_reg, Operand(Smi::FromInt(1)));
3679 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3680 __ Ret();
3681
3682 __ bind(&check_capacity);
3683 // Check for cow elements, in general they are not handled by this stub
3684 __ CheckMap(elements_reg,
3685 scratch,
3686 Heap::kFixedCOWArrayMapRootIndex,
3687 &miss_force_generic,
3688 DONT_DO_SMI_CHECK);
3689
3690 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3691 __ Branch(&slow, hs, length_reg, Operand(scratch));
3692
3693 // Grow the array and finish the store.
3694 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
3695 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3696 __ jmp(&finish_store);
3697
3698 __ bind(&slow);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003699 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003700 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003701}
3702
3703
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003704void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
3705 MacroAssembler* masm,
yangguo@chromium.org56454712012-02-16 15:33:53 +00003706 bool is_js_array,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003707 KeyedAccessStoreMode store_mode) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003708 // ----------- S t a t e -------------
3709 // -- a0 : value
3710 // -- a1 : key
3711 // -- a2 : receiver
3712 // -- ra : return address
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003713 // -- a3 : scratch (elements backing store)
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003714 // -- t0 : scratch (elements_reg)
3715 // -- t1 : scratch (mantissa_reg)
3716 // -- t2 : scratch (exponent_reg)
3717 // -- t3 : scratch4
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003718 // -- t4 : scratch
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003719 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00003720 Label miss_force_generic, transition_elements_kind, grow, slow;
3721 Label finish_store, check_capacity;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003722
3723 Register value_reg = a0;
3724 Register key_reg = a1;
3725 Register receiver_reg = a2;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003726 Register elements_reg = a3;
3727 Register scratch1 = t0;
3728 Register scratch2 = t1;
3729 Register scratch3 = t2;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003730 Register scratch4 = t3;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003731 Register scratch5 = t4;
yangguo@chromium.org56454712012-02-16 15:33:53 +00003732 Register length_reg = t3;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003733
3734 // This stub is meant to be tail-jumped to, the receiver must already
3735 // have been verified by the caller to not be a smi.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003736
3737 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003738 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003739
3740 __ lw(elements_reg,
3741 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3742
3743 // Check that the key is within bounds.
3744 if (is_js_array) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003745 __ lw(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003746 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003747 __ lw(scratch1,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003748 FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3749 }
3750 // Compare smis, unsigned compare catches both negative and out-of-bound
3751 // indexes.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003752 if (IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003753 __ Branch(&grow, hs, key_reg, Operand(scratch1));
3754 } else {
3755 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch1));
3756 }
3757
3758 __ bind(&finish_store);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003759
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003760 __ StoreNumberToDoubleElements(value_reg,
3761 key_reg,
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00003762 // All registers after this are overwritten.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003763 elements_reg,
3764 scratch1,
3765 scratch2,
3766 scratch3,
3767 scratch4,
3768 &transition_elements_kind);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003769
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003770 __ Ret(USE_DELAY_SLOT);
3771 __ mov(v0, value_reg); // In delay slot.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003772
3773 // Handle store cache miss, replacing the ic with the generic stub.
3774 __ bind(&miss_force_generic);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003775 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003776
3777 __ bind(&transition_elements_kind);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003778 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003779
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003780 if (is_js_array && IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003781 // Grow the array by a single element if possible.
3782 __ bind(&grow);
3783
3784 // Make sure the array is only growing by a single element, anything else
3785 // must be handled by the runtime.
3786 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch1));
3787
3788 // Transition on values that can't be stored in a FixedDoubleArray.
3789 Label value_is_smi;
3790 __ JumpIfSmi(value_reg, &value_is_smi);
3791 __ lw(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
3792 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
3793 __ Branch(&transition_elements_kind, ne, scratch1, Operand(at));
3794 __ bind(&value_is_smi);
3795
3796 // Check for the empty array, and preallocate a small backing store if
3797 // possible.
3798 __ lw(length_reg,
3799 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3800 __ lw(elements_reg,
3801 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3802 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
3803 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
3804
3805 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003806 __ Allocate(size, elements_reg, scratch1, scratch2, &slow, TAG_OBJECT);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003807
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003808 // Initialize the new FixedDoubleArray.
yangguo@chromium.org56454712012-02-16 15:33:53 +00003809 __ LoadRoot(scratch1, Heap::kFixedDoubleArrayMapRootIndex);
3810 __ sw(scratch1, FieldMemOperand(elements_reg, JSObject::kMapOffset));
3811 __ li(scratch1, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
3812 __ sw(scratch1,
3813 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
3814
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003815 __ mov(scratch1, elements_reg);
3816 __ StoreNumberToDoubleElements(value_reg,
3817 key_reg,
3818 // All registers after this are overwritten.
3819 scratch1,
3820 scratch2,
3821 scratch3,
3822 scratch4,
3823 scratch5,
3824 &transition_elements_kind);
3825
3826 __ li(scratch1, Operand(kHoleNanLower32));
3827 __ li(scratch2, Operand(kHoleNanUpper32));
3828 for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) {
3829 int offset = FixedDoubleArray::OffsetOfElementAt(i);
3830 __ sw(scratch1, FieldMemOperand(elements_reg, offset));
3831 __ sw(scratch2, FieldMemOperand(elements_reg, offset + kPointerSize));
3832 }
3833
yangguo@chromium.org56454712012-02-16 15:33:53 +00003834 // Install the new backing store in the JSArray.
3835 __ sw(elements_reg,
3836 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3837 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
3838 scratch1, kRAHasNotBeenSaved, kDontSaveFPRegs,
3839 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3840
3841 // Increment the length of the array.
3842 __ li(length_reg, Operand(Smi::FromInt(1)));
3843 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
danno@chromium.org00379b82012-05-04 09:16:29 +00003844 __ lw(elements_reg,
3845 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003846 __ Ret();
yangguo@chromium.org56454712012-02-16 15:33:53 +00003847
3848 __ bind(&check_capacity);
3849 // Make sure that the backing store can hold additional elements.
3850 __ lw(scratch1,
3851 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
3852 __ Branch(&slow, hs, length_reg, Operand(scratch1));
3853
3854 // Grow the array and finish the store.
3855 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
3856 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3857 __ jmp(&finish_store);
3858
3859 __ bind(&slow);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003860 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003861 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003862}
3863
3864
ager@chromium.org5c838252010-02-19 08:53:10 +00003865#undef __
3866
3867} } // namespace v8::internal
3868
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003869#endif // V8_TARGET_ARCH_MIPS