blob: d95f3becb6559db0479c7b6049dd9bb8ceb431de [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,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000456 DO_SMI_CHECK);
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.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000574 SmiCheck smi_check = representation.IsTagged()
575 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000576 if (index < 0) {
577 // Set the property straight into the object.
578 int offset = object->map()->instance_size() + (index * kPointerSize);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000579 if (FLAG_track_double_fields && representation.IsDouble()) {
580 __ sw(storage_reg, FieldMemOperand(receiver_reg, offset));
581 } else {
582 __ sw(value_reg, FieldMemOperand(receiver_reg, offset));
583 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000584
danno@chromium.orgf005df62013-04-30 16:36:45 +0000585 if (!FLAG_track_fields || !representation.IsSmi()) {
586 // Skip updating write barrier if storing a smi.
587 __ JumpIfSmi(value_reg, &exit);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000588
danno@chromium.orgf005df62013-04-30 16:36:45 +0000589 // Update the write barrier for the array address.
590 // Pass the now unused name_reg as a scratch register.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000591 if (!FLAG_track_double_fields || !representation.IsDouble()) {
592 __ mov(name_reg, value_reg);
593 } else {
594 ASSERT(storage_reg.is(name_reg));
595 }
danno@chromium.orgf005df62013-04-30 16:36:45 +0000596 __ RecordWriteField(receiver_reg,
597 offset,
598 name_reg,
599 scratch1,
600 kRAHasNotBeenSaved,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000601 kDontSaveFPRegs,
602 EMIT_REMEMBERED_SET,
603 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000604 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000605 } else {
606 // Write to the properties array.
607 int offset = index * kPointerSize + FixedArray::kHeaderSize;
608 // Get the properties array
609 __ lw(scratch1,
610 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000611 if (FLAG_track_double_fields && representation.IsDouble()) {
612 __ sw(storage_reg, FieldMemOperand(scratch1, offset));
613 } else {
614 __ sw(value_reg, FieldMemOperand(scratch1, offset));
615 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000616
danno@chromium.orgf005df62013-04-30 16:36:45 +0000617 if (!FLAG_track_fields || !representation.IsSmi()) {
618 // Skip updating write barrier if storing a smi.
619 __ JumpIfSmi(value_reg, &exit);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000620
danno@chromium.orgf005df62013-04-30 16:36:45 +0000621 // Update the write barrier for the array address.
622 // Ok to clobber receiver_reg and name_reg, since we return.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000623 if (!FLAG_track_double_fields || !representation.IsDouble()) {
624 __ mov(name_reg, value_reg);
625 } else {
626 ASSERT(storage_reg.is(name_reg));
627 }
danno@chromium.orgf005df62013-04-30 16:36:45 +0000628 __ RecordWriteField(scratch1,
629 offset,
630 name_reg,
631 receiver_reg,
632 kRAHasNotBeenSaved,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000633 kDontSaveFPRegs,
634 EMIT_REMEMBERED_SET,
635 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000636 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000637 }
638
639 // Return the value (register v0).
640 ASSERT(value_reg.is(a0));
641 __ bind(&exit);
642 __ mov(v0, a0);
643 __ Ret();
644}
645
646
647// Generate StoreField code, value is passed in a0 register.
648// When leaving generated code after success, the receiver_reg and name_reg
649// may be clobbered. Upon branch to miss_label, the receiver and name
650// registers have their original values.
651void StubCompiler::GenerateStoreField(MacroAssembler* masm,
652 Handle<JSObject> object,
653 LookupResult* lookup,
654 Register receiver_reg,
655 Register name_reg,
656 Register value_reg,
657 Register scratch1,
658 Register scratch2,
659 Label* miss_label) {
660 // a0 : value
661 Label exit;
662
663 // Check that the map of the object hasn't changed.
664 __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000665 DO_SMI_CHECK);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000666
667 // Perform global security token check if needed.
668 if (object->IsJSGlobalProxy()) {
669 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
670 }
671
672 // Stub never generated for non-global objects that require access
673 // checks.
674 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
675
676 int index = lookup->GetFieldIndex().field_index();
677
678 // Adjust for the number of properties stored in the object. Even in the
679 // face of a transition we can use the old map here because the size of the
680 // object and the number of in-object properties is not going to change.
681 index -= object->map()->inobject_properties();
682
danno@chromium.orgf005df62013-04-30 16:36:45 +0000683 Representation representation = lookup->representation();
684 ASSERT(!representation.IsNone());
685 if (FLAG_track_fields && representation.IsSmi()) {
686 __ JumpIfNotSmi(value_reg, miss_label);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +0000687 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
688 __ JumpIfSmi(value_reg, miss_label);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000689 } else if (FLAG_track_double_fields && representation.IsDouble()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000690 // Load the double storage.
691 if (index < 0) {
692 int offset = object->map()->instance_size() + (index * kPointerSize);
693 __ lw(scratch1, FieldMemOperand(receiver_reg, offset));
694 } else {
695 __ lw(scratch1,
696 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
697 int offset = index * kPointerSize + FixedArray::kHeaderSize;
698 __ lw(scratch1, FieldMemOperand(scratch1, offset));
699 }
700
701 // Store the value into the storage.
702 Label do_store, heap_number;
703 __ JumpIfNotSmi(value_reg, &heap_number);
704 __ SmiUntag(scratch2, value_reg);
705 __ mtc1(scratch2, f6);
706 __ cvt_d_w(f4, f6);
707 __ jmp(&do_store);
708
709 __ bind(&heap_number);
710 __ CheckMap(value_reg, scratch2, Heap::kHeapNumberMapRootIndex,
danno@chromium.orgf005df62013-04-30 16:36:45 +0000711 miss_label, DONT_DO_SMI_CHECK);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000712 __ ldc1(f4, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
713
danno@chromium.orgf005df62013-04-30 16:36:45 +0000714 __ bind(&do_store);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000715 __ sdc1(f4, FieldMemOperand(scratch1, HeapNumber::kValueOffset));
716 // Return the value (register v0).
717 ASSERT(value_reg.is(a0));
718 __ mov(v0, a0);
719 __ Ret();
720 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +0000721 }
722
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000723 // TODO(verwaest): Share this code as a code stub.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000724 SmiCheck smi_check = representation.IsTagged()
725 ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000726 if (index < 0) {
727 // Set the property straight into the object.
728 int offset = object->map()->instance_size() + (index * kPointerSize);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000729 __ sw(value_reg, FieldMemOperand(receiver_reg, offset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000730
danno@chromium.orgf005df62013-04-30 16:36:45 +0000731 if (!FLAG_track_fields || !representation.IsSmi()) {
732 // Skip updating write barrier if storing a smi.
733 __ JumpIfSmi(value_reg, &exit);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000734
danno@chromium.orgf005df62013-04-30 16:36:45 +0000735 // Update the write barrier for the array address.
736 // Pass the now unused name_reg as a scratch register.
737 __ mov(name_reg, value_reg);
738 __ RecordWriteField(receiver_reg,
739 offset,
740 name_reg,
741 scratch1,
742 kRAHasNotBeenSaved,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000743 kDontSaveFPRegs,
744 EMIT_REMEMBERED_SET,
745 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000746 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000747 } else {
748 // Write to the properties array.
749 int offset = index * kPointerSize + FixedArray::kHeaderSize;
750 // Get the properties array.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000751 __ lw(scratch1,
752 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000753 __ sw(value_reg, FieldMemOperand(scratch1, offset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000754
danno@chromium.orgf005df62013-04-30 16:36:45 +0000755 if (!FLAG_track_fields || !representation.IsSmi()) {
756 // Skip updating write barrier if storing a smi.
757 __ JumpIfSmi(value_reg, &exit);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000758
danno@chromium.orgf005df62013-04-30 16:36:45 +0000759 // Update the write barrier for the array address.
760 // Ok to clobber receiver_reg and name_reg, since we return.
761 __ mov(name_reg, value_reg);
762 __ RecordWriteField(scratch1,
763 offset,
764 name_reg,
765 receiver_reg,
766 kRAHasNotBeenSaved,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000767 kDontSaveFPRegs,
768 EMIT_REMEMBERED_SET,
769 smi_check);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000770 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000771 }
772
773 // Return the value (register v0).
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000774 ASSERT(value_reg.is(a0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000775 __ bind(&exit);
776 __ mov(v0, a0);
777 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000778}
779
780
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000781void BaseStoreStubCompiler::GenerateRestoreName(MacroAssembler* masm,
782 Label* label,
783 Handle<Name> name) {
784 if (!label->is_unused()) {
785 __ bind(label);
786 __ li(this->name(), Operand(name));
787 }
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000788}
789
790
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000791static void GenerateCallFunction(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000792 Handle<Object> object,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000793 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000794 Label* miss,
795 Code::ExtraICState extra_ic_state) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000796 // ----------- S t a t e -------------
797 // -- a0: receiver
798 // -- a1: function to call
799 // -----------------------------------
800 // Check that the function really is a function.
801 __ JumpIfSmi(a1, miss);
802 __ GetObjectType(a1, a3, a3);
803 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
804
805 // Patch the receiver on the stack with the global proxy if
806 // necessary.
807 if (object->IsGlobalObject()) {
808 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
809 __ sw(a3, MemOperand(sp, arguments.immediate() * kPointerSize));
810 }
811
812 // Invoke the function.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000813 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
814 ? CALL_AS_FUNCTION
815 : CALL_AS_METHOD;
816 __ InvokeFunction(a1, arguments, JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000817}
818
819
820static void PushInterceptorArguments(MacroAssembler* masm,
821 Register receiver,
822 Register holder,
823 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000824 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000825 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000826 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
827 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000828 Register scratch = name;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000829 __ li(scratch, Operand(interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000830 __ Push(scratch, receiver, holder);
831 __ lw(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
832 __ push(scratch);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000833 __ li(scratch, Operand(ExternalReference::isolate_address(masm->isolate())));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000834 __ push(scratch);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000835}
836
837
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000838static void CompileCallLoadPropertyWithInterceptor(
839 MacroAssembler* masm,
840 Register receiver,
841 Register holder,
842 Register name,
843 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000844 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
845
846 ExternalReference ref =
847 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
848 masm->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000849 __ PrepareCEntryArgs(6);
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000850 __ PrepareCEntryFunction(ref);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000851
852 CEntryStub stub(1);
853 __ CallStub(&stub);
854}
855
856
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000857static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000858
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000859// Reserves space for the extra arguments to API function in the
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000860// caller's frame.
861//
862// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
863static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
864 Register scratch) {
865 ASSERT(Smi::FromInt(0) == 0);
866 for (int i = 0; i < kFastApiCallArguments; i++) {
867 __ push(zero_reg);
868 }
869}
870
871
872// Undoes the effects of ReserveSpaceForFastApiCall.
873static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
874 __ Drop(kFastApiCallArguments);
875}
876
877
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000878static void GenerateFastApiDirectCall(MacroAssembler* masm,
879 const CallOptimization& optimization,
880 int argc) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000881 // ----------- S t a t e -------------
882 // -- sp[0] : holder (set by CheckPrototypes)
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000883 // -- sp[4] : callee JS function
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000884 // -- sp[8] : call data
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000885 // -- sp[12] : isolate
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000886 // -- sp[16] : ReturnValue
887 // -- sp[20] : last JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000888 // -- ...
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000889 // -- sp[(argc + 4) * 4] : first JS argument
890 // -- sp[(argc + 5) * 4] : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000891 // -----------------------------------
892 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000893 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000894 __ LoadHeapObject(t1, function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000895 __ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset));
896
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000897 // Pass the additional arguments.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000898 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000899 Handle<Object> call_data(api_call_info->data(), masm->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000900 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
901 __ li(a0, api_call_info);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000902 __ lw(t2, FieldMemOperand(a0, CallHandlerInfo::kDataOffset));
903 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000904 __ li(t2, call_data);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000905 }
906
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000907 __ li(t3, Operand(ExternalReference::isolate_address(masm->isolate())));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000908 // Store JS function, call data, isolate and ReturnValue.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000909 __ sw(t1, MemOperand(sp, 1 * kPointerSize));
910 __ sw(t2, MemOperand(sp, 2 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000911 __ sw(t3, MemOperand(sp, 3 * kPointerSize));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000912 __ LoadRoot(t1, Heap::kUndefinedValueRootIndex);
913 __ sw(t1, MemOperand(sp, 4 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000914
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000915 // Prepare arguments.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000916 __ Addu(a2, sp, Operand(4 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000917
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000918 // Allocate the v8::Arguments structure in the arguments' space since
919 // it's not controlled by GC.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000920 const int kApiStackSpace = 4;
921
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000922 FrameScope frame_scope(masm, StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000923 __ EnterExitFrame(false, kApiStackSpace);
924
925 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
926 // struct from the function (which is currently the case). This means we pass
927 // the first argument in a1 instead of a0. TryCallApiFunctionAndReturn
928 // will handle setting up a0.
929
930 // a1 = v8::Arguments&
931 // Arguments is built at sp + 1 (sp is a reserved spot for ra).
932 __ Addu(a1, sp, kPointerSize);
933
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000934 // v8::Arguments::implicit_args_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000935 __ sw(a2, MemOperand(a1, 0 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000936 // v8::Arguments::values_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000937 __ Addu(t0, a2, Operand(argc * kPointerSize));
938 __ sw(t0, MemOperand(a1, 1 * kPointerSize));
939 // v8::Arguments::length_ = argc
940 __ li(t0, Operand(argc));
941 __ sw(t0, MemOperand(a1, 2 * kPointerSize));
942 // v8::Arguments::is_construct_call = 0
943 __ sw(zero_reg, MemOperand(a1, 3 * kPointerSize));
944
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000945 const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000946 Address function_address = v8::ToCData<Address>(api_call_info->callback());
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000947 bool returns_handle =
948 !CallbackTable::ReturnsVoid(masm->isolate(), function_address);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000949 ApiFunction fun(function_address);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000950 ExternalReference::Type type =
951 returns_handle ?
952 ExternalReference::DIRECT_API_CALL :
953 ExternalReference::DIRECT_API_CALL_NEW;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000954 ExternalReference ref =
955 ExternalReference(&fun,
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000956 type,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000957 masm->isolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000958 AllowExternalCallThatCantCauseGC scope(masm);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000959 __ CallApiFunctionAndReturn(ref,
960 kStackUnwindSpace,
961 returns_handle,
962 kFastApiCallArguments + 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000963}
964
lrn@chromium.org7516f052011-03-30 08:52:27 +0000965class CallInterceptorCompiler BASE_EMBEDDED {
966 public:
967 CallInterceptorCompiler(StubCompiler* stub_compiler,
968 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000969 Register name,
970 Code::ExtraICState extra_ic_state)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000971 : stub_compiler_(stub_compiler),
972 arguments_(arguments),
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000973 name_(name),
974 extra_ic_state_(extra_ic_state) {}
lrn@chromium.org7516f052011-03-30 08:52:27 +0000975
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000976 void Compile(MacroAssembler* masm,
977 Handle<JSObject> object,
978 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000979 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000980 LookupResult* lookup,
981 Register receiver,
982 Register scratch1,
983 Register scratch2,
984 Register scratch3,
985 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000986 ASSERT(holder->HasNamedInterceptor());
987 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
988
989 // Check that the receiver isn't a smi.
990 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000991 CallOptimization optimization(lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000992 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000993 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
994 holder, lookup, name, optimization, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000995 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000996 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
997 name, holder, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000998 }
999 }
1000
1001 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001002 void CompileCacheable(MacroAssembler* masm,
1003 Handle<JSObject> object,
1004 Register receiver,
1005 Register scratch1,
1006 Register scratch2,
1007 Register scratch3,
1008 Handle<JSObject> interceptor_holder,
1009 LookupResult* lookup,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001010 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001011 const CallOptimization& optimization,
1012 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001013 ASSERT(optimization.is_constant_call());
1014 ASSERT(!lookup->holder()->IsGlobalObject());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001015 Counters* counters = masm->isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001016 int depth1 = kInvalidProtoDepth;
1017 int depth2 = kInvalidProtoDepth;
1018 bool can_do_fast_api_call = false;
1019 if (optimization.is_simple_api_call() &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001020 !lookup->holder()->IsGlobalObject()) {
1021 depth1 = optimization.GetPrototypeDepthOfExpectedType(
1022 object, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001023 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001024 depth2 = optimization.GetPrototypeDepthOfExpectedType(
1025 interceptor_holder, Handle<JSObject>(lookup->holder()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001026 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001027 can_do_fast_api_call =
1028 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001029 }
1030
1031 __ IncrementCounter(counters->call_const_interceptor(), 1,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001032 scratch1, scratch2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001033
1034 if (can_do_fast_api_call) {
1035 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
1036 scratch1, scratch2);
1037 ReserveSpaceForFastApiCall(masm, scratch1);
1038 }
1039
1040 // Check that the maps from receiver to interceptor's holder
1041 // haven't changed and thus we can invoke interceptor.
1042 Label miss_cleanup;
1043 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
1044 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001045 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
1046 scratch1, scratch2, scratch3,
1047 name, depth1, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001048
1049 // Invoke an interceptor and if it provides a value,
1050 // branch to |regular_invoke|.
1051 Label regular_invoke;
1052 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
1053 &regular_invoke);
1054
1055 // Interceptor returned nothing for this property. Try to use cached
1056 // constant function.
1057
1058 // Check that the maps from interceptor's holder to constant function's
1059 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001060 if (*interceptor_holder != lookup->holder()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001061 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001062 Handle<JSObject>(lookup->holder()),
1063 scratch1, scratch2, scratch3,
1064 name, depth2, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001065 } else {
1066 // CheckPrototypes has a side effect of fetching a 'holder'
1067 // for API (object which is instanceof for the signature). It's
1068 // safe to omit it here, as if present, it should be fetched
1069 // by the previous CheckPrototypes.
1070 ASSERT(depth2 == kInvalidProtoDepth);
1071 }
1072
1073 // Invoke function.
1074 if (can_do_fast_api_call) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001075 GenerateFastApiDirectCall(masm, optimization, arguments_.immediate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001076 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001077 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
1078 ? CALL_AS_FUNCTION
1079 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001080 Handle<JSFunction> function = optimization.constant_function();
1081 ParameterCount expected(function);
1082 __ InvokeFunction(function, expected, arguments_,
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001083 JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001084 }
1085
1086 // Deferred code for fast API call case---clean preallocated space.
1087 if (can_do_fast_api_call) {
1088 __ bind(&miss_cleanup);
1089 FreeSpaceForFastApiCall(masm);
1090 __ Branch(miss_label);
1091 }
1092
1093 // Invoke a regular function.
1094 __ bind(&regular_invoke);
1095 if (can_do_fast_api_call) {
1096 FreeSpaceForFastApiCall(masm);
1097 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00001098 }
1099
1100 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001101 Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001102 Register receiver,
1103 Register scratch1,
1104 Register scratch2,
1105 Register scratch3,
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001106 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001107 Handle<JSObject> interceptor_holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001108 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001109 Register holder =
1110 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001111 scratch1, scratch2, scratch3,
1112 name, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001113
1114 // Call a runtime function to load the interceptor property.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001115 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001116 // Save the name_ register across the call.
1117 __ push(name_);
1118
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001119 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001120
1121 __ CallExternalReference(
1122 ExternalReference(
1123 IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
1124 masm->isolate()),
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001125 6);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001126 // Restore the name_ register.
1127 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001128 // Leave the internal frame.
lrn@chromium.org7516f052011-03-30 08:52:27 +00001129 }
1130
1131 void LoadWithInterceptor(MacroAssembler* masm,
1132 Register receiver,
1133 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001134 Handle<JSObject> holder_obj,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001135 Register scratch,
1136 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001137 {
1138 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001139
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001140 __ Push(holder, name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001141 CompileCallLoadPropertyWithInterceptor(masm,
1142 receiver,
1143 holder,
1144 name_,
1145 holder_obj);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001146 __ pop(name_); // Restore the name.
1147 __ pop(receiver); // Restore the holder.
1148 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001149 // If interceptor returns no-result sentinel, call the constant function.
1150 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
1151 __ Branch(interceptor_succeeded, ne, v0, Operand(scratch));
lrn@chromium.org7516f052011-03-30 08:52:27 +00001152 }
1153
1154 StubCompiler* stub_compiler_;
1155 const ParameterCount& arguments_;
1156 Register name_;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001157 Code::ExtraICState extra_ic_state_;
lrn@chromium.org7516f052011-03-30 08:52:27 +00001158};
1159
1160
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001161// Calls GenerateCheckPropertyCell for each global object in the prototype chain
1162// from object to (but not including) holder.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001163static void GenerateCheckPropertyCells(MacroAssembler* masm,
1164 Handle<JSObject> object,
1165 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001166 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001167 Register scratch,
1168 Label* miss) {
1169 Handle<JSObject> current = object;
1170 while (!current.is_identical_to(holder)) {
1171 if (current->IsGlobalObject()) {
1172 GenerateCheckPropertyCell(masm,
1173 Handle<GlobalObject>::cast(current),
1174 name,
1175 scratch,
1176 miss);
1177 }
1178 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
1179 }
1180}
1181
1182
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001183// Convert and store int passed in register ival to IEEE 754 single precision
1184// floating point value at memory location (dst + 4 * wordoffset)
1185// If FPU is available use it for conversion.
1186static void StoreIntAsFloat(MacroAssembler* masm,
1187 Register dst,
1188 Register wordoffset,
1189 Register ival,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001190 Register scratch1) {
1191 __ mtc1(ival, f0);
1192 __ cvt_s_w(f0, f0);
1193 __ sll(scratch1, wordoffset, 2);
1194 __ addu(scratch1, dst, scratch1);
1195 __ swc1(f0, MemOperand(scratch1, 0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001196}
1197
1198
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001199void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001200 __ Jump(code, RelocInfo::CODE_TARGET);
1201}
1202
1203
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001204#undef __
1205#define __ ACCESS_MASM(masm())
1206
1207
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001208Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
1209 Register object_reg,
1210 Handle<JSObject> holder,
1211 Register holder_reg,
1212 Register scratch1,
1213 Register scratch2,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001214 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001215 int save_at_depth,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001216 Label* miss,
1217 PrototypeCheckType check) {
1218 Handle<JSObject> first = object;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001219 // Make sure there's no overlap between holder and object registers.
1220 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1221 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1222 && !scratch2.is(scratch1));
1223
1224 // Keep track of the current object in register reg.
1225 Register reg = object_reg;
1226 int depth = 0;
1227
1228 if (save_at_depth == depth) {
1229 __ sw(reg, MemOperand(sp));
1230 }
1231
1232 // Check the maps in the prototype chain.
1233 // Traverse the prototype chain from the object and do map checks.
1234 Handle<JSObject> current = object;
1235 while (!current.is_identical_to(holder)) {
1236 ++depth;
1237
1238 // Only global objects and objects that do not require access
1239 // checks are allowed in stubs.
1240 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1241
1242 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
1243 if (!current->HasFastProperties() &&
1244 !current->IsJSGlobalObject() &&
1245 !current->IsJSGlobalProxy()) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001246 if (!name->IsUniqueName()) {
1247 ASSERT(name->IsString());
1248 name = factory()->InternalizeString(Handle<String>::cast(name));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001249 }
1250 ASSERT(current->property_dictionary()->FindEntry(*name) ==
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001251 NameDictionary::kNotFound);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001252
1253 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1254 scratch1, scratch2);
1255
1256 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1257 reg = holder_reg; // From now on the object will be in holder_reg.
1258 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1259 } else {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001260 Register map_reg = scratch1;
1261 if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) {
1262 Handle<Map> current_map(current->map());
1263 // CheckMap implicitly loads the map of |reg| into |map_reg|.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001264 __ CheckMap(reg, map_reg, current_map, miss, DONT_DO_SMI_CHECK);
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001265 } else {
1266 __ lw(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
1267 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001268 // Check access rights to the global object. This has to happen after
1269 // the map check so that we know that the object is actually a global
1270 // object.
1271 if (current->IsJSGlobalProxy()) {
1272 __ CheckAccessGlobalProxy(reg, scratch2, miss);
1273 }
1274 reg = holder_reg; // From now on the object will be in holder_reg.
1275
1276 if (heap()->InNewSpace(*prototype)) {
1277 // The prototype is in new space; we cannot store a reference to it
1278 // in the code. Load it from the map.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001279 __ lw(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001280 } else {
1281 // The prototype is in old space; load it directly.
1282 __ li(reg, Operand(prototype));
1283 }
1284 }
1285
1286 if (save_at_depth == depth) {
1287 __ sw(reg, MemOperand(sp));
1288 }
1289
1290 // Go to the next object in the prototype chain.
1291 current = prototype;
1292 }
1293
1294 // Log the check depth.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001295 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001296
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001297 if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) {
1298 // Check the holder map.
1299 __ CheckMap(reg, scratch1, Handle<Map>(holder->map()), miss,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001300 DONT_DO_SMI_CHECK);
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001301 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001302
1303 // Perform security check for access to the global object.
1304 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1305 if (holder->IsJSGlobalProxy()) {
1306 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1307 }
1308
1309 // If we've skipped any global objects, it's not enough to verify that
1310 // their maps haven't changed. We also need to check that the property
1311 // cell for the property is still empty.
1312 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1313
1314 // Return the register containing the holder.
1315 return reg;
1316}
1317
1318
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001319void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success,
1320 Label* miss) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001321 if (!miss->is_unused()) {
1322 __ Branch(success);
1323 __ bind(miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001324 TailCallBuiltin(masm(), MissBuiltin(kind()));
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001325 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001326}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001327
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001328
1329Register BaseLoadStubCompiler::CallbackHandlerFrontend(
1330 Handle<JSObject> object,
1331 Register object_reg,
1332 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001333 Handle<Name> name,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001334 Label* success,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001335 Handle<ExecutableAccessorInfo> callback) {
1336 Label miss;
1337
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001338 Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001339
1340 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
1341 ASSERT(!reg.is(scratch2()));
1342 ASSERT(!reg.is(scratch3()));
1343 ASSERT(!reg.is(scratch4()));
1344
1345 // Load the properties dictionary.
1346 Register dictionary = scratch4();
1347 __ lw(dictionary, FieldMemOperand(reg, JSObject::kPropertiesOffset));
1348
1349 // Probe the dictionary.
1350 Label probe_done;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001351 NameDictionaryLookupStub::GeneratePositiveLookup(masm(),
1352 &miss,
1353 &probe_done,
1354 dictionary,
1355 this->name(),
1356 scratch2(),
1357 scratch3());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001358 __ bind(&probe_done);
1359
1360 // If probing finds an entry in the dictionary, scratch3 contains the
1361 // pointer into the dictionary. Check that the value is the callback.
1362 Register pointer = scratch3();
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001363 const int kElementsStartOffset = NameDictionary::kHeaderSize +
1364 NameDictionary::kElementsStartIndex * kPointerSize;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001365 const int kValueOffset = kElementsStartOffset + kPointerSize;
1366 __ lw(scratch2(), FieldMemOperand(pointer, kValueOffset));
1367 __ Branch(&miss, ne, scratch2(), Operand(callback));
1368 }
1369
1370 HandlerFrontendFooter(success, &miss);
1371 return reg;
1372}
1373
1374
1375void BaseLoadStubCompiler::NonexistentHandlerFrontend(
1376 Handle<JSObject> object,
1377 Handle<JSObject> last,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001378 Handle<Name> name,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001379 Label* success,
1380 Handle<GlobalObject> global) {
1381 Label miss;
1382
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001383 HandlerFrontendHeader(object, receiver(), last, name, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001384
1385 // If the last object in the prototype chain is a global object,
1386 // check that the global property cell is empty.
1387 if (!global.is_null()) {
1388 GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
1389 }
1390
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001391 HandlerFrontendFooter(success, &miss);
1392}
1393
1394
1395void BaseLoadStubCompiler::GenerateLoadField(Register reg,
1396 Handle<JSObject> holder,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001397 PropertyIndex field,
1398 Representation representation) {
1399 if (!reg.is(receiver())) __ mov(receiver(), reg);
1400 if (kind() == Code::LOAD_IC) {
1401 LoadFieldStub stub(field.is_inobject(holder),
1402 field.translate(holder),
1403 representation);
1404 GenerateTailCall(masm(), stub.GetCode(isolate()));
1405 } else {
1406 KeyedLoadFieldStub stub(field.is_inobject(holder),
1407 field.translate(holder),
1408 representation);
1409 GenerateTailCall(masm(), stub.GetCode(isolate()));
1410 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001411}
1412
1413
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001414void BaseLoadStubCompiler::GenerateLoadConstant(Handle<JSFunction> value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001415 // Return the constant value.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001416 __ LoadHeapObject(v0, value);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001417 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001418}
1419
1420
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001421void BaseLoadStubCompiler::GenerateLoadCallback(
1422 Register reg,
1423 Handle<ExecutableAccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001424 // Build AccessorInfo::args_ list on the stack and push property name below
1425 // the exit frame to make GC aware of them and store pointers to them.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001426 __ push(receiver());
1427 __ mov(scratch2(), sp); // scratch2 = AccessorInfo::args_
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001428 if (heap()->InNewSpace(callback->data())) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001429 __ li(scratch3(), callback);
1430 __ lw(scratch3(), FieldMemOperand(scratch3(),
1431 ExecutableAccessorInfo::kDataOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001432 } else {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001433 __ li(scratch3(), Handle<Object>(callback->data(), isolate()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001434 }
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001435 __ Subu(sp, sp, 5 * kPointerSize);
1436 __ sw(reg, MemOperand(sp, 4 * kPointerSize));
1437 __ sw(scratch3(), MemOperand(sp, 3 * kPointerSize));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001438 __ li(scratch3(),
1439 Operand(ExternalReference::isolate_address(isolate())));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001440 __ LoadRoot(scratch4(), Heap::kUndefinedValueRootIndex);
1441 __ sw(scratch3(), MemOperand(sp, 2 * kPointerSize));
1442 __ sw(scratch4(), MemOperand(sp, 1 * kPointerSize));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001443 __ sw(name(), MemOperand(sp, 0 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001444
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001445 __ mov(a2, scratch2()); // Saved in case scratch2 == a1.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001446 __ mov(a1, sp); // a1 (first argument - see note below) = Handle<Name>
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001447
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001448 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
1449 // struct from the function (which is currently the case). This means we pass
1450 // the arguments in a1-a2 instead of a0-a1. TryCallApiFunctionAndReturn
1451 // will handle setting up a0.
1452
1453 const int kApiStackSpace = 1;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001454 FrameScope frame_scope(masm(), StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001455 __ EnterExitFrame(false, kApiStackSpace);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001456
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001457 // Create AccessorInfo instance on the stack above the exit frame with
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001458 // scratch2 (internal::Object** args_) as the data.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001459 __ sw(a2, MemOperand(sp, kPointerSize));
1460 // a2 (second argument - see note above) = AccessorInfo&
1461 __ Addu(a2, sp, kPointerSize);
1462
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001463 const int kStackUnwindSpace = kFastApiCallArguments + 1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001464 Address getter_address = v8::ToCData<Address>(callback->getter());
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001465 bool returns_handle =
1466 !CallbackTable::ReturnsVoid(isolate(), getter_address);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001467 ApiFunction fun(getter_address);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001468 ExternalReference::Type type =
1469 returns_handle ?
1470 ExternalReference::DIRECT_GETTER_CALL :
1471 ExternalReference::DIRECT_GETTER_CALL_NEW;
1472
1473 ExternalReference ref = ExternalReference(&fun, type, isolate());
1474 __ CallApiFunctionAndReturn(ref,
1475 kStackUnwindSpace,
1476 returns_handle,
1477 3);
ager@chromium.org5c838252010-02-19 08:53:10 +00001478}
1479
1480
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001481void BaseLoadStubCompiler::GenerateLoadInterceptor(
1482 Register holder_reg,
1483 Handle<JSObject> object,
1484 Handle<JSObject> interceptor_holder,
1485 LookupResult* lookup,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001486 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001487 ASSERT(interceptor_holder->HasNamedInterceptor());
1488 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1489
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001490 // So far the most popular follow ups for interceptor loads are FIELD
1491 // and CALLBACKS, so inline only them, other cases may be added
1492 // later.
1493 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001494 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001495 if (lookup->IsField()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001496 compile_followup_inline = true;
1497 } else if (lookup->type() == CALLBACKS &&
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001498 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
1499 ExecutableAccessorInfo* callback =
1500 ExecutableAccessorInfo::cast(lookup->GetCallbackObject());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001501 compile_followup_inline = callback->getter() != NULL &&
1502 callback->IsCompatibleReceiver(*object);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001503 }
1504 }
1505
1506 if (compile_followup_inline) {
1507 // Compile the interceptor call, followed by inline code to load the
1508 // property from further up the prototype chain if the call fails.
1509 // Check that the maps haven't changed.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001510 ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001511
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001512 // Preserve the receiver register explicitly whenever it is different from
1513 // the holder and it is needed should the interceptor return without any
1514 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1515 // the FIELD case might cause a miss during the prototype check.
1516 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001517 bool must_preserve_receiver_reg = !receiver().is(holder_reg) &&
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001518 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1519
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001520 // Save necessary data before invoking an interceptor.
1521 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001522 {
1523 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001524 if (must_preserve_receiver_reg) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001525 __ Push(receiver(), holder_reg, this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001526 } else {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001527 __ Push(holder_reg, this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001528 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001529 // Invoke an interceptor. Note: map checks from receiver to
1530 // interceptor's holder has been compiled before (see a caller
1531 // of this method).
1532 CompileCallLoadPropertyWithInterceptor(masm(),
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001533 receiver(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001534 holder_reg,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001535 this->name(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001536 interceptor_holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001537 // Check if interceptor provided a value for property. If it's
1538 // the case, return immediately.
1539 Label interceptor_failed;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001540 __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
1541 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001542 frame_scope.GenerateLeaveFrame();
1543 __ Ret();
1544
1545 __ bind(&interceptor_failed);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001546 __ pop(this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001547 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001548 if (must_preserve_receiver_reg) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001549 __ pop(receiver());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001550 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001551 // Leave the internal frame.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001552 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001553 GenerateLoadPostInterceptor(holder_reg, interceptor_holder, name, lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001554 } else { // !compile_followup_inline
1555 // Call the runtime system to load the interceptor.
1556 // Check that the maps haven't changed.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001557 PushInterceptorArguments(masm(), receiver(), holder_reg,
1558 this->name(), interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001559
1560 ExternalReference ref = ExternalReference(
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001561 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001562 __ TailCallExternalReference(ref, 6, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001563 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001564}
1565
1566
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001567void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001568 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001569 __ Branch(miss, ne, a2, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001570 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001571}
1572
1573
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001574void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1575 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001576 Handle<Name> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001577 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001578 ASSERT(holder->IsGlobalObject());
1579
1580 // Get the number of arguments.
1581 const int argc = arguments().immediate();
1582
1583 // Get the receiver from the stack.
1584 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1585
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001586 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001587 __ JumpIfSmi(a0, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001588 CheckPrototypes(object, a0, holder, a3, a1, t0, name, miss);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001589}
1590
1591
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001592void CallStubCompiler::GenerateLoadFunctionFromCell(
1593 Handle<JSGlobalPropertyCell> cell,
1594 Handle<JSFunction> function,
1595 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001596 // Get the value from the cell.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001597 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001598 __ lw(a1, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
1599
1600 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001601 if (heap()->InNewSpace(*function)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001602 // We can't embed a pointer to a function in new space so we have
1603 // to verify that the shared function info is unchanged. This has
1604 // the nice side effect that multiple closures based on the same
1605 // function can all use this call IC. Before we load through the
1606 // function, we have to verify that it still is a function.
1607 __ JumpIfSmi(a1, miss);
1608 __ GetObjectType(a1, a3, a3);
1609 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
1610
1611 // Check the shared function info. Make sure it hasn't changed.
1612 __ li(a3, Handle<SharedFunctionInfo>(function->shared()));
1613 __ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
1614 __ Branch(miss, ne, t0, Operand(a3));
1615 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001616 __ Branch(miss, ne, a1, Operand(function));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001617 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001618}
1619
1620
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001621void CallStubCompiler::GenerateMissBranch() {
1622 Handle<Code> code =
danno@chromium.org40cb8782011-05-25 07:58:50 +00001623 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1624 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001625 extra_state_);
1626 __ Jump(code, RelocInfo::CODE_TARGET);
1627}
1628
1629
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001630Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1631 Handle<JSObject> holder,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001632 PropertyIndex index,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001633 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001634 // ----------- S t a t e -------------
1635 // -- a2 : name
1636 // -- ra : return address
1637 // -----------------------------------
1638 Label miss;
1639
1640 GenerateNameCheck(name, &miss);
1641
1642 const int argc = arguments().immediate();
1643
1644 // Get the receiver of the function from the stack into a0.
1645 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1646 // Check that the receiver isn't a smi.
1647 __ JumpIfSmi(a0, &miss, t0);
1648
1649 // Do the right check and compute the holder register.
1650 Register reg = CheckPrototypes(object, a0, holder, a1, a3, t0, name, &miss);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001651 GenerateFastPropertyLoad(masm(), a1, reg, index.is_inobject(holder),
1652 index.translate(holder), Representation::Tagged());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001653
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001654 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001655
1656 // Handle call cache miss.
1657 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001658 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001659
1660 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001661 return GetCode(Code::FIELD, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001662}
1663
1664
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001665Handle<Code> CallStubCompiler::CompileArrayPushCall(
1666 Handle<Object> object,
1667 Handle<JSObject> holder,
1668 Handle<JSGlobalPropertyCell> cell,
1669 Handle<JSFunction> function,
1670 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001671 // ----------- S t a t e -------------
1672 // -- a2 : name
1673 // -- ra : return address
1674 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1675 // -- ...
1676 // -- sp[argc * 4] : receiver
1677 // -----------------------------------
1678
1679 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001680 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001681
1682 Label miss;
1683
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001684 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001685
1686 Register receiver = a1;
1687
1688 // Get the receiver from the stack.
1689 const int argc = arguments().immediate();
1690 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1691
1692 // Check that the receiver isn't a smi.
1693 __ JumpIfSmi(receiver, &miss);
1694
1695 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001696 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, a3, v0, t0,
1697 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001698
1699 if (argc == 0) {
1700 // Nothing to do, just return the length.
1701 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1702 __ Drop(argc + 1);
1703 __ Ret();
1704 } else {
1705 Label call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001706 if (argc == 1) { // Otherwise fall through to call the builtin.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001707 Label attempt_to_grow_elements, with_write_barrier, check_double;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001708
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001709 Register elements = t2;
1710 Register end_elements = t1;
1711 // Get the elements array of the object.
1712 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1713
1714 // Check that the elements are in fast mode and writable.
1715 __ CheckMap(elements,
1716 v0,
1717 Heap::kFixedArrayMapRootIndex,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001718 &check_double,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001719 DONT_DO_SMI_CHECK);
1720
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001721 // Get the array's length into v0 and calculate new length.
1722 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1723 STATIC_ASSERT(kSmiTagSize == 1);
1724 STATIC_ASSERT(kSmiTag == 0);
1725 __ Addu(v0, v0, Operand(Smi::FromInt(argc)));
1726
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001727 // Get the elements' length.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001728 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1729
1730 // Check if we could survive without allocation.
1731 __ Branch(&attempt_to_grow_elements, gt, v0, Operand(t0));
1732
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001733 // Check if value is a smi.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001734 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1735 __ JumpIfNotSmi(t0, &with_write_barrier);
1736
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001737 // Save new length.
1738 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1739
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001740 // Store the value.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001741 // We may need a register containing the address end_elements below,
1742 // so write back the value in end_elements.
1743 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1744 __ Addu(end_elements, elements, end_elements);
1745 const int kEndElementsOffset =
1746 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001747 __ Addu(end_elements, end_elements, kEndElementsOffset);
1748 __ sw(t0, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001749
1750 // Check for a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001751 __ Drop(argc + 1);
1752 __ Ret();
1753
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001754 __ bind(&check_double);
1755
1756 // Check that the elements are in fast mode and writable.
1757 __ CheckMap(elements,
1758 a0,
1759 Heap::kFixedDoubleArrayMapRootIndex,
1760 &call_builtin,
1761 DONT_DO_SMI_CHECK);
1762
1763 // Get the array's length into r0 and calculate new length.
1764 __ lw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1765 STATIC_ASSERT(kSmiTagSize == 1);
1766 STATIC_ASSERT(kSmiTag == 0);
1767 __ Addu(a0, a0, Operand(Smi::FromInt(argc)));
1768
1769 // Get the elements' length.
1770 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1771
1772 // Check if we could survive without allocation.
1773 __ Branch(&call_builtin, gt, a0, Operand(t0));
1774
1775 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1776 __ StoreNumberToDoubleElements(
1777 t0, a0, elements, a3, t1, a2, t5,
1778 &call_builtin, argc * kDoubleSize);
1779
1780 // Save new length.
1781 __ sw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1782
1783 // Check for a smi.
1784 __ Drop(argc + 1);
1785 __ Ret();
1786
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001787 __ bind(&with_write_barrier);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001788
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001789 __ lw(a3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1790
1791 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
1792 Label fast_object, not_fast_object;
1793 __ CheckFastObjectElements(a3, t3, &not_fast_object);
1794 __ jmp(&fast_object);
1795 // In case of fast smi-only, convert to fast object, otherwise bail out.
1796 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001797 __ CheckFastSmiElements(a3, t3, &call_builtin);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001798
1799 __ lw(t3, FieldMemOperand(t0, HeapObject::kMapOffset));
1800 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
1801 __ Branch(&call_builtin, eq, t3, Operand(at));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001802 // edx: receiver
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001803 // a3: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001804 Label try_holey_map;
1805 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001806 FAST_ELEMENTS,
1807 a3,
1808 t3,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001809 &try_holey_map);
1810 __ mov(a2, receiver);
1811 ElementsTransitionGenerator::
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001812 GenerateMapChangeElementsTransition(masm(),
1813 DONT_TRACK_ALLOCATION_SITE,
1814 NULL);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001815 __ jmp(&fast_object);
1816
1817 __ bind(&try_holey_map);
1818 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1819 FAST_HOLEY_ELEMENTS,
1820 a3,
1821 t3,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001822 &call_builtin);
1823 __ mov(a2, receiver);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001824 ElementsTransitionGenerator::
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001825 GenerateMapChangeElementsTransition(masm(),
1826 DONT_TRACK_ALLOCATION_SITE,
1827 NULL);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001828 __ bind(&fast_object);
1829 } else {
1830 __ CheckFastObjectElements(a3, a3, &call_builtin);
1831 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001832
1833 // Save new length.
1834 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1835
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001836 // Store the value.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001837 // We may need a register containing the address end_elements below,
1838 // so write back the value in end_elements.
1839 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1840 __ Addu(end_elements, elements, end_elements);
1841 __ Addu(end_elements, end_elements, kEndElementsOffset);
1842 __ sw(t0, MemOperand(end_elements));
1843
1844 __ RecordWrite(elements,
1845 end_elements,
1846 t0,
1847 kRAHasNotBeenSaved,
1848 kDontSaveFPRegs,
1849 EMIT_REMEMBERED_SET,
1850 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001851 __ Drop(argc + 1);
1852 __ Ret();
1853
1854 __ bind(&attempt_to_grow_elements);
1855 // v0: array's length + 1.
1856 // t0: elements' length.
1857
1858 if (!FLAG_inline_new) {
1859 __ Branch(&call_builtin);
1860 }
1861
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001862 __ lw(a2, MemOperand(sp, (argc - 1) * kPointerSize));
1863 // Growing elements that are SMI-only requires special handling in case
1864 // the new element is non-Smi. For now, delegate to the builtin.
1865 Label no_fast_elements_check;
1866 __ JumpIfSmi(a2, &no_fast_elements_check);
1867 __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1868 __ CheckFastObjectElements(t3, t3, &call_builtin);
1869 __ bind(&no_fast_elements_check);
1870
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001871 ExternalReference new_space_allocation_top =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001872 ExternalReference::new_space_allocation_top_address(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001873 ExternalReference new_space_allocation_limit =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001874 ExternalReference::new_space_allocation_limit_address(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001875
1876 const int kAllocationDelta = 4;
1877 // Load top and check if it is the end of elements.
1878 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1879 __ Addu(end_elements, elements, end_elements);
1880 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset));
1881 __ li(t3, Operand(new_space_allocation_top));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001882 __ lw(a3, MemOperand(t3));
1883 __ Branch(&call_builtin, ne, end_elements, Operand(a3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001884
1885 __ li(t5, Operand(new_space_allocation_limit));
1886 __ lw(t5, MemOperand(t5));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001887 __ Addu(a3, a3, Operand(kAllocationDelta * kPointerSize));
1888 __ Branch(&call_builtin, hi, a3, Operand(t5));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001889
1890 // We fit and could grow elements.
1891 // Update new_space_allocation_top.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001892 __ sw(a3, MemOperand(t3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001893 // Push the argument.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001894 __ sw(a2, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001895 // Fill the rest with holes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001896 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001897 for (int i = 1; i < kAllocationDelta; i++) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001898 __ sw(a3, MemOperand(end_elements, i * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001899 }
1900
1901 // Update elements' and array's sizes.
1902 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1903 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta)));
1904 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1905
1906 // Elements are in new space, so write barrier is not required.
1907 __ Drop(argc + 1);
1908 __ Ret();
1909 }
1910 __ bind(&call_builtin);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001911 __ TailCallExternalReference(
1912 ExternalReference(Builtins::c_ArrayPush, isolate()), argc + 1, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001913 }
1914
1915 // Handle call cache miss.
1916 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001917 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001918
1919 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001920 return GetCode(function);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001921}
1922
1923
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001924Handle<Code> CallStubCompiler::CompileArrayPopCall(
1925 Handle<Object> object,
1926 Handle<JSObject> holder,
1927 Handle<JSGlobalPropertyCell> cell,
1928 Handle<JSFunction> function,
1929 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001930 // ----------- S t a t e -------------
1931 // -- a2 : name
1932 // -- ra : return address
1933 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1934 // -- ...
1935 // -- sp[argc * 4] : receiver
1936 // -----------------------------------
1937
1938 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001939 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001940
1941 Label miss, return_undefined, call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001942 Register receiver = a1;
1943 Register elements = a3;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001944 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001945
1946 // Get the receiver from the stack.
1947 const int argc = arguments().immediate();
1948 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001949 // Check that the receiver isn't a smi.
1950 __ JumpIfSmi(receiver, &miss);
1951
1952 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001953 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, elements,
1954 t0, v0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001955
1956 // Get the elements array of the object.
1957 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1958
1959 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001960 __ CheckMap(elements,
1961 v0,
1962 Heap::kFixedArrayMapRootIndex,
1963 &call_builtin,
1964 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001965
1966 // Get the array's length into t0 and calculate new length.
1967 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1968 __ Subu(t0, t0, Operand(Smi::FromInt(1)));
1969 __ Branch(&return_undefined, lt, t0, Operand(zero_reg));
1970
1971 // Get the last element.
1972 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1973 STATIC_ASSERT(kSmiTagSize == 1);
1974 STATIC_ASSERT(kSmiTag == 0);
1975 // We can't address the last element in one operation. Compute the more
1976 // expensive shift first, and use an offset later on.
1977 __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize);
1978 __ Addu(elements, elements, t1);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001979 __ lw(v0, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001980 __ Branch(&call_builtin, eq, v0, Operand(t2));
1981
1982 // Set the array's length.
1983 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1984
1985 // Fill with the hole.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001986 __ sw(t2, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001987 __ Drop(argc + 1);
1988 __ Ret();
1989
1990 __ bind(&return_undefined);
1991 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
1992 __ Drop(argc + 1);
1993 __ Ret();
1994
1995 __ bind(&call_builtin);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001996 __ TailCallExternalReference(
1997 ExternalReference(Builtins::c_ArrayPop, isolate()), argc + 1, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001998
1999 // Handle call cache miss.
2000 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002001 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002002
2003 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002004 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002005}
2006
2007
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002008Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
2009 Handle<Object> object,
2010 Handle<JSObject> holder,
2011 Handle<JSGlobalPropertyCell> cell,
2012 Handle<JSFunction> function,
2013 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002014 // ----------- S t a t e -------------
2015 // -- a2 : function name
2016 // -- ra : return address
2017 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2018 // -- ...
2019 // -- sp[argc * 4] : receiver
2020 // -----------------------------------
2021
2022 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002023 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002024
2025 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002026 Label miss;
2027 Label name_miss;
2028 Label index_out_of_range;
2029
2030 Label* index_out_of_range_label = &index_out_of_range;
2031
danno@chromium.org40cb8782011-05-25 07:58:50 +00002032 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002033 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002034 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002035 index_out_of_range_label = &miss;
2036 }
2037
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002038 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002039
2040 // Check that the maps starting from the prototype haven't changed.
2041 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2042 Context::STRING_FUNCTION_INDEX,
2043 v0,
2044 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002045 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002046 CheckPrototypes(
2047 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2048 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002049
2050 Register receiver = a1;
2051 Register index = t1;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002052 Register result = v0;
2053 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
2054 if (argc > 0) {
2055 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
2056 } else {
2057 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
2058 }
2059
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002060 StringCharCodeAtGenerator generator(receiver,
2061 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002062 result,
2063 &miss, // When not a string.
2064 &miss, // When not a number.
2065 index_out_of_range_label,
2066 STRING_INDEX_IS_NUMBER);
2067 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002068 __ Drop(argc + 1);
2069 __ Ret();
2070
2071 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002072 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002073
2074 if (index_out_of_range.is_linked()) {
2075 __ bind(&index_out_of_range);
2076 __ LoadRoot(v0, Heap::kNanValueRootIndex);
2077 __ Drop(argc + 1);
2078 __ Ret();
2079 }
2080
2081 __ bind(&miss);
2082 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002083 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002084 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002085 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002086
2087 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002088 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002089}
2090
2091
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002092Handle<Code> CallStubCompiler::CompileStringCharAtCall(
2093 Handle<Object> object,
2094 Handle<JSObject> holder,
2095 Handle<JSGlobalPropertyCell> cell,
2096 Handle<JSFunction> function,
2097 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002098 // ----------- S t a t e -------------
2099 // -- a2 : function name
2100 // -- ra : return address
2101 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2102 // -- ...
2103 // -- sp[argc * 4] : receiver
2104 // -----------------------------------
2105
2106 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002107 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002108
2109 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002110 Label miss;
2111 Label name_miss;
2112 Label index_out_of_range;
2113 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00002114 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002115 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002116 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002117 index_out_of_range_label = &miss;
2118 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002119 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002120
2121 // Check that the maps starting from the prototype haven't changed.
2122 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2123 Context::STRING_FUNCTION_INDEX,
2124 v0,
2125 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002126 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002127 CheckPrototypes(
2128 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2129 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002130
2131 Register receiver = v0;
2132 Register index = t1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00002133 Register scratch = a3;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002134 Register result = v0;
2135 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
2136 if (argc > 0) {
2137 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
2138 } else {
2139 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
2140 }
2141
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002142 StringCharAtGenerator generator(receiver,
2143 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00002144 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002145 result,
2146 &miss, // When not a string.
2147 &miss, // When not a number.
2148 index_out_of_range_label,
2149 STRING_INDEX_IS_NUMBER);
2150 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002151 __ Drop(argc + 1);
2152 __ Ret();
2153
2154 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002155 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002156
2157 if (index_out_of_range.is_linked()) {
2158 __ bind(&index_out_of_range);
ulan@chromium.org750145a2013-03-07 15:14:13 +00002159 __ LoadRoot(v0, Heap::kempty_stringRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002160 __ Drop(argc + 1);
2161 __ Ret();
2162 }
2163
2164 __ bind(&miss);
2165 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002166 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002167 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002168 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002169
2170 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002171 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002172}
2173
2174
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002175Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
2176 Handle<Object> object,
2177 Handle<JSObject> holder,
2178 Handle<JSGlobalPropertyCell> cell,
2179 Handle<JSFunction> function,
2180 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002181 // ----------- S t a t e -------------
2182 // -- a2 : function name
2183 // -- ra : return address
2184 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2185 // -- ...
2186 // -- sp[argc * 4] : receiver
2187 // -----------------------------------
2188
2189 const int argc = arguments().immediate();
2190
2191 // If the object is not a JSObject or we got an unexpected number of
2192 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002193 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002194
2195 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002196 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002197
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002198 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002199 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
2200
2201 STATIC_ASSERT(kSmiTag == 0);
2202 __ JumpIfSmi(a1, &miss);
2203
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002204 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2205 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002206 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002207 ASSERT(cell->value() == *function);
2208 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2209 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002210 GenerateLoadFunctionFromCell(cell, function, &miss);
2211 }
2212
2213 // Load the char code argument.
2214 Register code = a1;
2215 __ lw(code, MemOperand(sp, 0 * kPointerSize));
2216
2217 // Check the code is a smi.
2218 Label slow;
2219 STATIC_ASSERT(kSmiTag == 0);
2220 __ JumpIfNotSmi(code, &slow);
2221
2222 // Convert the smi code to uint16.
2223 __ And(code, code, Operand(Smi::FromInt(0xffff)));
2224
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002225 StringCharFromCodeGenerator generator(code, v0);
2226 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002227 __ Drop(argc + 1);
2228 __ Ret();
2229
2230 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002231 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002232
2233 // Tail call the full function. We do not have to patch the receiver
2234 // because the function makes no use of it.
2235 __ bind(&slow);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002236 ParameterCount expected(function);
2237 __ InvokeFunction(function, expected, arguments(),
2238 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002239
2240 __ bind(&miss);
2241 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002242 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002243
2244 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002245 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002246}
2247
2248
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002249Handle<Code> CallStubCompiler::CompileMathFloorCall(
2250 Handle<Object> object,
2251 Handle<JSObject> holder,
2252 Handle<JSGlobalPropertyCell> cell,
2253 Handle<JSFunction> function,
2254 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002255 // ----------- S t a t e -------------
2256 // -- a2 : function name
2257 // -- ra : return address
2258 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2259 // -- ...
2260 // -- sp[argc * 4] : receiver
2261 // -----------------------------------
2262
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002263
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002264 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002265 // If the object is not a JSObject or we got an unexpected number of
2266 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002267 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002268
2269 Label miss, slow;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002270 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002271
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002272 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002273 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002274 STATIC_ASSERT(kSmiTag == 0);
2275 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002276 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2277 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002278 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002279 ASSERT(cell->value() == *function);
2280 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2281 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002282 GenerateLoadFunctionFromCell(cell, function, &miss);
2283 }
2284
2285 // Load the (only) argument into v0.
2286 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2287
2288 // If the argument is a smi, just return.
2289 STATIC_ASSERT(kSmiTag == 0);
2290 __ And(t0, v0, Operand(kSmiTagMask));
2291 __ Drop(argc + 1, eq, t0, Operand(zero_reg));
2292 __ Ret(eq, t0, Operand(zero_reg));
2293
danno@chromium.org40cb8782011-05-25 07:58:50 +00002294 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002295
2296 Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return;
2297
2298 // If fpu is enabled, we use the floor instruction.
2299
2300 // Load the HeapNumber value.
2301 __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2302
2303 // Backup FCSR.
2304 __ cfc1(a3, FCSR);
2305 // Clearing FCSR clears the exception mask with no side-effects.
2306 __ ctc1(zero_reg, FCSR);
2307 // Convert the argument to an integer.
2308 __ floor_w_d(f0, f0);
2309
2310 // Start checking for special cases.
2311 // Get the argument exponent and clear the sign bit.
2312 __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize));
2313 __ And(t2, t1, Operand(~HeapNumber::kSignMask));
2314 __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord);
2315
2316 // Retrieve FCSR and check for fpu errors.
2317 __ cfc1(t5, FCSR);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002318 __ And(t5, t5, Operand(kFCSRExceptionFlagMask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002319 __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));
2320
2321 // Check for NaN, Infinity, and -Infinity.
2322 // They are invariant through a Math.Floor call, so just
2323 // return the original argument.
2324 __ Subu(t3, t2, Operand(HeapNumber::kExponentMask
2325 >> HeapNumber::kMantissaBitsInTopWord));
2326 __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg));
2327 // We had an overflow or underflow in the conversion. Check if we
2328 // have a big exponent.
2329 // If greater or equal, the argument is already round and in v0.
2330 __ Branch(&restore_fcsr_and_return, ge, t3,
2331 Operand(HeapNumber::kMantissaBits));
2332 __ Branch(&wont_fit_smi);
2333
2334 __ bind(&no_fpu_error);
2335 // Move the result back to v0.
2336 __ mfc1(v0, f0);
2337 // Check if the result fits into a smi.
2338 __ Addu(a1, v0, Operand(0x40000000));
2339 __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg));
2340 // Tag the result.
2341 STATIC_ASSERT(kSmiTag == 0);
2342 __ sll(v0, v0, kSmiTagSize);
2343
2344 // Check for -0.
2345 __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg));
2346 // t1 already holds the HeapNumber exponent.
2347 __ And(t0, t1, Operand(HeapNumber::kSignMask));
2348 // If our HeapNumber is negative it was -0, so load its address and return.
2349 // Else v0 is loaded with 0, so we can also just return.
2350 __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg));
2351 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2352
2353 __ bind(&restore_fcsr_and_return);
2354 // Restore FCSR and return.
2355 __ ctc1(a3, FCSR);
2356
2357 __ Drop(argc + 1);
2358 __ Ret();
2359
2360 __ bind(&wont_fit_smi);
2361 // Restore FCSR and fall to slow case.
2362 __ ctc1(a3, FCSR);
2363
2364 __ bind(&slow);
2365 // Tail call the full function. We do not have to patch the receiver
2366 // because the function makes no use of it.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002367 ParameterCount expected(function);
2368 __ InvokeFunction(function, expected, arguments(),
2369 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002370
2371 __ bind(&miss);
2372 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002373 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002374
2375 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002376 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002377}
2378
2379
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002380Handle<Code> CallStubCompiler::CompileMathAbsCall(
2381 Handle<Object> object,
2382 Handle<JSObject> holder,
2383 Handle<JSGlobalPropertyCell> cell,
2384 Handle<JSFunction> function,
2385 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002386 // ----------- S t a t e -------------
2387 // -- a2 : function name
2388 // -- ra : return address
2389 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2390 // -- ...
2391 // -- sp[argc * 4] : receiver
2392 // -----------------------------------
2393
2394 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002395 // If the object is not a JSObject or we got an unexpected number of
2396 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002397 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002398
2399 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002400
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002401 GenerateNameCheck(name, &miss);
2402 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002403 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002404 STATIC_ASSERT(kSmiTag == 0);
2405 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002406 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2407 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002408 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002409 ASSERT(cell->value() == *function);
2410 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2411 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002412 GenerateLoadFunctionFromCell(cell, function, &miss);
2413 }
2414
2415 // Load the (only) argument into v0.
2416 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2417
2418 // Check if the argument is a smi.
2419 Label not_smi;
2420 STATIC_ASSERT(kSmiTag == 0);
2421 __ JumpIfNotSmi(v0, &not_smi);
2422
2423 // Do bitwise not or do nothing depending on the sign of the
2424 // argument.
2425 __ sra(t0, v0, kBitsPerInt - 1);
2426 __ Xor(a1, v0, t0);
2427
2428 // Add 1 or do nothing depending on the sign of the argument.
2429 __ Subu(v0, a1, t0);
2430
2431 // If the result is still negative, go to the slow case.
2432 // This only happens for the most negative smi.
2433 Label slow;
2434 __ Branch(&slow, lt, v0, Operand(zero_reg));
2435
2436 // Smi case done.
2437 __ Drop(argc + 1);
2438 __ Ret();
2439
2440 // Check if the argument is a heap number and load its exponent and
2441 // sign.
2442 __ bind(&not_smi);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002443 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002444 __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2445
2446 // Check the sign of the argument. If the argument is positive,
2447 // just return it.
2448 Label negative_sign;
2449 __ And(t0, a1, Operand(HeapNumber::kSignMask));
2450 __ Branch(&negative_sign, ne, t0, Operand(zero_reg));
2451 __ Drop(argc + 1);
2452 __ Ret();
2453
2454 // If the argument is negative, clear the sign, and return a new
2455 // number.
2456 __ bind(&negative_sign);
2457 __ Xor(a1, a1, Operand(HeapNumber::kSignMask));
2458 __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2459 __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
2460 __ AllocateHeapNumber(v0, t0, t1, t2, &slow);
2461 __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2462 __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2463 __ Drop(argc + 1);
2464 __ Ret();
2465
2466 // Tail call the full function. We do not have to patch the receiver
2467 // because the function makes no use of it.
2468 __ bind(&slow);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002469 ParameterCount expected(function);
2470 __ InvokeFunction(function, expected, arguments(),
2471 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002472
2473 __ bind(&miss);
2474 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002475 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002476
2477 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002478 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002479}
2480
2481
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002482Handle<Code> CallStubCompiler::CompileFastApiCall(
lrn@chromium.org7516f052011-03-30 08:52:27 +00002483 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002484 Handle<Object> object,
2485 Handle<JSObject> holder,
2486 Handle<JSGlobalPropertyCell> cell,
2487 Handle<JSFunction> function,
2488 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002489
danno@chromium.org40cb8782011-05-25 07:58:50 +00002490 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002491
2492 ASSERT(optimization.is_simple_api_call());
2493 // Bail out if object is a global object as we don't want to
2494 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002495 if (object->IsGlobalObject()) return Handle<Code>::null();
2496 if (!cell.is_null()) return Handle<Code>::null();
2497 if (!object->IsJSObject()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002498 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002499 Handle<JSObject>::cast(object), holder);
2500 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002501
2502 Label miss, miss_before_stack_reserved;
2503
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002504 GenerateNameCheck(name, &miss_before_stack_reserved);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002505
2506 // Get the receiver from the stack.
2507 const int argc = arguments().immediate();
2508 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2509
2510 // Check that the receiver isn't a smi.
2511 __ JumpIfSmi(a1, &miss_before_stack_reserved);
2512
2513 __ IncrementCounter(counters->call_const(), 1, a0, a3);
2514 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2515
2516 ReserveSpaceForFastApiCall(masm(), a0);
2517
2518 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002519 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002520 depth, &miss);
2521
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002522 GenerateFastApiDirectCall(masm(), optimization, argc);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002523
2524 __ bind(&miss);
2525 FreeSpaceForFastApiCall(masm());
2526
2527 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002528 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002529
2530 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002531 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002532}
2533
2534
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002535void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
2536 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002537 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002538 CheckType check,
2539 Label* success) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002540 // ----------- S t a t e -------------
2541 // -- a2 : name
2542 // -- ra : return address
2543 // -----------------------------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002544 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002545 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002546
2547 // Get the receiver from the stack.
2548 const int argc = arguments().immediate();
2549 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2550
2551 // Check that the receiver isn't a smi.
2552 if (check != NUMBER_CHECK) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002553 __ JumpIfSmi(a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002554 }
2555
2556 // Make sure that it's okay not to patch the on stack receiver
2557 // unless we're doing a receiver map check.
2558 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002559 switch (check) {
2560 case RECEIVER_MAP_CHECK:
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002561 __ IncrementCounter(isolate()->counters()->call_const(), 1, a0, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002562
2563 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002564 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2565 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002566
2567 // Patch the receiver on the stack with the global proxy if
2568 // necessary.
2569 if (object->IsGlobalObject()) {
2570 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2571 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2572 }
2573 break;
2574
2575 case STRING_CHECK:
ulan@chromium.org750145a2013-03-07 15:14:13 +00002576 // Check that the object is a string.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002577 __ GetObjectType(a1, a3, a3);
2578 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2579 // Check that the maps starting from the prototype haven't changed.
2580 GenerateDirectLoadGlobalFunctionPrototype(
2581 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
2582 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002583 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002584 a0, holder, a3, a1, t0, name, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002585 break;
2586
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002587 case SYMBOL_CHECK:
2588 // Check that the object is a symbol.
2589 __ GetObjectType(a1, a1, a3);
2590 __ Branch(&miss, ne, a3, Operand(SYMBOL_TYPE));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002591 // Check that the maps starting from the prototype haven't changed.
2592 GenerateDirectLoadGlobalFunctionPrototype(
2593 masm(), Context::SYMBOL_FUNCTION_INDEX, a0, &miss);
2594 CheckPrototypes(
2595 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2596 a0, holder, a3, a1, t0, name, &miss);
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002597 break;
2598
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002599 case NUMBER_CHECK: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002600 Label fast;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002601 // Check that the object is a smi or a heap number.
2602 __ JumpIfSmi(a1, &fast);
2603 __ GetObjectType(a1, a0, a0);
2604 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
2605 __ bind(&fast);
2606 // Check that the maps starting from the prototype haven't changed.
2607 GenerateDirectLoadGlobalFunctionPrototype(
2608 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
2609 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002610 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002611 a0, holder, a3, a1, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002612 break;
2613 }
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002614 case BOOLEAN_CHECK: {
2615 Label fast;
2616 // Check that the object is a boolean.
2617 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
2618 __ Branch(&fast, eq, a1, Operand(t0));
2619 __ LoadRoot(t0, Heap::kFalseValueRootIndex);
2620 __ Branch(&miss, ne, a1, Operand(t0));
2621 __ bind(&fast);
2622 // Check that the maps starting from the prototype haven't changed.
2623 GenerateDirectLoadGlobalFunctionPrototype(
2624 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
2625 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002626 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002627 a0, holder, a3, a1, t0, name, &miss);
2628 break;
2629 }
2630 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002631
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002632 __ jmp(success);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002633
2634 // Handle call cache miss.
2635 __ bind(&miss);
2636
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002637 GenerateMissBranch();
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002638}
2639
2640
2641void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) {
2642 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
2643 ? CALL_AS_FUNCTION
2644 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002645 ParameterCount expected(function);
2646 __ InvokeFunction(function, expected, arguments(),
2647 JUMP_FUNCTION, NullCallWrapper(), call_kind);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002648}
2649
2650
2651Handle<Code> CallStubCompiler::CompileCallConstant(
2652 Handle<Object> object,
2653 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002654 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002655 CheckType check,
2656 Handle<JSFunction> function) {
2657 if (HasCustomCallGenerator(function)) {
2658 Handle<Code> code = CompileCustomCall(object, holder,
2659 Handle<JSGlobalPropertyCell>::null(),
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002660 function, Handle<String>::cast(name));
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002661 // A null handle means bail out to the regular compiler code below.
2662 if (!code.is_null()) return code;
2663 }
2664
2665 Label success;
2666
2667 CompileHandlerFrontend(object, holder, name, check, &success);
2668 __ bind(&success);
2669 CompileHandlerBackend(function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002670
2671 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002672 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002673}
2674
2675
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002676Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2677 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002678 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002679 // ----------- S t a t e -------------
2680 // -- a2 : name
2681 // -- ra : return address
2682 // -----------------------------------
2683
2684 Label miss;
2685
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002686 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002687
2688 // Get the number of arguments.
2689 const int argc = arguments().immediate();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002690 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002691 LookupPostInterceptor(holder, name, &lookup);
2692
2693 // Get the receiver from the stack.
2694 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2695
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002696 CallInterceptorCompiler compiler(this, arguments(), a2, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002697 compiler.Compile(masm(), object, holder, name, &lookup, a1, a3, t0, a0,
2698 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002699
2700 // Move returned value, the function to call, to a1.
2701 __ mov(a1, v0);
2702 // Restore receiver.
2703 __ lw(a0, MemOperand(sp, argc * kPointerSize));
2704
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002705 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002706
2707 // Handle call cache miss.
2708 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002709 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002710
2711 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002712 return GetCode(Code::INTERCEPTOR, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002713}
2714
2715
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002716Handle<Code> CallStubCompiler::CompileCallGlobal(
2717 Handle<JSObject> object,
2718 Handle<GlobalObject> holder,
2719 Handle<JSGlobalPropertyCell> cell,
2720 Handle<JSFunction> function,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002721 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002722 // ----------- S t a t e -------------
2723 // -- a2 : name
2724 // -- ra : return address
2725 // -----------------------------------
2726
2727 if (HasCustomCallGenerator(function)) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002728 Handle<Code> code = CompileCustomCall(
2729 object, holder, cell, function, Handle<String>::cast(name));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002730 // A null handle means bail out to the regular compiler code below.
2731 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002732 }
2733
2734 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002735 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002736
2737 // Get the number of arguments.
2738 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002739 GenerateGlobalReceiverCheck(object, holder, name, &miss);
2740 GenerateLoadFunctionFromCell(cell, function, &miss);
2741
2742 // Patch the receiver on the stack with the global proxy if
2743 // necessary.
2744 if (object->IsGlobalObject()) {
2745 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
2746 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2747 }
2748
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002749 // Set up the context (function already in r1).
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002750 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
2751
2752 // Jump to the cached code (tail call).
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002753 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002754 __ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002755 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002756 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002757 ? CALL_AS_FUNCTION
2758 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002759 // We call indirectly through the code field in the function to
2760 // allow recompilation to take effect without changing any of the
2761 // call sites.
2762 __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
2763 __ InvokeCode(a3, expected, arguments(), JUMP_FUNCTION,
2764 NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002765
2766 // Handle call cache miss.
2767 __ bind(&miss);
2768 __ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002769 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002770
2771 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002772 return GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002773}
2774
2775
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002776Handle<Code> StoreStubCompiler::CompileStoreCallback(
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002777 Handle<Name> name,
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002778 Handle<JSObject> object,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002779 Handle<JSObject> holder,
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002780 Handle<ExecutableAccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002781 Label miss;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002782 // Check that the maps haven't changed.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002783 __ JumpIfSmi(receiver(), &miss);
2784 CheckPrototypes(object, receiver(), holder,
2785 scratch1(), scratch2(), scratch3(), name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002786
2787 // Stub never generated for non-global objects that require access
2788 // checks.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002789 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002790
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002791 __ push(receiver()); // Receiver.
2792 __ li(at, Operand(callback)); // Callback info.
2793 __ Push(at, this->name(), value());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002794
2795 // Do tail-call to the runtime system.
2796 ExternalReference store_callback_property =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002797 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002798 __ TailCallExternalReference(store_callback_property, 4, 1);
2799
2800 // Handle store cache miss.
2801 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002802 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002803
2804 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002805 return GetICCode(kind(), Code::CALLBACKS, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002806}
2807
2808
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002809#undef __
2810#define __ ACCESS_MASM(masm)
2811
2812
2813void StoreStubCompiler::GenerateStoreViaSetter(
2814 MacroAssembler* masm,
2815 Handle<JSFunction> setter) {
2816 // ----------- S t a t e -------------
2817 // -- a0 : value
2818 // -- a1 : receiver
2819 // -- a2 : name
2820 // -- ra : return address
2821 // -----------------------------------
2822 {
2823 FrameScope scope(masm, StackFrame::INTERNAL);
2824
2825 // Save value register, so we can restore it later.
2826 __ push(a0);
2827
2828 if (!setter.is_null()) {
2829 // Call the JavaScript setter with receiver and value on the stack.
2830 __ push(a1);
2831 __ push(a0);
2832 ParameterCount actual(1);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002833 ParameterCount expected(setter);
2834 __ InvokeFunction(setter, expected, actual,
2835 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002836 } else {
2837 // If we generate a global code snippet for deoptimization only, remember
2838 // the place to continue after deoptimization.
2839 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2840 }
2841
2842 // We have to return the passed value, not the return value of the setter.
2843 __ pop(v0);
2844
2845 // Restore context register.
2846 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2847 }
2848 __ Ret();
2849}
2850
2851
2852#undef __
2853#define __ ACCESS_MASM(masm())
2854
2855
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002856Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002857 Handle<JSObject> object,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002858 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002859 Label miss;
2860
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002861 // Check that the map of the object hasn't changed.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002862 __ CheckMap(receiver(), scratch1(), Handle<Map>(object->map()), &miss,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002863 DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002864
2865 // Perform global security token check if needed.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002866 if (object->IsJSGlobalProxy()) {
2867 __ CheckAccessGlobalProxy(receiver(), scratch1(), &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002868 }
2869
2870 // Stub is never generated for non-global objects that require access
2871 // checks.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002872 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002873
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002874 __ Push(receiver(), this->name(), value());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002875
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002876 __ li(scratch1(), Operand(Smi::FromInt(strict_mode())));
2877 __ push(scratch1()); // strict mode
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002878
2879 // Do tail-call to the runtime system.
2880 ExternalReference store_ic_property =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002881 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002882 __ TailCallExternalReference(store_ic_property, 4, 1);
2883
2884 // Handle store cache miss.
2885 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002886 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002887
2888 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002889 return GetICCode(kind(), Code::INTERCEPTOR, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002890}
2891
2892
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002893Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2894 Handle<GlobalObject> object,
2895 Handle<JSGlobalPropertyCell> cell,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002896 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002897 Label miss;
2898
2899 // Check that the map of the global has not changed.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002900 __ lw(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset));
2901 __ Branch(&miss, ne, scratch1(), Operand(Handle<Map>(object->map())));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002902
2903 // Check that the value in the cell is not the hole. If it is, this
2904 // cell could have been deleted and reintroducing the global needs
2905 // to update the property details in the property dictionary of the
2906 // global object. We bail out to the runtime system to do that.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002907 __ li(scratch1(), Operand(cell));
2908 __ LoadRoot(scratch2(), Heap::kTheHoleValueRootIndex);
2909 __ lw(scratch3(),
2910 FieldMemOperand(scratch1(), JSGlobalPropertyCell::kValueOffset));
2911 __ Branch(&miss, eq, scratch3(), Operand(scratch2()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002912
2913 // Store the value in the cell.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002914 __ sw(value(),
2915 FieldMemOperand(scratch1(), JSGlobalPropertyCell::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002916 __ mov(v0, a0); // Stored value must be returned in v0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002917 // Cells are always rescanned, so no write barrier here.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002918
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002919 Counters* counters = isolate()->counters();
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002920 __ IncrementCounter(
2921 counters->named_store_global_inline(), 1, scratch1(), scratch2());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002922 __ Ret();
2923
2924 // Handle store cache miss.
2925 __ bind(&miss);
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002926 __ IncrementCounter(
2927 counters->named_store_global_inline_miss(), 1, scratch1(), scratch2());
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002928 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002929
2930 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002931 return GetICCode(kind(), Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002932}
2933
2934
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002935Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
2936 Handle<JSObject> object,
2937 Handle<JSObject> last,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002938 Handle<Name> name,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002939 Handle<GlobalObject> global) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002940 Label success;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002941
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002942 NonexistentHandlerFrontend(object, last, name, &success, global);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002943
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002944 __ bind(&success);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002945 // Return undefined if maps of the full prototype chain is still the same.
2946 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2947 __ Ret();
2948
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002949 // Return the generated code.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002950 return GetCode(kind(), Code::NONEXISTENT, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002951}
2952
2953
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002954Register* LoadStubCompiler::registers() {
2955 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2956 static Register registers[] = { a0, a2, a3, a1, t0, t1 };
2957 return registers;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002958}
2959
2960
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002961Register* KeyedLoadStubCompiler::registers() {
2962 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2963 static Register registers[] = { a1, a0, a2, a3, t0, t1 };
2964 return registers;
2965}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002966
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002967
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002968Register* StoreStubCompiler::registers() {
2969 // receiver, name, value, scratch1, scratch2, scratch3.
2970 static Register registers[] = { a1, a2, a0, a3, t0, t1 };
2971 return registers;
2972}
2973
2974
2975Register* KeyedStoreStubCompiler::registers() {
2976 // receiver, name, value, scratch1, scratch2, scratch3.
2977 static Register registers[] = { a2, a1, a0, a3, t0, t1 };
2978 return registers;
2979}
2980
2981
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002982void KeyedLoadStubCompiler::GenerateNameCheck(Handle<Name> name,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002983 Register name_reg,
2984 Label* miss) {
2985 __ Branch(miss, ne, name_reg, Operand(name));
lrn@chromium.org7516f052011-03-30 08:52:27 +00002986}
2987
2988
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002989void KeyedStoreStubCompiler::GenerateNameCheck(Handle<Name> name,
2990 Register name_reg,
2991 Label* miss) {
2992 __ Branch(miss, ne, name_reg, Operand(name));
2993}
2994
2995
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002996#undef __
2997#define __ ACCESS_MASM(masm)
2998
2999
3000void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
3001 Handle<JSFunction> getter) {
3002 // ----------- S t a t e -------------
3003 // -- a0 : receiver
3004 // -- a2 : name
3005 // -- ra : return address
3006 // -----------------------------------
3007 {
3008 FrameScope scope(masm, StackFrame::INTERNAL);
3009
3010 if (!getter.is_null()) {
3011 // Call the JavaScript getter with the receiver on the stack.
3012 __ push(a0);
3013 ParameterCount actual(0);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003014 ParameterCount expected(getter);
3015 __ InvokeFunction(getter, expected, actual,
3016 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003017 } else {
3018 // If we generate a global code snippet for deoptimization only, remember
3019 // the place to continue after deoptimization.
3020 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
3021 }
3022
3023 // Restore context register.
3024 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
3025 }
3026 __ Ret();
3027}
3028
3029
3030#undef __
3031#define __ ACCESS_MASM(masm())
3032
3033
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003034Handle<Code> LoadStubCompiler::CompileLoadGlobal(
3035 Handle<JSObject> object,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003036 Handle<GlobalObject> global,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003037 Handle<JSGlobalPropertyCell> cell,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003038 Handle<Name> name,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003039 bool is_dont_delete) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003040 Label success, miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003041
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003042 __ CheckMap(
3043 receiver(), scratch1(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
3044 HandlerFrontendHeader(
3045 object, receiver(), Handle<JSObject>::cast(global), name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003046
3047 // Get the value from the cell.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003048 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003049 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
3050
3051 // Check for deleted property if property can actually be deleted.
3052 if (!is_dont_delete) {
3053 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
3054 __ Branch(&miss, eq, t0, Operand(at));
3055 }
3056
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003057 HandlerFrontendFooter(&success, &miss);
3058 __ bind(&success);
3059
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003060 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003061 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003062 __ mov(v0, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003063 __ Ret();
3064
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003065 // Return the generated code.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003066 return GetICCode(kind(), Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003067}
3068
3069
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003070Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003071 MapHandleList* receiver_maps,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003072 CodeHandleList* handlers,
3073 Handle<Name> name,
3074 Code::StubType type,
3075 IcCheckType check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003076 Label miss;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003077
3078 if (check == PROPERTY) {
3079 GenerateNameCheck(name, this->name(), &miss);
3080 }
3081
3082 __ JumpIfSmi(receiver(), &miss);
3083 Register map_reg = scratch1();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003084
danno@chromium.org40cb8782011-05-25 07:58:50 +00003085 int receiver_count = receiver_maps->length();
danno@chromium.orgf005df62013-04-30 16:36:45 +00003086 int number_of_handled_maps = 0;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003087 __ lw(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003088 for (int current = 0; current < receiver_count; ++current) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00003089 Handle<Map> map = receiver_maps->at(current);
3090 if (!map->is_deprecated()) {
3091 number_of_handled_maps++;
3092 __ Jump(handlers->at(current), RelocInfo::CODE_TARGET,
3093 eq, map_reg, Operand(receiver_maps->at(current)));
3094 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003095 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00003096 ASSERT(number_of_handled_maps != 0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003097
3098 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003099 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003100
3101 // Return the generated code.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003102 InlineCacheState state =
danno@chromium.orgf005df62013-04-30 16:36:45 +00003103 number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003104 return GetICCode(kind(), type, name, state);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003105}
3106
3107
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003108Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
3109 MapHandleList* receiver_maps,
3110 CodeHandleList* handler_stubs,
3111 MapHandleList* transitioned_maps) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003112 Label miss;
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003113 __ JumpIfSmi(receiver(), &miss);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003114
3115 int receiver_count = receiver_maps->length();
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003116 __ lw(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003117 for (int i = 0; i < receiver_count; ++i) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003118 if (transitioned_maps->at(i).is_null()) {
3119 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq,
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003120 scratch1(), Operand(receiver_maps->at(i)));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003121 } else {
3122 Label next_map;
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003123 __ Branch(&next_map, ne, scratch1(), Operand(receiver_maps->at(i)));
3124 __ li(transition_map(), Operand(transitioned_maps->at(i)));
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003125 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003126 __ bind(&next_map);
3127 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003128 }
3129
3130 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003131 TailCallBuiltin(masm(), MissBuiltin(kind()));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003132
3133 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003134 return GetICCode(
3135 kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003136}
3137
3138
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003139Handle<Code> ConstructStubCompiler::CompileConstructStub(
3140 Handle<JSFunction> function) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003141 // a0 : argc
3142 // a1 : constructor
3143 // ra : return address
3144 // [sp] : last argument
3145 Label generic_stub_call;
3146
3147 // Use t7 for holding undefined which is used in several places below.
3148 __ LoadRoot(t7, Heap::kUndefinedValueRootIndex);
3149
3150#ifdef ENABLE_DEBUGGER_SUPPORT
3151 // Check to see whether there are any break points in the function code. If
3152 // there are jump to the generic constructor stub which calls the actual
3153 // code for the function thereby hitting the break points.
3154 __ lw(t5, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3155 __ lw(a2, FieldMemOperand(t5, SharedFunctionInfo::kDebugInfoOffset));
3156 __ Branch(&generic_stub_call, ne, a2, Operand(t7));
3157#endif
3158
3159 // Load the initial map and verify that it is in fact a map.
3160 // a1: constructor function
3161 // t7: undefined
3162 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003163 __ JumpIfSmi(a2, &generic_stub_call);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003164 __ GetObjectType(a2, a3, t0);
3165 __ Branch(&generic_stub_call, ne, t0, Operand(MAP_TYPE));
3166
3167#ifdef DEBUG
3168 // Cannot construct functions this way.
3169 // a0: argc
3170 // a1: constructor function
3171 // a2: initial map
3172 // t7: undefined
3173 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
3174 __ Check(ne, "Function constructed by construct stub.",
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003175 a3, Operand(JS_FUNCTION_TYPE));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003176#endif
3177
3178 // Now allocate the JSObject in new space.
3179 // a0: argc
3180 // a1: constructor function
3181 // a2: initial map
3182 // t7: undefined
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003183 ASSERT(function->has_initial_map());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003184 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003185#ifdef DEBUG
3186 int instance_size = function->initial_map()->instance_size();
3187 __ Check(eq, "Instance size of initial map changed.",
3188 a3, Operand(instance_size >> kPointerSizeLog2));
3189#endif
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003190 __ Allocate(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003191
3192 // Allocated the JSObject, now initialize the fields. Map is set to initial
3193 // map and properties and elements are set to empty fixed array.
3194 // a0: argc
3195 // a1: constructor function
3196 // a2: initial map
3197 // a3: object size (in words)
3198 // t4: JSObject (not tagged)
3199 // t7: undefined
3200 __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex);
3201 __ mov(t5, t4);
3202 __ sw(a2, MemOperand(t5, JSObject::kMapOffset));
3203 __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset));
3204 __ sw(t6, MemOperand(t5, JSObject::kElementsOffset));
3205 __ Addu(t5, t5, Operand(3 * kPointerSize));
3206 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
3207 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
3208 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
3209
3210
3211 // Calculate the location of the first argument. The stack contains only the
3212 // argc arguments.
3213 __ sll(a1, a0, kPointerSizeLog2);
3214 __ Addu(a1, a1, sp);
3215
3216 // Fill all the in-object properties with undefined.
3217 // a0: argc
3218 // a1: first argument
3219 // a3: object size (in words)
3220 // t4: JSObject (not tagged)
3221 // t5: First in-object property of JSObject (not tagged)
3222 // t7: undefined
3223 // Fill the initialized properties with a constant value or a passed argument
3224 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003225 Handle<SharedFunctionInfo> shared(function->shared());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003226 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3227 if (shared->IsThisPropertyAssignmentArgument(i)) {
3228 Label not_passed, next;
3229 // Check if the argument assigned to the property is actually passed.
3230 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3231 __ Branch(&not_passed, less_equal, a0, Operand(arg_number));
3232 // Argument passed - find it on the stack.
3233 __ lw(a2, MemOperand(a1, (arg_number + 1) * -kPointerSize));
3234 __ sw(a2, MemOperand(t5));
3235 __ Addu(t5, t5, kPointerSize);
3236 __ jmp(&next);
3237 __ bind(&not_passed);
3238 // Set the property to undefined.
3239 __ sw(t7, MemOperand(t5));
3240 __ Addu(t5, t5, Operand(kPointerSize));
3241 __ bind(&next);
3242 } else {
3243 // Set the property to the constant value.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003244 Handle<Object> constant(
3245 shared->GetThisPropertyAssignmentConstant(i), isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003246 __ li(a2, Operand(constant));
3247 __ sw(a2, MemOperand(t5));
3248 __ Addu(t5, t5, kPointerSize);
3249 }
3250 }
3251
3252 // Fill the unused in-object property fields with undefined.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003253 for (int i = shared->this_property_assignments_count();
3254 i < function->initial_map()->inobject_properties();
3255 i++) {
3256 __ sw(t7, MemOperand(t5));
3257 __ Addu(t5, t5, kPointerSize);
3258 }
3259
3260 // a0: argc
3261 // t4: JSObject (not tagged)
3262 // Move argc to a1 and the JSObject to return to v0 and tag it.
3263 __ mov(a1, a0);
3264 __ mov(v0, t4);
3265 __ Or(v0, v0, Operand(kHeapObjectTag));
3266
3267 // v0: JSObject
3268 // a1: argc
3269 // Remove caller arguments and receiver from the stack and return.
3270 __ sll(t0, a1, kPointerSizeLog2);
3271 __ Addu(sp, sp, t0);
3272 __ Addu(sp, sp, Operand(kPointerSize));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003273 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003274 __ IncrementCounter(counters->constructed_objects(), 1, a1, a2);
3275 __ IncrementCounter(counters->constructed_objects_stub(), 1, a1, a2);
3276 __ Ret();
3277
3278 // Jump to the generic stub in case the specialized code cannot handle the
3279 // construction.
3280 __ bind(&generic_stub_call);
3281 Handle<Code> generic_construct_stub =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003282 isolate()->builtins()->JSConstructStubGeneric();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003283 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
3284
3285 // Return the generated code.
3286 return GetCode();
3287}
3288
3289
danno@chromium.org40cb8782011-05-25 07:58:50 +00003290#undef __
3291#define __ ACCESS_MASM(masm)
3292
3293
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003294void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3295 MacroAssembler* masm) {
3296 // ---------- S t a t e --------------
3297 // -- ra : return address
3298 // -- a0 : key
3299 // -- a1 : receiver
3300 // -----------------------------------
3301 Label slow, miss_force_generic;
3302
3303 Register key = a0;
3304 Register receiver = a1;
3305
3306 __ JumpIfNotSmi(key, &miss_force_generic);
3307 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
3308 __ sra(a2, a0, kSmiTagSize);
3309 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
3310 __ Ret();
3311
3312 // Slow case, key and receiver still in a0 and a1.
3313 __ bind(&slow);
3314 __ IncrementCounter(
3315 masm->isolate()->counters()->keyed_load_external_array_slow(),
3316 1, a2, a3);
3317 // Entry registers are intact.
3318 // ---------- S t a t e --------------
3319 // -- ra : return address
3320 // -- a0 : key
3321 // -- a1 : receiver
3322 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003323 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003324
3325 // Miss case, call the runtime.
3326 __ bind(&miss_force_generic);
3327
3328 // ---------- S t a t e --------------
3329 // -- ra : return address
3330 // -- a0 : key
3331 // -- a1 : receiver
3332 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003333 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_MissForceGeneric);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003334}
3335
3336
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003337static void GenerateSmiKeyCheck(MacroAssembler* masm,
3338 Register key,
3339 Register scratch0,
3340 Register scratch1,
3341 FPURegister double_scratch0,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003342 FPURegister double_scratch1,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003343 Label* fail) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003344 Label key_ok;
3345 // Check for smi or a smi inside a heap number. We convert the heap
3346 // number and check if the conversion is exact and fits into the smi
3347 // range.
3348 __ JumpIfSmi(key, &key_ok);
3349 __ CheckMap(key,
3350 scratch0,
3351 Heap::kHeapNumberMapRootIndex,
3352 fail,
3353 DONT_DO_SMI_CHECK);
3354 __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
3355 __ EmitFPUTruncate(kRoundToZero,
3356 scratch0,
3357 double_scratch0,
3358 at,
3359 double_scratch1,
3360 scratch1,
3361 kCheckForInexactConversion);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003362
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003363 __ Branch(fail, ne, scratch1, Operand(zero_reg));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003364
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003365 __ SmiTagCheckOverflow(key, scratch0, scratch1);
3366 __ BranchOnOverflow(fail, scratch1);
3367 __ bind(&key_ok);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003368}
3369
3370
danno@chromium.org40cb8782011-05-25 07:58:50 +00003371void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3372 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003373 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003374 // ---------- S t a t e --------------
3375 // -- a0 : value
3376 // -- a1 : key
3377 // -- a2 : receiver
3378 // -- ra : return address
3379 // -----------------------------------
3380
danno@chromium.org40cb8782011-05-25 07:58:50 +00003381 Label slow, check_heap_number, miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003382
3383 // Register usage.
3384 Register value = a0;
3385 Register key = a1;
3386 Register receiver = a2;
3387 // a3 mostly holds the elements array or the destination external array.
3388
danno@chromium.org40cb8782011-05-25 07:58:50 +00003389 // This stub is meant to be tail-jumped to, the receiver must already
3390 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003391
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003392 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003393 GenerateSmiKeyCheck(masm, key, t0, t1, f2, f4, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003394
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003395 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3396
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003397 // Check that the index is in range.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003398 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3399 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003400 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003401
3402 // Handle both smis and HeapNumbers in the fast path. Go to the
3403 // runtime for all other kinds of values.
3404 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003405
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003406 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003407 // Double to pixel conversion is only implemented in the runtime for now.
3408 __ JumpIfNotSmi(value, &slow);
3409 } else {
3410 __ JumpIfNotSmi(value, &check_heap_number);
3411 }
3412 __ SmiUntag(t1, value);
3413 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3414
3415 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003416 // t1: value (integer).
3417
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003418 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003419 case EXTERNAL_PIXEL_ELEMENTS: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003420 // Clamp the value to [0..255].
3421 // v0 is used as a scratch register here.
3422 Label done;
3423 __ li(v0, Operand(255));
3424 // Normal branch: nop in delay slot.
3425 __ Branch(&done, gt, t1, Operand(v0));
3426 // Use delay slot in this branch.
3427 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg));
3428 __ mov(v0, zero_reg); // In delay slot.
3429 __ mov(v0, t1); // Value is in range 0..255.
3430 __ bind(&done);
3431 __ mov(t1, v0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003432
3433 __ srl(t8, key, 1);
3434 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003435 __ sb(t1, MemOperand(t8, 0));
3436 }
3437 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003438 case EXTERNAL_BYTE_ELEMENTS:
3439 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003440 __ srl(t8, key, 1);
3441 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003442 __ sb(t1, MemOperand(t8, 0));
3443 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003444 case EXTERNAL_SHORT_ELEMENTS:
3445 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003446 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003447 __ sh(t1, MemOperand(t8, 0));
3448 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003449 case EXTERNAL_INT_ELEMENTS:
3450 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003451 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003452 __ addu(t8, a3, t8);
3453 __ sw(t1, MemOperand(t8, 0));
3454 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003455 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003456 // Perform int-to-float conversion and store to memory.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003457 __ SmiUntag(t0, key);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003458 StoreIntAsFloat(masm, a3, t0, t1, t2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003459 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003460 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003461 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003462 __ addu(a3, a3, t8);
3463 // a3: effective address of the double element
3464 FloatingPointHelper::Destination destination;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003465 destination = FloatingPointHelper::kFPURegisters;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003466 FloatingPointHelper::ConvertIntToDouble(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003467 masm, t1, destination,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003468 f0, t2, t3, // These are: double_dst, dst_mantissa, dst_exponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003469 t0, f2); // These are: scratch2, single_scratch.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003470 __ sdc1(f0, MemOperand(a3, 0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003471 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003472 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003473 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003474 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003475 case FAST_HOLEY_ELEMENTS:
3476 case FAST_HOLEY_SMI_ELEMENTS:
3477 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003478 case DICTIONARY_ELEMENTS:
3479 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003480 UNREACHABLE();
3481 break;
3482 }
3483
3484 // Entry registers are intact, a0 holds the value which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003485 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003486 __ Ret();
3487
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003488 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003489 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003490 __ bind(&check_heap_number);
3491 __ GetObjectType(value, t1, t2);
3492 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE));
3493
3494 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3495
3496 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003497
3498 // The WebGL specification leaves the behavior of storing NaN and
3499 // +/-Infinity into integer arrays basically undefined. For more
3500 // reproducible behavior, convert these to zero.
3501
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003502
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003503 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003504
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003505 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
3506 __ cvt_s_d(f0, f0);
3507 __ sll(t8, key, 1);
3508 __ addu(t8, a3, t8);
3509 __ swc1(f0, MemOperand(t8, 0));
3510 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
3511 __ sll(t8, key, 2);
3512 __ addu(t8, a3, t8);
3513 __ sdc1(f0, MemOperand(t8, 0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003514 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003515 __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003516
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003517 switch (elements_kind) {
3518 case EXTERNAL_BYTE_ELEMENTS:
3519 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3520 __ srl(t8, key, 1);
3521 __ addu(t8, a3, t8);
3522 __ sb(t3, MemOperand(t8, 0));
3523 break;
3524 case EXTERNAL_SHORT_ELEMENTS:
3525 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3526 __ addu(t8, a3, key);
3527 __ sh(t3, MemOperand(t8, 0));
3528 break;
3529 case EXTERNAL_INT_ELEMENTS:
3530 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3531 __ sll(t8, key, 1);
3532 __ addu(t8, a3, t8);
3533 __ sw(t3, MemOperand(t8, 0));
3534 break;
3535 case EXTERNAL_PIXEL_ELEMENTS:
3536 case EXTERNAL_FLOAT_ELEMENTS:
3537 case EXTERNAL_DOUBLE_ELEMENTS:
3538 case FAST_ELEMENTS:
3539 case FAST_SMI_ELEMENTS:
3540 case FAST_DOUBLE_ELEMENTS:
3541 case FAST_HOLEY_ELEMENTS:
3542 case FAST_HOLEY_SMI_ELEMENTS:
3543 case FAST_HOLEY_DOUBLE_ELEMENTS:
3544 case DICTIONARY_ELEMENTS:
3545 case NON_STRICT_ARGUMENTS_ELEMENTS:
3546 UNREACHABLE();
3547 break;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003548 }
3549 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003550
3551 // Entry registers are intact, a0 holds the value
3552 // which is the return value.
3553 __ mov(v0, a0);
3554 __ Ret();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003555 }
3556
danno@chromium.org40cb8782011-05-25 07:58:50 +00003557 // Slow case, key and receiver still in a0 and a1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003558 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003559 __ IncrementCounter(
3560 masm->isolate()->counters()->keyed_load_external_array_slow(),
3561 1, a2, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003562 // Entry registers are intact.
3563 // ---------- S t a t e --------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003564 // -- ra : return address
danno@chromium.org40cb8782011-05-25 07:58:50 +00003565 // -- a0 : key
3566 // -- a1 : receiver
3567 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003568 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003569
3570 // Miss case, call the runtime.
3571 __ bind(&miss_force_generic);
3572
3573 // ---------- S t a t e --------------
3574 // -- ra : return address
3575 // -- a0 : key
3576 // -- a1 : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003577 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003578 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003579}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003580
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003581
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003582void KeyedStoreStubCompiler::GenerateStoreFastElement(
3583 MacroAssembler* masm,
3584 bool is_js_array,
yangguo@chromium.org56454712012-02-16 15:33:53 +00003585 ElementsKind elements_kind,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003586 KeyedAccessStoreMode store_mode) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003587 // ----------- S t a t e -------------
3588 // -- a0 : value
3589 // -- a1 : key
3590 // -- a2 : receiver
3591 // -- ra : return address
3592 // -- a3 : scratch
3593 // -- a4 : scratch (elements)
3594 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00003595 Label miss_force_generic, transition_elements_kind, grow, slow;
3596 Label finish_store, check_capacity;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003597
3598 Register value_reg = a0;
3599 Register key_reg = a1;
3600 Register receiver_reg = a2;
yangguo@chromium.org56454712012-02-16 15:33:53 +00003601 Register scratch = t0;
3602 Register elements_reg = a3;
3603 Register length_reg = t1;
3604 Register scratch2 = t2;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003605
3606 // This stub is meant to be tail-jumped to, the receiver must already
3607 // have been verified by the caller to not be a smi.
3608
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003609 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003610 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003611
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003612 if (IsFastSmiElementsKind(elements_kind)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003613 __ JumpIfNotSmi(value_reg, &transition_elements_kind);
3614 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003615
3616 // Check that the key is within bounds.
yangguo@chromium.org56454712012-02-16 15:33:53 +00003617 __ lw(elements_reg,
3618 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003619 if (is_js_array) {
3620 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3621 } else {
3622 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3623 }
3624 // Compare smis.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003625 if (is_js_array && IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003626 __ Branch(&grow, hs, key_reg, Operand(scratch));
3627 } else {
3628 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
3629 }
3630
3631 // Make sure elements is a fast element array, not 'cow'.
3632 __ CheckMap(elements_reg,
3633 scratch,
3634 Heap::kFixedArrayMapRootIndex,
3635 &miss_force_generic,
3636 DONT_DO_SMI_CHECK);
3637
3638 __ bind(&finish_store);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003639
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003640 if (IsFastSmiElementsKind(elements_kind)) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003641 __ Addu(scratch,
3642 elements_reg,
3643 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3644 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
3645 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
3646 __ Addu(scratch, scratch, scratch2);
3647 __ sw(value_reg, MemOperand(scratch));
3648 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003649 ASSERT(IsFastObjectElementsKind(elements_kind));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003650 __ Addu(scratch,
3651 elements_reg,
3652 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3653 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
3654 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
3655 __ Addu(scratch, scratch, scratch2);
3656 __ sw(value_reg, MemOperand(scratch));
3657 __ mov(receiver_reg, value_reg);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003658 __ RecordWrite(elements_reg, // Object.
3659 scratch, // Address.
3660 receiver_reg, // Value.
3661 kRAHasNotBeenSaved,
3662 kDontSaveFPRegs);
3663 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003664 // value_reg (a0) is preserved.
3665 // Done.
3666 __ Ret();
3667
3668 __ bind(&miss_force_generic);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003669 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003670
3671 __ bind(&transition_elements_kind);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003672 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003673
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003674 if (is_js_array && IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003675 // Grow the array by a single element if possible.
3676 __ bind(&grow);
3677
3678 // Make sure the array is only growing by a single element, anything else
3679 // must be handled by the runtime.
3680 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch));
3681
3682 // Check for the empty array, and preallocate a small backing store if
3683 // possible.
3684 __ lw(length_reg,
3685 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3686 __ lw(elements_reg,
3687 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3688 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
3689 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
3690
3691 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003692 __ Allocate(size, elements_reg, scratch, scratch2, &slow, TAG_OBJECT);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003693
3694 __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex);
3695 __ sw(scratch, FieldMemOperand(elements_reg, JSObject::kMapOffset));
3696 __ li(scratch, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
3697 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3698 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
3699 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
3700 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::SizeFor(i)));
3701 }
3702
3703 // Store the element at index zero.
3704 __ sw(value_reg, FieldMemOperand(elements_reg, FixedArray::SizeFor(0)));
3705
3706 // Install the new backing store in the JSArray.
3707 __ sw(elements_reg,
3708 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3709 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
3710 scratch, kRAHasNotBeenSaved, kDontSaveFPRegs,
3711 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3712
3713 // Increment the length of the array.
3714 __ li(length_reg, Operand(Smi::FromInt(1)));
3715 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3716 __ Ret();
3717
3718 __ bind(&check_capacity);
3719 // Check for cow elements, in general they are not handled by this stub
3720 __ CheckMap(elements_reg,
3721 scratch,
3722 Heap::kFixedCOWArrayMapRootIndex,
3723 &miss_force_generic,
3724 DONT_DO_SMI_CHECK);
3725
3726 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3727 __ Branch(&slow, hs, length_reg, Operand(scratch));
3728
3729 // Grow the array and finish the store.
3730 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
3731 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3732 __ jmp(&finish_store);
3733
3734 __ bind(&slow);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003735 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003736 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003737}
3738
3739
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003740void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
3741 MacroAssembler* masm,
yangguo@chromium.org56454712012-02-16 15:33:53 +00003742 bool is_js_array,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003743 KeyedAccessStoreMode store_mode) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003744 // ----------- S t a t e -------------
3745 // -- a0 : value
3746 // -- a1 : key
3747 // -- a2 : receiver
3748 // -- ra : return address
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003749 // -- a3 : scratch (elements backing store)
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003750 // -- t0 : scratch (elements_reg)
3751 // -- t1 : scratch (mantissa_reg)
3752 // -- t2 : scratch (exponent_reg)
3753 // -- t3 : scratch4
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003754 // -- t4 : scratch
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003755 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00003756 Label miss_force_generic, transition_elements_kind, grow, slow;
3757 Label finish_store, check_capacity;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003758
3759 Register value_reg = a0;
3760 Register key_reg = a1;
3761 Register receiver_reg = a2;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003762 Register elements_reg = a3;
3763 Register scratch1 = t0;
3764 Register scratch2 = t1;
3765 Register scratch3 = t2;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003766 Register scratch4 = t3;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003767 Register scratch5 = t4;
yangguo@chromium.org56454712012-02-16 15:33:53 +00003768 Register length_reg = t3;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003769
3770 // This stub is meant to be tail-jumped to, the receiver must already
3771 // have been verified by the caller to not be a smi.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003772
3773 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003774 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003775
3776 __ lw(elements_reg,
3777 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3778
3779 // Check that the key is within bounds.
3780 if (is_js_array) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003781 __ lw(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003782 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003783 __ lw(scratch1,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003784 FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3785 }
3786 // Compare smis, unsigned compare catches both negative and out-of-bound
3787 // indexes.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003788 if (IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003789 __ Branch(&grow, hs, key_reg, Operand(scratch1));
3790 } else {
3791 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch1));
3792 }
3793
3794 __ bind(&finish_store);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003795
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003796 __ StoreNumberToDoubleElements(value_reg,
3797 key_reg,
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00003798 // All registers after this are overwritten.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003799 elements_reg,
3800 scratch1,
3801 scratch2,
3802 scratch3,
3803 scratch4,
3804 &transition_elements_kind);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003805
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003806 __ Ret(USE_DELAY_SLOT);
3807 __ mov(v0, value_reg); // In delay slot.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003808
3809 // Handle store cache miss, replacing the ic with the generic stub.
3810 __ bind(&miss_force_generic);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003811 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003812
3813 __ bind(&transition_elements_kind);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003814 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003815
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003816 if (is_js_array && IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003817 // Grow the array by a single element if possible.
3818 __ bind(&grow);
3819
3820 // Make sure the array is only growing by a single element, anything else
3821 // must be handled by the runtime.
3822 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch1));
3823
3824 // Transition on values that can't be stored in a FixedDoubleArray.
3825 Label value_is_smi;
3826 __ JumpIfSmi(value_reg, &value_is_smi);
3827 __ lw(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
3828 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
3829 __ Branch(&transition_elements_kind, ne, scratch1, Operand(at));
3830 __ bind(&value_is_smi);
3831
3832 // Check for the empty array, and preallocate a small backing store if
3833 // possible.
3834 __ lw(length_reg,
3835 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3836 __ lw(elements_reg,
3837 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3838 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
3839 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
3840
3841 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003842 __ Allocate(size, elements_reg, scratch1, scratch2, &slow, TAG_OBJECT);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003843
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003844 // Initialize the new FixedDoubleArray.
yangguo@chromium.org56454712012-02-16 15:33:53 +00003845 __ LoadRoot(scratch1, Heap::kFixedDoubleArrayMapRootIndex);
3846 __ sw(scratch1, FieldMemOperand(elements_reg, JSObject::kMapOffset));
3847 __ li(scratch1, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
3848 __ sw(scratch1,
3849 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
3850
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003851 __ mov(scratch1, elements_reg);
3852 __ StoreNumberToDoubleElements(value_reg,
3853 key_reg,
3854 // All registers after this are overwritten.
3855 scratch1,
3856 scratch2,
3857 scratch3,
3858 scratch4,
3859 scratch5,
3860 &transition_elements_kind);
3861
3862 __ li(scratch1, Operand(kHoleNanLower32));
3863 __ li(scratch2, Operand(kHoleNanUpper32));
3864 for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) {
3865 int offset = FixedDoubleArray::OffsetOfElementAt(i);
3866 __ sw(scratch1, FieldMemOperand(elements_reg, offset));
3867 __ sw(scratch2, FieldMemOperand(elements_reg, offset + kPointerSize));
3868 }
3869
yangguo@chromium.org56454712012-02-16 15:33:53 +00003870 // Install the new backing store in the JSArray.
3871 __ sw(elements_reg,
3872 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3873 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
3874 scratch1, kRAHasNotBeenSaved, kDontSaveFPRegs,
3875 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3876
3877 // Increment the length of the array.
3878 __ li(length_reg, Operand(Smi::FromInt(1)));
3879 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
danno@chromium.org00379b82012-05-04 09:16:29 +00003880 __ lw(elements_reg,
3881 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003882 __ Ret();
yangguo@chromium.org56454712012-02-16 15:33:53 +00003883
3884 __ bind(&check_capacity);
3885 // Make sure that the backing store can hold additional elements.
3886 __ lw(scratch1,
3887 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
3888 __ Branch(&slow, hs, length_reg, Operand(scratch1));
3889
3890 // Grow the array and finish the store.
3891 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
3892 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3893 __ jmp(&finish_store);
3894
3895 __ bind(&slow);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003896 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003897 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003898}
3899
3900
ager@chromium.org5c838252010-02-19 08:53:10 +00003901#undef __
3902
3903} } // namespace v8::internal
3904
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003905#endif // V8_TARGET_ARCH_MIPS