blob: aeb26ee9ac0dea3757fdfc7499e817346fb69999 [file] [log] [blame]
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001// Copyright 2012 the V8 project authors. All rights reserved.
ager@chromium.org5c838252010-02-19 08:53:10 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000030#if defined(V8_TARGET_ARCH_MIPS)
31
ager@chromium.org5c838252010-02-19 08:53:10 +000032#include "ic-inl.h"
karlklose@chromium.org83a47282011-05-11 11:54:09 +000033#include "codegen.h"
ager@chromium.org5c838252010-02-19 08:53:10 +000034#include "stub-cache.h"
35
36namespace v8 {
37namespace internal {
38
39#define __ ACCESS_MASM(masm)
40
41
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000042static void ProbeTable(Isolate* isolate,
43 MacroAssembler* masm,
44 Code::Flags flags,
45 StubCache::Table table,
fschneider@chromium.org35814e52012-03-01 15:43:35 +000046 Register receiver,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000047 Register name,
fschneider@chromium.org35814e52012-03-01 15:43:35 +000048 // Number of the cache entry, not scaled.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000049 Register offset,
50 Register scratch,
fschneider@chromium.org35814e52012-03-01 15:43:35 +000051 Register scratch2,
52 Register offset_scratch) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000053 ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
54 ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
fschneider@chromium.org35814e52012-03-01 15:43:35 +000055 ExternalReference map_offset(isolate->stub_cache()->map_reference(table));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000056
57 uint32_t key_off_addr = reinterpret_cast<uint32_t>(key_offset.address());
58 uint32_t value_off_addr = reinterpret_cast<uint32_t>(value_offset.address());
fschneider@chromium.org35814e52012-03-01 15:43:35 +000059 uint32_t map_off_addr = reinterpret_cast<uint32_t>(map_offset.address());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000060
61 // Check the relative positions of the address fields.
62 ASSERT(value_off_addr > key_off_addr);
63 ASSERT((value_off_addr - key_off_addr) % 4 == 0);
64 ASSERT((value_off_addr - key_off_addr) < (256 * 4));
fschneider@chromium.org35814e52012-03-01 15:43:35 +000065 ASSERT(map_off_addr > key_off_addr);
66 ASSERT((map_off_addr - key_off_addr) % 4 == 0);
67 ASSERT((map_off_addr - key_off_addr) < (256 * 4));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000068
69 Label miss;
fschneider@chromium.org35814e52012-03-01 15:43:35 +000070 Register base_addr = scratch;
71 scratch = no_reg;
72
73 // Multiply by 3 because there are 3 fields per entry (name, code, map).
74 __ sll(offset_scratch, offset, 1);
75 __ Addu(offset_scratch, offset_scratch, offset);
76
77 // Calculate the base address of the entry.
78 __ li(base_addr, Operand(key_offset));
79 __ sll(at, offset_scratch, kPointerSizeLog2);
80 __ Addu(base_addr, base_addr, at);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000081
82 // Check that the key in the entry matches the name.
fschneider@chromium.org35814e52012-03-01 15:43:35 +000083 __ lw(at, MemOperand(base_addr, 0));
84 __ Branch(&miss, ne, name, Operand(at));
85
86 // Check the map matches.
87 __ lw(at, MemOperand(base_addr, map_off_addr - key_off_addr));
88 __ lw(scratch2, FieldMemOperand(receiver, HeapObject::kMapOffset));
89 __ Branch(&miss, ne, at, Operand(scratch2));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000090
91 // Get the code entry from the cache.
fschneider@chromium.org35814e52012-03-01 15:43:35 +000092 Register code = scratch2;
93 scratch2 = no_reg;
94 __ lw(code, MemOperand(base_addr, value_off_addr - key_off_addr));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000095
96 // Check that the flags match what we're looking for.
fschneider@chromium.org35814e52012-03-01 15:43:35 +000097 Register flags_reg = base_addr;
98 base_addr = no_reg;
99 __ lw(flags_reg, FieldMemOperand(code, Code::kFlagsOffset));
100 __ And(flags_reg, flags_reg, Operand(~Code::kFlagsNotUsedInLookup));
101 __ Branch(&miss, ne, flags_reg, Operand(flags));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000102
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000103#ifdef DEBUG
104 if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
105 __ jmp(&miss);
106 } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
107 __ jmp(&miss);
108 }
109#endif
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000110
111 // Jump to the first instruction in the code stub.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000112 __ Addu(at, code, Operand(Code::kHeaderSize - kHeapObjectTag));
113 __ Jump(at);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000114
115 // Miss: fall through.
116 __ bind(&miss);
117}
118
119
120// Helper function used to check that the dictionary doesn't contain
121// the property. This function may return false negatives, so miss_label
122// must always call a backup property check that is complete.
123// This function is safe to call if the receiver has fast properties.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000124// Name must be unique and receiver must be a heap object.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000125static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
126 Label* miss_label,
127 Register receiver,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000128 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000129 Register scratch0,
130 Register scratch1) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000131 ASSERT(name->IsUniqueName());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000132 Counters* counters = masm->isolate()->counters();
133 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
134 __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
135
136 Label done;
137
138 const int kInterceptorOrAccessCheckNeededMask =
139 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
140
141 // Bail out if the receiver has a named interceptor or requires access checks.
142 Register map = scratch1;
143 __ lw(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
144 __ lbu(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
145 __ And(scratch0, scratch0, Operand(kInterceptorOrAccessCheckNeededMask));
146 __ Branch(miss_label, ne, scratch0, Operand(zero_reg));
147
148 // Check that receiver is a JSObject.
149 __ lbu(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
150 __ Branch(miss_label, lt, scratch0, Operand(FIRST_SPEC_OBJECT_TYPE));
151
152 // Load properties array.
153 Register properties = scratch0;
154 __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
155 // Check that the properties array is a dictionary.
156 __ lw(map, FieldMemOperand(properties, HeapObject::kMapOffset));
157 Register tmp = properties;
158 __ LoadRoot(tmp, Heap::kHashTableMapRootIndex);
159 __ Branch(miss_label, ne, map, Operand(tmp));
160
161 // Restore the temporarily used register.
162 __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
163
164
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000165 NameDictionaryLookupStub::GenerateNegativeLookup(masm,
166 miss_label,
167 &done,
168 receiver,
169 properties,
170 name,
171 scratch1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000172 __ bind(&done);
173 __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
174}
175
176
ager@chromium.org5c838252010-02-19 08:53:10 +0000177void StubCache::GenerateProbe(MacroAssembler* masm,
178 Code::Flags flags,
179 Register receiver,
180 Register name,
181 Register scratch,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000182 Register extra,
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000183 Register extra2,
184 Register extra3) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000185 Isolate* isolate = masm->isolate();
186 Label miss;
187
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000188 // Make sure that code is valid. The multiplying code relies on the
189 // entry size being 12.
190 ASSERT(sizeof(Entry) == 12);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000191
192 // Make sure the flags does not name a specific type.
193 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
194
195 // Make sure that there are no register conflicts.
196 ASSERT(!scratch.is(receiver));
197 ASSERT(!scratch.is(name));
198 ASSERT(!extra.is(receiver));
199 ASSERT(!extra.is(name));
200 ASSERT(!extra.is(scratch));
201 ASSERT(!extra2.is(receiver));
202 ASSERT(!extra2.is(name));
203 ASSERT(!extra2.is(scratch));
204 ASSERT(!extra2.is(extra));
205
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000206 // Check register validity.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000207 ASSERT(!scratch.is(no_reg));
208 ASSERT(!extra.is(no_reg));
209 ASSERT(!extra2.is(no_reg));
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000210 ASSERT(!extra3.is(no_reg));
211
212 Counters* counters = masm->isolate()->counters();
213 __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1,
214 extra2, extra3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000215
216 // Check that the receiver isn't a smi.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000217 __ JumpIfSmi(receiver, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000218
219 // Get the map of the receiver and compute the hash.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000220 __ lw(scratch, FieldMemOperand(name, Name::kHashFieldOffset));
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000221 __ lw(at, FieldMemOperand(receiver, HeapObject::kMapOffset));
222 __ Addu(scratch, scratch, at);
223 uint32_t mask = kPrimaryTableSize - 1;
224 // We shift out the last two bits because they are not part of the hash and
225 // they are always 01 for maps.
226 __ srl(scratch, scratch, kHeapObjectTagSize);
227 __ Xor(scratch, scratch, Operand((flags >> kHeapObjectTagSize) & mask));
228 __ And(scratch, scratch, Operand(mask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000229
230 // Probe the primary table.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000231 ProbeTable(isolate,
232 masm,
233 flags,
234 kPrimary,
235 receiver,
236 name,
237 scratch,
238 extra,
239 extra2,
240 extra3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000241
242 // Primary miss: Compute hash for secondary probe.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000243 __ srl(at, name, kHeapObjectTagSize);
244 __ Subu(scratch, scratch, at);
245 uint32_t mask2 = kSecondaryTableSize - 1;
246 __ Addu(scratch, scratch, Operand((flags >> kHeapObjectTagSize) & mask2));
247 __ And(scratch, scratch, Operand(mask2));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000248
249 // Probe the secondary table.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000250 ProbeTable(isolate,
251 masm,
252 flags,
253 kSecondary,
254 receiver,
255 name,
256 scratch,
257 extra,
258 extra2,
259 extra3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000260
261 // Cache miss: Fall-through and let caller handle the miss by
262 // entering the runtime system.
263 __ bind(&miss);
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000264 __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1,
265 extra2, extra3);
ager@chromium.org5c838252010-02-19 08:53:10 +0000266}
267
268
269void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
270 int index,
271 Register prototype) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000272 // Load the global or builtins object from the current context.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000273 __ lw(prototype,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000274 MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
275 // Load the native context from the global or builtins object.
276 __ lw(prototype,
277 FieldMemOperand(prototype, GlobalObject::kNativeContextOffset));
278 // Load the function from the native context.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000279 __ lw(prototype, MemOperand(prototype, Context::SlotOffset(index)));
280 // Load the initial map. The global functions all have initial maps.
281 __ lw(prototype,
282 FieldMemOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
283 // Load the prototype from the initial map.
284 __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000285}
286
287
lrn@chromium.org7516f052011-03-30 08:52:27 +0000288void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000289 MacroAssembler* masm,
290 int index,
291 Register prototype,
292 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000293 Isolate* isolate = masm->isolate();
294 // Check we're still in the same context.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000295 __ lw(prototype,
296 MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000297 ASSERT(!prototype.is(at));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000298 __ li(at, isolate->global_object());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000299 __ Branch(miss, ne, prototype, Operand(at));
300 // Get the global function with the given index.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000301 Handle<JSFunction> function(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000302 JSFunction::cast(isolate->native_context()->get(index)));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000303 // Load its initial map. The global functions all have initial maps.
304 __ li(prototype, Handle<Map>(function->initial_map()));
305 // Load the prototype from the initial map.
306 __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000307}
308
309
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000310void StubCompiler::DoGenerateFastPropertyLoad(MacroAssembler* masm,
311 Register dst,
312 Register src,
313 bool inobject,
314 int index) {
315 int offset = index * kPointerSize;
316 if (!inobject) {
317 // Calculate the offset into the properties array.
318 offset = offset + FixedArray::kHeaderSize;
319 __ lw(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
320 src = dst;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000321 }
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000322 __ lw(dst, FieldMemOperand(src, offset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000323}
324
325
326void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
327 Register receiver,
328 Register scratch,
329 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000330 // Check that the receiver isn't a smi.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000331 __ JumpIfSmi(receiver, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000332
333 // Check that the object is a JS array.
334 __ GetObjectType(receiver, scratch, scratch);
335 __ Branch(miss_label, ne, scratch, Operand(JS_ARRAY_TYPE));
336
337 // Load length directly from the JS array.
338 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
339 __ Ret();
340}
341
342
343// Generate code to check if an object is a string. If the object is a
344// heap object, its map's instance type is left in the scratch1 register.
345// If this is not needed, scratch1 and scratch2 may be the same register.
346static void GenerateStringCheck(MacroAssembler* masm,
347 Register receiver,
348 Register scratch1,
349 Register scratch2,
350 Label* smi,
351 Label* non_string_object) {
352 // Check that the receiver isn't a smi.
353 __ JumpIfSmi(receiver, smi, t0);
354
355 // Check that the object is a string.
356 __ lw(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
357 __ lbu(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
358 __ And(scratch2, scratch1, Operand(kIsNotStringMask));
359 // The cast is to resolve the overload for the argument of 0x0.
360 __ Branch(non_string_object,
361 ne,
362 scratch2,
363 Operand(static_cast<int32_t>(kStringTag)));
ager@chromium.org5c838252010-02-19 08:53:10 +0000364}
365
366
lrn@chromium.org7516f052011-03-30 08:52:27 +0000367// Generate code to load the length from a string object and return the length.
368// If the receiver object is not a string or a wrapped string object the
369// execution continues at the miss label. The register containing the
370// receiver is potentially clobbered.
371void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
372 Register receiver,
373 Register scratch1,
374 Register scratch2,
375 Label* miss,
376 bool support_wrappers) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000377 Label check_wrapper;
378
379 // Check if the object is a string leaving the instance type in the
380 // scratch1 register.
381 GenerateStringCheck(masm, receiver, scratch1, scratch2, miss,
382 support_wrappers ? &check_wrapper : miss);
383
384 // Load length directly from the string.
385 __ lw(v0, FieldMemOperand(receiver, String::kLengthOffset));
386 __ Ret();
387
388 if (support_wrappers) {
389 // Check if the object is a JSValue wrapper.
390 __ bind(&check_wrapper);
391 __ Branch(miss, ne, scratch1, Operand(JS_VALUE_TYPE));
392
393 // Unwrap the value and check if the wrapped value is a string.
394 __ lw(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
395 GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
396 __ lw(v0, FieldMemOperand(scratch1, String::kLengthOffset));
397 __ Ret();
398 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000399}
400
401
ager@chromium.org5c838252010-02-19 08:53:10 +0000402void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
403 Register receiver,
404 Register scratch1,
405 Register scratch2,
406 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000407 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
408 __ mov(v0, scratch1);
409 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000410}
411
412
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000413// Generate code to check that a global property cell is empty. Create
414// the property cell at compilation time if no cell exists for the
415// property.
416static void GenerateCheckPropertyCell(MacroAssembler* masm,
417 Handle<GlobalObject> global,
418 Handle<Name> name,
419 Register scratch,
420 Label* miss) {
421 Handle<JSGlobalPropertyCell> cell =
422 GlobalObject::EnsurePropertyCell(global, name);
423 ASSERT(cell->value()->IsTheHole());
424 __ li(scratch, Operand(cell));
425 __ lw(scratch,
426 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
427 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
428 __ Branch(miss, ne, scratch, Operand(at));
429}
430
431
432// Generate StoreTransition code, value is passed in a0 register.
ager@chromium.org5c838252010-02-19 08:53:10 +0000433// After executing generated code, the receiver_reg and name_reg
434// may be clobbered.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000435void StubCompiler::GenerateStoreTransition(MacroAssembler* masm,
436 Handle<JSObject> object,
437 LookupResult* lookup,
438 Handle<Map> transition,
439 Handle<Name> name,
440 Register receiver_reg,
441 Register name_reg,
442 Register value_reg,
443 Register scratch1,
444 Register scratch2,
445 Label* miss_label,
446 Label* miss_restore_name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000447 // a0 : value.
448 Label exit;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000449
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000450 // Check that the map of the object hasn't changed.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000451 __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000452 DO_SMI_CHECK, REQUIRE_EXACT_MAP);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000453
454 // Perform global security token check if needed.
455 if (object->IsJSGlobalProxy()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000456 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
457 }
458
danno@chromium.orgf005df62013-04-30 16:36:45 +0000459 int descriptor = transition->LastAdded();
460 DescriptorArray* descriptors = transition->instance_descriptors();
461 PropertyDetails details = descriptors->GetDetails(descriptor);
462 Representation representation = details.representation();
463 ASSERT(!representation.IsNone());
464
465 // Ensure no transitions to deprecated maps are followed.
466 __ CheckMapDeprecated(transition, scratch1, miss_label);
467
468 if (FLAG_track_fields && representation.IsSmi()) {
469 __ JumpIfNotSmi(value_reg, miss_label);
470 } else if (FLAG_track_double_fields && representation.IsDouble()) {
471 Label do_store;
472 __ JumpIfSmi(value_reg, &do_store);
473 __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex,
474 miss_label, DONT_DO_SMI_CHECK);
475 __ bind(&do_store);
476 }
477
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000478 // Check that we are allowed to write this.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000479 if (object->GetPrototype()->IsJSObject()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000480 JSObject* holder;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000481 // holder == object indicates that no property was found.
482 if (lookup->holder() != *object) {
483 holder = lookup->holder();
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000484 } else {
485 // Find the top object.
486 holder = *object;
487 do {
488 holder = JSObject::cast(holder->GetPrototype());
489 } while (holder->GetPrototype()->IsJSObject());
490 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000491 Register holder_reg = CheckPrototypes(
492 object, receiver_reg, Handle<JSObject>(holder), name_reg,
493 scratch1, scratch2, name, miss_restore_name);
494 // If no property was found, and the holder (the last object in the
495 // prototype chain) is in slow mode, we need to do a negative lookup on the
496 // holder.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000497 if (lookup->holder() == *object) {
498 if (holder->IsJSGlobalObject()) {
499 GenerateCheckPropertyCell(
500 masm,
501 Handle<GlobalObject>(GlobalObject::cast(holder)),
502 name,
503 scratch1,
504 miss_restore_name);
505 } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
506 GenerateDictionaryNegativeLookup(
507 masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
508 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000509 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000510 }
511
512 // Stub never generated for non-global objects that require access
513 // checks.
514 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
515
516 // Perform map transition for the receiver if necessary.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000517 if (object->map()->unused_property_fields() == 0) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000518 // The properties must be extended before we can store the value.
519 // We jump to a runtime call that extends the properties array.
520 __ push(receiver_reg);
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000521 __ li(a2, Operand(transition));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000522 __ Push(a2, a0);
523 __ TailCallExternalReference(
524 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
525 masm->isolate()),
526 3, 1);
527 return;
528 }
529
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000530 // Update the map of the object.
531 __ li(scratch1, Operand(transition));
532 __ sw(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
verwaest@chromium.org37141392012-05-31 13:27:02 +0000533
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000534 // Update the write barrier for the map field and pass the now unused
535 // name_reg as scratch register.
536 __ RecordWriteField(receiver_reg,
537 HeapObject::kMapOffset,
538 scratch1,
539 name_reg,
540 kRAHasNotBeenSaved,
541 kDontSaveFPRegs,
542 OMIT_REMEMBERED_SET,
543 OMIT_SMI_CHECK);
544
545 int index = transition->instance_descriptors()->GetFieldIndex(
546 transition->LastAdded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000547
548 // Adjust for the number of properties stored in the object. Even in the
549 // face of a transition we can use the old map here because the size of the
550 // object and the number of in-object properties is not going to change.
551 index -= object->map()->inobject_properties();
552
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000553 // TODO(verwaest): Share this code as a code stub.
554 if (index < 0) {
555 // Set the property straight into the object.
556 int offset = object->map()->instance_size() + (index * kPointerSize);
557 __ sw(value_reg, FieldMemOperand(receiver_reg, offset));
558
danno@chromium.orgf005df62013-04-30 16:36:45 +0000559 if (!FLAG_track_fields || !representation.IsSmi()) {
560 // Skip updating write barrier if storing a smi.
561 __ JumpIfSmi(value_reg, &exit);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000562
danno@chromium.orgf005df62013-04-30 16:36:45 +0000563 // Update the write barrier for the array address.
564 // Pass the now unused name_reg as a scratch register.
565 __ mov(name_reg, value_reg);
566 __ RecordWriteField(receiver_reg,
567 offset,
568 name_reg,
569 scratch1,
570 kRAHasNotBeenSaved,
571 kDontSaveFPRegs);
572 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000573 } else {
574 // Write to the properties array.
575 int offset = index * kPointerSize + FixedArray::kHeaderSize;
576 // Get the properties array
577 __ lw(scratch1,
578 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
579 __ sw(value_reg, FieldMemOperand(scratch1, offset));
580
danno@chromium.orgf005df62013-04-30 16:36:45 +0000581 if (!FLAG_track_fields || !representation.IsSmi()) {
582 // Skip updating write barrier if storing a smi.
583 __ JumpIfSmi(value_reg, &exit);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000584
danno@chromium.orgf005df62013-04-30 16:36:45 +0000585 // Update the write barrier for the array address.
586 // Ok to clobber receiver_reg and name_reg, since we return.
587 __ mov(name_reg, value_reg);
588 __ RecordWriteField(scratch1,
589 offset,
590 name_reg,
591 receiver_reg,
592 kRAHasNotBeenSaved,
593 kDontSaveFPRegs);
594 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000595 }
596
597 // Return the value (register v0).
598 ASSERT(value_reg.is(a0));
599 __ bind(&exit);
600 __ mov(v0, a0);
601 __ Ret();
602}
603
604
605// Generate StoreField code, value is passed in a0 register.
606// When leaving generated code after success, the receiver_reg and name_reg
607// may be clobbered. Upon branch to miss_label, the receiver and name
608// registers have their original values.
609void StubCompiler::GenerateStoreField(MacroAssembler* masm,
610 Handle<JSObject> object,
611 LookupResult* lookup,
612 Register receiver_reg,
613 Register name_reg,
614 Register value_reg,
615 Register scratch1,
616 Register scratch2,
617 Label* miss_label) {
618 // a0 : value
619 Label exit;
620
621 // Check that the map of the object hasn't changed.
622 __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
623 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
624
625 // Perform global security token check if needed.
626 if (object->IsJSGlobalProxy()) {
627 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
628 }
629
630 // Stub never generated for non-global objects that require access
631 // checks.
632 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
633
634 int index = lookup->GetFieldIndex().field_index();
635
636 // Adjust for the number of properties stored in the object. Even in the
637 // face of a transition we can use the old map here because the size of the
638 // object and the number of in-object properties is not going to change.
639 index -= object->map()->inobject_properties();
640
danno@chromium.orgf005df62013-04-30 16:36:45 +0000641 Representation representation = lookup->representation();
642 ASSERT(!representation.IsNone());
643 if (FLAG_track_fields && representation.IsSmi()) {
644 __ JumpIfNotSmi(value_reg, miss_label);
645 } else if (FLAG_track_double_fields && representation.IsDouble()) {
646 Label do_store;
647 __ JumpIfSmi(value_reg, &do_store);
648 __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex,
649 miss_label, DONT_DO_SMI_CHECK);
650 __ bind(&do_store);
651 }
652
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000653 // TODO(verwaest): Share this code as a code stub.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000654 if (index < 0) {
655 // Set the property straight into the object.
656 int offset = object->map()->instance_size() + (index * kPointerSize);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000657 __ sw(value_reg, FieldMemOperand(receiver_reg, offset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000658
danno@chromium.orgf005df62013-04-30 16:36:45 +0000659 if (!FLAG_track_fields || !representation.IsSmi()) {
660 // Skip updating write barrier if storing a smi.
661 __ JumpIfSmi(value_reg, &exit);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000662
danno@chromium.orgf005df62013-04-30 16:36:45 +0000663 // Update the write barrier for the array address.
664 // Pass the now unused name_reg as a scratch register.
665 __ mov(name_reg, value_reg);
666 __ RecordWriteField(receiver_reg,
667 offset,
668 name_reg,
669 scratch1,
670 kRAHasNotBeenSaved,
671 kDontSaveFPRegs);
672 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000673 } else {
674 // Write to the properties array.
675 int offset = index * kPointerSize + FixedArray::kHeaderSize;
676 // Get the properties array.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000677 __ lw(scratch1,
678 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000679 __ sw(value_reg, FieldMemOperand(scratch1, offset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000680
danno@chromium.orgf005df62013-04-30 16:36:45 +0000681 if (!FLAG_track_fields || !representation.IsSmi()) {
682 // Skip updating write barrier if storing a smi.
683 __ JumpIfSmi(value_reg, &exit);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000684
danno@chromium.orgf005df62013-04-30 16:36:45 +0000685 // Update the write barrier for the array address.
686 // Ok to clobber receiver_reg and name_reg, since we return.
687 __ mov(name_reg, value_reg);
688 __ RecordWriteField(scratch1,
689 offset,
690 name_reg,
691 receiver_reg,
692 kRAHasNotBeenSaved,
693 kDontSaveFPRegs);
694 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000695 }
696
697 // Return the value (register v0).
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000698 ASSERT(value_reg.is(a0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000699 __ bind(&exit);
700 __ mov(v0, a0);
701 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000702}
703
704
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000705void BaseStoreStubCompiler::GenerateRestoreName(MacroAssembler* masm,
706 Label* label,
707 Handle<Name> name) {
708 if (!label->is_unused()) {
709 __ bind(label);
710 __ li(this->name(), Operand(name));
711 }
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000712}
713
714
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000715static void GenerateCallFunction(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000716 Handle<Object> object,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000717 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000718 Label* miss,
719 Code::ExtraICState extra_ic_state) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000720 // ----------- S t a t e -------------
721 // -- a0: receiver
722 // -- a1: function to call
723 // -----------------------------------
724 // Check that the function really is a function.
725 __ JumpIfSmi(a1, miss);
726 __ GetObjectType(a1, a3, a3);
727 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
728
729 // Patch the receiver on the stack with the global proxy if
730 // necessary.
731 if (object->IsGlobalObject()) {
732 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
733 __ sw(a3, MemOperand(sp, arguments.immediate() * kPointerSize));
734 }
735
736 // Invoke the function.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000737 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
738 ? CALL_AS_FUNCTION
739 : CALL_AS_METHOD;
740 __ InvokeFunction(a1, arguments, JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000741}
742
743
744static void PushInterceptorArguments(MacroAssembler* masm,
745 Register receiver,
746 Register holder,
747 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000748 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000749 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000750 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
751 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000752 Register scratch = name;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000753 __ li(scratch, Operand(interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000754 __ Push(scratch, receiver, holder);
755 __ lw(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
756 __ push(scratch);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000757 __ li(scratch, Operand(ExternalReference::isolate_address(masm->isolate())));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000758 __ push(scratch);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000759}
760
761
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000762static void CompileCallLoadPropertyWithInterceptor(
763 MacroAssembler* masm,
764 Register receiver,
765 Register holder,
766 Register name,
767 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000768 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
769
770 ExternalReference ref =
771 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
772 masm->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000773 __ PrepareCEntryArgs(6);
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000774 __ PrepareCEntryFunction(ref);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000775
776 CEntryStub stub(1);
777 __ CallStub(&stub);
778}
779
780
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000781static const int kFastApiCallArguments = 4;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000782
783
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000784// Reserves space for the extra arguments to API function in the
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000785// caller's frame.
786//
787// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
788static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
789 Register scratch) {
790 ASSERT(Smi::FromInt(0) == 0);
791 for (int i = 0; i < kFastApiCallArguments; i++) {
792 __ push(zero_reg);
793 }
794}
795
796
797// Undoes the effects of ReserveSpaceForFastApiCall.
798static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
799 __ Drop(kFastApiCallArguments);
800}
801
802
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000803static void GenerateFastApiDirectCall(MacroAssembler* masm,
804 const CallOptimization& optimization,
805 int argc) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000806 // ----------- S t a t e -------------
807 // -- sp[0] : holder (set by CheckPrototypes)
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000808 // -- sp[4] : callee JS function
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000809 // -- sp[8] : call data
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000810 // -- sp[12] : isolate
811 // -- sp[16] : last JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000812 // -- ...
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000813 // -- sp[(argc + 3) * 4] : first JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000814 // -- sp[(argc + 4) * 4] : receiver
815 // -----------------------------------
816 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000817 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000818 __ LoadHeapObject(t1, function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000819 __ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset));
820
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000821 // Pass the additional arguments.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000822 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000823 Handle<Object> call_data(api_call_info->data(), masm->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000824 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
825 __ li(a0, api_call_info);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000826 __ lw(t2, FieldMemOperand(a0, CallHandlerInfo::kDataOffset));
827 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000828 __ li(t2, call_data);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000829 }
830
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000831 __ li(t3, Operand(ExternalReference::isolate_address(masm->isolate())));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000832 // Store JS function, call data and isolate.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000833 __ sw(t1, MemOperand(sp, 1 * kPointerSize));
834 __ sw(t2, MemOperand(sp, 2 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000835 __ sw(t3, MemOperand(sp, 3 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000836
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000837 // Prepare arguments.
838 __ Addu(a2, sp, Operand(3 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000839
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000840 // Allocate the v8::Arguments structure in the arguments' space since
841 // it's not controlled by GC.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000842 const int kApiStackSpace = 4;
843
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000844 FrameScope frame_scope(masm, StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000845 __ EnterExitFrame(false, kApiStackSpace);
846
847 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
848 // struct from the function (which is currently the case). This means we pass
849 // the first argument in a1 instead of a0. TryCallApiFunctionAndReturn
850 // will handle setting up a0.
851
852 // a1 = v8::Arguments&
853 // Arguments is built at sp + 1 (sp is a reserved spot for ra).
854 __ Addu(a1, sp, kPointerSize);
855
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000856 // v8::Arguments::implicit_args_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000857 __ sw(a2, MemOperand(a1, 0 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000858 // v8::Arguments::values_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000859 __ Addu(t0, a2, Operand(argc * kPointerSize));
860 __ sw(t0, MemOperand(a1, 1 * kPointerSize));
861 // v8::Arguments::length_ = argc
862 __ li(t0, Operand(argc));
863 __ sw(t0, MemOperand(a1, 2 * kPointerSize));
864 // v8::Arguments::is_construct_call = 0
865 __ sw(zero_reg, MemOperand(a1, 3 * kPointerSize));
866
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000867 const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000868 Address function_address = v8::ToCData<Address>(api_call_info->callback());
869 ApiFunction fun(function_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000870 ExternalReference ref =
871 ExternalReference(&fun,
872 ExternalReference::DIRECT_API_CALL,
873 masm->isolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000874 AllowExternalCallThatCantCauseGC scope(masm);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000875 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000876}
877
lrn@chromium.org7516f052011-03-30 08:52:27 +0000878class CallInterceptorCompiler BASE_EMBEDDED {
879 public:
880 CallInterceptorCompiler(StubCompiler* stub_compiler,
881 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000882 Register name,
883 Code::ExtraICState extra_ic_state)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000884 : stub_compiler_(stub_compiler),
885 arguments_(arguments),
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000886 name_(name),
887 extra_ic_state_(extra_ic_state) {}
lrn@chromium.org7516f052011-03-30 08:52:27 +0000888
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000889 void Compile(MacroAssembler* masm,
890 Handle<JSObject> object,
891 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000892 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000893 LookupResult* lookup,
894 Register receiver,
895 Register scratch1,
896 Register scratch2,
897 Register scratch3,
898 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000899 ASSERT(holder->HasNamedInterceptor());
900 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
901
902 // Check that the receiver isn't a smi.
903 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000904 CallOptimization optimization(lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000905 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000906 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
907 holder, lookup, name, optimization, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000908 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000909 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
910 name, holder, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000911 }
912 }
913
914 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000915 void CompileCacheable(MacroAssembler* masm,
916 Handle<JSObject> object,
917 Register receiver,
918 Register scratch1,
919 Register scratch2,
920 Register scratch3,
921 Handle<JSObject> interceptor_holder,
922 LookupResult* lookup,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000923 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000924 const CallOptimization& optimization,
925 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000926 ASSERT(optimization.is_constant_call());
927 ASSERT(!lookup->holder()->IsGlobalObject());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000928 Counters* counters = masm->isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000929 int depth1 = kInvalidProtoDepth;
930 int depth2 = kInvalidProtoDepth;
931 bool can_do_fast_api_call = false;
932 if (optimization.is_simple_api_call() &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000933 !lookup->holder()->IsGlobalObject()) {
934 depth1 = optimization.GetPrototypeDepthOfExpectedType(
935 object, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000936 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000937 depth2 = optimization.GetPrototypeDepthOfExpectedType(
938 interceptor_holder, Handle<JSObject>(lookup->holder()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000939 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000940 can_do_fast_api_call =
941 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000942 }
943
944 __ IncrementCounter(counters->call_const_interceptor(), 1,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000945 scratch1, scratch2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000946
947 if (can_do_fast_api_call) {
948 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
949 scratch1, scratch2);
950 ReserveSpaceForFastApiCall(masm, scratch1);
951 }
952
953 // Check that the maps from receiver to interceptor's holder
954 // haven't changed and thus we can invoke interceptor.
955 Label miss_cleanup;
956 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
957 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000958 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
959 scratch1, scratch2, scratch3,
960 name, depth1, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000961
962 // Invoke an interceptor and if it provides a value,
963 // branch to |regular_invoke|.
964 Label regular_invoke;
965 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
966 &regular_invoke);
967
968 // Interceptor returned nothing for this property. Try to use cached
969 // constant function.
970
971 // Check that the maps from interceptor's holder to constant function's
972 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000973 if (*interceptor_holder != lookup->holder()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000974 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000975 Handle<JSObject>(lookup->holder()),
976 scratch1, scratch2, scratch3,
977 name, depth2, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000978 } else {
979 // CheckPrototypes has a side effect of fetching a 'holder'
980 // for API (object which is instanceof for the signature). It's
981 // safe to omit it here, as if present, it should be fetched
982 // by the previous CheckPrototypes.
983 ASSERT(depth2 == kInvalidProtoDepth);
984 }
985
986 // Invoke function.
987 if (can_do_fast_api_call) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000988 GenerateFastApiDirectCall(masm, optimization, arguments_.immediate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000989 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000990 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
991 ? CALL_AS_FUNCTION
992 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000993 Handle<JSFunction> function = optimization.constant_function();
994 ParameterCount expected(function);
995 __ InvokeFunction(function, expected, arguments_,
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000996 JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000997 }
998
999 // Deferred code for fast API call case---clean preallocated space.
1000 if (can_do_fast_api_call) {
1001 __ bind(&miss_cleanup);
1002 FreeSpaceForFastApiCall(masm);
1003 __ Branch(miss_label);
1004 }
1005
1006 // Invoke a regular function.
1007 __ bind(&regular_invoke);
1008 if (can_do_fast_api_call) {
1009 FreeSpaceForFastApiCall(masm);
1010 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00001011 }
1012
1013 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001014 Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001015 Register receiver,
1016 Register scratch1,
1017 Register scratch2,
1018 Register scratch3,
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001019 Handle<Name> name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001020 Handle<JSObject> interceptor_holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001021 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001022 Register holder =
1023 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001024 scratch1, scratch2, scratch3,
1025 name, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001026
1027 // Call a runtime function to load the interceptor property.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001028 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001029 // Save the name_ register across the call.
1030 __ push(name_);
1031
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001032 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001033
1034 __ CallExternalReference(
1035 ExternalReference(
1036 IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
1037 masm->isolate()),
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001038 6);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001039 // Restore the name_ register.
1040 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001041 // Leave the internal frame.
lrn@chromium.org7516f052011-03-30 08:52:27 +00001042 }
1043
1044 void LoadWithInterceptor(MacroAssembler* masm,
1045 Register receiver,
1046 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001047 Handle<JSObject> holder_obj,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001048 Register scratch,
1049 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001050 {
1051 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001052
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001053 __ Push(holder, name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001054 CompileCallLoadPropertyWithInterceptor(masm,
1055 receiver,
1056 holder,
1057 name_,
1058 holder_obj);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001059 __ pop(name_); // Restore the name.
1060 __ pop(receiver); // Restore the holder.
1061 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001062 // If interceptor returns no-result sentinel, call the constant function.
1063 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
1064 __ Branch(interceptor_succeeded, ne, v0, Operand(scratch));
lrn@chromium.org7516f052011-03-30 08:52:27 +00001065 }
1066
1067 StubCompiler* stub_compiler_;
1068 const ParameterCount& arguments_;
1069 Register name_;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001070 Code::ExtraICState extra_ic_state_;
lrn@chromium.org7516f052011-03-30 08:52:27 +00001071};
1072
1073
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001074// Calls GenerateCheckPropertyCell for each global object in the prototype chain
1075// from object to (but not including) holder.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001076static void GenerateCheckPropertyCells(MacroAssembler* masm,
1077 Handle<JSObject> object,
1078 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001079 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001080 Register scratch,
1081 Label* miss) {
1082 Handle<JSObject> current = object;
1083 while (!current.is_identical_to(holder)) {
1084 if (current->IsGlobalObject()) {
1085 GenerateCheckPropertyCell(masm,
1086 Handle<GlobalObject>::cast(current),
1087 name,
1088 scratch,
1089 miss);
1090 }
1091 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
1092 }
1093}
1094
1095
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001096// Convert and store int passed in register ival to IEEE 754 single precision
1097// floating point value at memory location (dst + 4 * wordoffset)
1098// If FPU is available use it for conversion.
1099static void StoreIntAsFloat(MacroAssembler* masm,
1100 Register dst,
1101 Register wordoffset,
1102 Register ival,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001103 Register scratch1) {
1104 __ mtc1(ival, f0);
1105 __ cvt_s_w(f0, f0);
1106 __ sll(scratch1, wordoffset, 2);
1107 __ addu(scratch1, dst, scratch1);
1108 __ swc1(f0, MemOperand(scratch1, 0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001109}
1110
1111
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001112void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001113 __ Jump(code, RelocInfo::CODE_TARGET);
1114}
1115
1116
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001117#undef __
1118#define __ ACCESS_MASM(masm())
1119
1120
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001121Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
1122 Register object_reg,
1123 Handle<JSObject> holder,
1124 Register holder_reg,
1125 Register scratch1,
1126 Register scratch2,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001127 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001128 int save_at_depth,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001129 Label* miss,
1130 PrototypeCheckType check) {
1131 Handle<JSObject> first = object;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001132 // Make sure there's no overlap between holder and object registers.
1133 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1134 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1135 && !scratch2.is(scratch1));
1136
1137 // Keep track of the current object in register reg.
1138 Register reg = object_reg;
1139 int depth = 0;
1140
1141 if (save_at_depth == depth) {
1142 __ sw(reg, MemOperand(sp));
1143 }
1144
1145 // Check the maps in the prototype chain.
1146 // Traverse the prototype chain from the object and do map checks.
1147 Handle<JSObject> current = object;
1148 while (!current.is_identical_to(holder)) {
1149 ++depth;
1150
1151 // Only global objects and objects that do not require access
1152 // checks are allowed in stubs.
1153 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1154
1155 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
1156 if (!current->HasFastProperties() &&
1157 !current->IsJSGlobalObject() &&
1158 !current->IsJSGlobalProxy()) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001159 if (!name->IsUniqueName()) {
1160 ASSERT(name->IsString());
1161 name = factory()->InternalizeString(Handle<String>::cast(name));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001162 }
1163 ASSERT(current->property_dictionary()->FindEntry(*name) ==
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001164 NameDictionary::kNotFound);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001165
1166 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1167 scratch1, scratch2);
1168
1169 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1170 reg = holder_reg; // From now on the object will be in holder_reg.
1171 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1172 } else {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001173 Register map_reg = scratch1;
1174 if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) {
1175 Handle<Map> current_map(current->map());
1176 // CheckMap implicitly loads the map of |reg| into |map_reg|.
1177 __ CheckMap(reg, map_reg, current_map, miss, DONT_DO_SMI_CHECK,
1178 ALLOW_ELEMENT_TRANSITION_MAPS);
1179 } else {
1180 __ lw(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
1181 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001182 // Check access rights to the global object. This has to happen after
1183 // the map check so that we know that the object is actually a global
1184 // object.
1185 if (current->IsJSGlobalProxy()) {
1186 __ CheckAccessGlobalProxy(reg, scratch2, miss);
1187 }
1188 reg = holder_reg; // From now on the object will be in holder_reg.
1189
1190 if (heap()->InNewSpace(*prototype)) {
1191 // The prototype is in new space; we cannot store a reference to it
1192 // in the code. Load it from the map.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001193 __ lw(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001194 } else {
1195 // The prototype is in old space; load it directly.
1196 __ li(reg, Operand(prototype));
1197 }
1198 }
1199
1200 if (save_at_depth == depth) {
1201 __ sw(reg, MemOperand(sp));
1202 }
1203
1204 // Go to the next object in the prototype chain.
1205 current = prototype;
1206 }
1207
1208 // Log the check depth.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001209 LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001210
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001211 if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) {
1212 // Check the holder map.
1213 __ CheckMap(reg, scratch1, Handle<Map>(holder->map()), miss,
1214 DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
1215 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001216
1217 // Perform security check for access to the global object.
1218 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1219 if (holder->IsJSGlobalProxy()) {
1220 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1221 }
1222
1223 // If we've skipped any global objects, it's not enough to verify that
1224 // their maps haven't changed. We also need to check that the property
1225 // cell for the property is still empty.
1226 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1227
1228 // Return the register containing the holder.
1229 return reg;
1230}
1231
1232
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001233void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success,
1234 Label* miss) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001235 if (!miss->is_unused()) {
1236 __ Branch(success);
1237 __ bind(miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001238 TailCallBuiltin(masm(), MissBuiltin(kind()));
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001239 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001240}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001241
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001242
1243Register BaseLoadStubCompiler::CallbackHandlerFrontend(
1244 Handle<JSObject> object,
1245 Register object_reg,
1246 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001247 Handle<Name> name,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001248 Label* success,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001249 Handle<ExecutableAccessorInfo> callback) {
1250 Label miss;
1251
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001252 Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001253
1254 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
1255 ASSERT(!reg.is(scratch2()));
1256 ASSERT(!reg.is(scratch3()));
1257 ASSERT(!reg.is(scratch4()));
1258
1259 // Load the properties dictionary.
1260 Register dictionary = scratch4();
1261 __ lw(dictionary, FieldMemOperand(reg, JSObject::kPropertiesOffset));
1262
1263 // Probe the dictionary.
1264 Label probe_done;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001265 NameDictionaryLookupStub::GeneratePositiveLookup(masm(),
1266 &miss,
1267 &probe_done,
1268 dictionary,
1269 this->name(),
1270 scratch2(),
1271 scratch3());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001272 __ bind(&probe_done);
1273
1274 // If probing finds an entry in the dictionary, scratch3 contains the
1275 // pointer into the dictionary. Check that the value is the callback.
1276 Register pointer = scratch3();
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001277 const int kElementsStartOffset = NameDictionary::kHeaderSize +
1278 NameDictionary::kElementsStartIndex * kPointerSize;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001279 const int kValueOffset = kElementsStartOffset + kPointerSize;
1280 __ lw(scratch2(), FieldMemOperand(pointer, kValueOffset));
1281 __ Branch(&miss, ne, scratch2(), Operand(callback));
1282 }
1283
1284 HandlerFrontendFooter(success, &miss);
1285 return reg;
1286}
1287
1288
1289void BaseLoadStubCompiler::NonexistentHandlerFrontend(
1290 Handle<JSObject> object,
1291 Handle<JSObject> last,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001292 Handle<Name> name,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001293 Label* success,
1294 Handle<GlobalObject> global) {
1295 Label miss;
1296
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001297 HandlerFrontendHeader(object, receiver(), last, name, &miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001298
1299 // If the last object in the prototype chain is a global object,
1300 // check that the global property cell is empty.
1301 if (!global.is_null()) {
1302 GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
1303 }
1304
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001305 HandlerFrontendFooter(success, &miss);
1306}
1307
1308
1309void BaseLoadStubCompiler::GenerateLoadField(Register reg,
1310 Handle<JSObject> holder,
1311 PropertyIndex index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001312 GenerateFastPropertyLoad(masm(), v0, reg, holder, index);
1313 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001314}
1315
1316
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001317void BaseLoadStubCompiler::GenerateLoadConstant(Handle<JSFunction> value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001318 // Return the constant value.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001319 __ LoadHeapObject(v0, value);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001320 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001321}
1322
1323
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001324void BaseLoadStubCompiler::GenerateLoadCallback(
1325 Register reg,
1326 Handle<ExecutableAccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001327 // Build AccessorInfo::args_ list on the stack and push property name below
1328 // the exit frame to make GC aware of them and store pointers to them.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001329 __ push(receiver());
1330 __ mov(scratch2(), sp); // scratch2 = AccessorInfo::args_
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001331 if (heap()->InNewSpace(callback->data())) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001332 __ li(scratch3(), callback);
1333 __ lw(scratch3(), FieldMemOperand(scratch3(),
1334 ExecutableAccessorInfo::kDataOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001335 } else {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001336 __ li(scratch3(), Handle<Object>(callback->data(), isolate()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001337 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001338 __ Subu(sp, sp, 4 * kPointerSize);
1339 __ sw(reg, MemOperand(sp, 3 * kPointerSize));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001340 __ sw(scratch3(), MemOperand(sp, 2 * kPointerSize));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001341 __ li(scratch3(),
1342 Operand(ExternalReference::isolate_address(isolate())));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001343 __ sw(scratch3(), MemOperand(sp, 1 * kPointerSize));
1344 __ sw(name(), MemOperand(sp, 0 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001345
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001346 __ mov(a2, scratch2()); // Saved in case scratch2 == a1.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001347 __ mov(a1, sp); // a1 (first argument - see note below) = Handle<Name>
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001348
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001349 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
1350 // struct from the function (which is currently the case). This means we pass
1351 // the arguments in a1-a2 instead of a0-a1. TryCallApiFunctionAndReturn
1352 // will handle setting up a0.
1353
1354 const int kApiStackSpace = 1;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001355 FrameScope frame_scope(masm(), StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001356 __ EnterExitFrame(false, kApiStackSpace);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001357
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001358 // Create AccessorInfo instance on the stack above the exit frame with
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001359 // scratch2 (internal::Object** args_) as the data.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001360 __ sw(a2, MemOperand(sp, kPointerSize));
1361 // a2 (second argument - see note above) = AccessorInfo&
1362 __ Addu(a2, sp, kPointerSize);
1363
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001364 const int kStackUnwindSpace = 5;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001365 Address getter_address = v8::ToCData<Address>(callback->getter());
1366 ApiFunction fun(getter_address);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001367 ExternalReference ref = ExternalReference(
1368 &fun, ExternalReference::DIRECT_GETTER_CALL, isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001369 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
ager@chromium.org5c838252010-02-19 08:53:10 +00001370}
1371
1372
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001373void BaseLoadStubCompiler::GenerateLoadInterceptor(
1374 Register holder_reg,
1375 Handle<JSObject> object,
1376 Handle<JSObject> interceptor_holder,
1377 LookupResult* lookup,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001378 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001379 ASSERT(interceptor_holder->HasNamedInterceptor());
1380 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1381
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001382 // So far the most popular follow ups for interceptor loads are FIELD
1383 // and CALLBACKS, so inline only them, other cases may be added
1384 // later.
1385 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001386 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001387 if (lookup->IsField()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001388 compile_followup_inline = true;
1389 } else if (lookup->type() == CALLBACKS &&
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001390 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
1391 ExecutableAccessorInfo* callback =
1392 ExecutableAccessorInfo::cast(lookup->GetCallbackObject());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001393 compile_followup_inline = callback->getter() != NULL &&
1394 callback->IsCompatibleReceiver(*object);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001395 }
1396 }
1397
1398 if (compile_followup_inline) {
1399 // Compile the interceptor call, followed by inline code to load the
1400 // property from further up the prototype chain if the call fails.
1401 // Check that the maps haven't changed.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001402 ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001403
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001404 // Preserve the receiver register explicitly whenever it is different from
1405 // the holder and it is needed should the interceptor return without any
1406 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1407 // the FIELD case might cause a miss during the prototype check.
1408 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001409 bool must_preserve_receiver_reg = !receiver().is(holder_reg) &&
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001410 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1411
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001412 // Save necessary data before invoking an interceptor.
1413 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001414 {
1415 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001416 if (must_preserve_receiver_reg) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001417 __ Push(receiver(), holder_reg, this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001418 } else {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001419 __ Push(holder_reg, this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001420 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001421 // Invoke an interceptor. Note: map checks from receiver to
1422 // interceptor's holder has been compiled before (see a caller
1423 // of this method).
1424 CompileCallLoadPropertyWithInterceptor(masm(),
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001425 receiver(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001426 holder_reg,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001427 this->name(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001428 interceptor_holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001429 // Check if interceptor provided a value for property. If it's
1430 // the case, return immediately.
1431 Label interceptor_failed;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001432 __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
1433 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001434 frame_scope.GenerateLeaveFrame();
1435 __ Ret();
1436
1437 __ bind(&interceptor_failed);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001438 __ pop(this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001439 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001440 if (must_preserve_receiver_reg) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001441 __ pop(receiver());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001442 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001443 // Leave the internal frame.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001444 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001445 GenerateLoadPostInterceptor(holder_reg, interceptor_holder, name, lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001446 } else { // !compile_followup_inline
1447 // Call the runtime system to load the interceptor.
1448 // Check that the maps haven't changed.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001449 PushInterceptorArguments(masm(), receiver(), holder_reg,
1450 this->name(), interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001451
1452 ExternalReference ref = ExternalReference(
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001453 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001454 __ TailCallExternalReference(ref, 6, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001455 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001456}
1457
1458
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001459void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001460 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001461 __ Branch(miss, ne, a2, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001462 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001463}
1464
1465
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001466void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1467 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001468 Handle<Name> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001469 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001470 ASSERT(holder->IsGlobalObject());
1471
1472 // Get the number of arguments.
1473 const int argc = arguments().immediate();
1474
1475 // Get the receiver from the stack.
1476 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1477
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001478 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001479 __ JumpIfSmi(a0, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001480 CheckPrototypes(object, a0, holder, a3, a1, t0, name, miss);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001481}
1482
1483
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001484void CallStubCompiler::GenerateLoadFunctionFromCell(
1485 Handle<JSGlobalPropertyCell> cell,
1486 Handle<JSFunction> function,
1487 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001488 // Get the value from the cell.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001489 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001490 __ lw(a1, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
1491
1492 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001493 if (heap()->InNewSpace(*function)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001494 // We can't embed a pointer to a function in new space so we have
1495 // to verify that the shared function info is unchanged. This has
1496 // the nice side effect that multiple closures based on the same
1497 // function can all use this call IC. Before we load through the
1498 // function, we have to verify that it still is a function.
1499 __ JumpIfSmi(a1, miss);
1500 __ GetObjectType(a1, a3, a3);
1501 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
1502
1503 // Check the shared function info. Make sure it hasn't changed.
1504 __ li(a3, Handle<SharedFunctionInfo>(function->shared()));
1505 __ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
1506 __ Branch(miss, ne, t0, Operand(a3));
1507 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001508 __ Branch(miss, ne, a1, Operand(function));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001509 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001510}
1511
1512
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001513void CallStubCompiler::GenerateMissBranch() {
1514 Handle<Code> code =
danno@chromium.org40cb8782011-05-25 07:58:50 +00001515 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1516 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001517 extra_state_);
1518 __ Jump(code, RelocInfo::CODE_TARGET);
1519}
1520
1521
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001522Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1523 Handle<JSObject> holder,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001524 PropertyIndex index,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001525 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001526 // ----------- S t a t e -------------
1527 // -- a2 : name
1528 // -- ra : return address
1529 // -----------------------------------
1530 Label miss;
1531
1532 GenerateNameCheck(name, &miss);
1533
1534 const int argc = arguments().immediate();
1535
1536 // Get the receiver of the function from the stack into a0.
1537 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1538 // Check that the receiver isn't a smi.
1539 __ JumpIfSmi(a0, &miss, t0);
1540
1541 // Do the right check and compute the holder register.
1542 Register reg = CheckPrototypes(object, a0, holder, a1, a3, t0, name, &miss);
1543 GenerateFastPropertyLoad(masm(), a1, reg, holder, index);
1544
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001545 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001546
1547 // Handle call cache miss.
1548 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001549 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001550
1551 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001552 return GetCode(Code::FIELD, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001553}
1554
1555
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001556Handle<Code> CallStubCompiler::CompileArrayPushCall(
1557 Handle<Object> object,
1558 Handle<JSObject> holder,
1559 Handle<JSGlobalPropertyCell> cell,
1560 Handle<JSFunction> function,
1561 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001562 // ----------- S t a t e -------------
1563 // -- a2 : name
1564 // -- ra : return address
1565 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1566 // -- ...
1567 // -- sp[argc * 4] : receiver
1568 // -----------------------------------
1569
1570 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001571 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001572
1573 Label miss;
1574
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001575 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001576
1577 Register receiver = a1;
1578
1579 // Get the receiver from the stack.
1580 const int argc = arguments().immediate();
1581 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1582
1583 // Check that the receiver isn't a smi.
1584 __ JumpIfSmi(receiver, &miss);
1585
1586 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001587 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, a3, v0, t0,
1588 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001589
1590 if (argc == 0) {
1591 // Nothing to do, just return the length.
1592 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1593 __ Drop(argc + 1);
1594 __ Ret();
1595 } else {
1596 Label call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001597 if (argc == 1) { // Otherwise fall through to call the builtin.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001598 Label attempt_to_grow_elements, with_write_barrier, check_double;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001599
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001600 Register elements = t2;
1601 Register end_elements = t1;
1602 // Get the elements array of the object.
1603 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1604
1605 // Check that the elements are in fast mode and writable.
1606 __ CheckMap(elements,
1607 v0,
1608 Heap::kFixedArrayMapRootIndex,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001609 &check_double,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001610 DONT_DO_SMI_CHECK);
1611
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001612 // Get the array's length into v0 and calculate new length.
1613 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1614 STATIC_ASSERT(kSmiTagSize == 1);
1615 STATIC_ASSERT(kSmiTag == 0);
1616 __ Addu(v0, v0, Operand(Smi::FromInt(argc)));
1617
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001618 // Get the elements' length.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001619 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1620
1621 // Check if we could survive without allocation.
1622 __ Branch(&attempt_to_grow_elements, gt, v0, Operand(t0));
1623
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001624 // Check if value is a smi.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001625 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1626 __ JumpIfNotSmi(t0, &with_write_barrier);
1627
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001628 // Save new length.
1629 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1630
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001631 // Store the value.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001632 // We may need a register containing the address end_elements below,
1633 // so write back the value in end_elements.
1634 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1635 __ Addu(end_elements, elements, end_elements);
1636 const int kEndElementsOffset =
1637 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001638 __ Addu(end_elements, end_elements, kEndElementsOffset);
1639 __ sw(t0, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001640
1641 // Check for a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001642 __ Drop(argc + 1);
1643 __ Ret();
1644
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001645 __ bind(&check_double);
1646
1647 // Check that the elements are in fast mode and writable.
1648 __ CheckMap(elements,
1649 a0,
1650 Heap::kFixedDoubleArrayMapRootIndex,
1651 &call_builtin,
1652 DONT_DO_SMI_CHECK);
1653
1654 // Get the array's length into r0 and calculate new length.
1655 __ lw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1656 STATIC_ASSERT(kSmiTagSize == 1);
1657 STATIC_ASSERT(kSmiTag == 0);
1658 __ Addu(a0, a0, Operand(Smi::FromInt(argc)));
1659
1660 // Get the elements' length.
1661 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1662
1663 // Check if we could survive without allocation.
1664 __ Branch(&call_builtin, gt, a0, Operand(t0));
1665
1666 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1667 __ StoreNumberToDoubleElements(
1668 t0, a0, elements, a3, t1, a2, t5,
1669 &call_builtin, argc * kDoubleSize);
1670
1671 // Save new length.
1672 __ sw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1673
1674 // Check for a smi.
1675 __ Drop(argc + 1);
1676 __ Ret();
1677
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001678 __ bind(&with_write_barrier);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001679
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001680 __ lw(a3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1681
1682 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
1683 Label fast_object, not_fast_object;
1684 __ CheckFastObjectElements(a3, t3, &not_fast_object);
1685 __ jmp(&fast_object);
1686 // In case of fast smi-only, convert to fast object, otherwise bail out.
1687 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001688 __ CheckFastSmiElements(a3, t3, &call_builtin);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001689
1690 __ lw(t3, FieldMemOperand(t0, HeapObject::kMapOffset));
1691 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
1692 __ Branch(&call_builtin, eq, t3, Operand(at));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001693 // edx: receiver
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001694 // a3: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001695 Label try_holey_map;
1696 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001697 FAST_ELEMENTS,
1698 a3,
1699 t3,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001700 &try_holey_map);
1701 __ mov(a2, receiver);
1702 ElementsTransitionGenerator::
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001703 GenerateMapChangeElementsTransition(masm(),
1704 DONT_TRACK_ALLOCATION_SITE,
1705 NULL);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001706 __ jmp(&fast_object);
1707
1708 __ bind(&try_holey_map);
1709 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1710 FAST_HOLEY_ELEMENTS,
1711 a3,
1712 t3,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001713 &call_builtin);
1714 __ mov(a2, receiver);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001715 ElementsTransitionGenerator::
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001716 GenerateMapChangeElementsTransition(masm(),
1717 DONT_TRACK_ALLOCATION_SITE,
1718 NULL);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001719 __ bind(&fast_object);
1720 } else {
1721 __ CheckFastObjectElements(a3, a3, &call_builtin);
1722 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001723
1724 // Save new length.
1725 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1726
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001727 // Store the value.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001728 // We may need a register containing the address end_elements below,
1729 // so write back the value in end_elements.
1730 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1731 __ Addu(end_elements, elements, end_elements);
1732 __ Addu(end_elements, end_elements, kEndElementsOffset);
1733 __ sw(t0, MemOperand(end_elements));
1734
1735 __ RecordWrite(elements,
1736 end_elements,
1737 t0,
1738 kRAHasNotBeenSaved,
1739 kDontSaveFPRegs,
1740 EMIT_REMEMBERED_SET,
1741 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001742 __ Drop(argc + 1);
1743 __ Ret();
1744
1745 __ bind(&attempt_to_grow_elements);
1746 // v0: array's length + 1.
1747 // t0: elements' length.
1748
1749 if (!FLAG_inline_new) {
1750 __ Branch(&call_builtin);
1751 }
1752
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001753 __ lw(a2, MemOperand(sp, (argc - 1) * kPointerSize));
1754 // Growing elements that are SMI-only requires special handling in case
1755 // the new element is non-Smi. For now, delegate to the builtin.
1756 Label no_fast_elements_check;
1757 __ JumpIfSmi(a2, &no_fast_elements_check);
1758 __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1759 __ CheckFastObjectElements(t3, t3, &call_builtin);
1760 __ bind(&no_fast_elements_check);
1761
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001762 ExternalReference new_space_allocation_top =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001763 ExternalReference::new_space_allocation_top_address(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001764 ExternalReference new_space_allocation_limit =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001765 ExternalReference::new_space_allocation_limit_address(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001766
1767 const int kAllocationDelta = 4;
1768 // Load top and check if it is the end of elements.
1769 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1770 __ Addu(end_elements, elements, end_elements);
1771 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset));
1772 __ li(t3, Operand(new_space_allocation_top));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001773 __ lw(a3, MemOperand(t3));
1774 __ Branch(&call_builtin, ne, end_elements, Operand(a3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001775
1776 __ li(t5, Operand(new_space_allocation_limit));
1777 __ lw(t5, MemOperand(t5));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001778 __ Addu(a3, a3, Operand(kAllocationDelta * kPointerSize));
1779 __ Branch(&call_builtin, hi, a3, Operand(t5));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001780
1781 // We fit and could grow elements.
1782 // Update new_space_allocation_top.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001783 __ sw(a3, MemOperand(t3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001784 // Push the argument.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001785 __ sw(a2, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001786 // Fill the rest with holes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001787 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001788 for (int i = 1; i < kAllocationDelta; i++) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001789 __ sw(a3, MemOperand(end_elements, i * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001790 }
1791
1792 // Update elements' and array's sizes.
1793 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1794 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta)));
1795 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1796
1797 // Elements are in new space, so write barrier is not required.
1798 __ Drop(argc + 1);
1799 __ Ret();
1800 }
1801 __ bind(&call_builtin);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001802 __ TailCallExternalReference(
1803 ExternalReference(Builtins::c_ArrayPush, isolate()), argc + 1, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001804 }
1805
1806 // Handle call cache miss.
1807 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001808 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001809
1810 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001811 return GetCode(function);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001812}
1813
1814
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001815Handle<Code> CallStubCompiler::CompileArrayPopCall(
1816 Handle<Object> object,
1817 Handle<JSObject> holder,
1818 Handle<JSGlobalPropertyCell> cell,
1819 Handle<JSFunction> function,
1820 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001821 // ----------- S t a t e -------------
1822 // -- a2 : name
1823 // -- ra : return address
1824 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1825 // -- ...
1826 // -- sp[argc * 4] : receiver
1827 // -----------------------------------
1828
1829 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001830 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001831
1832 Label miss, return_undefined, call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001833 Register receiver = a1;
1834 Register elements = a3;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001835 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001836
1837 // Get the receiver from the stack.
1838 const int argc = arguments().immediate();
1839 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001840 // Check that the receiver isn't a smi.
1841 __ JumpIfSmi(receiver, &miss);
1842
1843 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001844 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, elements,
1845 t0, v0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001846
1847 // Get the elements array of the object.
1848 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1849
1850 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001851 __ CheckMap(elements,
1852 v0,
1853 Heap::kFixedArrayMapRootIndex,
1854 &call_builtin,
1855 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001856
1857 // Get the array's length into t0 and calculate new length.
1858 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1859 __ Subu(t0, t0, Operand(Smi::FromInt(1)));
1860 __ Branch(&return_undefined, lt, t0, Operand(zero_reg));
1861
1862 // Get the last element.
1863 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1864 STATIC_ASSERT(kSmiTagSize == 1);
1865 STATIC_ASSERT(kSmiTag == 0);
1866 // We can't address the last element in one operation. Compute the more
1867 // expensive shift first, and use an offset later on.
1868 __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize);
1869 __ Addu(elements, elements, t1);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001870 __ lw(v0, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001871 __ Branch(&call_builtin, eq, v0, Operand(t2));
1872
1873 // Set the array's length.
1874 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1875
1876 // Fill with the hole.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001877 __ sw(t2, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001878 __ Drop(argc + 1);
1879 __ Ret();
1880
1881 __ bind(&return_undefined);
1882 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
1883 __ Drop(argc + 1);
1884 __ Ret();
1885
1886 __ bind(&call_builtin);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001887 __ TailCallExternalReference(
1888 ExternalReference(Builtins::c_ArrayPop, isolate()), argc + 1, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001889
1890 // Handle call cache miss.
1891 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001892 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001893
1894 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001895 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001896}
1897
1898
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001899Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1900 Handle<Object> object,
1901 Handle<JSObject> holder,
1902 Handle<JSGlobalPropertyCell> cell,
1903 Handle<JSFunction> function,
1904 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001905 // ----------- S t a t e -------------
1906 // -- a2 : function name
1907 // -- ra : return address
1908 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1909 // -- ...
1910 // -- sp[argc * 4] : receiver
1911 // -----------------------------------
1912
1913 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001914 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001915
1916 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001917 Label miss;
1918 Label name_miss;
1919 Label index_out_of_range;
1920
1921 Label* index_out_of_range_label = &index_out_of_range;
1922
danno@chromium.org40cb8782011-05-25 07:58:50 +00001923 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001924 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001925 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001926 index_out_of_range_label = &miss;
1927 }
1928
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001929 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001930
1931 // Check that the maps starting from the prototype haven't changed.
1932 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1933 Context::STRING_FUNCTION_INDEX,
1934 v0,
1935 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001936 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001937 CheckPrototypes(
1938 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
1939 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001940
1941 Register receiver = a1;
1942 Register index = t1;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001943 Register result = v0;
1944 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1945 if (argc > 0) {
1946 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1947 } else {
1948 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1949 }
1950
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001951 StringCharCodeAtGenerator generator(receiver,
1952 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001953 result,
1954 &miss, // When not a string.
1955 &miss, // When not a number.
1956 index_out_of_range_label,
1957 STRING_INDEX_IS_NUMBER);
1958 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001959 __ Drop(argc + 1);
1960 __ Ret();
1961
1962 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001963 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001964
1965 if (index_out_of_range.is_linked()) {
1966 __ bind(&index_out_of_range);
1967 __ LoadRoot(v0, Heap::kNanValueRootIndex);
1968 __ Drop(argc + 1);
1969 __ Ret();
1970 }
1971
1972 __ bind(&miss);
1973 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001974 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001975 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001976 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001977
1978 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001979 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001980}
1981
1982
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001983Handle<Code> CallStubCompiler::CompileStringCharAtCall(
1984 Handle<Object> object,
1985 Handle<JSObject> holder,
1986 Handle<JSGlobalPropertyCell> cell,
1987 Handle<JSFunction> function,
1988 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001989 // ----------- S t a t e -------------
1990 // -- a2 : function name
1991 // -- ra : return address
1992 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1993 // -- ...
1994 // -- sp[argc * 4] : receiver
1995 // -----------------------------------
1996
1997 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001998 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001999
2000 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002001 Label miss;
2002 Label name_miss;
2003 Label index_out_of_range;
2004 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00002005 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002006 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002007 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002008 index_out_of_range_label = &miss;
2009 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002010 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002011
2012 // Check that the maps starting from the prototype haven't changed.
2013 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2014 Context::STRING_FUNCTION_INDEX,
2015 v0,
2016 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002017 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002018 CheckPrototypes(
2019 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2020 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002021
2022 Register receiver = v0;
2023 Register index = t1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00002024 Register scratch = a3;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002025 Register result = v0;
2026 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
2027 if (argc > 0) {
2028 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
2029 } else {
2030 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
2031 }
2032
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002033 StringCharAtGenerator generator(receiver,
2034 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00002035 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002036 result,
2037 &miss, // When not a string.
2038 &miss, // When not a number.
2039 index_out_of_range_label,
2040 STRING_INDEX_IS_NUMBER);
2041 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002042 __ Drop(argc + 1);
2043 __ Ret();
2044
2045 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002046 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002047
2048 if (index_out_of_range.is_linked()) {
2049 __ bind(&index_out_of_range);
ulan@chromium.org750145a2013-03-07 15:14:13 +00002050 __ LoadRoot(v0, Heap::kempty_stringRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002051 __ Drop(argc + 1);
2052 __ Ret();
2053 }
2054
2055 __ bind(&miss);
2056 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002057 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002058 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002059 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002060
2061 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002062 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002063}
2064
2065
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002066Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
2067 Handle<Object> object,
2068 Handle<JSObject> holder,
2069 Handle<JSGlobalPropertyCell> cell,
2070 Handle<JSFunction> function,
2071 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002072 // ----------- S t a t e -------------
2073 // -- a2 : function name
2074 // -- ra : return address
2075 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2076 // -- ...
2077 // -- sp[argc * 4] : receiver
2078 // -----------------------------------
2079
2080 const int argc = arguments().immediate();
2081
2082 // If the object is not a JSObject or we got an unexpected number of
2083 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002084 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002085
2086 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002087 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002088
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002089 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002090 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
2091
2092 STATIC_ASSERT(kSmiTag == 0);
2093 __ JumpIfSmi(a1, &miss);
2094
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002095 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2096 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002097 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002098 ASSERT(cell->value() == *function);
2099 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2100 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002101 GenerateLoadFunctionFromCell(cell, function, &miss);
2102 }
2103
2104 // Load the char code argument.
2105 Register code = a1;
2106 __ lw(code, MemOperand(sp, 0 * kPointerSize));
2107
2108 // Check the code is a smi.
2109 Label slow;
2110 STATIC_ASSERT(kSmiTag == 0);
2111 __ JumpIfNotSmi(code, &slow);
2112
2113 // Convert the smi code to uint16.
2114 __ And(code, code, Operand(Smi::FromInt(0xffff)));
2115
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002116 StringCharFromCodeGenerator generator(code, v0);
2117 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002118 __ Drop(argc + 1);
2119 __ Ret();
2120
2121 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002122 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002123
2124 // Tail call the full function. We do not have to patch the receiver
2125 // because the function makes no use of it.
2126 __ bind(&slow);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002127 ParameterCount expected(function);
2128 __ InvokeFunction(function, expected, arguments(),
2129 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002130
2131 __ bind(&miss);
2132 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002133 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002134
2135 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002136 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002137}
2138
2139
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002140Handle<Code> CallStubCompiler::CompileMathFloorCall(
2141 Handle<Object> object,
2142 Handle<JSObject> holder,
2143 Handle<JSGlobalPropertyCell> cell,
2144 Handle<JSFunction> function,
2145 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002146 // ----------- S t a t e -------------
2147 // -- a2 : function name
2148 // -- ra : return address
2149 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2150 // -- ...
2151 // -- sp[argc * 4] : receiver
2152 // -----------------------------------
2153
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002154
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002155 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002156 // If the object is not a JSObject or we got an unexpected number of
2157 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002158 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002159
2160 Label miss, slow;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002161 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002162
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002163 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002164 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002165 STATIC_ASSERT(kSmiTag == 0);
2166 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002167 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2168 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002169 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002170 ASSERT(cell->value() == *function);
2171 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2172 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002173 GenerateLoadFunctionFromCell(cell, function, &miss);
2174 }
2175
2176 // Load the (only) argument into v0.
2177 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2178
2179 // If the argument is a smi, just return.
2180 STATIC_ASSERT(kSmiTag == 0);
2181 __ And(t0, v0, Operand(kSmiTagMask));
2182 __ Drop(argc + 1, eq, t0, Operand(zero_reg));
2183 __ Ret(eq, t0, Operand(zero_reg));
2184
danno@chromium.org40cb8782011-05-25 07:58:50 +00002185 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002186
2187 Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return;
2188
2189 // If fpu is enabled, we use the floor instruction.
2190
2191 // Load the HeapNumber value.
2192 __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2193
2194 // Backup FCSR.
2195 __ cfc1(a3, FCSR);
2196 // Clearing FCSR clears the exception mask with no side-effects.
2197 __ ctc1(zero_reg, FCSR);
2198 // Convert the argument to an integer.
2199 __ floor_w_d(f0, f0);
2200
2201 // Start checking for special cases.
2202 // Get the argument exponent and clear the sign bit.
2203 __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize));
2204 __ And(t2, t1, Operand(~HeapNumber::kSignMask));
2205 __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord);
2206
2207 // Retrieve FCSR and check for fpu errors.
2208 __ cfc1(t5, FCSR);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002209 __ And(t5, t5, Operand(kFCSRExceptionFlagMask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002210 __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));
2211
2212 // Check for NaN, Infinity, and -Infinity.
2213 // They are invariant through a Math.Floor call, so just
2214 // return the original argument.
2215 __ Subu(t3, t2, Operand(HeapNumber::kExponentMask
2216 >> HeapNumber::kMantissaBitsInTopWord));
2217 __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg));
2218 // We had an overflow or underflow in the conversion. Check if we
2219 // have a big exponent.
2220 // If greater or equal, the argument is already round and in v0.
2221 __ Branch(&restore_fcsr_and_return, ge, t3,
2222 Operand(HeapNumber::kMantissaBits));
2223 __ Branch(&wont_fit_smi);
2224
2225 __ bind(&no_fpu_error);
2226 // Move the result back to v0.
2227 __ mfc1(v0, f0);
2228 // Check if the result fits into a smi.
2229 __ Addu(a1, v0, Operand(0x40000000));
2230 __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg));
2231 // Tag the result.
2232 STATIC_ASSERT(kSmiTag == 0);
2233 __ sll(v0, v0, kSmiTagSize);
2234
2235 // Check for -0.
2236 __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg));
2237 // t1 already holds the HeapNumber exponent.
2238 __ And(t0, t1, Operand(HeapNumber::kSignMask));
2239 // If our HeapNumber is negative it was -0, so load its address and return.
2240 // Else v0 is loaded with 0, so we can also just return.
2241 __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg));
2242 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2243
2244 __ bind(&restore_fcsr_and_return);
2245 // Restore FCSR and return.
2246 __ ctc1(a3, FCSR);
2247
2248 __ Drop(argc + 1);
2249 __ Ret();
2250
2251 __ bind(&wont_fit_smi);
2252 // Restore FCSR and fall to slow case.
2253 __ ctc1(a3, FCSR);
2254
2255 __ bind(&slow);
2256 // Tail call the full function. We do not have to patch the receiver
2257 // because the function makes no use of it.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002258 ParameterCount expected(function);
2259 __ InvokeFunction(function, expected, arguments(),
2260 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002261
2262 __ bind(&miss);
2263 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002264 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002265
2266 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002267 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002268}
2269
2270
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002271Handle<Code> CallStubCompiler::CompileMathAbsCall(
2272 Handle<Object> object,
2273 Handle<JSObject> holder,
2274 Handle<JSGlobalPropertyCell> cell,
2275 Handle<JSFunction> function,
2276 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002277 // ----------- S t a t e -------------
2278 // -- a2 : function name
2279 // -- ra : return address
2280 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2281 // -- ...
2282 // -- sp[argc * 4] : receiver
2283 // -----------------------------------
2284
2285 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002286 // If the object is not a JSObject or we got an unexpected number of
2287 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002288 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002289
2290 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002291
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002292 GenerateNameCheck(name, &miss);
2293 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002294 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002295 STATIC_ASSERT(kSmiTag == 0);
2296 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002297 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2298 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002299 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002300 ASSERT(cell->value() == *function);
2301 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2302 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002303 GenerateLoadFunctionFromCell(cell, function, &miss);
2304 }
2305
2306 // Load the (only) argument into v0.
2307 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2308
2309 // Check if the argument is a smi.
2310 Label not_smi;
2311 STATIC_ASSERT(kSmiTag == 0);
2312 __ JumpIfNotSmi(v0, &not_smi);
2313
2314 // Do bitwise not or do nothing depending on the sign of the
2315 // argument.
2316 __ sra(t0, v0, kBitsPerInt - 1);
2317 __ Xor(a1, v0, t0);
2318
2319 // Add 1 or do nothing depending on the sign of the argument.
2320 __ Subu(v0, a1, t0);
2321
2322 // If the result is still negative, go to the slow case.
2323 // This only happens for the most negative smi.
2324 Label slow;
2325 __ Branch(&slow, lt, v0, Operand(zero_reg));
2326
2327 // Smi case done.
2328 __ Drop(argc + 1);
2329 __ Ret();
2330
2331 // Check if the argument is a heap number and load its exponent and
2332 // sign.
2333 __ bind(&not_smi);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002334 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002335 __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2336
2337 // Check the sign of the argument. If the argument is positive,
2338 // just return it.
2339 Label negative_sign;
2340 __ And(t0, a1, Operand(HeapNumber::kSignMask));
2341 __ Branch(&negative_sign, ne, t0, Operand(zero_reg));
2342 __ Drop(argc + 1);
2343 __ Ret();
2344
2345 // If the argument is negative, clear the sign, and return a new
2346 // number.
2347 __ bind(&negative_sign);
2348 __ Xor(a1, a1, Operand(HeapNumber::kSignMask));
2349 __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2350 __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
2351 __ AllocateHeapNumber(v0, t0, t1, t2, &slow);
2352 __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2353 __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2354 __ Drop(argc + 1);
2355 __ Ret();
2356
2357 // Tail call the full function. We do not have to patch the receiver
2358 // because the function makes no use of it.
2359 __ bind(&slow);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002360 ParameterCount expected(function);
2361 __ InvokeFunction(function, expected, arguments(),
2362 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002363
2364 __ bind(&miss);
2365 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002366 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002367
2368 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002369 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002370}
2371
2372
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002373Handle<Code> CallStubCompiler::CompileFastApiCall(
lrn@chromium.org7516f052011-03-30 08:52:27 +00002374 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002375 Handle<Object> object,
2376 Handle<JSObject> holder,
2377 Handle<JSGlobalPropertyCell> cell,
2378 Handle<JSFunction> function,
2379 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002380
danno@chromium.org40cb8782011-05-25 07:58:50 +00002381 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002382
2383 ASSERT(optimization.is_simple_api_call());
2384 // Bail out if object is a global object as we don't want to
2385 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002386 if (object->IsGlobalObject()) return Handle<Code>::null();
2387 if (!cell.is_null()) return Handle<Code>::null();
2388 if (!object->IsJSObject()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002389 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002390 Handle<JSObject>::cast(object), holder);
2391 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002392
2393 Label miss, miss_before_stack_reserved;
2394
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002395 GenerateNameCheck(name, &miss_before_stack_reserved);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002396
2397 // Get the receiver from the stack.
2398 const int argc = arguments().immediate();
2399 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2400
2401 // Check that the receiver isn't a smi.
2402 __ JumpIfSmi(a1, &miss_before_stack_reserved);
2403
2404 __ IncrementCounter(counters->call_const(), 1, a0, a3);
2405 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2406
2407 ReserveSpaceForFastApiCall(masm(), a0);
2408
2409 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002410 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002411 depth, &miss);
2412
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002413 GenerateFastApiDirectCall(masm(), optimization, argc);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002414
2415 __ bind(&miss);
2416 FreeSpaceForFastApiCall(masm());
2417
2418 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002419 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002420
2421 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002422 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002423}
2424
2425
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002426void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
2427 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002428 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002429 CheckType check,
2430 Label* success) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002431 // ----------- S t a t e -------------
2432 // -- a2 : name
2433 // -- ra : return address
2434 // -----------------------------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002435 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002436 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002437
2438 // Get the receiver from the stack.
2439 const int argc = arguments().immediate();
2440 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2441
2442 // Check that the receiver isn't a smi.
2443 if (check != NUMBER_CHECK) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002444 __ JumpIfSmi(a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002445 }
2446
2447 // Make sure that it's okay not to patch the on stack receiver
2448 // unless we're doing a receiver map check.
2449 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002450 switch (check) {
2451 case RECEIVER_MAP_CHECK:
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002452 __ IncrementCounter(isolate()->counters()->call_const(), 1, a0, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002453
2454 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002455 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2456 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002457
2458 // Patch the receiver on the stack with the global proxy if
2459 // necessary.
2460 if (object->IsGlobalObject()) {
2461 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2462 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2463 }
2464 break;
2465
2466 case STRING_CHECK:
ulan@chromium.org750145a2013-03-07 15:14:13 +00002467 // Check that the object is a string.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002468 __ GetObjectType(a1, a3, a3);
2469 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2470 // Check that the maps starting from the prototype haven't changed.
2471 GenerateDirectLoadGlobalFunctionPrototype(
2472 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
2473 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002474 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002475 a0, holder, a3, a1, t0, name, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002476 break;
2477
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002478 case SYMBOL_CHECK:
2479 // Check that the object is a symbol.
2480 __ GetObjectType(a1, a1, a3);
2481 __ Branch(&miss, ne, a3, Operand(SYMBOL_TYPE));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002482 // Check that the maps starting from the prototype haven't changed.
2483 GenerateDirectLoadGlobalFunctionPrototype(
2484 masm(), Context::SYMBOL_FUNCTION_INDEX, a0, &miss);
2485 CheckPrototypes(
2486 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
2487 a0, holder, a3, a1, t0, name, &miss);
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002488 break;
2489
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002490 case NUMBER_CHECK: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002491 Label fast;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002492 // Check that the object is a smi or a heap number.
2493 __ JumpIfSmi(a1, &fast);
2494 __ GetObjectType(a1, a0, a0);
2495 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
2496 __ bind(&fast);
2497 // Check that the maps starting from the prototype haven't changed.
2498 GenerateDirectLoadGlobalFunctionPrototype(
2499 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
2500 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002501 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002502 a0, holder, a3, a1, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002503 break;
2504 }
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002505 case BOOLEAN_CHECK: {
2506 Label fast;
2507 // Check that the object is a boolean.
2508 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
2509 __ Branch(&fast, eq, a1, Operand(t0));
2510 __ LoadRoot(t0, Heap::kFalseValueRootIndex);
2511 __ Branch(&miss, ne, a1, Operand(t0));
2512 __ bind(&fast);
2513 // Check that the maps starting from the prototype haven't changed.
2514 GenerateDirectLoadGlobalFunctionPrototype(
2515 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
2516 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002517 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002518 a0, holder, a3, a1, t0, name, &miss);
2519 break;
2520 }
2521 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002522
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002523 __ jmp(success);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002524
2525 // Handle call cache miss.
2526 __ bind(&miss);
2527
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002528 GenerateMissBranch();
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002529}
2530
2531
2532void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) {
2533 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
2534 ? CALL_AS_FUNCTION
2535 : CALL_AS_METHOD;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002536 ParameterCount expected(function);
2537 __ InvokeFunction(function, expected, arguments(),
2538 JUMP_FUNCTION, NullCallWrapper(), call_kind);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002539}
2540
2541
2542Handle<Code> CallStubCompiler::CompileCallConstant(
2543 Handle<Object> object,
2544 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002545 Handle<Name> name,
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002546 CheckType check,
2547 Handle<JSFunction> function) {
2548 if (HasCustomCallGenerator(function)) {
2549 Handle<Code> code = CompileCustomCall(object, holder,
2550 Handle<JSGlobalPropertyCell>::null(),
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002551 function, Handle<String>::cast(name));
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002552 // A null handle means bail out to the regular compiler code below.
2553 if (!code.is_null()) return code;
2554 }
2555
2556 Label success;
2557
2558 CompileHandlerFrontend(object, holder, name, check, &success);
2559 __ bind(&success);
2560 CompileHandlerBackend(function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002561
2562 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002563 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002564}
2565
2566
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002567Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2568 Handle<JSObject> holder,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002569 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002570 // ----------- S t a t e -------------
2571 // -- a2 : name
2572 // -- ra : return address
2573 // -----------------------------------
2574
2575 Label miss;
2576
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002577 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002578
2579 // Get the number of arguments.
2580 const int argc = arguments().immediate();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002581 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002582 LookupPostInterceptor(holder, name, &lookup);
2583
2584 // Get the receiver from the stack.
2585 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2586
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002587 CallInterceptorCompiler compiler(this, arguments(), a2, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002588 compiler.Compile(masm(), object, holder, name, &lookup, a1, a3, t0, a0,
2589 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002590
2591 // Move returned value, the function to call, to a1.
2592 __ mov(a1, v0);
2593 // Restore receiver.
2594 __ lw(a0, MemOperand(sp, argc * kPointerSize));
2595
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002596 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002597
2598 // Handle call cache miss.
2599 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002600 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002601
2602 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002603 return GetCode(Code::INTERCEPTOR, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002604}
2605
2606
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002607Handle<Code> CallStubCompiler::CompileCallGlobal(
2608 Handle<JSObject> object,
2609 Handle<GlobalObject> holder,
2610 Handle<JSGlobalPropertyCell> cell,
2611 Handle<JSFunction> function,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002612 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002613 // ----------- S t a t e -------------
2614 // -- a2 : name
2615 // -- ra : return address
2616 // -----------------------------------
2617
2618 if (HasCustomCallGenerator(function)) {
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002619 Handle<Code> code = CompileCustomCall(
2620 object, holder, cell, function, Handle<String>::cast(name));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002621 // A null handle means bail out to the regular compiler code below.
2622 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002623 }
2624
2625 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002626 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002627
2628 // Get the number of arguments.
2629 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002630 GenerateGlobalReceiverCheck(object, holder, name, &miss);
2631 GenerateLoadFunctionFromCell(cell, function, &miss);
2632
2633 // Patch the receiver on the stack with the global proxy if
2634 // necessary.
2635 if (object->IsGlobalObject()) {
2636 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
2637 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2638 }
2639
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002640 // Set up the context (function already in r1).
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002641 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
2642
2643 // Jump to the cached code (tail call).
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002644 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002645 __ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002646 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002647 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002648 ? CALL_AS_FUNCTION
2649 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002650 // We call indirectly through the code field in the function to
2651 // allow recompilation to take effect without changing any of the
2652 // call sites.
2653 __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
2654 __ InvokeCode(a3, expected, arguments(), JUMP_FUNCTION,
2655 NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002656
2657 // Handle call cache miss.
2658 __ bind(&miss);
2659 __ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002660 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002661
2662 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002663 return GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002664}
2665
2666
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002667Handle<Code> StoreStubCompiler::CompileStoreCallback(
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002668 Handle<Name> name,
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002669 Handle<JSObject> object,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002670 Handle<JSObject> holder,
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002671 Handle<ExecutableAccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002672 Label miss;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002673 // Check that the maps haven't changed.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002674 __ JumpIfSmi(receiver(), &miss);
2675 CheckPrototypes(object, receiver(), holder,
2676 scratch1(), scratch2(), scratch3(), name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002677
2678 // Stub never generated for non-global objects that require access
2679 // checks.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002680 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002681
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002682 __ push(receiver()); // Receiver.
2683 __ li(at, Operand(callback)); // Callback info.
2684 __ Push(at, this->name(), value());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002685
2686 // Do tail-call to the runtime system.
2687 ExternalReference store_callback_property =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002688 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002689 __ TailCallExternalReference(store_callback_property, 4, 1);
2690
2691 // Handle store cache miss.
2692 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002693 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002694
2695 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002696 return GetICCode(kind(), Code::CALLBACKS, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002697}
2698
2699
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002700#undef __
2701#define __ ACCESS_MASM(masm)
2702
2703
2704void StoreStubCompiler::GenerateStoreViaSetter(
2705 MacroAssembler* masm,
2706 Handle<JSFunction> setter) {
2707 // ----------- S t a t e -------------
2708 // -- a0 : value
2709 // -- a1 : receiver
2710 // -- a2 : name
2711 // -- ra : return address
2712 // -----------------------------------
2713 {
2714 FrameScope scope(masm, StackFrame::INTERNAL);
2715
2716 // Save value register, so we can restore it later.
2717 __ push(a0);
2718
2719 if (!setter.is_null()) {
2720 // Call the JavaScript setter with receiver and value on the stack.
2721 __ push(a1);
2722 __ push(a0);
2723 ParameterCount actual(1);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002724 ParameterCount expected(setter);
2725 __ InvokeFunction(setter, expected, actual,
2726 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002727 } else {
2728 // If we generate a global code snippet for deoptimization only, remember
2729 // the place to continue after deoptimization.
2730 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2731 }
2732
2733 // We have to return the passed value, not the return value of the setter.
2734 __ pop(v0);
2735
2736 // Restore context register.
2737 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2738 }
2739 __ Ret();
2740}
2741
2742
2743#undef __
2744#define __ ACCESS_MASM(masm())
2745
2746
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002747Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002748 Handle<JSObject> object,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002749 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002750 Label miss;
2751
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002752 // Check that the map of the object hasn't changed.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002753 __ CheckMap(receiver(), scratch1(), Handle<Map>(object->map()), &miss,
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002754 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002755
2756 // Perform global security token check if needed.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002757 if (object->IsJSGlobalProxy()) {
2758 __ CheckAccessGlobalProxy(receiver(), scratch1(), &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002759 }
2760
2761 // Stub is never generated for non-global objects that require access
2762 // checks.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002763 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002764
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002765 __ Push(receiver(), this->name(), value());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002766
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002767 __ li(scratch1(), Operand(Smi::FromInt(strict_mode())));
2768 __ push(scratch1()); // strict mode
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002769
2770 // Do tail-call to the runtime system.
2771 ExternalReference store_ic_property =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002772 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002773 __ TailCallExternalReference(store_ic_property, 4, 1);
2774
2775 // Handle store cache miss.
2776 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002777 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002778
2779 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002780 return GetICCode(kind(), Code::INTERCEPTOR, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002781}
2782
2783
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002784Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2785 Handle<GlobalObject> object,
2786 Handle<JSGlobalPropertyCell> cell,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002787 Handle<Name> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002788 Label miss;
2789
2790 // Check that the map of the global has not changed.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002791 __ lw(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset));
2792 __ Branch(&miss, ne, scratch1(), Operand(Handle<Map>(object->map())));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002793
2794 // Check that the value in the cell is not the hole. If it is, this
2795 // cell could have been deleted and reintroducing the global needs
2796 // to update the property details in the property dictionary of the
2797 // global object. We bail out to the runtime system to do that.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002798 __ li(scratch1(), Operand(cell));
2799 __ LoadRoot(scratch2(), Heap::kTheHoleValueRootIndex);
2800 __ lw(scratch3(),
2801 FieldMemOperand(scratch1(), JSGlobalPropertyCell::kValueOffset));
2802 __ Branch(&miss, eq, scratch3(), Operand(scratch2()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002803
2804 // Store the value in the cell.
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002805 __ sw(value(),
2806 FieldMemOperand(scratch1(), JSGlobalPropertyCell::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002807 __ mov(v0, a0); // Stored value must be returned in v0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002808 // Cells are always rescanned, so no write barrier here.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002809
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002810 Counters* counters = isolate()->counters();
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002811 __ IncrementCounter(
2812 counters->named_store_global_inline(), 1, scratch1(), scratch2());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002813 __ Ret();
2814
2815 // Handle store cache miss.
2816 __ bind(&miss);
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00002817 __ IncrementCounter(
2818 counters->named_store_global_inline_miss(), 1, scratch1(), scratch2());
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002819 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002820
2821 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002822 return GetICCode(kind(), Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002823}
2824
2825
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002826Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
2827 Handle<JSObject> object,
2828 Handle<JSObject> last,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002829 Handle<Name> name,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002830 Handle<GlobalObject> global) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002831 Label success;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002832
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002833 NonexistentHandlerFrontend(object, last, name, &success, global);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002834
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002835 __ bind(&success);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002836 // Return undefined if maps of the full prototype chain is still the same.
2837 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2838 __ Ret();
2839
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002840 // Return the generated code.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002841 return GetCode(kind(), Code::NONEXISTENT, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002842}
2843
2844
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002845Register* LoadStubCompiler::registers() {
2846 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2847 static Register registers[] = { a0, a2, a3, a1, t0, t1 };
2848 return registers;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002849}
2850
2851
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002852Register* KeyedLoadStubCompiler::registers() {
2853 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2854 static Register registers[] = { a1, a0, a2, a3, t0, t1 };
2855 return registers;
2856}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002857
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002858
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002859Register* StoreStubCompiler::registers() {
2860 // receiver, name, value, scratch1, scratch2, scratch3.
2861 static Register registers[] = { a1, a2, a0, a3, t0, t1 };
2862 return registers;
2863}
2864
2865
2866Register* KeyedStoreStubCompiler::registers() {
2867 // receiver, name, value, scratch1, scratch2, scratch3.
2868 static Register registers[] = { a2, a1, a0, a3, t0, t1 };
2869 return registers;
2870}
2871
2872
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002873void KeyedLoadStubCompiler::GenerateNameCheck(Handle<Name> name,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002874 Register name_reg,
2875 Label* miss) {
2876 __ Branch(miss, ne, name_reg, Operand(name));
lrn@chromium.org7516f052011-03-30 08:52:27 +00002877}
2878
2879
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002880void KeyedStoreStubCompiler::GenerateNameCheck(Handle<Name> name,
2881 Register name_reg,
2882 Label* miss) {
2883 __ Branch(miss, ne, name_reg, Operand(name));
2884}
2885
2886
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002887#undef __
2888#define __ ACCESS_MASM(masm)
2889
2890
2891void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
2892 Handle<JSFunction> getter) {
2893 // ----------- S t a t e -------------
2894 // -- a0 : receiver
2895 // -- a2 : name
2896 // -- ra : return address
2897 // -----------------------------------
2898 {
2899 FrameScope scope(masm, StackFrame::INTERNAL);
2900
2901 if (!getter.is_null()) {
2902 // Call the JavaScript getter with the receiver on the stack.
2903 __ push(a0);
2904 ParameterCount actual(0);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002905 ParameterCount expected(getter);
2906 __ InvokeFunction(getter, expected, actual,
2907 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002908 } else {
2909 // If we generate a global code snippet for deoptimization only, remember
2910 // the place to continue after deoptimization.
2911 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
2912 }
2913
2914 // Restore context register.
2915 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2916 }
2917 __ Ret();
2918}
2919
2920
2921#undef __
2922#define __ ACCESS_MASM(masm())
2923
2924
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002925Handle<Code> LoadStubCompiler::CompileLoadGlobal(
2926 Handle<JSObject> object,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002927 Handle<GlobalObject> global,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002928 Handle<JSGlobalPropertyCell> cell,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002929 Handle<Name> name,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002930 bool is_dont_delete) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002931 Label success, miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002932
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002933 __ CheckMap(
2934 receiver(), scratch1(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
2935 HandlerFrontendHeader(
2936 object, receiver(), Handle<JSObject>::cast(global), name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002937
2938 // Get the value from the cell.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002939 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002940 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
2941
2942 // Check for deleted property if property can actually be deleted.
2943 if (!is_dont_delete) {
2944 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
2945 __ Branch(&miss, eq, t0, Operand(at));
2946 }
2947
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002948 HandlerFrontendFooter(&success, &miss);
2949 __ bind(&success);
2950
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002951 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002952 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002953 __ mov(v0, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002954 __ Ret();
2955
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002956 // Return the generated code.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002957 return GetICCode(kind(), Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002958}
2959
2960
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002961Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002962 MapHandleList* receiver_maps,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002963 CodeHandleList* handlers,
2964 Handle<Name> name,
2965 Code::StubType type,
2966 IcCheckType check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002967 Label miss;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002968
2969 if (check == PROPERTY) {
2970 GenerateNameCheck(name, this->name(), &miss);
2971 }
2972
2973 __ JumpIfSmi(receiver(), &miss);
2974 Register map_reg = scratch1();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002975
danno@chromium.org40cb8782011-05-25 07:58:50 +00002976 int receiver_count = receiver_maps->length();
danno@chromium.orgf005df62013-04-30 16:36:45 +00002977 int number_of_handled_maps = 0;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002978 __ lw(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00002979 for (int current = 0; current < receiver_count; ++current) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00002980 Handle<Map> map = receiver_maps->at(current);
2981 if (!map->is_deprecated()) {
2982 number_of_handled_maps++;
2983 __ Jump(handlers->at(current), RelocInfo::CODE_TARGET,
2984 eq, map_reg, Operand(receiver_maps->at(current)));
2985 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00002986 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00002987 ASSERT(number_of_handled_maps != 0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002988
2989 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002990 TailCallBuiltin(masm(), MissBuiltin(kind()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002991
2992 // Return the generated code.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002993 InlineCacheState state =
danno@chromium.orgf005df62013-04-30 16:36:45 +00002994 number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00002995 return GetICCode(kind(), type, name, state);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002996}
2997
2998
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002999Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
3000 MapHandleList* receiver_maps,
3001 CodeHandleList* handler_stubs,
3002 MapHandleList* transitioned_maps) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003003 Label miss;
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003004 __ JumpIfSmi(receiver(), &miss);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003005
3006 int receiver_count = receiver_maps->length();
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003007 __ lw(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003008 for (int i = 0; i < receiver_count; ++i) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003009 if (transitioned_maps->at(i).is_null()) {
3010 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq,
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003011 scratch1(), Operand(receiver_maps->at(i)));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003012 } else {
3013 Label next_map;
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003014 __ Branch(&next_map, ne, scratch1(), Operand(receiver_maps->at(i)));
3015 __ li(transition_map(), Operand(transitioned_maps->at(i)));
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003016 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003017 __ bind(&next_map);
3018 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003019 }
3020
3021 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003022 TailCallBuiltin(masm(), MissBuiltin(kind()));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003023
3024 // Return the generated code.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003025 return GetICCode(
3026 kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003027}
3028
3029
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003030Handle<Code> ConstructStubCompiler::CompileConstructStub(
3031 Handle<JSFunction> function) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003032 // a0 : argc
3033 // a1 : constructor
3034 // ra : return address
3035 // [sp] : last argument
3036 Label generic_stub_call;
3037
3038 // Use t7 for holding undefined which is used in several places below.
3039 __ LoadRoot(t7, Heap::kUndefinedValueRootIndex);
3040
3041#ifdef ENABLE_DEBUGGER_SUPPORT
3042 // Check to see whether there are any break points in the function code. If
3043 // there are jump to the generic constructor stub which calls the actual
3044 // code for the function thereby hitting the break points.
3045 __ lw(t5, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3046 __ lw(a2, FieldMemOperand(t5, SharedFunctionInfo::kDebugInfoOffset));
3047 __ Branch(&generic_stub_call, ne, a2, Operand(t7));
3048#endif
3049
3050 // Load the initial map and verify that it is in fact a map.
3051 // a1: constructor function
3052 // t7: undefined
3053 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003054 __ JumpIfSmi(a2, &generic_stub_call);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003055 __ GetObjectType(a2, a3, t0);
3056 __ Branch(&generic_stub_call, ne, t0, Operand(MAP_TYPE));
3057
3058#ifdef DEBUG
3059 // Cannot construct functions this way.
3060 // a0: argc
3061 // a1: constructor function
3062 // a2: initial map
3063 // t7: undefined
3064 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
3065 __ Check(ne, "Function constructed by construct stub.",
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003066 a3, Operand(JS_FUNCTION_TYPE));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003067#endif
3068
3069 // Now allocate the JSObject in new space.
3070 // a0: argc
3071 // a1: constructor function
3072 // a2: initial map
3073 // t7: undefined
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003074 ASSERT(function->has_initial_map());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003075 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003076#ifdef DEBUG
3077 int instance_size = function->initial_map()->instance_size();
3078 __ Check(eq, "Instance size of initial map changed.",
3079 a3, Operand(instance_size >> kPointerSizeLog2));
3080#endif
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003081 __ Allocate(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003082
3083 // Allocated the JSObject, now initialize the fields. Map is set to initial
3084 // map and properties and elements are set to empty fixed array.
3085 // a0: argc
3086 // a1: constructor function
3087 // a2: initial map
3088 // a3: object size (in words)
3089 // t4: JSObject (not tagged)
3090 // t7: undefined
3091 __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex);
3092 __ mov(t5, t4);
3093 __ sw(a2, MemOperand(t5, JSObject::kMapOffset));
3094 __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset));
3095 __ sw(t6, MemOperand(t5, JSObject::kElementsOffset));
3096 __ Addu(t5, t5, Operand(3 * kPointerSize));
3097 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
3098 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
3099 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
3100
3101
3102 // Calculate the location of the first argument. The stack contains only the
3103 // argc arguments.
3104 __ sll(a1, a0, kPointerSizeLog2);
3105 __ Addu(a1, a1, sp);
3106
3107 // Fill all the in-object properties with undefined.
3108 // a0: argc
3109 // a1: first argument
3110 // a3: object size (in words)
3111 // t4: JSObject (not tagged)
3112 // t5: First in-object property of JSObject (not tagged)
3113 // t7: undefined
3114 // Fill the initialized properties with a constant value or a passed argument
3115 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003116 Handle<SharedFunctionInfo> shared(function->shared());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003117 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3118 if (shared->IsThisPropertyAssignmentArgument(i)) {
3119 Label not_passed, next;
3120 // Check if the argument assigned to the property is actually passed.
3121 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3122 __ Branch(&not_passed, less_equal, a0, Operand(arg_number));
3123 // Argument passed - find it on the stack.
3124 __ lw(a2, MemOperand(a1, (arg_number + 1) * -kPointerSize));
3125 __ sw(a2, MemOperand(t5));
3126 __ Addu(t5, t5, kPointerSize);
3127 __ jmp(&next);
3128 __ bind(&not_passed);
3129 // Set the property to undefined.
3130 __ sw(t7, MemOperand(t5));
3131 __ Addu(t5, t5, Operand(kPointerSize));
3132 __ bind(&next);
3133 } else {
3134 // Set the property to the constant value.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003135 Handle<Object> constant(
3136 shared->GetThisPropertyAssignmentConstant(i), isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003137 __ li(a2, Operand(constant));
3138 __ sw(a2, MemOperand(t5));
3139 __ Addu(t5, t5, kPointerSize);
3140 }
3141 }
3142
3143 // Fill the unused in-object property fields with undefined.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003144 for (int i = shared->this_property_assignments_count();
3145 i < function->initial_map()->inobject_properties();
3146 i++) {
3147 __ sw(t7, MemOperand(t5));
3148 __ Addu(t5, t5, kPointerSize);
3149 }
3150
3151 // a0: argc
3152 // t4: JSObject (not tagged)
3153 // Move argc to a1 and the JSObject to return to v0 and tag it.
3154 __ mov(a1, a0);
3155 __ mov(v0, t4);
3156 __ Or(v0, v0, Operand(kHeapObjectTag));
3157
3158 // v0: JSObject
3159 // a1: argc
3160 // Remove caller arguments and receiver from the stack and return.
3161 __ sll(t0, a1, kPointerSizeLog2);
3162 __ Addu(sp, sp, t0);
3163 __ Addu(sp, sp, Operand(kPointerSize));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003164 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003165 __ IncrementCounter(counters->constructed_objects(), 1, a1, a2);
3166 __ IncrementCounter(counters->constructed_objects_stub(), 1, a1, a2);
3167 __ Ret();
3168
3169 // Jump to the generic stub in case the specialized code cannot handle the
3170 // construction.
3171 __ bind(&generic_stub_call);
3172 Handle<Code> generic_construct_stub =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003173 isolate()->builtins()->JSConstructStubGeneric();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003174 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
3175
3176 // Return the generated code.
3177 return GetCode();
3178}
3179
3180
danno@chromium.org40cb8782011-05-25 07:58:50 +00003181#undef __
3182#define __ ACCESS_MASM(masm)
3183
3184
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003185void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3186 MacroAssembler* masm) {
3187 // ---------- S t a t e --------------
3188 // -- ra : return address
3189 // -- a0 : key
3190 // -- a1 : receiver
3191 // -----------------------------------
3192 Label slow, miss_force_generic;
3193
3194 Register key = a0;
3195 Register receiver = a1;
3196
3197 __ JumpIfNotSmi(key, &miss_force_generic);
3198 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
3199 __ sra(a2, a0, kSmiTagSize);
3200 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
3201 __ Ret();
3202
3203 // Slow case, key and receiver still in a0 and a1.
3204 __ bind(&slow);
3205 __ IncrementCounter(
3206 masm->isolate()->counters()->keyed_load_external_array_slow(),
3207 1, a2, a3);
3208 // Entry registers are intact.
3209 // ---------- S t a t e --------------
3210 // -- ra : return address
3211 // -- a0 : key
3212 // -- a1 : receiver
3213 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003214 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003215
3216 // Miss case, call the runtime.
3217 __ bind(&miss_force_generic);
3218
3219 // ---------- S t a t e --------------
3220 // -- ra : return address
3221 // -- a0 : key
3222 // -- a1 : receiver
3223 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003224 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_MissForceGeneric);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003225}
3226
3227
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003228static void GenerateSmiKeyCheck(MacroAssembler* masm,
3229 Register key,
3230 Register scratch0,
3231 Register scratch1,
3232 FPURegister double_scratch0,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003233 FPURegister double_scratch1,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003234 Label* fail) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003235 Label key_ok;
3236 // Check for smi or a smi inside a heap number. We convert the heap
3237 // number and check if the conversion is exact and fits into the smi
3238 // range.
3239 __ JumpIfSmi(key, &key_ok);
3240 __ CheckMap(key,
3241 scratch0,
3242 Heap::kHeapNumberMapRootIndex,
3243 fail,
3244 DONT_DO_SMI_CHECK);
3245 __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
3246 __ EmitFPUTruncate(kRoundToZero,
3247 scratch0,
3248 double_scratch0,
3249 at,
3250 double_scratch1,
3251 scratch1,
3252 kCheckForInexactConversion);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003253
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003254 __ Branch(fail, ne, scratch1, Operand(zero_reg));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003255
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003256 __ SmiTagCheckOverflow(key, scratch0, scratch1);
3257 __ BranchOnOverflow(fail, scratch1);
3258 __ bind(&key_ok);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003259}
3260
3261
danno@chromium.org40cb8782011-05-25 07:58:50 +00003262void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3263 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003264 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003265 // ---------- S t a t e --------------
3266 // -- a0 : value
3267 // -- a1 : key
3268 // -- a2 : receiver
3269 // -- ra : return address
3270 // -----------------------------------
3271
danno@chromium.org40cb8782011-05-25 07:58:50 +00003272 Label slow, check_heap_number, miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003273
3274 // Register usage.
3275 Register value = a0;
3276 Register key = a1;
3277 Register receiver = a2;
3278 // a3 mostly holds the elements array or the destination external array.
3279
danno@chromium.org40cb8782011-05-25 07:58:50 +00003280 // This stub is meant to be tail-jumped to, the receiver must already
3281 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003282
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003283 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003284 GenerateSmiKeyCheck(masm, key, t0, t1, f2, f4, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003285
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003286 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3287
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003288 // Check that the index is in range.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003289 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3290 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003291 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003292
3293 // Handle both smis and HeapNumbers in the fast path. Go to the
3294 // runtime for all other kinds of values.
3295 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003296
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003297 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003298 // Double to pixel conversion is only implemented in the runtime for now.
3299 __ JumpIfNotSmi(value, &slow);
3300 } else {
3301 __ JumpIfNotSmi(value, &check_heap_number);
3302 }
3303 __ SmiUntag(t1, value);
3304 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3305
3306 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003307 // t1: value (integer).
3308
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003309 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003310 case EXTERNAL_PIXEL_ELEMENTS: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003311 // Clamp the value to [0..255].
3312 // v0 is used as a scratch register here.
3313 Label done;
3314 __ li(v0, Operand(255));
3315 // Normal branch: nop in delay slot.
3316 __ Branch(&done, gt, t1, Operand(v0));
3317 // Use delay slot in this branch.
3318 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg));
3319 __ mov(v0, zero_reg); // In delay slot.
3320 __ mov(v0, t1); // Value is in range 0..255.
3321 __ bind(&done);
3322 __ mov(t1, v0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003323
3324 __ srl(t8, key, 1);
3325 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003326 __ sb(t1, MemOperand(t8, 0));
3327 }
3328 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003329 case EXTERNAL_BYTE_ELEMENTS:
3330 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003331 __ srl(t8, key, 1);
3332 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003333 __ sb(t1, MemOperand(t8, 0));
3334 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003335 case EXTERNAL_SHORT_ELEMENTS:
3336 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003337 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003338 __ sh(t1, MemOperand(t8, 0));
3339 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003340 case EXTERNAL_INT_ELEMENTS:
3341 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003342 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003343 __ addu(t8, a3, t8);
3344 __ sw(t1, MemOperand(t8, 0));
3345 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003346 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003347 // Perform int-to-float conversion and store to memory.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003348 __ SmiUntag(t0, key);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003349 StoreIntAsFloat(masm, a3, t0, t1, t2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003350 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003351 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003352 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003353 __ addu(a3, a3, t8);
3354 // a3: effective address of the double element
3355 FloatingPointHelper::Destination destination;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003356 destination = FloatingPointHelper::kFPURegisters;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003357 FloatingPointHelper::ConvertIntToDouble(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003358 masm, t1, destination,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003359 f0, t2, t3, // These are: double_dst, dst_mantissa, dst_exponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003360 t0, f2); // These are: scratch2, single_scratch.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003361 __ sdc1(f0, MemOperand(a3, 0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003362 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003363 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003364 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003365 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003366 case FAST_HOLEY_ELEMENTS:
3367 case FAST_HOLEY_SMI_ELEMENTS:
3368 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003369 case DICTIONARY_ELEMENTS:
3370 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003371 UNREACHABLE();
3372 break;
3373 }
3374
3375 // Entry registers are intact, a0 holds the value which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003376 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003377 __ Ret();
3378
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003379 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003380 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003381 __ bind(&check_heap_number);
3382 __ GetObjectType(value, t1, t2);
3383 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE));
3384
3385 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3386
3387 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003388
3389 // The WebGL specification leaves the behavior of storing NaN and
3390 // +/-Infinity into integer arrays basically undefined. For more
3391 // reproducible behavior, convert these to zero.
3392
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003393
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003394 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003395
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003396 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
3397 __ cvt_s_d(f0, f0);
3398 __ sll(t8, key, 1);
3399 __ addu(t8, a3, t8);
3400 __ swc1(f0, MemOperand(t8, 0));
3401 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
3402 __ sll(t8, key, 2);
3403 __ addu(t8, a3, t8);
3404 __ sdc1(f0, MemOperand(t8, 0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003405 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003406 __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003407
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003408 switch (elements_kind) {
3409 case EXTERNAL_BYTE_ELEMENTS:
3410 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3411 __ srl(t8, key, 1);
3412 __ addu(t8, a3, t8);
3413 __ sb(t3, MemOperand(t8, 0));
3414 break;
3415 case EXTERNAL_SHORT_ELEMENTS:
3416 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3417 __ addu(t8, a3, key);
3418 __ sh(t3, MemOperand(t8, 0));
3419 break;
3420 case EXTERNAL_INT_ELEMENTS:
3421 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3422 __ sll(t8, key, 1);
3423 __ addu(t8, a3, t8);
3424 __ sw(t3, MemOperand(t8, 0));
3425 break;
3426 case EXTERNAL_PIXEL_ELEMENTS:
3427 case EXTERNAL_FLOAT_ELEMENTS:
3428 case EXTERNAL_DOUBLE_ELEMENTS:
3429 case FAST_ELEMENTS:
3430 case FAST_SMI_ELEMENTS:
3431 case FAST_DOUBLE_ELEMENTS:
3432 case FAST_HOLEY_ELEMENTS:
3433 case FAST_HOLEY_SMI_ELEMENTS:
3434 case FAST_HOLEY_DOUBLE_ELEMENTS:
3435 case DICTIONARY_ELEMENTS:
3436 case NON_STRICT_ARGUMENTS_ELEMENTS:
3437 UNREACHABLE();
3438 break;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003439 }
3440 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003441
3442 // Entry registers are intact, a0 holds the value
3443 // which is the return value.
3444 __ mov(v0, a0);
3445 __ Ret();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003446 }
3447
danno@chromium.org40cb8782011-05-25 07:58:50 +00003448 // Slow case, key and receiver still in a0 and a1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003449 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003450 __ IncrementCounter(
3451 masm->isolate()->counters()->keyed_load_external_array_slow(),
3452 1, a2, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003453 // Entry registers are intact.
3454 // ---------- S t a t e --------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003455 // -- ra : return address
danno@chromium.org40cb8782011-05-25 07:58:50 +00003456 // -- a0 : key
3457 // -- a1 : receiver
3458 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003459 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003460
3461 // Miss case, call the runtime.
3462 __ bind(&miss_force_generic);
3463
3464 // ---------- S t a t e --------------
3465 // -- ra : return address
3466 // -- a0 : key
3467 // -- a1 : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003468 // -----------------------------------
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003469 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003470}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003471
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003472
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003473void KeyedStoreStubCompiler::GenerateStoreFastElement(
3474 MacroAssembler* masm,
3475 bool is_js_array,
yangguo@chromium.org56454712012-02-16 15:33:53 +00003476 ElementsKind elements_kind,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003477 KeyedAccessStoreMode store_mode) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003478 // ----------- S t a t e -------------
3479 // -- a0 : value
3480 // -- a1 : key
3481 // -- a2 : receiver
3482 // -- ra : return address
3483 // -- a3 : scratch
3484 // -- a4 : scratch (elements)
3485 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00003486 Label miss_force_generic, transition_elements_kind, grow, slow;
3487 Label finish_store, check_capacity;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003488
3489 Register value_reg = a0;
3490 Register key_reg = a1;
3491 Register receiver_reg = a2;
yangguo@chromium.org56454712012-02-16 15:33:53 +00003492 Register scratch = t0;
3493 Register elements_reg = a3;
3494 Register length_reg = t1;
3495 Register scratch2 = t2;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003496
3497 // This stub is meant to be tail-jumped to, the receiver must already
3498 // have been verified by the caller to not be a smi.
3499
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003500 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003501 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003502
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003503 if (IsFastSmiElementsKind(elements_kind)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003504 __ JumpIfNotSmi(value_reg, &transition_elements_kind);
3505 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003506
3507 // Check that the key is within bounds.
yangguo@chromium.org56454712012-02-16 15:33:53 +00003508 __ lw(elements_reg,
3509 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003510 if (is_js_array) {
3511 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3512 } else {
3513 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3514 }
3515 // Compare smis.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003516 if (is_js_array && IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003517 __ Branch(&grow, hs, key_reg, Operand(scratch));
3518 } else {
3519 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
3520 }
3521
3522 // Make sure elements is a fast element array, not 'cow'.
3523 __ CheckMap(elements_reg,
3524 scratch,
3525 Heap::kFixedArrayMapRootIndex,
3526 &miss_force_generic,
3527 DONT_DO_SMI_CHECK);
3528
3529 __ bind(&finish_store);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003530
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003531 if (IsFastSmiElementsKind(elements_kind)) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003532 __ Addu(scratch,
3533 elements_reg,
3534 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3535 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
3536 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
3537 __ Addu(scratch, scratch, scratch2);
3538 __ sw(value_reg, MemOperand(scratch));
3539 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003540 ASSERT(IsFastObjectElementsKind(elements_kind));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003541 __ Addu(scratch,
3542 elements_reg,
3543 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3544 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
3545 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
3546 __ Addu(scratch, scratch, scratch2);
3547 __ sw(value_reg, MemOperand(scratch));
3548 __ mov(receiver_reg, value_reg);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003549 __ RecordWrite(elements_reg, // Object.
3550 scratch, // Address.
3551 receiver_reg, // Value.
3552 kRAHasNotBeenSaved,
3553 kDontSaveFPRegs);
3554 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003555 // value_reg (a0) is preserved.
3556 // Done.
3557 __ Ret();
3558
3559 __ bind(&miss_force_generic);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003560 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003561
3562 __ bind(&transition_elements_kind);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003563 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003564
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003565 if (is_js_array && IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003566 // Grow the array by a single element if possible.
3567 __ bind(&grow);
3568
3569 // Make sure the array is only growing by a single element, anything else
3570 // must be handled by the runtime.
3571 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch));
3572
3573 // Check for the empty array, and preallocate a small backing store if
3574 // possible.
3575 __ lw(length_reg,
3576 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3577 __ lw(elements_reg,
3578 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3579 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
3580 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
3581
3582 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003583 __ Allocate(size, elements_reg, scratch, scratch2, &slow, TAG_OBJECT);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003584
3585 __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex);
3586 __ sw(scratch, FieldMemOperand(elements_reg, JSObject::kMapOffset));
3587 __ li(scratch, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
3588 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3589 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
3590 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
3591 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::SizeFor(i)));
3592 }
3593
3594 // Store the element at index zero.
3595 __ sw(value_reg, FieldMemOperand(elements_reg, FixedArray::SizeFor(0)));
3596
3597 // Install the new backing store in the JSArray.
3598 __ sw(elements_reg,
3599 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3600 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
3601 scratch, kRAHasNotBeenSaved, kDontSaveFPRegs,
3602 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3603
3604 // Increment the length of the array.
3605 __ li(length_reg, Operand(Smi::FromInt(1)));
3606 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3607 __ Ret();
3608
3609 __ bind(&check_capacity);
3610 // Check for cow elements, in general they are not handled by this stub
3611 __ CheckMap(elements_reg,
3612 scratch,
3613 Heap::kFixedCOWArrayMapRootIndex,
3614 &miss_force_generic,
3615 DONT_DO_SMI_CHECK);
3616
3617 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3618 __ Branch(&slow, hs, length_reg, Operand(scratch));
3619
3620 // Grow the array and finish the store.
3621 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
3622 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3623 __ jmp(&finish_store);
3624
3625 __ bind(&slow);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003626 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003627 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003628}
3629
3630
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003631void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
3632 MacroAssembler* masm,
yangguo@chromium.org56454712012-02-16 15:33:53 +00003633 bool is_js_array,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003634 KeyedAccessStoreMode store_mode) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003635 // ----------- S t a t e -------------
3636 // -- a0 : value
3637 // -- a1 : key
3638 // -- a2 : receiver
3639 // -- ra : return address
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003640 // -- a3 : scratch (elements backing store)
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003641 // -- t0 : scratch (elements_reg)
3642 // -- t1 : scratch (mantissa_reg)
3643 // -- t2 : scratch (exponent_reg)
3644 // -- t3 : scratch4
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003645 // -- t4 : scratch
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003646 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00003647 Label miss_force_generic, transition_elements_kind, grow, slow;
3648 Label finish_store, check_capacity;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003649
3650 Register value_reg = a0;
3651 Register key_reg = a1;
3652 Register receiver_reg = a2;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003653 Register elements_reg = a3;
3654 Register scratch1 = t0;
3655 Register scratch2 = t1;
3656 Register scratch3 = t2;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003657 Register scratch4 = t3;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003658 Register scratch5 = t4;
yangguo@chromium.org56454712012-02-16 15:33:53 +00003659 Register length_reg = t3;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003660
3661 // This stub is meant to be tail-jumped to, the receiver must already
3662 // have been verified by the caller to not be a smi.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003663
3664 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003665 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003666
3667 __ lw(elements_reg,
3668 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3669
3670 // Check that the key is within bounds.
3671 if (is_js_array) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003672 __ lw(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003673 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003674 __ lw(scratch1,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003675 FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3676 }
3677 // Compare smis, unsigned compare catches both negative and out-of-bound
3678 // indexes.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003679 if (IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003680 __ Branch(&grow, hs, key_reg, Operand(scratch1));
3681 } else {
3682 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch1));
3683 }
3684
3685 __ bind(&finish_store);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003686
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003687 __ StoreNumberToDoubleElements(value_reg,
3688 key_reg,
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00003689 // All registers after this are overwritten.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003690 elements_reg,
3691 scratch1,
3692 scratch2,
3693 scratch3,
3694 scratch4,
3695 &transition_elements_kind);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003696
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003697 __ Ret(USE_DELAY_SLOT);
3698 __ mov(v0, value_reg); // In delay slot.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003699
3700 // Handle store cache miss, replacing the ic with the generic stub.
3701 __ bind(&miss_force_generic);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003702 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003703
3704 __ bind(&transition_elements_kind);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003705 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003706
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003707 if (is_js_array && IsGrowStoreMode(store_mode)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003708 // Grow the array by a single element if possible.
3709 __ bind(&grow);
3710
3711 // Make sure the array is only growing by a single element, anything else
3712 // must be handled by the runtime.
3713 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch1));
3714
3715 // Transition on values that can't be stored in a FixedDoubleArray.
3716 Label value_is_smi;
3717 __ JumpIfSmi(value_reg, &value_is_smi);
3718 __ lw(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
3719 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
3720 __ Branch(&transition_elements_kind, ne, scratch1, Operand(at));
3721 __ bind(&value_is_smi);
3722
3723 // Check for the empty array, and preallocate a small backing store if
3724 // possible.
3725 __ lw(length_reg,
3726 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3727 __ lw(elements_reg,
3728 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3729 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
3730 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
3731
3732 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003733 __ Allocate(size, elements_reg, scratch1, scratch2, &slow, TAG_OBJECT);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003734
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003735 // Initialize the new FixedDoubleArray.
yangguo@chromium.org56454712012-02-16 15:33:53 +00003736 __ LoadRoot(scratch1, Heap::kFixedDoubleArrayMapRootIndex);
3737 __ sw(scratch1, FieldMemOperand(elements_reg, JSObject::kMapOffset));
3738 __ li(scratch1, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
3739 __ sw(scratch1,
3740 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
3741
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003742 __ mov(scratch1, elements_reg);
3743 __ StoreNumberToDoubleElements(value_reg,
3744 key_reg,
3745 // All registers after this are overwritten.
3746 scratch1,
3747 scratch2,
3748 scratch3,
3749 scratch4,
3750 scratch5,
3751 &transition_elements_kind);
3752
3753 __ li(scratch1, Operand(kHoleNanLower32));
3754 __ li(scratch2, Operand(kHoleNanUpper32));
3755 for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) {
3756 int offset = FixedDoubleArray::OffsetOfElementAt(i);
3757 __ sw(scratch1, FieldMemOperand(elements_reg, offset));
3758 __ sw(scratch2, FieldMemOperand(elements_reg, offset + kPointerSize));
3759 }
3760
yangguo@chromium.org56454712012-02-16 15:33:53 +00003761 // Install the new backing store in the JSArray.
3762 __ sw(elements_reg,
3763 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3764 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
3765 scratch1, kRAHasNotBeenSaved, kDontSaveFPRegs,
3766 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3767
3768 // Increment the length of the array.
3769 __ li(length_reg, Operand(Smi::FromInt(1)));
3770 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
danno@chromium.org00379b82012-05-04 09:16:29 +00003771 __ lw(elements_reg,
3772 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003773 __ Ret();
yangguo@chromium.org56454712012-02-16 15:33:53 +00003774
3775 __ bind(&check_capacity);
3776 // Make sure that the backing store can hold additional elements.
3777 __ lw(scratch1,
3778 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
3779 __ Branch(&slow, hs, length_reg, Operand(scratch1));
3780
3781 // Grow the array and finish the store.
3782 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
3783 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3784 __ jmp(&finish_store);
3785
3786 __ bind(&slow);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003787 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003788 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003789}
3790
3791
ager@chromium.org5c838252010-02-19 08:53:10 +00003792#undef __
3793
3794} } // namespace v8::internal
3795
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003796#endif // V8_TARGET_ARCH_MIPS