blob: 4a73be2dbe983798e99cf2dc7f6d37ccc9499411 [file] [log] [blame]
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001// Copyright 2012 the V8 project authors. All rights reserved.
ager@chromium.org5c838252010-02-19 08:53:10 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000030#if defined(V8_TARGET_ARCH_MIPS)
31
ager@chromium.org5c838252010-02-19 08:53:10 +000032#include "ic-inl.h"
karlklose@chromium.org83a47282011-05-11 11:54:09 +000033#include "codegen.h"
ager@chromium.org5c838252010-02-19 08:53:10 +000034#include "stub-cache.h"
35
36namespace v8 {
37namespace internal {
38
39#define __ ACCESS_MASM(masm)
40
41
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000042static void ProbeTable(Isolate* isolate,
43 MacroAssembler* masm,
44 Code::Flags flags,
45 StubCache::Table table,
fschneider@chromium.org35814e52012-03-01 15:43:35 +000046 Register receiver,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000047 Register name,
fschneider@chromium.org35814e52012-03-01 15:43:35 +000048 // Number of the cache entry, not scaled.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000049 Register offset,
50 Register scratch,
fschneider@chromium.org35814e52012-03-01 15:43:35 +000051 Register scratch2,
52 Register offset_scratch) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000053 ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
54 ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
fschneider@chromium.org35814e52012-03-01 15:43:35 +000055 ExternalReference map_offset(isolate->stub_cache()->map_reference(table));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000056
57 uint32_t key_off_addr = reinterpret_cast<uint32_t>(key_offset.address());
58 uint32_t value_off_addr = reinterpret_cast<uint32_t>(value_offset.address());
fschneider@chromium.org35814e52012-03-01 15:43:35 +000059 uint32_t map_off_addr = reinterpret_cast<uint32_t>(map_offset.address());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000060
61 // Check the relative positions of the address fields.
62 ASSERT(value_off_addr > key_off_addr);
63 ASSERT((value_off_addr - key_off_addr) % 4 == 0);
64 ASSERT((value_off_addr - key_off_addr) < (256 * 4));
fschneider@chromium.org35814e52012-03-01 15:43:35 +000065 ASSERT(map_off_addr > key_off_addr);
66 ASSERT((map_off_addr - key_off_addr) % 4 == 0);
67 ASSERT((map_off_addr - key_off_addr) < (256 * 4));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000068
69 Label miss;
fschneider@chromium.org35814e52012-03-01 15:43:35 +000070 Register base_addr = scratch;
71 scratch = no_reg;
72
73 // Multiply by 3 because there are 3 fields per entry (name, code, map).
74 __ sll(offset_scratch, offset, 1);
75 __ Addu(offset_scratch, offset_scratch, offset);
76
77 // Calculate the base address of the entry.
78 __ li(base_addr, Operand(key_offset));
79 __ sll(at, offset_scratch, kPointerSizeLog2);
80 __ Addu(base_addr, base_addr, at);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000081
82 // Check that the key in the entry matches the name.
fschneider@chromium.org35814e52012-03-01 15:43:35 +000083 __ lw(at, MemOperand(base_addr, 0));
84 __ Branch(&miss, ne, name, Operand(at));
85
86 // Check the map matches.
87 __ lw(at, MemOperand(base_addr, map_off_addr - key_off_addr));
88 __ lw(scratch2, FieldMemOperand(receiver, HeapObject::kMapOffset));
89 __ Branch(&miss, ne, at, Operand(scratch2));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000090
91 // Get the code entry from the cache.
fschneider@chromium.org35814e52012-03-01 15:43:35 +000092 Register code = scratch2;
93 scratch2 = no_reg;
94 __ lw(code, MemOperand(base_addr, value_off_addr - key_off_addr));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000095
96 // Check that the flags match what we're looking for.
fschneider@chromium.org35814e52012-03-01 15:43:35 +000097 Register flags_reg = base_addr;
98 base_addr = no_reg;
99 __ lw(flags_reg, FieldMemOperand(code, Code::kFlagsOffset));
100 __ And(flags_reg, flags_reg, Operand(~Code::kFlagsNotUsedInLookup));
101 __ Branch(&miss, ne, flags_reg, Operand(flags));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000102
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000103#ifdef DEBUG
104 if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
105 __ jmp(&miss);
106 } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
107 __ jmp(&miss);
108 }
109#endif
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000110
111 // Jump to the first instruction in the code stub.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000112 __ Addu(at, code, Operand(Code::kHeaderSize - kHeapObjectTag));
113 __ Jump(at);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000114
115 // Miss: fall through.
116 __ bind(&miss);
117}
118
119
120// Helper function used to check that the dictionary doesn't contain
121// the property. This function may return false negatives, so miss_label
122// must always call a backup property check that is complete.
123// This function is safe to call if the receiver has fast properties.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000124// Name must be unique and receiver must be a heap object.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000125static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
126 Label* miss_label,
127 Register receiver,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000128 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000129 Register scratch0,
130 Register scratch1) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000131 ASSERT(name->IsUniqueName());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000132 Counters* counters = masm->isolate()->counters();
133 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
134 __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
135
136 Label done;
137
138 const int kInterceptorOrAccessCheckNeededMask =
139 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
140
141 // Bail out if the receiver has a named interceptor or requires access checks.
142 Register map = scratch1;
143 __ lw(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
144 __ lbu(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
145 __ And(scratch0, scratch0, Operand(kInterceptorOrAccessCheckNeededMask));
146 __ Branch(miss_label, ne, scratch0, Operand(zero_reg));
147
148 // Check that receiver is a JSObject.
149 __ lbu(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
150 __ Branch(miss_label, lt, scratch0, Operand(FIRST_SPEC_OBJECT_TYPE));
151
152 // Load properties array.
153 Register properties = scratch0;
154 __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
155 // Check that the properties array is a dictionary.
156 __ lw(map, FieldMemOperand(properties, HeapObject::kMapOffset));
157 Register tmp = properties;
158 __ LoadRoot(tmp, Heap::kHashTableMapRootIndex);
159 __ Branch(miss_label, ne, map, Operand(tmp));
160
161 // Restore the temporarily used register.
162 __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
163
164
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000165 NameDictionaryLookupStub::GenerateNegativeLookup(masm,
166 miss_label,
167 &done,
168 receiver,
169 properties,
170 name,
171 scratch1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000172 __ bind(&done);
173 __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
174}
175
176
ager@chromium.org5c838252010-02-19 08:53:10 +0000177void StubCache::GenerateProbe(MacroAssembler* masm,
178 Code::Flags flags,
179 Register receiver,
180 Register name,
181 Register scratch,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000182 Register extra,
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000183 Register extra2,
184 Register extra3) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000185 Isolate* isolate = masm->isolate();
186 Label miss;
187
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000188 // Make sure that code is valid. The multiplying code relies on the
189 // entry size being 12.
190 ASSERT(sizeof(Entry) == 12);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000191
192 // Make sure the flags does not name a specific type.
193 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
194
195 // Make sure that there are no register conflicts.
196 ASSERT(!scratch.is(receiver));
197 ASSERT(!scratch.is(name));
198 ASSERT(!extra.is(receiver));
199 ASSERT(!extra.is(name));
200 ASSERT(!extra.is(scratch));
201 ASSERT(!extra2.is(receiver));
202 ASSERT(!extra2.is(name));
203 ASSERT(!extra2.is(scratch));
204 ASSERT(!extra2.is(extra));
205
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000206 // Check register validity.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000207 ASSERT(!scratch.is(no_reg));
208 ASSERT(!extra.is(no_reg));
209 ASSERT(!extra2.is(no_reg));
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000210 ASSERT(!extra3.is(no_reg));
211
212 Counters* counters = masm->isolate()->counters();
213 __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1,
214 extra2, extra3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000215
216 // Check that the receiver isn't a smi.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000217 __ JumpIfSmi(receiver, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000218
219 // Get the map of the receiver and compute the hash.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000220 __ lw(scratch, FieldMemOperand(name, Name::kHashFieldOffset));
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000221 __ lw(at, FieldMemOperand(receiver, HeapObject::kMapOffset));
222 __ Addu(scratch, scratch, at);
223 uint32_t mask = kPrimaryTableSize - 1;
224 // We shift out the last two bits because they are not part of the hash and
225 // they are always 01 for maps.
226 __ srl(scratch, scratch, kHeapObjectTagSize);
227 __ Xor(scratch, scratch, Operand((flags >> kHeapObjectTagSize) & mask));
228 __ And(scratch, scratch, Operand(mask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000229
230 // Probe the primary table.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000231 ProbeTable(isolate,
232 masm,
233 flags,
234 kPrimary,
235 receiver,
236 name,
237 scratch,
238 extra,
239 extra2,
240 extra3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000241
242 // Primary miss: Compute hash for secondary probe.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000243 __ srl(at, name, kHeapObjectTagSize);
244 __ Subu(scratch, scratch, at);
245 uint32_t mask2 = kSecondaryTableSize - 1;
246 __ Addu(scratch, scratch, Operand((flags >> kHeapObjectTagSize) & mask2));
247 __ And(scratch, scratch, Operand(mask2));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000248
249 // Probe the secondary table.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000250 ProbeTable(isolate,
251 masm,
252 flags,
253 kSecondary,
254 receiver,
255 name,
256 scratch,
257 extra,
258 extra2,
259 extra3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000260
261 // Cache miss: Fall-through and let caller handle the miss by
262 // entering the runtime system.
263 __ bind(&miss);
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000264 __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1,
265 extra2, extra3);
ager@chromium.org5c838252010-02-19 08:53:10 +0000266}
267
268
269void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
270 int index,
271 Register prototype) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000272 // Load the global or builtins object from the current context.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000273 __ lw(prototype,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000274 MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
275 // Load the native context from the global or builtins object.
276 __ lw(prototype,
277 FieldMemOperand(prototype, GlobalObject::kNativeContextOffset));
278 // Load the function from the native context.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000279 __ lw(prototype, MemOperand(prototype, Context::SlotOffset(index)));
280 // Load the initial map. The global functions all have initial maps.
281 __ lw(prototype,
282 FieldMemOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
283 // Load the prototype from the initial map.
284 __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000285}
286
287
lrn@chromium.org7516f052011-03-30 08:52:27 +0000288void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000289 MacroAssembler* masm,
290 int index,
291 Register prototype,
292 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000293 Isolate* isolate = masm->isolate();
294 // Check we're still in the same context.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000295 __ lw(prototype,
296 MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000297 ASSERT(!prototype.is(at));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000298 __ li(at, isolate->global_object());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000299 __ Branch(miss, ne, prototype, Operand(at));
300 // Get the global function with the given index.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000301 Handle<JSFunction> function(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000302 JSFunction::cast(isolate->native_context()->get(index)));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000303 // Load its initial map. The global functions all have initial maps.
304 __ li(prototype, Handle<Map>(function->initial_map()));
305 // Load the prototype from the initial map.
306 __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000307}
308
309
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000310void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
311 Register dst,
312 Register src,
313 bool inobject,
314 int index,
315 Representation representation) {
316 ASSERT(!FLAG_track_double_fields || !representation.IsDouble());
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000317 int offset = index * kPointerSize;
318 if (!inobject) {
319 // Calculate the offset into the properties array.
320 offset = offset + FixedArray::kHeaderSize;
321 __ lw(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
322 src = dst;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000323 }
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000324 __ lw(dst, FieldMemOperand(src, offset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000325}
326
327
328void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
329 Register receiver,
330 Register scratch,
331 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000332 // Check that the receiver isn't a smi.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000333 __ JumpIfSmi(receiver, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000334
335 // Check that the object is a JS array.
336 __ GetObjectType(receiver, scratch, scratch);
337 __ Branch(miss_label, ne, scratch, Operand(JS_ARRAY_TYPE));
338
339 // Load length directly from the JS array.
340 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
341 __ Ret();
342}
343
344
345// Generate code to check if an object is a string. If the object is a
346// heap object, its map's instance type is left in the scratch1 register.
347// If this is not needed, scratch1 and scratch2 may be the same register.
348static void GenerateStringCheck(MacroAssembler* masm,
349 Register receiver,
350 Register scratch1,
351 Register scratch2,
352 Label* smi,
353 Label* non_string_object) {
354 // Check that the receiver isn't a smi.
355 __ JumpIfSmi(receiver, smi, t0);
356
357 // Check that the object is a string.
358 __ lw(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
359 __ lbu(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
360 __ And(scratch2, scratch1, Operand(kIsNotStringMask));
361 // The cast is to resolve the overload for the argument of 0x0.
362 __ Branch(non_string_object,
363 ne,
364 scratch2,
365 Operand(static_cast<int32_t>(kStringTag)));
ager@chromium.org5c838252010-02-19 08:53:10 +0000366}
367
368
lrn@chromium.org7516f052011-03-30 08:52:27 +0000369// Generate code to load the length from a string object and return the length.
370// If the receiver object is not a string or a wrapped string object the
371// execution continues at the miss label. The register containing the
372// receiver is potentially clobbered.
373void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
374 Register receiver,
375 Register scratch1,
376 Register scratch2,
377 Label* miss,
378 bool support_wrappers) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000379 Label check_wrapper;
380
381 // Check if the object is a string leaving the instance type in the
382 // scratch1 register.
383 GenerateStringCheck(masm, receiver, scratch1, scratch2, miss,
384 support_wrappers ? &check_wrapper : miss);
385
386 // Load length directly from the string.
387 __ lw(v0, FieldMemOperand(receiver, String::kLengthOffset));
388 __ Ret();
389
390 if (support_wrappers) {
391 // Check if the object is a JSValue wrapper.
392 __ bind(&check_wrapper);
393 __ Branch(miss, ne, scratch1, Operand(JS_VALUE_TYPE));
394
395 // Unwrap the value and check if the wrapped value is a string.
396 __ lw(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
397 GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
398 __ lw(v0, FieldMemOperand(scratch1, String::kLengthOffset));
399 __ Ret();
400 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000401}
402
403
ager@chromium.org5c838252010-02-19 08:53:10 +0000404void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
405 Register receiver,
406 Register scratch1,
407 Register scratch2,
408 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000409 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
410 __ mov(v0, scratch1);
411 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000412}
413
414
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000415// Generate code to check that a global property cell is empty. Create
416// the property cell at compilation time if no cell exists for the
417// property.
418static void GenerateCheckPropertyCell(MacroAssembler* masm,
419 Handle<GlobalObject> global,
420 Handle<Name> name,
421 Register scratch,
422 Label* miss) {
423 Handle<JSGlobalPropertyCell> cell =
424 GlobalObject::EnsurePropertyCell(global, name);
425 ASSERT(cell->value()->IsTheHole());
426 __ li(scratch, Operand(cell));
427 __ lw(scratch,
428 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
429 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
430 __ Branch(miss, ne, scratch, Operand(at));
431}
432
433
434// Generate StoreTransition code, value is passed in a0 register.
ager@chromium.org5c838252010-02-19 08:53:10 +0000435// After executing generated code, the receiver_reg and name_reg
436// may be clobbered.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000437void StubCompiler::GenerateStoreTransition(MacroAssembler* masm,
438 Handle<JSObject> object,
439 LookupResult* lookup,
440 Handle<Map> transition,
441 Handle<Name> name,
442 Register receiver_reg,
443 Register name_reg,
444 Register value_reg,
445 Register scratch1,
446 Register scratch2,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000447 Register scratch3,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000448 Label* miss_label,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000449 Label* miss_restore_name,
450 Label* slow) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000451 // a0 : value.
452 Label exit;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000453
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000454 // Check that the map of the object hasn't changed.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000455 __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000456 DO_SMI_CHECK, REQUIRE_EXACT_MAP);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000457
458 // Perform global security token check if needed.
459 if (object->IsJSGlobalProxy()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000460 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
461 }
462
danno@chromium.orgf005df62013-04-30 16:36:45 +0000463 int descriptor = transition->LastAdded();
464 DescriptorArray* descriptors = transition->instance_descriptors();
465 PropertyDetails details = descriptors->GetDetails(descriptor);
466 Representation representation = details.representation();
467 ASSERT(!representation.IsNone());
468
469 // Ensure no transitions to deprecated maps are followed.
470 __ CheckMapDeprecated(transition, scratch1, miss_label);
471
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000472 // Check that we are allowed to write this.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000473 if (object->GetPrototype()->IsJSObject()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000474 JSObject* holder;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000475 // holder == object indicates that no property was found.
476 if (lookup->holder() != *object) {
477 holder = lookup->holder();
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000478 } else {
479 // Find the top object.
480 holder = *object;
481 do {
482 holder = JSObject::cast(holder->GetPrototype());
483 } while (holder->GetPrototype()->IsJSObject());
484 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000485 Register holder_reg = CheckPrototypes(
486 object, receiver_reg, Handle<JSObject>(holder), name_reg,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000487 scratch1, scratch2, name, miss_restore_name, SKIP_RECEIVER);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000488 // If no property was found, and the holder (the last object in the
489 // prototype chain) is in slow mode, we need to do a negative lookup on the
490 // holder.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000491 if (lookup->holder() == *object) {
492 if (holder->IsJSGlobalObject()) {
493 GenerateCheckPropertyCell(
494 masm,
495 Handle<GlobalObject>(GlobalObject::cast(holder)),
496 name,
497 scratch1,
498 miss_restore_name);
499 } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
500 GenerateDictionaryNegativeLookup(
501 masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
502 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000503 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000504 }
505
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000506 Register storage_reg = name_reg;
507
508 if (FLAG_track_fields && representation.IsSmi()) {
509 __ JumpIfNotSmi(value_reg, miss_restore_name);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +0000510 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
511 __ JumpIfSmi(value_reg, miss_restore_name);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000512 } else if (FLAG_track_double_fields && representation.IsDouble()) {
513 Label do_store, heap_number;
514 __ LoadRoot(scratch3, Heap::kHeapNumberMapRootIndex);
515 __ AllocateHeapNumber(storage_reg, scratch1, scratch2, scratch3, slow);
516
517 __ JumpIfNotSmi(value_reg, &heap_number);
518 __ SmiUntag(scratch1, value_reg);
519 __ mtc1(scratch1, f6);
520 __ cvt_d_w(f4, f6);
521 __ jmp(&do_store);
522
523 __ bind(&heap_number);
524 __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex,
525 miss_restore_name, DONT_DO_SMI_CHECK);
526 __ ldc1(f4, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
527
528 __ bind(&do_store);
529 __ sdc1(f4, FieldMemOperand(storage_reg, HeapNumber::kValueOffset));
530 }
531
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000532 // Stub never generated for non-global objects that require access
533 // checks.
534 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
535
536 // Perform map transition for the receiver if necessary.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000537 if (object->map()->unused_property_fields() == 0) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000538 // The properties must be extended before we can store the value.
539 // We jump to a runtime call that extends the properties array.
540 __ push(receiver_reg);
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000541 __ li(a2, Operand(transition));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000542 __ Push(a2, a0);
543 __ TailCallExternalReference(
544 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
545 masm->isolate()),
546 3, 1);
547 return;
548 }
549
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000550 // Update the map of the object.
551 __ li(scratch1, Operand(transition));
552 __ sw(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
verwaest@chromium.org37141392012-05-31 13:27:02 +0000553
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000554 // Update the write barrier for the map field and pass the now unused
555 // name_reg as scratch register.
556 __ RecordWriteField(receiver_reg,
557 HeapObject::kMapOffset,
558 scratch1,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000559 scratch2,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000560 kRAHasNotBeenSaved,
561 kDontSaveFPRegs,
562 OMIT_REMEMBERED_SET,
563 OMIT_SMI_CHECK);
564
565 int index = transition->instance_descriptors()->GetFieldIndex(
566 transition->LastAdded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000567
568 // Adjust for the number of properties stored in the object. Even in the
569 // face of a transition we can use the old map here because the size of the
570 // object and the number of in-object properties is not going to change.
571 index -= object->map()->inobject_properties();
572
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000573 // TODO(verwaest): Share this code as a code stub.
574 if (index < 0) {
575 // Set the property straight into the object.
576 int offset = object->map()->instance_size() + (index * kPointerSize);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000577 if (FLAG_track_double_fields && representation.IsDouble()) {
578 __ sw(storage_reg, FieldMemOperand(receiver_reg, offset));
579 } else {
580 __ sw(value_reg, FieldMemOperand(receiver_reg, offset));
581 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000582
danno@chromium.orgf005df62013-04-30 16:36:45 +0000583 if (!FLAG_track_fields || !representation.IsSmi()) {
584 // Skip updating write barrier if storing a smi.
585 __ JumpIfSmi(value_reg, &exit);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000586
danno@chromium.orgf005df62013-04-30 16:36:45 +0000587 // Update the write barrier for the array address.
588 // Pass the now unused name_reg as a scratch register.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000589 if (!FLAG_track_double_fields || !representation.IsDouble()) {
590 __ mov(name_reg, value_reg);
591 } else {
592 ASSERT(storage_reg.is(name_reg));
593 }
danno@chromium.orgf005df62013-04-30 16:36:45 +0000594 __ RecordWriteField(receiver_reg,
595 offset,
596 name_reg,
597 scratch1,
598 kRAHasNotBeenSaved,
599 kDontSaveFPRegs);
600 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000601 } else {
602 // Write to the properties array.
603 int offset = index * kPointerSize + FixedArray::kHeaderSize;
604 // Get the properties array
605 __ lw(scratch1,
606 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000607 if (FLAG_track_double_fields && representation.IsDouble()) {
608 __ sw(storage_reg, FieldMemOperand(scratch1, offset));
609 } else {
610 __ sw(value_reg, FieldMemOperand(scratch1, offset));
611 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000612
danno@chromium.orgf005df62013-04-30 16:36:45 +0000613 if (!FLAG_track_fields || !representation.IsSmi()) {
614 // Skip updating write barrier if storing a smi.
615 __ JumpIfSmi(value_reg, &exit);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000616
danno@chromium.orgf005df62013-04-30 16:36:45 +0000617 // Update the write barrier for the array address.
618 // Ok to clobber receiver_reg and name_reg, since we return.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000619 if (!FLAG_track_double_fields || !representation.IsDouble()) {
620 __ mov(name_reg, value_reg);
621 } else {
622 ASSERT(storage_reg.is(name_reg));
623 }
danno@chromium.orgf005df62013-04-30 16:36:45 +0000624 __ RecordWriteField(scratch1,
625 offset,
626 name_reg,
627 receiver_reg,
628 kRAHasNotBeenSaved,
629 kDontSaveFPRegs);
630 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000631 }
632
633 // Return the value (register v0).
634 ASSERT(value_reg.is(a0));
635 __ bind(&exit);
636 __ mov(v0, a0);
637 __ Ret();
638}
639
640
641// Generate StoreField code, value is passed in a0 register.
642// When leaving generated code after success, the receiver_reg and name_reg
643// may be clobbered. Upon branch to miss_label, the receiver and name
644// registers have their original values.
645void StubCompiler::GenerateStoreField(MacroAssembler* masm,
646 Handle<JSObject> object,
647 LookupResult* lookup,
648 Register receiver_reg,
649 Register name_reg,
650 Register value_reg,
651 Register scratch1,
652 Register scratch2,
653 Label* miss_label) {
654 // a0 : value
655 Label exit;
656
657 // Check that the map of the object hasn't changed.
658 __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
659 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
660
661 // Perform global security token check if needed.
662 if (object->IsJSGlobalProxy()) {
663 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
664 }
665
666 // Stub never generated for non-global objects that require access
667 // checks.
668 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
669
670 int index = lookup->GetFieldIndex().field_index();
671
672 // Adjust for the number of properties stored in the object. Even in the
673 // face of a transition we can use the old map here because the size of the
674 // object and the number of in-object properties is not going to change.
675 index -= object->map()->inobject_properties();
676
danno@chromium.orgf005df62013-04-30 16:36:45 +0000677 Representation representation = lookup->representation();
678 ASSERT(!representation.IsNone());
679 if (FLAG_track_fields && representation.IsSmi()) {
680 __ JumpIfNotSmi(value_reg, miss_label);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +0000681 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
682 __ JumpIfSmi(value_reg, miss_label);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000683 } else if (FLAG_track_double_fields && representation.IsDouble()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000684 // Load the double storage.
685 if (index < 0) {
686 int offset = object->map()->instance_size() + (index * kPointerSize);
687 __ lw(scratch1, FieldMemOperand(receiver_reg, offset));
688 } else {
689 __ lw(scratch1,
690 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
691 int offset = index * kPointerSize + FixedArray::kHeaderSize;
692 __ lw(scratch1, FieldMemOperand(scratch1, offset));
693 }
694
695 // Store the value into the storage.
696 Label do_store, heap_number;
697 __ JumpIfNotSmi(value_reg, &heap_number);
698 __ SmiUntag(scratch2, value_reg);
699 __ mtc1(scratch2, f6);
700 __ cvt_d_w(f4, f6);
701 __ jmp(&do_store);
702
703 __ bind(&heap_number);
704 __ CheckMap(value_reg, scratch2, Heap::kHeapNumberMapRootIndex,
danno@chromium.orgf005df62013-04-30 16:36:45 +0000705 miss_label, DONT_DO_SMI_CHECK);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000706 __ ldc1(f4, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
707
danno@chromium.orgf005df62013-04-30 16:36:45 +0000708 __ bind(&do_store);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000709 __ sdc1(f4, FieldMemOperand(scratch1, HeapNumber::kValueOffset));
710 // Return the value (register v0).
711 ASSERT(value_reg.is(a0));
712 __ mov(v0, a0);
713 __ Ret();
714 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +0000715 }
716
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000717 // TODO(verwaest): Share this code as a code stub.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000718 if (index < 0) {
719 // Set the property straight into the object.
720 int offset = object->map()->instance_size() + (index * kPointerSize);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000721 __ sw(value_reg, FieldMemOperand(receiver_reg, offset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000722
danno@chromium.orgf005df62013-04-30 16:36:45 +0000723 if (!FLAG_track_fields || !representation.IsSmi()) {
724 // Skip updating write barrier if storing a smi.
725 __ JumpIfSmi(value_reg, &exit);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000726
danno@chromium.orgf005df62013-04-30 16:36:45 +0000727 // Update the write barrier for the array address.
728 // Pass the now unused name_reg as a scratch register.
729 __ mov(name_reg, value_reg);
730 __ RecordWriteField(receiver_reg,
731 offset,
732 name_reg,
733 scratch1,
734 kRAHasNotBeenSaved,
735 kDontSaveFPRegs);
736 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000737 } else {
738 // Write to the properties array.
739 int offset = index * kPointerSize + FixedArray::kHeaderSize;
740 // Get the properties array.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000741 __ lw(scratch1,
742 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000743 __ sw(value_reg, FieldMemOperand(scratch1, offset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000744
danno@chromium.orgf005df62013-04-30 16:36:45 +0000745 if (!FLAG_track_fields || !representation.IsSmi()) {
746 // Skip updating write barrier if storing a smi.
747 __ JumpIfSmi(value_reg, &exit);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000748
danno@chromium.orgf005df62013-04-30 16:36:45 +0000749 // Update the write barrier for the array address.
750 // Ok to clobber receiver_reg and name_reg, since we return.
751 __ mov(name_reg, value_reg);
752 __ RecordWriteField(scratch1,
753 offset,
754 name_reg,
755 receiver_reg,
756 kRAHasNotBeenSaved,
757 kDontSaveFPRegs);
758 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000759 }
760
761 // Return the value (register v0).
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000762 ASSERT(value_reg.is(a0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000763 __ bind(&exit);
764 __ mov(v0, a0);
765 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000766}
767
768
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000769void BaseStoreStubCompiler::GenerateRestoreName(MacroAssembler* masm,
770 Label* label,
771 Handle<Name> name) {
772 if (!label->is_unused()) {
773 __ bind(label);
774 __ li(this->name(), Operand(name));
775 }
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000776}
777
778
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000779static void GenerateCallFunction(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000780 Handle<Object> object,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000781 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000782 Label* miss,
783 Code::ExtraICState extra_ic_state) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000784 // ----------- S t a t e -------------
785 // -- a0: receiver
786 // -- a1: function to call
787 // -----------------------------------
788 // Check that the function really is a function.
789 __ JumpIfSmi(a1, miss);
790 __ GetObjectType(a1, a3, a3);
791 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
792
793 // Patch the receiver on the stack with the global proxy if
794 // necessary.
795 if (object->IsGlobalObject()) {
796 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
797 __ sw(a3, MemOperand(sp, arguments.immediate() * kPointerSize));
798 }
799
800 // Invoke the function.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000801 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
802 ? CALL_AS_FUNCTION
803 : CALL_AS_METHOD;
804 __ InvokeFunction(a1, arguments, JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000805}
806
807
808static void PushInterceptorArguments(MacroAssembler* masm,
809 Register receiver,
810 Register holder,
811 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000812 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000813 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000814 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
815 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000816 Register scratch = name;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000817 __ li(scratch, Operand(interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000818 __ Push(scratch, receiver, holder);
819 __ lw(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
820 __ push(scratch);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000821 __ li(scratch, Operand(ExternalReference::isolate_address(masm->isolate())));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000822 __ push(scratch);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000823}
824
825
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000826static void CompileCallLoadPropertyWithInterceptor(
827 MacroAssembler* masm,
828 Register receiver,
829 Register holder,
830 Register name,
831 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000832 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
833
834 ExternalReference ref =
835 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
836 masm->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000837 __ PrepareCEntryArgs(6);
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000838 __ PrepareCEntryFunction(ref);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000839
840 CEntryStub stub(1);
841 __ CallStub(&stub);
842}
843
844
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000845static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000846
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000847// Reserves space for the extra arguments to API function in the
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000848// caller's frame.
849//
850// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
851static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
852 Register scratch) {
853 ASSERT(Smi::FromInt(0) == 0);
854 for (int i = 0; i < kFastApiCallArguments; i++) {
855 __ push(zero_reg);
856 }
857}
858
859
860// Undoes the effects of ReserveSpaceForFastApiCall.
861static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
862 __ Drop(kFastApiCallArguments);
863}
864
865
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000866static void GenerateFastApiDirectCall(MacroAssembler* masm,
867 const CallOptimization& optimization,
868 int argc) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000869 // ----------- S t a t e -------------
870 // -- sp[0] : holder (set by CheckPrototypes)
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000871 // -- sp[4] : callee JS function
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000872 // -- sp[8] : call data
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000873 // -- sp[12] : isolate
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000874 // -- sp[16] : ReturnValue
875 // -- sp[20] : last JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000876 // -- ...
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000877 // -- sp[(argc + 4) * 4] : first JS argument
878 // -- sp[(argc + 5) * 4] : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000879 // -----------------------------------
880 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000881 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000882 __ LoadHeapObject(t1, function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000883 __ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset));
884
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000885 // Pass the additional arguments.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000886 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000887 Handle<Object> call_data(api_call_info->data(), masm->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000888 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
889 __ li(a0, api_call_info);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000890 __ lw(t2, FieldMemOperand(a0, CallHandlerInfo::kDataOffset));
891 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000892 __ li(t2, call_data);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000893 }
894
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000895 __ li(t3, Operand(ExternalReference::isolate_address(masm->isolate())));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000896 // Store JS function, call data, isolate and ReturnValue.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000897 __ sw(t1, MemOperand(sp, 1 * kPointerSize));
898 __ sw(t2, MemOperand(sp, 2 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000899 __ sw(t3, MemOperand(sp, 3 * kPointerSize));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000900 __ LoadRoot(t1, Heap::kUndefinedValueRootIndex);
901 __ sw(t1, MemOperand(sp, 4 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000902
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000903 // Prepare arguments.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000904 __ Addu(a2, sp, Operand(4 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000905
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000906 // Allocate the v8::Arguments structure in the arguments' space since
907 // it's not controlled by GC.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000908 const int kApiStackSpace = 4;
909
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000910 FrameScope frame_scope(masm, StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000911 __ EnterExitFrame(false, kApiStackSpace);
912
913 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
914 // struct from the function (which is currently the case). This means we pass
915 // the first argument in a1 instead of a0. TryCallApiFunctionAndReturn
916 // will handle setting up a0.
917
918 // a1 = v8::Arguments&
919 // Arguments is built at sp + 1 (sp is a reserved spot for ra).
920 __ Addu(a1, sp, kPointerSize);
921
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000922 // v8::Arguments::implicit_args_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000923 __ sw(a2, MemOperand(a1, 0 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000924 // v8::Arguments::values_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000925 __ Addu(t0, a2, Operand(argc * kPointerSize));
926 __ sw(t0, MemOperand(a1, 1 * kPointerSize));
927 // v8::Arguments::length_ = argc
928 __ li(t0, Operand(argc));
929 __ sw(t0, MemOperand(a1, 2 * kPointerSize));
930 // v8::Arguments::is_construct_call = 0
931 __ sw(zero_reg, MemOperand(a1, 3 * kPointerSize));
932
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000933 const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000934 Address function_address = v8::ToCData<Address>(api_call_info->callback());
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000935 bool returns_handle =
936 !CallbackTable::ReturnsVoid(masm->isolate(), function_address);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000937 ApiFunction fun(function_address);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000938 ExternalReference::Type type =
939 returns_handle ?
940 ExternalReference::DIRECT_API_CALL :
941 ExternalReference::DIRECT_API_CALL_NEW;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000942 ExternalReference ref =
943 ExternalReference(&fun,
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000944 type,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000945 masm->isolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000946 AllowExternalCallThatCantCauseGC scope(masm);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000947 __ CallApiFunctionAndReturn(ref,
948 kStackUnwindSpace,
949 returns_handle,
950 kFastApiCallArguments + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000951}
952
lrn@chromium.org7516f052011-03-30 08:52:27 +0000953class CallInterceptorCompiler BASE_EMBEDDED {
954 public:
955 CallInterceptorCompiler(StubCompiler* stub_compiler,
956 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000957 Register name,
958 Code::ExtraICState extra_ic_state)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000959 : stub_compiler_(stub_compiler),
960 arguments_(arguments),
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000961 name_(name),
962 extra_ic_state_(extra_ic_state) {}
lrn@chromium.org7516f052011-03-30 08:52:27 +0000963
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000964 void Compile(MacroAssembler* masm,
965 Handle<JSObject> object,
966 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000967 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000968 LookupResult* lookup,
969 Register receiver,
970 Register scratch1,
971 Register scratch2,
972 Register scratch3,
973 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000974 ASSERT(holder->HasNamedInterceptor());
975 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
976
977 // Check that the receiver isn't a smi.
978 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000979 CallOptimization optimization(lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000980 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000981 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
982 holder, lookup, name, optimization, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000983 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000984 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
985 name, holder, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000986 }
987 }
988
989 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000990 void CompileCacheable(MacroAssembler* masm,
991 Handle<JSObject> object,
992 Register receiver,
993 Register scratch1,
994 Register scratch2,
995 Register scratch3,
996 Handle<JSObject> interceptor_holder,
997 LookupResult* lookup,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000998 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000999 const CallOptimization& optimization,
1000 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001001 ASSERT(optimization.is_constant_call());
1002 ASSERT(!lookup->holder()->IsGlobalObject());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001003 Counters* counters = masm->isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001004 int depth1 = kInvalidProtoDepth;
1005 int depth2 = kInvalidProtoDepth;
1006 bool can_do_fast_api_call = false;
1007 if (optimization.is_simple_api_call() &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001008 !lookup->holder()->IsGlobalObject()) {
1009 depth1 = optimization.GetPrototypeDepthOfExpectedType(
1010 object, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001011 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001012 depth2 = optimization.GetPrototypeDepthOfExpectedType(
1013 interceptor_holder, Handle<JSObject>(lookup->holder()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001014 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001015 can_do_fast_api_call =
1016 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001017 }
1018
1019 __ IncrementCounter(counters->call_const_interceptor(), 1,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001020 scratch1, scratch2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001021
1022 if (can_do_fast_api_call) {
1023 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
1024 scratch1, scratch2);
1025 ReserveSpaceForFastApiCall(masm, scratch1);
1026 }
1027
1028 // Check that the maps from receiver to interceptor's holder
1029 // haven't changed and thus we can invoke interceptor.
1030 Label miss_cleanup;
1031 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
1032 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001033 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
1034 scratch1, scratch2, scratch3,
1035 name, depth1, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001036
1037 // Invoke an interceptor and if it provides a value,
1038 // branch to |regular_invoke|.
1039 Label regular_invoke;
1040 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
1041 &regular_invoke);
1042
1043 // Interceptor returned nothing for this property. Try to use cached
1044 // constant function.
1045
1046 // Check that the maps from interceptor's holder to constant function's
1047 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001048 if (*interceptor_holder != lookup->holder()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001049 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001050 Handle<JSObject>(lookup->holder()),
1051 scratch1, scratch2, scratch3,
1052 name, depth2, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001053 } else {
1054 // CheckPrototypes has a side effect of fetching a 'holder'
1055 // for API (object which is instanceof for the signature). It's
1056 // safe to omit it here, as if present, it should be fetched
1057 // by the previous CheckPrototypes.
1058 ASSERT(depth2 == kInvalidProtoDepth);
1059 }
1060
1061 // Invoke function.
1062 if (can_do_fast_api_call) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001063 GenerateFastApiDirectCall(masm, optimization, arguments_.immediate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001064 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001065 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
1066 ? CALL_AS_FUNCTION
1067 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001068 Handle<JSFunction> function = optimization.constant_function();
1069 ParameterCount expected(function);
1070 __ InvokeFunction(function, expected, arguments_,
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001071 JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001072 }
1073
1074 // Deferred code for fast API call case---clean preallocated space.
1075 if (can_do_fast_api_call) {
1076 __ bind(&miss_cleanup);
1077 FreeSpaceForFastApiCall(masm);
1078 __ Branch(miss_label);
1079 }
1080
1081 // Invoke a regular function.
1082 __ bind(&regular_invoke);
1083 if (can_do_fast_api_call) {
1084 FreeSpaceForFastApiCall(masm);
1085 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00001086 }
1087
1088 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001089 Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001090 Register receiver,
1091 Register scratch1,
1092 Register scratch2,
1093 Register scratch3,
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001094 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001095 Handle<JSObject> interceptor_holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001096 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001097 Register holder =
1098 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001099 scratch1, scratch2, scratch3,
1100 name, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001101
1102 // Call a runtime function to load the interceptor property.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001103 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001104 // Save the name_ register across the call.
1105 __ push(name_);
1106
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001107 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001108
1109 __ CallExternalReference(
1110 ExternalReference(
1111 IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
1112 masm->isolate()),
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001113 6);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001114 // Restore the name_ register.
1115 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001116 // Leave the internal frame.
lrn@chromium.org7516f052011-03-30 08:52:27 +00001117 }
1118
1119 void LoadWithInterceptor(MacroAssembler* masm,
1120 Register receiver,
1121 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001122 Handle<JSObject> holder_obj,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001123 Register scratch,
1124 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001125 {
1126 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001127
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001128 __ Push(holder, name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001129 CompileCallLoadPropertyWithInterceptor(masm,
1130 receiver,
1131 holder,
1132 name_,
1133 holder_obj);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001134 __ pop(name_); // Restore the name.
1135 __ pop(receiver); // Restore the holder.
1136 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001137 // If interceptor returns no-result sentinel, call the constant function.
1138 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
1139 __ Branch(interceptor_succeeded, ne, v0, Operand(scratch));
lrn@chromium.org7516f052011-03-30 08:52:27 +00001140 }
1141
1142 StubCompiler* stub_compiler_;
1143 const ParameterCount& arguments_;
1144 Register name_;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001145 Code::ExtraICState extra_ic_state_;
lrn@chromium.org7516f052011-03-30 08:52:27 +00001146};
1147
1148
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001149// Calls GenerateCheckPropertyCell for each global object in the prototype chain
1150// from object to (but not including) holder.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001151static void GenerateCheckPropertyCells(MacroAssembler* masm,
1152 Handle<JSObject> object,
1153 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001154 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001155 Register scratch,
1156 Label* miss) {
1157 Handle<JSObject> current = object;
1158 while (!current.is_identical_to(holder)) {
1159 if (current->IsGlobalObject()) {
1160 GenerateCheckPropertyCell(masm,
1161 Handle<GlobalObject>::cast(current),
1162 name,
1163 scratch,
1164 miss);
1165 }
1166 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
1167 }
1168}
1169
1170
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001171// Convert and store int passed in register ival to IEEE 754 single precision
1172// floating point value at memory location (dst + 4 * wordoffset)
1173// If FPU is available use it for conversion.
1174static void StoreIntAsFloat(MacroAssembler* masm,
1175 Register dst,
1176 Register wordoffset,
1177 Register ival,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001178 Register scratch1) {
1179 __ mtc1(ival, f0);
1180 __ cvt_s_w(f0, f0);
1181 __ sll(scratch1, wordoffset, 2);
1182 __ addu(scratch1, dst, scratch1);
1183 __ swc1(f0, MemOperand(scratch1, 0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001184}
1185
1186
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001187void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001188 __ Jump(code, RelocInfo::CODE_TARGET);
1189}
1190
1191
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001192#undef __
1193#define __ ACCESS_MASM(masm())
1194
1195
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001196Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
1197 Register object_reg,
1198 Handle<JSObject> holder,
1199 Register holder_reg,
1200 Register scratch1,
1201 Register scratch2,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001202 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001203 int save_at_depth,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001204 Label* miss,
1205 PrototypeCheckType check) {
1206 Handle<JSObject> first = object;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001207 // Make sure there's no overlap between holder and object registers.
1208 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1209 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1210 && !scratch2.is(scratch1));
1211
1212 // Keep track of the current object in register reg.
1213 Register reg = object_reg;
1214 int depth = 0;
1215
1216 if (save_at_depth == depth) {
1217 __ sw(reg, MemOperand(sp));
1218 }
1219
1220 // Check the maps in the prototype chain.
1221 // Traverse the prototype chain from the object and do map checks.
1222 Handle<JSObject> current = object;
1223 while (!current.is_identical_to(holder)) {
1224 ++depth;
1225
1226 // Only global objects and objects that do not require access
1227 // checks are allowed in stubs.
1228 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1229
1230 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
1231 if (!current->HasFastProperties() &&
1232 !current->IsJSGlobalObject() &&
1233 !current->IsJSGlobalProxy()) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001234 if (!name->IsUniqueName()) {
1235 ASSERT(name->IsString());
1236 name = factory()->InternalizeString(Handle<String>::cast(name));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001237 }
1238 ASSERT(current->property_dictionary()->FindEntry(*name) ==
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001239 NameDictionary::kNotFound);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001240
1241 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1242 scratch1, scratch2);
1243
1244 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1245 reg = holder_reg; // From now on the object will be in holder_reg.
1246 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1247 } else {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001248 Register map_reg = scratch1;
1249 if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) {
1250 Handle<Map> current_map(current->map());
1251 // CheckMap implicitly loads the map of |reg| into |map_reg|.
1252 __ CheckMap(reg, map_reg, current_map, miss, DONT_DO_SMI_CHECK,
1253 ALLOW_ELEMENT_TRANSITION_MAPS);
1254 } else {
1255 __ lw(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
1256 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001257 // Check access rights to the global object. This has to happen after
1258 // the map check so that we know that the object is actually a global
1259 // object.
1260 if (current->IsJSGlobalProxy()) {
1261 __ CheckAccessGlobalProxy(reg, scratch2, miss);
1262 }
1263 reg = holder_reg; // From now on the object will be in holder_reg.
1264
1265 if (heap()->InNewSpace(*prototype)) {
1266 // The prototype is in new space; we cannot store a reference to it
1267 // in the code. Load it from the map.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001268 __ lw(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001269 } else {
1270 // The prototype is in old space; load it directly.
1271 __ li(reg, Operand(prototype));
1272 }
1273 }
1274
1275 if (save_at_depth == depth) {
1276 __ sw(reg, MemOperand(sp));
1277 }
1278
1279 // Go to the next object in the prototype chain.
1280 current = prototype;
1281 }
1282
1283 // Log the check depth.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001284 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001285
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001286 if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) {
1287 // Check the holder map.
1288 __ CheckMap(reg, scratch1, Handle<Map>(holder->map()), miss,
1289 DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
1290 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001291
1292 // Perform security check for access to the global object.
1293 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1294 if (holder->IsJSGlobalProxy()) {
1295 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1296 }
1297
1298 // If we've skipped any global objects, it's not enough to verify that
1299 // their maps haven't changed. We also need to check that the property
1300 // cell for the property is still empty.
1301 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1302
1303 // Return the register containing the holder.
1304 return reg;
1305}
1306
1307
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001308void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success,
1309 Label* miss) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001310 if (!miss->is_unused()) {
1311 __ Branch(success);
1312 __ bind(miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001313 TailCallBuiltin(masm(), MissBuiltin(kind()));
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001314 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001315}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001316
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001317
1318Register BaseLoadStubCompiler::CallbackHandlerFrontend(
1319 Handle<JSObject> object,
1320 Register object_reg,
1321 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001322 Handle<Name> name,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001323 Label* success,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001324 Handle<ExecutableAccessorInfo> callback) {
1325 Label miss;
1326
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001327 Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001328
1329 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
1330 ASSERT(!reg.is(scratch2()));
1331 ASSERT(!reg.is(scratch3()));
1332 ASSERT(!reg.is(scratch4()));
1333
1334 // Load the properties dictionary.
1335 Register dictionary = scratch4();
1336 __ lw(dictionary, FieldMemOperand(reg, JSObject::kPropertiesOffset));
1337
1338 // Probe the dictionary.
1339 Label probe_done;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001340 NameDictionaryLookupStub::GeneratePositiveLookup(masm(),
1341 &miss,
1342 &probe_done,
1343 dictionary,
1344 this->name(),
1345 scratch2(),
1346 scratch3());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001347 __ bind(&probe_done);
1348
1349 // If probing finds an entry in the dictionary, scratch3 contains the
1350 // pointer into the dictionary. Check that the value is the callback.
1351 Register pointer = scratch3();
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001352 const int kElementsStartOffset = NameDictionary::kHeaderSize +
1353 NameDictionary::kElementsStartIndex * kPointerSize;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001354 const int kValueOffset = kElementsStartOffset + kPointerSize;
1355 __ lw(scratch2(), FieldMemOperand(pointer, kValueOffset));
1356 __ Branch(&miss, ne, scratch2(), Operand(callback));
1357 }
1358
1359 HandlerFrontendFooter(success, &miss);
1360 return reg;
1361}
1362
1363
1364void BaseLoadStubCompiler::NonexistentHandlerFrontend(
1365 Handle<JSObject> object,
1366 Handle<JSObject> last,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001367 Handle<Name> name,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001368 Label* success,
1369 Handle<GlobalObject> global) {
1370 Label miss;
1371
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001372 HandlerFrontendHeader(object, receiver(), last, name, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001373
1374 // If the last object in the prototype chain is a global object,
1375 // check that the global property cell is empty.
1376 if (!global.is_null()) {
1377 GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
1378 }
1379
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001380 HandlerFrontendFooter(success, &miss);
1381}
1382
1383
1384void BaseLoadStubCompiler::GenerateLoadField(Register reg,
1385 Handle<JSObject> holder,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001386 PropertyIndex field,
1387 Representation representation) {
1388 if (!reg.is(receiver())) __ mov(receiver(), reg);
1389 if (kind() == Code::LOAD_IC) {
1390 LoadFieldStub stub(field.is_inobject(holder),
1391 field.translate(holder),
1392 representation);
1393 GenerateTailCall(masm(), stub.GetCode(isolate()));
1394 } else {
1395 KeyedLoadFieldStub stub(field.is_inobject(holder),
1396 field.translate(holder),
1397 representation);
1398 GenerateTailCall(masm(), stub.GetCode(isolate()));
1399 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001400}
1401
1402
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001403void BaseLoadStubCompiler::GenerateLoadConstant(Handle<JSFunction> value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001404 // Return the constant value.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001405 __ LoadHeapObject(v0, value);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001406 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001407}
1408
1409
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001410void BaseLoadStubCompiler::GenerateLoadCallback(
1411 Register reg,
1412 Handle<ExecutableAccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001413 // Build AccessorInfo::args_ list on the stack and push property name below
1414 // the exit frame to make GC aware of them and store pointers to them.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001415 __ push(receiver());
1416 __ mov(scratch2(), sp); // scratch2 = AccessorInfo::args_
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001417 if (heap()->InNewSpace(callback->data())) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001418 __ li(scratch3(), callback);
1419 __ lw(scratch3(), FieldMemOperand(scratch3(),
1420 ExecutableAccessorInfo::kDataOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001421 } else {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001422 __ li(scratch3(), Handle<Object>(callback->data(), isolate()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001423 }
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001424 __ Subu(sp, sp, 5 * kPointerSize);
1425 __ sw(reg, MemOperand(sp, 4 * kPointerSize));
1426 __ sw(scratch3(), MemOperand(sp, 3 * kPointerSize));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001427 __ li(scratch3(),
1428 Operand(ExternalReference::isolate_address(isolate())));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001429 __ LoadRoot(scratch4(), Heap::kUndefinedValueRootIndex);
1430 __ sw(scratch3(), MemOperand(sp, 2 * kPointerSize));
1431 __ sw(scratch4(), MemOperand(sp, 1 * kPointerSize));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001432 __ sw(name(), MemOperand(sp, 0 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001433
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001434 __ mov(a2, scratch2()); // Saved in case scratch2 == a1.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001435 __ mov(a1, sp); // a1 (first argument - see note below) = Handle<Name>
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001436
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001437 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
1438 // struct from the function (which is currently the case). This means we pass
1439 // the arguments in a1-a2 instead of a0-a1. TryCallApiFunctionAndReturn
1440 // will handle setting up a0.
1441
1442 const int kApiStackSpace = 1;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001443 FrameScope frame_scope(masm(), StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001444 __ EnterExitFrame(false, kApiStackSpace);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001445
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001446 // Create AccessorInfo instance on the stack above the exit frame with
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001447 // scratch2 (internal::Object** args_) as the data.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001448 __ sw(a2, MemOperand(sp, kPointerSize));
1449 // a2 (second argument - see note above) = AccessorInfo&
1450 __ Addu(a2, sp, kPointerSize);
1451
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001452 const int kStackUnwindSpace = kFastApiCallArguments + 1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001453 Address getter_address = v8::ToCData<Address>(callback->getter());
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001454 bool returns_handle =
1455 !CallbackTable::ReturnsVoid(isolate(), getter_address);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001456 ApiFunction fun(getter_address);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001457 ExternalReference::Type type =
1458 returns_handle ?
1459 ExternalReference::DIRECT_GETTER_CALL :
1460 ExternalReference::DIRECT_GETTER_CALL_NEW;
1461
1462 ExternalReference ref = ExternalReference(&fun, type, isolate());
1463 __ CallApiFunctionAndReturn(ref,
1464 kStackUnwindSpace,
1465 returns_handle,
1466 3);
ager@chromium.org5c838252010-02-19 08:53:10 +00001467}
1468
1469
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001470void BaseLoadStubCompiler::GenerateLoadInterceptor(
1471 Register holder_reg,
1472 Handle<JSObject> object,
1473 Handle<JSObject> interceptor_holder,
1474 LookupResult* lookup,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001475 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001476 ASSERT(interceptor_holder->HasNamedInterceptor());
1477 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1478
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001479 // So far the most popular follow ups for interceptor loads are FIELD
1480 // and CALLBACKS, so inline only them, other cases may be added
1481 // later.
1482 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001483 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001484 if (lookup->IsField()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001485 compile_followup_inline = true;
1486 } else if (lookup->type() == CALLBACKS &&
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001487 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
1488 ExecutableAccessorInfo* callback =
1489 ExecutableAccessorInfo::cast(lookup->GetCallbackObject());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001490 compile_followup_inline = callback->getter() != NULL &&
1491 callback->IsCompatibleReceiver(*object);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001492 }
1493 }
1494
1495 if (compile_followup_inline) {
1496 // Compile the interceptor call, followed by inline code to load the
1497 // property from further up the prototype chain if the call fails.
1498 // Check that the maps haven't changed.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001499 ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001500
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001501 // Preserve the receiver register explicitly whenever it is different from
1502 // the holder and it is needed should the interceptor return without any
1503 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1504 // the FIELD case might cause a miss during the prototype check.
1505 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001506 bool must_preserve_receiver_reg = !receiver().is(holder_reg) &&
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001507 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1508
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001509 // Save necessary data before invoking an interceptor.
1510 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001511 {
1512 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001513 if (must_preserve_receiver_reg) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001514 __ Push(receiver(), holder_reg, this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001515 } else {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001516 __ Push(holder_reg, this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001517 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001518 // Invoke an interceptor. Note: map checks from receiver to
1519 // interceptor's holder has been compiled before (see a caller
1520 // of this method).
1521 CompileCallLoadPropertyWithInterceptor(masm(),
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001522 receiver(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001523 holder_reg,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001524 this->name(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001525 interceptor_holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001526 // Check if interceptor provided a value for property. If it's
1527 // the case, return immediately.
1528 Label interceptor_failed;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001529 __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
1530 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001531 frame_scope.GenerateLeaveFrame();
1532 __ Ret();
1533
1534 __ bind(&interceptor_failed);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001535 __ pop(this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001536 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001537 if (must_preserve_receiver_reg) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001538 __ pop(receiver());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001539 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001540 // Leave the internal frame.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001541 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001542 GenerateLoadPostInterceptor(holder_reg, interceptor_holder, name, lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001543 } else { // !compile_followup_inline
1544 // Call the runtime system to load the interceptor.
1545 // Check that the maps haven't changed.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001546 PushInterceptorArguments(masm(), receiver(), holder_reg,
1547 this->name(), interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001548
1549 ExternalReference ref = ExternalReference(
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001550 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001551 __ TailCallExternalReference(ref, 6, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001552 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001553}
1554
1555
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001556void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001557 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001558 __ Branch(miss, ne, a2, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001559 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001560}
1561
1562
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001563void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1564 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001565 Handle<Name> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001566 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001567 ASSERT(holder->IsGlobalObject());
1568
1569 // Get the number of arguments.
1570 const int argc = arguments().immediate();
1571
1572 // Get the receiver from the stack.
1573 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1574
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001575 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001576 __ JumpIfSmi(a0, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001577 CheckPrototypes(object, a0, holder, a3, a1, t0, name, miss);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001578}
1579
1580
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001581void CallStubCompiler::GenerateLoadFunctionFromCell(
1582 Handle<JSGlobalPropertyCell> cell,
1583 Handle<JSFunction> function,
1584 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001585 // Get the value from the cell.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001586 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001587 __ lw(a1, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
1588
1589 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001590 if (heap()->InNewSpace(*function)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001591 // We can't embed a pointer to a function in new space so we have
1592 // to verify that the shared function info is unchanged. This has
1593 // the nice side effect that multiple closures based on the same
1594 // function can all use this call IC. Before we load through the
1595 // function, we have to verify that it still is a function.
1596 __ JumpIfSmi(a1, miss);
1597 __ GetObjectType(a1, a3, a3);
1598 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
1599
1600 // Check the shared function info. Make sure it hasn't changed.
1601 __ li(a3, Handle<SharedFunctionInfo>(function->shared()));
1602 __ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
1603 __ Branch(miss, ne, t0, Operand(a3));
1604 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001605 __ Branch(miss, ne, a1, Operand(function));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001606 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001607}
1608
1609
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001610void CallStubCompiler::GenerateMissBranch() {
1611 Handle<Code> code =
danno@chromium.org40cb8782011-05-25 07:58:50 +00001612 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1613 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001614 extra_state_);
1615 __ Jump(code, RelocInfo::CODE_TARGET);
1616}
1617
1618
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001619Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1620 Handle<JSObject> holder,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001621 PropertyIndex index,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001622 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001623 // ----------- S t a t e -------------
1624 // -- a2 : name
1625 // -- ra : return address
1626 // -----------------------------------
1627 Label miss;
1628
1629 GenerateNameCheck(name, &miss);
1630
1631 const int argc = arguments().immediate();
1632
1633 // Get the receiver of the function from the stack into a0.
1634 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1635 // Check that the receiver isn't a smi.
1636 __ JumpIfSmi(a0, &miss, t0);
1637
1638 // Do the right check and compute the holder register.
1639 Register reg = CheckPrototypes(object, a0, holder, a1, a3, t0, name, &miss);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001640 GenerateFastPropertyLoad(masm(), a1, reg, index.is_inobject(holder),
1641 index.translate(holder), Representation::Tagged());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001642
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001643 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001644
1645 // Handle call cache miss.
1646 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001647 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001648
1649 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001650 return GetCode(Code::FIELD, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001651}
1652
1653
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001654Handle<Code> CallStubCompiler::CompileArrayPushCall(
1655 Handle<Object> object,
1656 Handle<JSObject> holder,
1657 Handle<JSGlobalPropertyCell> cell,
1658 Handle<JSFunction> function,
1659 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001660 // ----------- S t a t e -------------
1661 // -- a2 : name
1662 // -- ra : return address
1663 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1664 // -- ...
1665 // -- sp[argc * 4] : receiver
1666 // -----------------------------------
1667
1668 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001669 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001670
1671 Label miss;
1672
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001673 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001674
1675 Register receiver = a1;
1676
1677 // Get the receiver from the stack.
1678 const int argc = arguments().immediate();
1679 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1680
1681 // Check that the receiver isn't a smi.
1682 __ JumpIfSmi(receiver, &miss);
1683
1684 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001685 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, a3, v0, t0,
1686 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001687
1688 if (argc == 0) {
1689 // Nothing to do, just return the length.
1690 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1691 __ Drop(argc + 1);
1692 __ Ret();
1693 } else {
1694 Label call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001695 if (argc == 1) { // Otherwise fall through to call the builtin.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001696 Label attempt_to_grow_elements, with_write_barrier, check_double;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001697
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001698 Register elements = t2;
1699 Register end_elements = t1;
1700 // Get the elements array of the object.
1701 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1702
1703 // Check that the elements are in fast mode and writable.
1704 __ CheckMap(elements,
1705 v0,
1706 Heap::kFixedArrayMapRootIndex,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001707 &check_double,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001708 DONT_DO_SMI_CHECK);
1709
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001710 // Get the array's length into v0 and calculate new length.
1711 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1712 STATIC_ASSERT(kSmiTagSize == 1);
1713 STATIC_ASSERT(kSmiTag == 0);
1714 __ Addu(v0, v0, Operand(Smi::FromInt(argc)));
1715
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001716 // Get the elements' length.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001717 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1718
1719 // Check if we could survive without allocation.
1720 __ Branch(&attempt_to_grow_elements, gt, v0, Operand(t0));
1721
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001722 // Check if value is a smi.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001723 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1724 __ JumpIfNotSmi(t0, &with_write_barrier);
1725
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001726 // Save new length.
1727 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1728
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001729 // Store the value.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001730 // We may need a register containing the address end_elements below,
1731 // so write back the value in end_elements.
1732 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1733 __ Addu(end_elements, elements, end_elements);
1734 const int kEndElementsOffset =
1735 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001736 __ Addu(end_elements, end_elements, kEndElementsOffset);
1737 __ sw(t0, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001738
1739 // Check for a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001740 __ Drop(argc + 1);
1741 __ Ret();
1742
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001743 __ bind(&check_double);
1744
1745 // Check that the elements are in fast mode and writable.
1746 __ CheckMap(elements,
1747 a0,
1748 Heap::kFixedDoubleArrayMapRootIndex,
1749 &call_builtin,
1750 DONT_DO_SMI_CHECK);
1751
1752 // Get the array's length into r0 and calculate new length.
1753 __ lw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1754 STATIC_ASSERT(kSmiTagSize == 1);
1755 STATIC_ASSERT(kSmiTag == 0);
1756 __ Addu(a0, a0, Operand(Smi::FromInt(argc)));
1757
1758 // Get the elements' length.
1759 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1760
1761 // Check if we could survive without allocation.
1762 __ Branch(&call_builtin, gt, a0, Operand(t0));
1763
1764 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1765 __ StoreNumberToDoubleElements(
1766 t0, a0, elements, a3, t1, a2, t5,
1767 &call_builtin, argc * kDoubleSize);
1768
1769 // Save new length.
1770 __ sw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1771
1772 // Check for a smi.
1773 __ Drop(argc + 1);
1774 __ Ret();
1775
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001776 __ bind(&with_write_barrier);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001777
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001778 __ lw(a3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1779
1780 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
1781 Label fast_object, not_fast_object;
1782 __ CheckFastObjectElements(a3, t3, &not_fast_object);
1783 __ jmp(&fast_object);
1784 // In case of fast smi-only, convert to fast object, otherwise bail out.
1785 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001786 __ CheckFastSmiElements(a3, t3, &call_builtin);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001787
1788 __ lw(t3, FieldMemOperand(t0, HeapObject::kMapOffset));
1789 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
1790 __ Branch(&call_builtin, eq, t3, Operand(at));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001791 // edx: receiver
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001792 // a3: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001793 Label try_holey_map;
1794 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001795 FAST_ELEMENTS,
1796 a3,
1797 t3,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001798 &try_holey_map);
1799 __ mov(a2, receiver);
1800 ElementsTransitionGenerator::
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001801 GenerateMapChangeElementsTransition(masm(),
1802 DONT_TRACK_ALLOCATION_SITE,
1803 NULL);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001804 __ jmp(&fast_object);
1805
1806 __ bind(&try_holey_map);
1807 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1808 FAST_HOLEY_ELEMENTS,
1809 a3,
1810 t3,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001811 &call_builtin);
1812 __ mov(a2, receiver);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001813 ElementsTransitionGenerator::
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001814 GenerateMapChangeElementsTransition(masm(),
1815 DONT_TRACK_ALLOCATION_SITE,
1816 NULL);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001817 __ bind(&fast_object);
1818 } else {
1819 __ CheckFastObjectElements(a3, a3, &call_builtin);
1820 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001821
1822 // Save new length.
1823 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1824
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001825 // Store the value.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001826 // We may need a register containing the address end_elements below,
1827 // so write back the value in end_elements.
1828 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1829 __ Addu(end_elements, elements, end_elements);
1830 __ Addu(end_elements, end_elements, kEndElementsOffset);
1831 __ sw(t0, MemOperand(end_elements));
1832
1833 __ RecordWrite(elements,
1834 end_elements,
1835 t0,
1836 kRAHasNotBeenSaved,
1837 kDontSaveFPRegs,
1838 EMIT_REMEMBERED_SET,
1839 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001840 __ Drop(argc + 1);
1841 __ Ret();
1842
1843 __ bind(&attempt_to_grow_elements);
1844 // v0: array's length + 1.
1845 // t0: elements' length.
1846
1847 if (!FLAG_inline_new) {
1848 __ Branch(&call_builtin);
1849 }
1850
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001851 __ lw(a2, MemOperand(sp, (argc - 1) * kPointerSize));
1852 // Growing elements that are SMI-only requires special handling in case
1853 // the new element is non-Smi. For now, delegate to the builtin.
1854 Label no_fast_elements_check;
1855 __ JumpIfSmi(a2, &no_fast_elements_check);
1856 __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1857 __ CheckFastObjectElements(t3, t3, &call_builtin);
1858 __ bind(&no_fast_elements_check);
1859
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001860 ExternalReference new_space_allocation_top =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001861 ExternalReference::new_space_allocation_top_address(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001862 ExternalReference new_space_allocation_limit =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001863 ExternalReference::new_space_allocation_limit_address(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001864
1865 const int kAllocationDelta = 4;
1866 // Load top and check if it is the end of elements.
1867 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1868 __ Addu(end_elements, elements, end_elements);
1869 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset));
1870 __ li(t3, Operand(new_space_allocation_top));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001871 __ lw(a3, MemOperand(t3));
1872 __ Branch(&call_builtin, ne, end_elements, Operand(a3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001873
1874 __ li(t5, Operand(new_space_allocation_limit));
1875 __ lw(t5, MemOperand(t5));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001876 __ Addu(a3, a3, Operand(kAllocationDelta * kPointerSize));
1877 __ Branch(&call_builtin, hi, a3, Operand(t5));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001878
1879 // We fit and could grow elements.
1880 // Update new_space_allocation_top.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001881 __ sw(a3, MemOperand(t3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001882 // Push the argument.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001883 __ sw(a2, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001884 // Fill the rest with holes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001885 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001886 for (int i = 1; i < kAllocationDelta; i++) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001887 __ sw(a3, MemOperand(end_elements, i * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001888 }
1889
1890 // Update elements' and array's sizes.
1891 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1892 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta)));
1893 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1894
1895 // Elements are in new space, so write barrier is not required.
1896 __ Drop(argc + 1);
1897 __ Ret();
1898 }
1899 __ bind(&call_builtin);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001900 __ TailCallExternalReference(
1901 ExternalReference(Builtins::c_ArrayPush, isolate()), argc + 1, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001902 }
1903
1904 // Handle call cache miss.
1905 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001906 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001907
1908 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001909 return GetCode(function);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001910}
1911
1912
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001913Handle<Code> CallStubCompiler::CompileArrayPopCall(
1914 Handle<Object> object,
1915 Handle<JSObject> holder,
1916 Handle<JSGlobalPropertyCell> cell,
1917 Handle<JSFunction> function,
1918 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001919 // ----------- S t a t e -------------
1920 // -- a2 : name
1921 // -- ra : return address
1922 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1923 // -- ...
1924 // -- sp[argc * 4] : receiver
1925 // -----------------------------------
1926
1927 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001928 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001929
1930 Label miss, return_undefined, call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001931 Register receiver = a1;
1932 Register elements = a3;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001933 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001934
1935 // Get the receiver from the stack.
1936 const int argc = arguments().immediate();
1937 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001938 // Check that the receiver isn't a smi.
1939 __ JumpIfSmi(receiver, &miss);
1940
1941 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001942 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, elements,
1943 t0, v0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001944
1945 // Get the elements array of the object.
1946 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1947
1948 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001949 __ CheckMap(elements,
1950 v0,
1951 Heap::kFixedArrayMapRootIndex,
1952 &call_builtin,
1953 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001954
1955 // Get the array's length into t0 and calculate new length.
1956 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1957 __ Subu(t0, t0, Operand(Smi::FromInt(1)));
1958 __ Branch(&return_undefined, lt, t0, Operand(zero_reg));
1959
1960 // Get the last element.
1961 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1962 STATIC_ASSERT(kSmiTagSize == 1);
1963 STATIC_ASSERT(kSmiTag == 0);
1964 // We can't address the last element in one operation. Compute the more
1965 // expensive shift first, and use an offset later on.
1966 __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize);
1967 __ Addu(elements, elements, t1);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001968 __ lw(v0, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001969 __ Branch(&call_builtin, eq, v0, Operand(t2));
1970
1971 // Set the array's length.
1972 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1973
1974 // Fill with the hole.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001975 __ sw(t2, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001976 __ Drop(argc + 1);
1977 __ Ret();
1978
1979 __ bind(&return_undefined);
1980 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
1981 __ Drop(argc + 1);
1982 __ Ret();
1983
1984 __ bind(&call_builtin);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001985 __ TailCallExternalReference(
1986 ExternalReference(Builtins::c_ArrayPop, isolate()), argc + 1, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001987
1988 // Handle call cache miss.
1989 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001990 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001991
1992 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001993 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001994}
1995
1996
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001997Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1998 Handle<Object> object,
1999 Handle<JSObject> holder,
2000 Handle<JSGlobalPropertyCell> cell,
2001 Handle<JSFunction> function,
2002 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002003 // ----------- S t a t e -------------
2004 // -- a2 : function name
2005 // -- ra : return address
2006 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2007 // -- ...
2008 // -- sp[argc * 4] : receiver
2009 // -----------------------------------
2010
2011 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002012 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002013
2014 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002015 Label miss;
2016 Label name_miss;
2017 Label index_out_of_range;
2018
2019 Label* index_out_of_range_label = &index_out_of_range;
2020
danno@chromium.org40cb8782011-05-25 07:58:50 +00002021 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002022 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002023 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002024 index_out_of_range_label = &miss;
2025 }
2026
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002027 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002028
2029 // Check that the maps starting from the prototype haven't changed.
2030 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2031 Context::STRING_FUNCTION_INDEX,
2032 v0,
2033 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002034 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002035 CheckPrototypes(
2036 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2037 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002038
2039 Register receiver = a1;
2040 Register index = t1;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002041 Register result = v0;
2042 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
2043 if (argc > 0) {
2044 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
2045 } else {
2046 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
2047 }
2048
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002049 StringCharCodeAtGenerator generator(receiver,
2050 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002051 result,
2052 &miss, // When not a string.
2053 &miss, // When not a number.
2054 index_out_of_range_label,
2055 STRING_INDEX_IS_NUMBER);
2056 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002057 __ Drop(argc + 1);
2058 __ Ret();
2059
2060 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002061 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002062
2063 if (index_out_of_range.is_linked()) {
2064 __ bind(&index_out_of_range);
2065 __ LoadRoot(v0, Heap::kNanValueRootIndex);
2066 __ Drop(argc + 1);
2067 __ Ret();
2068 }
2069
2070 __ bind(&miss);
2071 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002072 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002073 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002074 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002075
2076 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002077 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002078}
2079
2080
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002081Handle<Code> CallStubCompiler::CompileStringCharAtCall(
2082 Handle<Object> object,
2083 Handle<JSObject> holder,
2084 Handle<JSGlobalPropertyCell> cell,
2085 Handle<JSFunction> function,
2086 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002087 // ----------- S t a t e -------------
2088 // -- a2 : function name
2089 // -- ra : return address
2090 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2091 // -- ...
2092 // -- sp[argc * 4] : receiver
2093 // -----------------------------------
2094
2095 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002096 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002097
2098 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002099 Label miss;
2100 Label name_miss;
2101 Label index_out_of_range;
2102 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00002103 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002104 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002105 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002106 index_out_of_range_label = &miss;
2107 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002108 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002109
2110 // Check that the maps starting from the prototype haven't changed.
2111 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2112 Context::STRING_FUNCTION_INDEX,
2113 v0,
2114 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002115 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002116 CheckPrototypes(
2117 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2118 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002119
2120 Register receiver = v0;
2121 Register index = t1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00002122 Register scratch = a3;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002123 Register result = v0;
2124 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
2125 if (argc > 0) {
2126 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
2127 } else {
2128 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
2129 }
2130
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002131 StringCharAtGenerator generator(receiver,
2132 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00002133 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002134 result,
2135 &miss, // When not a string.
2136 &miss, // When not a number.
2137 index_out_of_range_label,
2138 STRING_INDEX_IS_NUMBER);
2139 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002140 __ Drop(argc + 1);
2141 __ Ret();
2142
2143 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002144 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002145
2146 if (index_out_of_range.is_linked()) {
2147 __ bind(&index_out_of_range);
ulan@chromium.org750145a2013-03-07 15:14:13 +00002148 __ LoadRoot(v0, Heap::kempty_stringRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002149 __ Drop(argc + 1);
2150 __ Ret();
2151 }
2152
2153 __ bind(&miss);
2154 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002155 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002156 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002157 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002158
2159 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002160 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002161}
2162
2163
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002164Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
2165 Handle<Object> object,
2166 Handle<JSObject> holder,
2167 Handle<JSGlobalPropertyCell> cell,
2168 Handle<JSFunction> function,
2169 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002170 // ----------- S t a t e -------------
2171 // -- a2 : function name
2172 // -- ra : return address
2173 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2174 // -- ...
2175 // -- sp[argc * 4] : receiver
2176 // -----------------------------------
2177
2178 const int argc = arguments().immediate();
2179
2180 // If the object is not a JSObject or we got an unexpected number of
2181 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002182 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002183
2184 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002185 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002186
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002187 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002188 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
2189
2190 STATIC_ASSERT(kSmiTag == 0);
2191 __ JumpIfSmi(a1, &miss);
2192
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002193 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2194 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002195 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002196 ASSERT(cell->value() == *function);
2197 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2198 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002199 GenerateLoadFunctionFromCell(cell, function, &miss);
2200 }
2201
2202 // Load the char code argument.
2203 Register code = a1;
2204 __ lw(code, MemOperand(sp, 0 * kPointerSize));
2205
2206 // Check the code is a smi.
2207 Label slow;
2208 STATIC_ASSERT(kSmiTag == 0);
2209 __ JumpIfNotSmi(code, &slow);
2210
2211 // Convert the smi code to uint16.
2212 __ And(code, code, Operand(Smi::FromInt(0xffff)));
2213
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002214 StringCharFromCodeGenerator generator(code, v0);
2215 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002216 __ Drop(argc + 1);
2217 __ Ret();
2218
2219 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002220 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002221
2222 // Tail call the full function. We do not have to patch the receiver
2223 // because the function makes no use of it.
2224 __ bind(&slow);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002225 ParameterCount expected(function);
2226 __ InvokeFunction(function, expected, arguments(),
2227 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002228
2229 __ bind(&miss);
2230 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002231 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002232
2233 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002234 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002235}
2236
2237
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002238Handle<Code> CallStubCompiler::CompileMathFloorCall(
2239 Handle<Object> object,
2240 Handle<JSObject> holder,
2241 Handle<JSGlobalPropertyCell> cell,
2242 Handle<JSFunction> function,
2243 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002244 // ----------- S t a t e -------------
2245 // -- a2 : function name
2246 // -- ra : return address
2247 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2248 // -- ...
2249 // -- sp[argc * 4] : receiver
2250 // -----------------------------------
2251
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002252
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002253 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002254 // If the object is not a JSObject or we got an unexpected number of
2255 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002256 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002257
2258 Label miss, slow;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002259 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002260
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002261 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002262 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002263 STATIC_ASSERT(kSmiTag == 0);
2264 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002265 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2266 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002267 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002268 ASSERT(cell->value() == *function);
2269 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2270 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002271 GenerateLoadFunctionFromCell(cell, function, &miss);
2272 }
2273
2274 // Load the (only) argument into v0.
2275 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2276
2277 // If the argument is a smi, just return.
2278 STATIC_ASSERT(kSmiTag == 0);
2279 __ And(t0, v0, Operand(kSmiTagMask));
2280 __ Drop(argc + 1, eq, t0, Operand(zero_reg));
2281 __ Ret(eq, t0, Operand(zero_reg));
2282
danno@chromium.org40cb8782011-05-25 07:58:50 +00002283 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002284
2285 Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return;
2286
2287 // If fpu is enabled, we use the floor instruction.
2288
2289 // Load the HeapNumber value.
2290 __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2291
2292 // Backup FCSR.
2293 __ cfc1(a3, FCSR);
2294 // Clearing FCSR clears the exception mask with no side-effects.
2295 __ ctc1(zero_reg, FCSR);
2296 // Convert the argument to an integer.
2297 __ floor_w_d(f0, f0);
2298
2299 // Start checking for special cases.
2300 // Get the argument exponent and clear the sign bit.
2301 __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize));
2302 __ And(t2, t1, Operand(~HeapNumber::kSignMask));
2303 __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord);
2304
2305 // Retrieve FCSR and check for fpu errors.
2306 __ cfc1(t5, FCSR);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002307 __ And(t5, t5, Operand(kFCSRExceptionFlagMask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002308 __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));
2309
2310 // Check for NaN, Infinity, and -Infinity.
2311 // They are invariant through a Math.Floor call, so just
2312 // return the original argument.
2313 __ Subu(t3, t2, Operand(HeapNumber::kExponentMask
2314 >> HeapNumber::kMantissaBitsInTopWord));
2315 __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg));
2316 // We had an overflow or underflow in the conversion. Check if we
2317 // have a big exponent.
2318 // If greater or equal, the argument is already round and in v0.
2319 __ Branch(&restore_fcsr_and_return, ge, t3,
2320 Operand(HeapNumber::kMantissaBits));
2321 __ Branch(&wont_fit_smi);
2322
2323 __ bind(&no_fpu_error);
2324 // Move the result back to v0.
2325 __ mfc1(v0, f0);
2326 // Check if the result fits into a smi.
2327 __ Addu(a1, v0, Operand(0x40000000));
2328 __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg));
2329 // Tag the result.
2330 STATIC_ASSERT(kSmiTag == 0);
2331 __ sll(v0, v0, kSmiTagSize);
2332
2333 // Check for -0.
2334 __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg));
2335 // t1 already holds the HeapNumber exponent.
2336 __ And(t0, t1, Operand(HeapNumber::kSignMask));
2337 // If our HeapNumber is negative it was -0, so load its address and return.
2338 // Else v0 is loaded with 0, so we can also just return.
2339 __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg));
2340 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2341
2342 __ bind(&restore_fcsr_and_return);
2343 // Restore FCSR and return.
2344 __ ctc1(a3, FCSR);
2345
2346 __ Drop(argc + 1);
2347 __ Ret();
2348
2349 __ bind(&wont_fit_smi);
2350 // Restore FCSR and fall to slow case.
2351 __ ctc1(a3, FCSR);
2352
2353 __ bind(&slow);
2354 // Tail call the full function. We do not have to patch the receiver
2355 // because the function makes no use of it.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002356 ParameterCount expected(function);
2357 __ InvokeFunction(function, expected, arguments(),
2358 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002359
2360 __ bind(&miss);
2361 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002362 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002363
2364 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002365 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002366}
2367
2368
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002369Handle<Code> CallStubCompiler::CompileMathAbsCall(
2370 Handle<Object> object,
2371 Handle<JSObject> holder,
2372 Handle<JSGlobalPropertyCell> cell,
2373 Handle<JSFunction> function,
2374 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002375 // ----------- S t a t e -------------
2376 // -- a2 : function name
2377 // -- ra : return address
2378 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2379 // -- ...
2380 // -- sp[argc * 4] : receiver
2381 // -----------------------------------
2382
2383 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002384 // If the object is not a JSObject or we got an unexpected number of
2385 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002386 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002387
2388 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002389
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002390 GenerateNameCheck(name, &miss);
2391 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002392 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002393 STATIC_ASSERT(kSmiTag == 0);
2394 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002395 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2396 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002397 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002398 ASSERT(cell->value() == *function);
2399 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2400 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002401 GenerateLoadFunctionFromCell(cell, function, &miss);
2402 }
2403
2404 // Load the (only) argument into v0.
2405 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2406
2407 // Check if the argument is a smi.
2408 Label not_smi;
2409 STATIC_ASSERT(kSmiTag == 0);
2410 __ JumpIfNotSmi(v0, &not_smi);
2411
2412 // Do bitwise not or do nothing depending on the sign of the
2413 // argument.
2414 __ sra(t0, v0, kBitsPerInt - 1);
2415 __ Xor(a1, v0, t0);
2416
2417 // Add 1 or do nothing depending on the sign of the argument.
2418 __ Subu(v0, a1, t0);
2419
2420 // If the result is still negative, go to the slow case.
2421 // This only happens for the most negative smi.
2422 Label slow;
2423 __ Branch(&slow, lt, v0, Operand(zero_reg));
2424
2425 // Smi case done.
2426 __ Drop(argc + 1);
2427 __ Ret();
2428
2429 // Check if the argument is a heap number and load its exponent and
2430 // sign.
2431 __ bind(&not_smi);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002432 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002433 __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2434
2435 // Check the sign of the argument. If the argument is positive,
2436 // just return it.
2437 Label negative_sign;
2438 __ And(t0, a1, Operand(HeapNumber::kSignMask));
2439 __ Branch(&negative_sign, ne, t0, Operand(zero_reg));
2440 __ Drop(argc + 1);
2441 __ Ret();
2442
2443 // If the argument is negative, clear the sign, and return a new
2444 // number.
2445 __ bind(&negative_sign);
2446 __ Xor(a1, a1, Operand(HeapNumber::kSignMask));
2447 __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2448 __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
2449 __ AllocateHeapNumber(v0, t0, t1, t2, &slow);
2450 __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2451 __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2452 __ Drop(argc + 1);
2453 __ Ret();
2454
2455 // Tail call the full function. We do not have to patch the receiver
2456 // because the function makes no use of it.
2457 __ bind(&slow);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002458 ParameterCount expected(function);
2459 __ InvokeFunction(function, expected, arguments(),
2460 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002461
2462 __ bind(&miss);
2463 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002464 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002465
2466 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002467 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002468}
2469
2470
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002471Handle<Code> CallStubCompiler::CompileFastApiCall(
lrn@chromium.org7516f052011-03-30 08:52:27 +00002472 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002473 Handle<Object> object,
2474 Handle<JSObject> holder,
2475 Handle<JSGlobalPropertyCell> cell,
2476 Handle<JSFunction> function,
2477 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002478
danno@chromium.org40cb8782011-05-25 07:58:50 +00002479 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002480
2481 ASSERT(optimization.is_simple_api_call());
2482 // Bail out if object is a global object as we don't want to
2483 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002484 if (object->IsGlobalObject()) return Handle<Code>::null();
2485 if (!cell.is_null()) return Handle<Code>::null();
2486 if (!object->IsJSObject()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002487 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002488 Handle<JSObject>::cast(object), holder);
2489 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002490
2491 Label miss, miss_before_stack_reserved;
2492
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002493 GenerateNameCheck(name, &miss_before_stack_reserved);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002494
2495 // Get the receiver from the stack.
2496 const int argc = arguments().immediate();
2497 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2498
2499 // Check that the receiver isn't a smi.
2500 __ JumpIfSmi(a1, &miss_before_stack_reserved);
2501
2502 __ IncrementCounter(counters->call_const(), 1, a0, a3);
2503 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2504
2505 ReserveSpaceForFastApiCall(masm(), a0);
2506
2507 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002508 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002509 depth, &miss);
2510
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002511 GenerateFastApiDirectCall(masm(), optimization, argc);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002512
2513 __ bind(&miss);
2514 FreeSpaceForFastApiCall(masm());
2515
2516 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002517 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002518
2519 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002520 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002521}
2522
2523
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002524void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
2525 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002526 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002527 CheckType check,
2528 Label* success) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002529 // ----------- S t a t e -------------
2530 // -- a2 : name
2531 // -- ra : return address
2532 // -----------------------------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002533 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002534 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002535
2536 // Get the receiver from the stack.
2537 const int argc = arguments().immediate();
2538 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2539
2540 // Check that the receiver isn't a smi.
2541 if (check != NUMBER_CHECK) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002542 __ JumpIfSmi(a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002543 }
2544
2545 // Make sure that it's okay not to patch the on stack receiver
2546 // unless we're doing a receiver map check.
2547 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002548 switch (check) {
2549 case RECEIVER_MAP_CHECK:
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002550 __ IncrementCounter(isolate()->counters()->call_const(), 1, a0, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002551
2552 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002553 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2554 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002555
2556 // Patch the receiver on the stack with the global proxy if
2557 // necessary.
2558 if (object->IsGlobalObject()) {
2559 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2560 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2561 }
2562 break;
2563
2564 case STRING_CHECK:
ulan@chromium.org750145a2013-03-07 15:14:13 +00002565 // Check that the object is a string.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002566 __ GetObjectType(a1, a3, a3);
2567 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2568 // Check that the maps starting from the prototype haven't changed.
2569 GenerateDirectLoadGlobalFunctionPrototype(
2570 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
2571 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002572 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002573 a0, holder, a3, a1, t0, name, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002574 break;
2575
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002576 case SYMBOL_CHECK:
2577 // Check that the object is a symbol.
2578 __ GetObjectType(a1, a1, a3);
2579 __ Branch(&miss, ne, a3, Operand(SYMBOL_TYPE));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002580 // Check that the maps starting from the prototype haven't changed.
2581 GenerateDirectLoadGlobalFunctionPrototype(
2582 masm(), Context::SYMBOL_FUNCTION_INDEX, a0, &miss);
2583 CheckPrototypes(
2584 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2585 a0, holder, a3, a1, t0, name, &miss);
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002586 break;
2587
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002588 case NUMBER_CHECK: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002589 Label fast;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002590 // Check that the object is a smi or a heap number.
2591 __ JumpIfSmi(a1, &fast);
2592 __ GetObjectType(a1, a0, a0);
2593 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
2594 __ bind(&fast);
2595 // Check that the maps starting from the prototype haven't changed.
2596 GenerateDirectLoadGlobalFunctionPrototype(
2597 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
2598 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002599 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002600 a0, holder, a3, a1, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002601 break;
2602 }
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002603 case BOOLEAN_CHECK: {
2604 Label fast;
2605 // Check that the object is a boolean.
2606 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
2607 __ Branch(&fast, eq, a1, Operand(t0));
2608 __ LoadRoot(t0, Heap::kFalseValueRootIndex);
2609 __ Branch(&miss, ne, a1, Operand(t0));
2610 __ bind(&fast);
2611 // Check that the maps starting from the prototype haven't changed.
2612 GenerateDirectLoadGlobalFunctionPrototype(
2613 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
2614 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002615 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002616 a0, holder, a3, a1, t0, name, &miss);
2617 break;
2618 }
2619 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002620
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002621 __ jmp(success);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002622
2623 // Handle call cache miss.
2624 __ bind(&miss);
2625
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002626 GenerateMissBranch();
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002627}
2628
2629
2630void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) {
2631 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
2632 ? CALL_AS_FUNCTION
2633 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002634 ParameterCount expected(function);
2635 __ InvokeFunction(function, expected, arguments(),
2636 JUMP_FUNCTION, NullCallWrapper(), call_kind);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002637}
2638
2639
2640Handle<Code> CallStubCompiler::CompileCallConstant(
2641 Handle<Object> object,
2642 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002643 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002644 CheckType check,
2645 Handle<JSFunction> function) {
2646 if (HasCustomCallGenerator(function)) {
2647 Handle<Code> code = CompileCustomCall(object, holder,
2648 Handle<JSGlobalPropertyCell>::null(),
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002649 function, Handle<String>::cast(name));
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002650 // A null handle means bail out to the regular compiler code below.
2651 if (!code.is_null()) return code;
2652 }
2653
2654 Label success;
2655
2656 CompileHandlerFrontend(object, holder, name, check, &success);
2657 __ bind(&success);
2658 CompileHandlerBackend(function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002659
2660 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002661 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002662}
2663
2664
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002665Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2666 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002667 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002668 // ----------- S t a t e -------------
2669 // -- a2 : name
2670 // -- ra : return address
2671 // -----------------------------------
2672
2673 Label miss;
2674
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002675 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002676
2677 // Get the number of arguments.
2678 const int argc = arguments().immediate();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002679 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002680 LookupPostInterceptor(holder, name, &lookup);
2681
2682 // Get the receiver from the stack.
2683 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2684
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002685 CallInterceptorCompiler compiler(this, arguments(), a2, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002686 compiler.Compile(masm(), object, holder, name, &lookup, a1, a3, t0, a0,
2687 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002688
2689 // Move returned value, the function to call, to a1.
2690 __ mov(a1, v0);
2691 // Restore receiver.
2692 __ lw(a0, MemOperand(sp, argc * kPointerSize));
2693
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002694 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002695
2696 // Handle call cache miss.
2697 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002698 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002699
2700 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002701 return GetCode(Code::INTERCEPTOR, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002702}
2703
2704
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002705Handle<Code> CallStubCompiler::CompileCallGlobal(
2706 Handle<JSObject> object,
2707 Handle<GlobalObject> holder,
2708 Handle<JSGlobalPropertyCell> cell,
2709 Handle<JSFunction> function,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002710 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002711 // ----------- S t a t e -------------
2712 // -- a2 : name
2713 // -- ra : return address
2714 // -----------------------------------
2715
2716 if (HasCustomCallGenerator(function)) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002717 Handle<Code> code = CompileCustomCall(
2718 object, holder, cell, function, Handle<String>::cast(name));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002719 // A null handle means bail out to the regular compiler code below.
2720 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002721 }
2722
2723 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002724 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002725
2726 // Get the number of arguments.
2727 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002728 GenerateGlobalReceiverCheck(object, holder, name, &miss);
2729 GenerateLoadFunctionFromCell(cell, function, &miss);
2730
2731 // Patch the receiver on the stack with the global proxy if
2732 // necessary.
2733 if (object->IsGlobalObject()) {
2734 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
2735 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2736 }
2737
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002738 // Set up the context (function already in r1).
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002739 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
2740
2741 // Jump to the cached code (tail call).
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002742 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002743 __ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002744 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002745 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002746 ? CALL_AS_FUNCTION
2747 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002748 // We call indirectly through the code field in the function to
2749 // allow recompilation to take effect without changing any of the
2750 // call sites.
2751 __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
2752 __ InvokeCode(a3, expected, arguments(), JUMP_FUNCTION,
2753 NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002754
2755 // Handle call cache miss.
2756 __ bind(&miss);
2757 __ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002758 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002759
2760 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002761 return GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002762}
2763
2764
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002765Handle<Code> StoreStubCompiler::CompileStoreCallback(
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002766 Handle<Name> name,
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002767 Handle<JSObject> object,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002768 Handle<JSObject> holder,
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002769 Handle<ExecutableAccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002770 Label miss;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002771 // Check that the maps haven't changed.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002772 __ JumpIfSmi(receiver(), &miss);
2773 CheckPrototypes(object, receiver(), holder,
2774 scratch1(), scratch2(), scratch3(), name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002775
2776 // Stub never generated for non-global objects that require access
2777 // checks.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002778 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002779
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002780 __ push(receiver()); // Receiver.
2781 __ li(at, Operand(callback)); // Callback info.
2782 __ Push(at, this->name(), value());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002783
2784 // Do tail-call to the runtime system.
2785 ExternalReference store_callback_property =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002786 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002787 __ TailCallExternalReference(store_callback_property, 4, 1);
2788
2789 // Handle store cache miss.
2790 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002791 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002792
2793 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002794 return GetICCode(kind(), Code::CALLBACKS, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002795}
2796
2797
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002798#undef __
2799#define __ ACCESS_MASM(masm)
2800
2801
2802void StoreStubCompiler::GenerateStoreViaSetter(
2803 MacroAssembler* masm,
2804 Handle<JSFunction> setter) {
2805 // ----------- S t a t e -------------
2806 // -- a0 : value
2807 // -- a1 : receiver
2808 // -- a2 : name
2809 // -- ra : return address
2810 // -----------------------------------
2811 {
2812 FrameScope scope(masm, StackFrame::INTERNAL);
2813
2814 // Save value register, so we can restore it later.
2815 __ push(a0);
2816
2817 if (!setter.is_null()) {
2818 // Call the JavaScript setter with receiver and value on the stack.
2819 __ push(a1);
2820 __ push(a0);
2821 ParameterCount actual(1);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002822 ParameterCount expected(setter);
2823 __ InvokeFunction(setter, expected, actual,
2824 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002825 } else {
2826 // If we generate a global code snippet for deoptimization only, remember
2827 // the place to continue after deoptimization.
2828 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2829 }
2830
2831 // We have to return the passed value, not the return value of the setter.
2832 __ pop(v0);
2833
2834 // Restore context register.
2835 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2836 }
2837 __ Ret();
2838}
2839
2840
2841#undef __
2842#define __ ACCESS_MASM(masm())
2843
2844
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002845Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002846 Handle<JSObject> object,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002847 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002848 Label miss;
2849
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002850 // Check that the map of the object hasn't changed.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002851 __ CheckMap(receiver(), scratch1(), Handle<Map>(object->map()), &miss,
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002852 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002853
2854 // Perform global security token check if needed.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002855 if (object->IsJSGlobalProxy()) {
2856 __ CheckAccessGlobalProxy(receiver(), scratch1(), &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002857 }
2858
2859 // Stub is never generated for non-global objects that require access
2860 // checks.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002861 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002862
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002863 __ Push(receiver(), this->name(), value());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002864
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002865 __ li(scratch1(), Operand(Smi::FromInt(strict_mode())));
2866 __ push(scratch1()); // strict mode
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002867
2868 // Do tail-call to the runtime system.
2869 ExternalReference store_ic_property =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002870 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002871 __ TailCallExternalReference(store_ic_property, 4, 1);
2872
2873 // Handle store cache miss.
2874 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002875 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002876
2877 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002878 return GetICCode(kind(), Code::INTERCEPTOR, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002879}
2880
2881
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002882Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2883 Handle<GlobalObject> object,
2884 Handle<JSGlobalPropertyCell> cell,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002885 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002886 Label miss;
2887
2888 // Check that the map of the global has not changed.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002889 __ lw(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset));
2890 __ Branch(&miss, ne, scratch1(), Operand(Handle<Map>(object->map())));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002891
2892 // Check that the value in the cell is not the hole. If it is, this
2893 // cell could have been deleted and reintroducing the global needs
2894 // to update the property details in the property dictionary of the
2895 // global object. We bail out to the runtime system to do that.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002896 __ li(scratch1(), Operand(cell));
2897 __ LoadRoot(scratch2(), Heap::kTheHoleValueRootIndex);
2898 __ lw(scratch3(),
2899 FieldMemOperand(scratch1(), JSGlobalPropertyCell::kValueOffset));
2900 __ Branch(&miss, eq, scratch3(), Operand(scratch2()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002901
2902 // Store the value in the cell.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002903 __ sw(value(),
2904 FieldMemOperand(scratch1(), JSGlobalPropertyCell::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002905 __ mov(v0, a0); // Stored value must be returned in v0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002906 // Cells are always rescanned, so no write barrier here.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002907
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002908 Counters* counters = isolate()->counters();
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002909 __ IncrementCounter(
2910 counters->named_store_global_inline(), 1, scratch1(), scratch2());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002911 __ Ret();
2912
2913 // Handle store cache miss.
2914 __ bind(&miss);
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002915 __ IncrementCounter(
2916 counters->named_store_global_inline_miss(), 1, scratch1(), scratch2());
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002917 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002918
2919 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002920 return GetICCode(kind(), Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002921}
2922
2923
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002924Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
2925 Handle<JSObject> object,
2926 Handle<JSObject> last,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002927 Handle<Name> name,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002928 Handle<GlobalObject> global) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002929 Label success;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002930
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002931 NonexistentHandlerFrontend(object, last, name, &success, global);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002932
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002933 __ bind(&success);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002934 // Return undefined if maps of the full prototype chain is still the same.
2935 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2936 __ Ret();
2937
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002938 // Return the generated code.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002939 return GetCode(kind(), Code::NONEXISTENT, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002940}
2941
2942
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002943Register* LoadStubCompiler::registers() {
2944 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2945 static Register registers[] = { a0, a2, a3, a1, t0, t1 };
2946 return registers;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002947}
2948
2949
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002950Register* KeyedLoadStubCompiler::registers() {
2951 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2952 static Register registers[] = { a1, a0, a2, a3, t0, t1 };
2953 return registers;
2954}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002955
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002956
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002957Register* StoreStubCompiler::registers() {
2958 // receiver, name, value, scratch1, scratch2, scratch3.
2959 static Register registers[] = { a1, a2, a0, a3, t0, t1 };
2960 return registers;
2961}
2962
2963
2964Register* KeyedStoreStubCompiler::registers() {
2965 // receiver, name, value, scratch1, scratch2, scratch3.
2966 static Register registers[] = { a2, a1, a0, a3, t0, t1 };
2967 return registers;
2968}
2969
2970
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002971void KeyedLoadStubCompiler::GenerateNameCheck(Handle<Name> name,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002972 Register name_reg,
2973 Label* miss) {
2974 __ Branch(miss, ne, name_reg, Operand(name));
lrn@chromium.org7516f052011-03-30 08:52:27 +00002975}
2976
2977
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002978void KeyedStoreStubCompiler::GenerateNameCheck(Handle<Name> name,
2979 Register name_reg,
2980 Label* miss) {
2981 __ Branch(miss, ne, name_reg, Operand(name));
2982}
2983
2984
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002985#undef __
2986#define __ ACCESS_MASM(masm)
2987
2988
2989void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
2990 Handle<JSFunction> getter) {
2991 // ----------- S t a t e -------------
2992 // -- a0 : receiver
2993 // -- a2 : name
2994 // -- ra : return address
2995 // -----------------------------------
2996 {
2997 FrameScope scope(masm, StackFrame::INTERNAL);
2998
2999 if (!getter.is_null()) {
3000 // Call the JavaScript getter with the receiver on the stack.
3001 __ push(a0);
3002 ParameterCount actual(0);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003003 ParameterCount expected(getter);
3004 __ InvokeFunction(getter, expected, actual,
3005 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003006 } else {
3007 // If we generate a global code snippet for deoptimization only, remember
3008 // the place to continue after deoptimization.
3009 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
3010 }
3011
3012 // Restore context register.
3013 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
3014 }
3015 __ Ret();
3016}
3017
3018
3019#undef __
3020#define __ ACCESS_MASM(masm())
3021
3022
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003023Handle<Code> LoadStubCompiler::CompileLoadGlobal(
3024 Handle<JSObject> object,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003025 Handle<GlobalObject> global,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003026 Handle<JSGlobalPropertyCell> cell,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003027 Handle<Name> name,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003028 bool is_dont_delete) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003029 Label success, miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003030
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003031 __ CheckMap(
3032 receiver(), scratch1(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
3033 HandlerFrontendHeader(
3034 object, receiver(), Handle<JSObject>::cast(global), name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003035
3036 // Get the value from the cell.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003037 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003038 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
3039
3040 // Check for deleted property if property can actually be deleted.
3041 if (!is_dont_delete) {
3042 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
3043 __ Branch(&miss, eq, t0, Operand(at));
3044 }
3045
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003046 HandlerFrontendFooter(&success, &miss);
3047 __ bind(&success);
3048
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003049 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003050 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003051 __ mov(v0, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003052 __ Ret();
3053
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003054 // Return the generated code.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003055 return GetICCode(kind(), Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003056}
3057
3058
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003059Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003060 MapHandleList* receiver_maps,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003061 CodeHandleList* handlers,
3062 Handle<Name> name,
3063 Code::StubType type,
3064 IcCheckType check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003065 Label miss;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003066
3067 if (check == PROPERTY) {
3068 GenerateNameCheck(name, this->name(), &miss);
3069 }
3070
3071 __ JumpIfSmi(receiver(), &miss);
3072 Register map_reg = scratch1();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003073
danno@chromium.org40cb8782011-05-25 07:58:50 +00003074 int receiver_count = receiver_maps->length();
danno@chromium.orgf005df62013-04-30 16:36:45 +00003075 int number_of_handled_maps = 0;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003076 __ lw(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003077 for (int current = 0; current < receiver_count; ++current) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00003078 Handle<Map> map = receiver_maps->at(current);
3079 if (!map->is_deprecated()) {
3080 number_of_handled_maps++;
3081 __ Jump(handlers->at(current), RelocInfo::CODE_TARGET,
3082 eq, map_reg, Operand(receiver_maps->at(current)));
3083 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003084 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00003085 ASSERT(number_of_handled_maps != 0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003086
3087 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003088 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003089
3090 // Return the generated code.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003091 InlineCacheState state =
danno@chromium.orgf005df62013-04-30 16:36:45 +00003092 number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003093 return GetICCode(kind(), type, name, state);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003094}
3095
3096
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003097Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
3098 MapHandleList* receiver_maps,
3099 CodeHandleList* handler_stubs,
3100 MapHandleList* transitioned_maps) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003101 Label miss;
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003102 __ JumpIfSmi(receiver(), &miss);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003103
3104 int receiver_count = receiver_maps->length();
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003105 __ lw(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003106 for (int i = 0; i < receiver_count; ++i) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003107 if (transitioned_maps->at(i).is_null()) {
3108 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq,
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003109 scratch1(), Operand(receiver_maps->at(i)));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003110 } else {
3111 Label next_map;
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003112 __ Branch(&next_map, ne, scratch1(), Operand(receiver_maps->at(i)));
3113 __ li(transition_map(), Operand(transitioned_maps->at(i)));
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003114 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003115 __ bind(&next_map);
3116 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003117 }
3118
3119 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003120 TailCallBuiltin(masm(), MissBuiltin(kind()));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003121
3122 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003123 return GetICCode(
3124 kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003125}
3126
3127
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003128Handle<Code> ConstructStubCompiler::CompileConstructStub(
3129 Handle<JSFunction> function) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003130 // a0 : argc
3131 // a1 : constructor
3132 // ra : return address
3133 // [sp] : last argument
3134 Label generic_stub_call;
3135
3136 // Use t7 for holding undefined which is used in several places below.
3137 __ LoadRoot(t7, Heap::kUndefinedValueRootIndex);
3138
3139#ifdef ENABLE_DEBUGGER_SUPPORT
3140 // Check to see whether there are any break points in the function code. If
3141 // there are jump to the generic constructor stub which calls the actual
3142 // code for the function thereby hitting the break points.
3143 __ lw(t5, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3144 __ lw(a2, FieldMemOperand(t5, SharedFunctionInfo::kDebugInfoOffset));
3145 __ Branch(&generic_stub_call, ne, a2, Operand(t7));
3146#endif
3147
3148 // Load the initial map and verify that it is in fact a map.
3149 // a1: constructor function
3150 // t7: undefined
3151 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003152 __ JumpIfSmi(a2, &generic_stub_call);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003153 __ GetObjectType(a2, a3, t0);
3154 __ Branch(&generic_stub_call, ne, t0, Operand(MAP_TYPE));
3155
3156#ifdef DEBUG
3157 // Cannot construct functions this way.
3158 // a0: argc
3159 // a1: constructor function
3160 // a2: initial map
3161 // t7: undefined
3162 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
3163 __ Check(ne, "Function constructed by construct stub.",
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003164 a3, Operand(JS_FUNCTION_TYPE));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003165#endif
3166
3167 // Now allocate the JSObject in new space.
3168 // a0: argc
3169 // a1: constructor function
3170 // a2: initial map
3171 // t7: undefined
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003172 ASSERT(function->has_initial_map());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003173 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003174#ifdef DEBUG
3175 int instance_size = function->initial_map()->instance_size();
3176 __ Check(eq, "Instance size of initial map changed.",
3177 a3, Operand(instance_size >> kPointerSizeLog2));
3178#endif
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003179 __ Allocate(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003180
3181 // Allocated the JSObject, now initialize the fields. Map is set to initial
3182 // map and properties and elements are set to empty fixed array.
3183 // a0: argc
3184 // a1: constructor function
3185 // a2: initial map
3186 // a3: object size (in words)
3187 // t4: JSObject (not tagged)
3188 // t7: undefined
3189 __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex);
3190 __ mov(t5, t4);
3191 __ sw(a2, MemOperand(t5, JSObject::kMapOffset));
3192 __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset));
3193 __ sw(t6, MemOperand(t5, JSObject::kElementsOffset));
3194 __ Addu(t5, t5, Operand(3 * kPointerSize));
3195 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
3196 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
3197 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
3198
3199
3200 // Calculate the location of the first argument. The stack contains only the
3201 // argc arguments.
3202 __ sll(a1, a0, kPointerSizeLog2);
3203 __ Addu(a1, a1, sp);
3204
3205 // Fill all the in-object properties with undefined.
3206 // a0: argc
3207 // a1: first argument
3208 // a3: object size (in words)
3209 // t4: JSObject (not tagged)
3210 // t5: First in-object property of JSObject (not tagged)
3211 // t7: undefined
3212 // Fill the initialized properties with a constant value or a passed argument
3213 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003214 Handle<SharedFunctionInfo> shared(function->shared());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003215 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3216 if (shared->IsThisPropertyAssignmentArgument(i)) {
3217 Label not_passed, next;
3218 // Check if the argument assigned to the property is actually passed.
3219 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3220 __ Branch(&not_passed, less_equal, a0, Operand(arg_number));
3221 // Argument passed - find it on the stack.
3222 __ lw(a2, MemOperand(a1, (arg_number + 1) * -kPointerSize));
3223 __ sw(a2, MemOperand(t5));
3224 __ Addu(t5, t5, kPointerSize);
3225 __ jmp(&next);
3226 __ bind(&not_passed);
3227 // Set the property to undefined.
3228 __ sw(t7, MemOperand(t5));
3229 __ Addu(t5, t5, Operand(kPointerSize));
3230 __ bind(&next);
3231 } else {
3232 // Set the property to the constant value.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003233 Handle<Object> constant(
3234 shared->GetThisPropertyAssignmentConstant(i), isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003235 __ li(a2, Operand(constant));
3236 __ sw(a2, MemOperand(t5));
3237 __ Addu(t5, t5, kPointerSize);
3238 }
3239 }
3240
3241 // Fill the unused in-object property fields with undefined.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003242 for (int i = shared->this_property_assignments_count();
3243 i < function->initial_map()->inobject_properties();
3244 i++) {
3245 __ sw(t7, MemOperand(t5));
3246 __ Addu(t5, t5, kPointerSize);
3247 }
3248
3249 // a0: argc
3250 // t4: JSObject (not tagged)
3251 // Move argc to a1 and the JSObject to return to v0 and tag it.
3252 __ mov(a1, a0);
3253 __ mov(v0, t4);
3254 __ Or(v0, v0, Operand(kHeapObjectTag));
3255
3256 // v0: JSObject
3257 // a1: argc
3258 // Remove caller arguments and receiver from the stack and return.
3259 __ sll(t0, a1, kPointerSizeLog2);
3260 __ Addu(sp, sp, t0);
3261 __ Addu(sp, sp, Operand(kPointerSize));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003262 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003263 __ IncrementCounter(counters->constructed_objects(), 1, a1, a2);
3264 __ IncrementCounter(counters->constructed_objects_stub(), 1, a1, a2);
3265 __ Ret();
3266
3267 // Jump to the generic stub in case the specialized code cannot handle the
3268 // construction.
3269 __ bind(&generic_stub_call);
3270 Handle<Code> generic_construct_stub =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003271 isolate()->builtins()->JSConstructStubGeneric();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003272 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
3273
3274 // Return the generated code.
3275 return GetCode();
3276}
3277
3278
danno@chromium.org40cb8782011-05-25 07:58:50 +00003279#undef __
3280#define __ ACCESS_MASM(masm)
3281
3282
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003283void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3284 MacroAssembler* masm) {
3285 // ---------- S t a t e --------------
3286 // -- ra : return address
3287 // -- a0 : key
3288 // -- a1 : receiver
3289 // -----------------------------------
3290 Label slow, miss_force_generic;
3291
3292 Register key = a0;
3293 Register receiver = a1;
3294
3295 __ JumpIfNotSmi(key, &miss_force_generic);
3296 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
3297 __ sra(a2, a0, kSmiTagSize);
3298 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
3299 __ Ret();
3300
3301 // Slow case, key and receiver still in a0 and a1.
3302 __ bind(&slow);
3303 __ IncrementCounter(
3304 masm->isolate()->counters()->keyed_load_external_array_slow(),
3305 1, a2, a3);
3306 // Entry registers are intact.
3307 // ---------- S t a t e --------------
3308 // -- ra : return address
3309 // -- a0 : key
3310 // -- a1 : receiver
3311 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003312 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003313
3314 // Miss case, call the runtime.
3315 __ bind(&miss_force_generic);
3316
3317 // ---------- S t a t e --------------
3318 // -- ra : return address
3319 // -- a0 : key
3320 // -- a1 : receiver
3321 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003322 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_MissForceGeneric);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003323}
3324
3325
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003326static void GenerateSmiKeyCheck(MacroAssembler* masm,
3327 Register key,
3328 Register scratch0,
3329 Register scratch1,
3330 FPURegister double_scratch0,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003331 FPURegister double_scratch1,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003332 Label* fail) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003333 Label key_ok;
3334 // Check for smi or a smi inside a heap number. We convert the heap
3335 // number and check if the conversion is exact and fits into the smi
3336 // range.
3337 __ JumpIfSmi(key, &key_ok);
3338 __ CheckMap(key,
3339 scratch0,
3340 Heap::kHeapNumberMapRootIndex,
3341 fail,
3342 DONT_DO_SMI_CHECK);
3343 __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
3344 __ EmitFPUTruncate(kRoundToZero,
3345 scratch0,
3346 double_scratch0,
3347 at,
3348 double_scratch1,
3349 scratch1,
3350 kCheckForInexactConversion);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003351
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003352 __ Branch(fail, ne, scratch1, Operand(zero_reg));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003353
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003354 __ SmiTagCheckOverflow(key, scratch0, scratch1);
3355 __ BranchOnOverflow(fail, scratch1);
3356 __ bind(&key_ok);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003357}
3358
3359
danno@chromium.org40cb8782011-05-25 07:58:50 +00003360void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3361 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003362 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003363 // ---------- S t a t e --------------
3364 // -- a0 : value
3365 // -- a1 : key
3366 // -- a2 : receiver
3367 // -- ra : return address
3368 // -----------------------------------
3369
danno@chromium.org40cb8782011-05-25 07:58:50 +00003370 Label slow, check_heap_number, miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003371
3372 // Register usage.
3373 Register value = a0;
3374 Register key = a1;
3375 Register receiver = a2;
3376 // a3 mostly holds the elements array or the destination external array.
3377
danno@chromium.org40cb8782011-05-25 07:58:50 +00003378 // This stub is meant to be tail-jumped to, the receiver must already
3379 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003380
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003381 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003382 GenerateSmiKeyCheck(masm, key, t0, t1, f2, f4, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003383
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003384 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3385
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003386 // Check that the index is in range.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003387 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3388 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003389 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003390
3391 // Handle both smis and HeapNumbers in the fast path. Go to the
3392 // runtime for all other kinds of values.
3393 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003394
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003395 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003396 // Double to pixel conversion is only implemented in the runtime for now.
3397 __ JumpIfNotSmi(value, &slow);
3398 } else {
3399 __ JumpIfNotSmi(value, &check_heap_number);
3400 }
3401 __ SmiUntag(t1, value);
3402 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3403
3404 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003405 // t1: value (integer).
3406
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003407 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003408 case EXTERNAL_PIXEL_ELEMENTS: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003409 // Clamp the value to [0..255].
3410 // v0 is used as a scratch register here.
3411 Label done;
3412 __ li(v0, Operand(255));
3413 // Normal branch: nop in delay slot.
3414 __ Branch(&done, gt, t1, Operand(v0));
3415 // Use delay slot in this branch.
3416 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg));
3417 __ mov(v0, zero_reg); // In delay slot.
3418 __ mov(v0, t1); // Value is in range 0..255.
3419 __ bind(&done);
3420 __ mov(t1, v0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003421
3422 __ srl(t8, key, 1);
3423 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003424 __ sb(t1, MemOperand(t8, 0));
3425 }
3426 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003427 case EXTERNAL_BYTE_ELEMENTS:
3428 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003429 __ srl(t8, key, 1);
3430 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003431 __ sb(t1, MemOperand(t8, 0));
3432 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003433 case EXTERNAL_SHORT_ELEMENTS:
3434 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003435 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003436 __ sh(t1, MemOperand(t8, 0));
3437 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003438 case EXTERNAL_INT_ELEMENTS:
3439 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003440 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003441 __ addu(t8, a3, t8);
3442 __ sw(t1, MemOperand(t8, 0));
3443 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003444 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003445 // Perform int-to-float conversion and store to memory.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003446 __ SmiUntag(t0, key);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003447 StoreIntAsFloat(masm, a3, t0, t1, t2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003448 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003449 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003450 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003451 __ addu(a3, a3, t8);
3452 // a3: effective address of the double element
3453 FloatingPointHelper::Destination destination;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003454 destination = FloatingPointHelper::kFPURegisters;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003455 FloatingPointHelper::ConvertIntToDouble(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003456 masm, t1, destination,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003457 f0, t2, t3, // These are: double_dst, dst_mantissa, dst_exponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003458 t0, f2); // These are: scratch2, single_scratch.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003459 __ sdc1(f0, MemOperand(a3, 0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003460 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003461 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003462 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003463 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003464 case FAST_HOLEY_ELEMENTS:
3465 case FAST_HOLEY_SMI_ELEMENTS:
3466 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003467 case DICTIONARY_ELEMENTS:
3468 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003469 UNREACHABLE();
3470 break;
3471 }
3472
3473 // Entry registers are intact, a0 holds the value which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003474 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003475 __ Ret();
3476
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003477 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003478 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003479 __ bind(&check_heap_number);
3480 __ GetObjectType(value, t1, t2);
3481 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE));
3482
3483 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3484
3485 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003486
3487 // The WebGL specification leaves the behavior of storing NaN and
3488 // +/-Infinity into integer arrays basically undefined. For more
3489 // reproducible behavior, convert these to zero.
3490
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003491
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003492 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003493
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003494 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
3495 __ cvt_s_d(f0, f0);
3496 __ sll(t8, key, 1);
3497 __ addu(t8, a3, t8);
3498 __ swc1(f0, MemOperand(t8, 0));
3499 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
3500 __ sll(t8, key, 2);
3501 __ addu(t8, a3, t8);
3502 __ sdc1(f0, MemOperand(t8, 0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003503 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003504 __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003505
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003506 switch (elements_kind) {
3507 case EXTERNAL_BYTE_ELEMENTS:
3508 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3509 __ srl(t8, key, 1);
3510 __ addu(t8, a3, t8);
3511 __ sb(t3, MemOperand(t8, 0));
3512 break;
3513 case EXTERNAL_SHORT_ELEMENTS:
3514 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3515 __ addu(t8, a3, key);
3516 __ sh(t3, MemOperand(t8, 0));
3517 break;
3518 case EXTERNAL_INT_ELEMENTS:
3519 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3520 __ sll(t8, key, 1);
3521 __ addu(t8, a3, t8);
3522 __ sw(t3, MemOperand(t8, 0));
3523 break;
3524 case EXTERNAL_PIXEL_ELEMENTS:
3525 case EXTERNAL_FLOAT_ELEMENTS:
3526 case EXTERNAL_DOUBLE_ELEMENTS:
3527 case FAST_ELEMENTS:
3528 case FAST_SMI_ELEMENTS:
3529 case FAST_DOUBLE_ELEMENTS:
3530 case FAST_HOLEY_ELEMENTS:
3531 case FAST_HOLEY_SMI_ELEMENTS:
3532 case FAST_HOLEY_DOUBLE_ELEMENTS:
3533 case DICTIONARY_ELEMENTS:
3534 case NON_STRICT_ARGUMENTS_ELEMENTS:
3535 UNREACHABLE();
3536 break;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003537 }
3538 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003539
3540 // Entry registers are intact, a0 holds the value
3541 // which is the return value.
3542 __ mov(v0, a0);
3543 __ Ret();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003544 }
3545
danno@chromium.org40cb8782011-05-25 07:58:50 +00003546 // Slow case, key and receiver still in a0 and a1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003547 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003548 __ IncrementCounter(
3549 masm->isolate()->counters()->keyed_load_external_array_slow(),
3550 1, a2, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003551 // Entry registers are intact.
3552 // ---------- S t a t e --------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003553 // -- ra : return address
danno@chromium.org40cb8782011-05-25 07:58:50 +00003554 // -- a0 : key
3555 // -- a1 : receiver
3556 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003557 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003558
3559 // Miss case, call the runtime.
3560 __ bind(&miss_force_generic);
3561
3562 // ---------- S t a t e --------------
3563 // -- ra : return address
3564 // -- a0 : key
3565 // -- a1 : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003566 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003567 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003568}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003569
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003570
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003571void KeyedStoreStubCompiler::GenerateStoreFastElement(
3572 MacroAssembler* masm,
3573 bool is_js_array,
yangguo@chromium.org56454712012-02-16 15:33:53 +00003574 ElementsKind elements_kind,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003575 KeyedAccessStoreMode store_mode) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003576 // ----------- S t a t e -------------
3577 // -- a0 : value
3578 // -- a1 : key
3579 // -- a2 : receiver
3580 // -- ra : return address
3581 // -- a3 : scratch
3582 // -- a4 : scratch (elements)
3583 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00003584 Label miss_force_generic, transition_elements_kind, grow, slow;
3585 Label finish_store, check_capacity;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003586
3587 Register value_reg = a0;
3588 Register key_reg = a1;
3589 Register receiver_reg = a2;
yangguo@chromium.org56454712012-02-16 15:33:53 +00003590 Register scratch = t0;
3591 Register elements_reg = a3;
3592 Register length_reg = t1;
3593 Register scratch2 = t2;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003594
3595 // This stub is meant to be tail-jumped to, the receiver must already
3596 // have been verified by the caller to not be a smi.
3597
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003598 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003599 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003600
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003601 if (IsFastSmiElementsKind(elements_kind)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003602 __ JumpIfNotSmi(value_reg, &transition_elements_kind);
3603 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003604
3605 // Check that the key is within bounds.
yangguo@chromium.org56454712012-02-16 15:33:53 +00003606 __ lw(elements_reg,
3607 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003608 if (is_js_array) {
3609 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3610 } else {
3611 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3612 }
3613 // Compare smis.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003614 if (is_js_array && IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003615 __ Branch(&grow, hs, key_reg, Operand(scratch));
3616 } else {
3617 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
3618 }
3619
3620 // Make sure elements is a fast element array, not 'cow'.
3621 __ CheckMap(elements_reg,
3622 scratch,
3623 Heap::kFixedArrayMapRootIndex,
3624 &miss_force_generic,
3625 DONT_DO_SMI_CHECK);
3626
3627 __ bind(&finish_store);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003628
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003629 if (IsFastSmiElementsKind(elements_kind)) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003630 __ Addu(scratch,
3631 elements_reg,
3632 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3633 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
3634 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
3635 __ Addu(scratch, scratch, scratch2);
3636 __ sw(value_reg, MemOperand(scratch));
3637 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003638 ASSERT(IsFastObjectElementsKind(elements_kind));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003639 __ Addu(scratch,
3640 elements_reg,
3641 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3642 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
3643 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
3644 __ Addu(scratch, scratch, scratch2);
3645 __ sw(value_reg, MemOperand(scratch));
3646 __ mov(receiver_reg, value_reg);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003647 __ RecordWrite(elements_reg, // Object.
3648 scratch, // Address.
3649 receiver_reg, // Value.
3650 kRAHasNotBeenSaved,
3651 kDontSaveFPRegs);
3652 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003653 // value_reg (a0) is preserved.
3654 // Done.
3655 __ Ret();
3656
3657 __ bind(&miss_force_generic);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003658 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003659
3660 __ bind(&transition_elements_kind);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003661 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003662
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003663 if (is_js_array && IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003664 // Grow the array by a single element if possible.
3665 __ bind(&grow);
3666
3667 // Make sure the array is only growing by a single element, anything else
3668 // must be handled by the runtime.
3669 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch));
3670
3671 // Check for the empty array, and preallocate a small backing store if
3672 // possible.
3673 __ lw(length_reg,
3674 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3675 __ lw(elements_reg,
3676 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3677 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
3678 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
3679
3680 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003681 __ Allocate(size, elements_reg, scratch, scratch2, &slow, TAG_OBJECT);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003682
3683 __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex);
3684 __ sw(scratch, FieldMemOperand(elements_reg, JSObject::kMapOffset));
3685 __ li(scratch, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
3686 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3687 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
3688 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
3689 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::SizeFor(i)));
3690 }
3691
3692 // Store the element at index zero.
3693 __ sw(value_reg, FieldMemOperand(elements_reg, FixedArray::SizeFor(0)));
3694
3695 // Install the new backing store in the JSArray.
3696 __ sw(elements_reg,
3697 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3698 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
3699 scratch, kRAHasNotBeenSaved, kDontSaveFPRegs,
3700 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3701
3702 // Increment the length of the array.
3703 __ li(length_reg, Operand(Smi::FromInt(1)));
3704 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3705 __ Ret();
3706
3707 __ bind(&check_capacity);
3708 // Check for cow elements, in general they are not handled by this stub
3709 __ CheckMap(elements_reg,
3710 scratch,
3711 Heap::kFixedCOWArrayMapRootIndex,
3712 &miss_force_generic,
3713 DONT_DO_SMI_CHECK);
3714
3715 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3716 __ Branch(&slow, hs, length_reg, Operand(scratch));
3717
3718 // Grow the array and finish the store.
3719 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
3720 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3721 __ jmp(&finish_store);
3722
3723 __ bind(&slow);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003724 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003725 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003726}
3727
3728
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003729void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
3730 MacroAssembler* masm,
yangguo@chromium.org56454712012-02-16 15:33:53 +00003731 bool is_js_array,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003732 KeyedAccessStoreMode store_mode) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003733 // ----------- S t a t e -------------
3734 // -- a0 : value
3735 // -- a1 : key
3736 // -- a2 : receiver
3737 // -- ra : return address
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003738 // -- a3 : scratch (elements backing store)
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003739 // -- t0 : scratch (elements_reg)
3740 // -- t1 : scratch (mantissa_reg)
3741 // -- t2 : scratch (exponent_reg)
3742 // -- t3 : scratch4
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003743 // -- t4 : scratch
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003744 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00003745 Label miss_force_generic, transition_elements_kind, grow, slow;
3746 Label finish_store, check_capacity;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003747
3748 Register value_reg = a0;
3749 Register key_reg = a1;
3750 Register receiver_reg = a2;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003751 Register elements_reg = a3;
3752 Register scratch1 = t0;
3753 Register scratch2 = t1;
3754 Register scratch3 = t2;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003755 Register scratch4 = t3;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003756 Register scratch5 = t4;
yangguo@chromium.org56454712012-02-16 15:33:53 +00003757 Register length_reg = t3;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003758
3759 // This stub is meant to be tail-jumped to, the receiver must already
3760 // have been verified by the caller to not be a smi.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003761
3762 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003763 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003764
3765 __ lw(elements_reg,
3766 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3767
3768 // Check that the key is within bounds.
3769 if (is_js_array) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003770 __ lw(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003771 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003772 __ lw(scratch1,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003773 FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3774 }
3775 // Compare smis, unsigned compare catches both negative and out-of-bound
3776 // indexes.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003777 if (IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003778 __ Branch(&grow, hs, key_reg, Operand(scratch1));
3779 } else {
3780 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch1));
3781 }
3782
3783 __ bind(&finish_store);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003784
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003785 __ StoreNumberToDoubleElements(value_reg,
3786 key_reg,
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00003787 // All registers after this are overwritten.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003788 elements_reg,
3789 scratch1,
3790 scratch2,
3791 scratch3,
3792 scratch4,
3793 &transition_elements_kind);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003794
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003795 __ Ret(USE_DELAY_SLOT);
3796 __ mov(v0, value_reg); // In delay slot.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003797
3798 // Handle store cache miss, replacing the ic with the generic stub.
3799 __ bind(&miss_force_generic);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003800 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003801
3802 __ bind(&transition_elements_kind);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003803 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003804
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003805 if (is_js_array && IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003806 // Grow the array by a single element if possible.
3807 __ bind(&grow);
3808
3809 // Make sure the array is only growing by a single element, anything else
3810 // must be handled by the runtime.
3811 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch1));
3812
3813 // Transition on values that can't be stored in a FixedDoubleArray.
3814 Label value_is_smi;
3815 __ JumpIfSmi(value_reg, &value_is_smi);
3816 __ lw(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
3817 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
3818 __ Branch(&transition_elements_kind, ne, scratch1, Operand(at));
3819 __ bind(&value_is_smi);
3820
3821 // Check for the empty array, and preallocate a small backing store if
3822 // possible.
3823 __ lw(length_reg,
3824 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3825 __ lw(elements_reg,
3826 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3827 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
3828 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
3829
3830 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003831 __ Allocate(size, elements_reg, scratch1, scratch2, &slow, TAG_OBJECT);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003832
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003833 // Initialize the new FixedDoubleArray.
yangguo@chromium.org56454712012-02-16 15:33:53 +00003834 __ LoadRoot(scratch1, Heap::kFixedDoubleArrayMapRootIndex);
3835 __ sw(scratch1, FieldMemOperand(elements_reg, JSObject::kMapOffset));
3836 __ li(scratch1, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
3837 __ sw(scratch1,
3838 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
3839
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003840 __ mov(scratch1, elements_reg);
3841 __ StoreNumberToDoubleElements(value_reg,
3842 key_reg,
3843 // All registers after this are overwritten.
3844 scratch1,
3845 scratch2,
3846 scratch3,
3847 scratch4,
3848 scratch5,
3849 &transition_elements_kind);
3850
3851 __ li(scratch1, Operand(kHoleNanLower32));
3852 __ li(scratch2, Operand(kHoleNanUpper32));
3853 for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) {
3854 int offset = FixedDoubleArray::OffsetOfElementAt(i);
3855 __ sw(scratch1, FieldMemOperand(elements_reg, offset));
3856 __ sw(scratch2, FieldMemOperand(elements_reg, offset + kPointerSize));
3857 }
3858
yangguo@chromium.org56454712012-02-16 15:33:53 +00003859 // Install the new backing store in the JSArray.
3860 __ sw(elements_reg,
3861 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3862 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
3863 scratch1, kRAHasNotBeenSaved, kDontSaveFPRegs,
3864 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3865
3866 // Increment the length of the array.
3867 __ li(length_reg, Operand(Smi::FromInt(1)));
3868 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
danno@chromium.org00379b82012-05-04 09:16:29 +00003869 __ lw(elements_reg,
3870 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003871 __ Ret();
yangguo@chromium.org56454712012-02-16 15:33:53 +00003872
3873 __ bind(&check_capacity);
3874 // Make sure that the backing store can hold additional elements.
3875 __ lw(scratch1,
3876 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
3877 __ Branch(&slow, hs, length_reg, Operand(scratch1));
3878
3879 // Grow the array and finish the store.
3880 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
3881 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3882 __ jmp(&finish_store);
3883
3884 __ bind(&slow);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003885 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003886 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003887}
3888
3889
ager@chromium.org5c838252010-02-19 08:53:10 +00003890#undef __
3891
3892} } // namespace v8::internal
3893
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003894#endif // V8_TARGET_ARCH_MIPS