blob: dd5681b3359073345d1dda0f2418d75fdce77a66 [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.
124// Name must be a symbol 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,
128 Handle<String> name,
129 Register scratch0,
130 Register scratch1) {
131 ASSERT(name->IsSymbol());
132 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
165 StringDictionaryLookupStub::GenerateNegativeLookup(masm,
166 miss_label,
167 &done,
168 receiver,
169 properties,
170 name,
171 scratch1);
172 __ 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.
220 __ lw(scratch, FieldMemOperand(name, String::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
ager@chromium.org5c838252010-02-19 08:53:10 +0000310// Load a fast property out of a holder object (src). In-object properties
311// are loaded directly otherwise the property is loaded from the properties
312// fixed array.
313void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000314 Register dst,
315 Register src,
316 Handle<JSObject> holder,
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +0000317 PropertyIndex index) {
318 if (index.is_header_index()) {
319 int offset = index.header_index() * kPointerSize;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000320 __ lw(dst, FieldMemOperand(src, offset));
321 } else {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +0000322 // Adjust for the number of properties stored in the holder.
323 int slot = index.field_index() - holder->map()->inobject_properties();
324 if (slot < 0) {
325 // Get the property straight out of the holder.
326 int offset = holder->map()->instance_size() + (slot * kPointerSize);
327 __ lw(dst, FieldMemOperand(src, offset));
328 } else {
329 // Calculate the offset into the properties array.
330 int offset = slot * kPointerSize + FixedArray::kHeaderSize;
331 __ lw(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
332 __ lw(dst, FieldMemOperand(dst, offset));
333 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000334 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000335}
336
337
338void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
339 Register receiver,
340 Register scratch,
341 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000342 // Check that the receiver isn't a smi.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000343 __ JumpIfSmi(receiver, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000344
345 // Check that the object is a JS array.
346 __ GetObjectType(receiver, scratch, scratch);
347 __ Branch(miss_label, ne, scratch, Operand(JS_ARRAY_TYPE));
348
349 // Load length directly from the JS array.
350 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
351 __ Ret();
352}
353
354
355// Generate code to check if an object is a string. If the object is a
356// heap object, its map's instance type is left in the scratch1 register.
357// If this is not needed, scratch1 and scratch2 may be the same register.
358static void GenerateStringCheck(MacroAssembler* masm,
359 Register receiver,
360 Register scratch1,
361 Register scratch2,
362 Label* smi,
363 Label* non_string_object) {
364 // Check that the receiver isn't a smi.
365 __ JumpIfSmi(receiver, smi, t0);
366
367 // Check that the object is a string.
368 __ lw(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
369 __ lbu(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
370 __ And(scratch2, scratch1, Operand(kIsNotStringMask));
371 // The cast is to resolve the overload for the argument of 0x0.
372 __ Branch(non_string_object,
373 ne,
374 scratch2,
375 Operand(static_cast<int32_t>(kStringTag)));
ager@chromium.org5c838252010-02-19 08:53:10 +0000376}
377
378
lrn@chromium.org7516f052011-03-30 08:52:27 +0000379// Generate code to load the length from a string object and return the length.
380// If the receiver object is not a string or a wrapped string object the
381// execution continues at the miss label. The register containing the
382// receiver is potentially clobbered.
383void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
384 Register receiver,
385 Register scratch1,
386 Register scratch2,
387 Label* miss,
388 bool support_wrappers) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000389 Label check_wrapper;
390
391 // Check if the object is a string leaving the instance type in the
392 // scratch1 register.
393 GenerateStringCheck(masm, receiver, scratch1, scratch2, miss,
394 support_wrappers ? &check_wrapper : miss);
395
396 // Load length directly from the string.
397 __ lw(v0, FieldMemOperand(receiver, String::kLengthOffset));
398 __ Ret();
399
400 if (support_wrappers) {
401 // Check if the object is a JSValue wrapper.
402 __ bind(&check_wrapper);
403 __ Branch(miss, ne, scratch1, Operand(JS_VALUE_TYPE));
404
405 // Unwrap the value and check if the wrapped value is a string.
406 __ lw(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
407 GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
408 __ lw(v0, FieldMemOperand(scratch1, String::kLengthOffset));
409 __ Ret();
410 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000411}
412
413
ager@chromium.org5c838252010-02-19 08:53:10 +0000414void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
415 Register receiver,
416 Register scratch1,
417 Register scratch2,
418 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000419 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
420 __ mov(v0, scratch1);
421 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000422}
423
424
lrn@chromium.org7516f052011-03-30 08:52:27 +0000425// Generate StoreField code, value is passed in a0 register.
ager@chromium.org5c838252010-02-19 08:53:10 +0000426// After executing generated code, the receiver_reg and name_reg
427// may be clobbered.
428void StubCompiler::GenerateStoreField(MacroAssembler* masm,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000429 Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +0000430 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000431 Handle<Map> transition,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000432 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +0000433 Register receiver_reg,
434 Register name_reg,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000435 Register scratch1,
436 Register scratch2,
ager@chromium.org5c838252010-02-19 08:53:10 +0000437 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000438 // a0 : value.
439 Label exit;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000440
441 LookupResult lookup(masm->isolate());
442 object->Lookup(*name, &lookup);
443 if (lookup.IsFound() && (lookup.IsReadOnly() || !lookup.IsCacheable())) {
444 // In sloppy mode, we could just return the value and be done. However, we
445 // might be in strict mode, where we have to throw. Since we cannot tell,
446 // go into slow case unconditionally.
447 __ jmp(miss_label);
448 return;
449 }
450
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000451 // Check that the map of the object hasn't changed.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000452 CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
453 : REQUIRE_EXACT_MAP;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000454 __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000455 DO_SMI_CHECK, mode);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000456
457 // Perform global security token check if needed.
458 if (object->IsJSGlobalProxy()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000459 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
460 }
461
462 // Check that we are allowed to write this.
463 if (!transition.is_null() && object->GetPrototype()->IsJSObject()) {
464 JSObject* holder;
465 if (lookup.IsFound()) {
466 holder = lookup.holder();
467 } else {
468 // Find the top object.
469 holder = *object;
470 do {
471 holder = JSObject::cast(holder->GetPrototype());
472 } while (holder->GetPrototype()->IsJSObject());
473 }
474 // We need an extra register, push
475 __ push(name_reg);
476 Label miss_pop, done_check;
477 CheckPrototypes(object, receiver_reg, Handle<JSObject>(holder), name_reg,
478 scratch1, scratch2, name, &miss_pop);
479 __ jmp(&done_check);
480 __ bind(&miss_pop);
481 __ pop(name_reg);
482 __ jmp(miss_label);
483 __ bind(&done_check);
484 __ pop(name_reg);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000485 }
486
487 // Stub never generated for non-global objects that require access
488 // checks.
489 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
490
491 // Perform map transition for the receiver if necessary.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000492 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000493 // The properties must be extended before we can store the value.
494 // We jump to a runtime call that extends the properties array.
495 __ push(receiver_reg);
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000496 __ li(a2, Operand(transition));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000497 __ Push(a2, a0);
498 __ TailCallExternalReference(
499 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
500 masm->isolate()),
501 3, 1);
502 return;
503 }
504
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000505 if (!transition.is_null()) {
verwaest@chromium.org37141392012-05-31 13:27:02 +0000506 // Update the map of the object.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000507 __ li(scratch1, Operand(transition));
508 __ sw(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
verwaest@chromium.org37141392012-05-31 13:27:02 +0000509
510 // Update the write barrier for the map field and pass the now unused
511 // name_reg as scratch register.
512 __ RecordWriteField(receiver_reg,
513 HeapObject::kMapOffset,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000514 scratch1,
verwaest@chromium.org37141392012-05-31 13:27:02 +0000515 name_reg,
516 kRAHasNotBeenSaved,
517 kDontSaveFPRegs,
518 OMIT_REMEMBERED_SET,
519 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000520 }
521
522 // Adjust for the number of properties stored in the object. Even in the
523 // face of a transition we can use the old map here because the size of the
524 // object and the number of in-object properties is not going to change.
525 index -= object->map()->inobject_properties();
526
527 if (index < 0) {
528 // Set the property straight into the object.
529 int offset = object->map()->instance_size() + (index * kPointerSize);
530 __ sw(a0, FieldMemOperand(receiver_reg, offset));
531
532 // Skip updating write barrier if storing a smi.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000533 __ JumpIfSmi(a0, &exit, scratch1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000534
535 // Update the write barrier for the array address.
536 // Pass the now unused name_reg as a scratch register.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000537 __ mov(name_reg, a0);
538 __ RecordWriteField(receiver_reg,
539 offset,
540 name_reg,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000541 scratch1,
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000542 kRAHasNotBeenSaved,
543 kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000544 } else {
545 // Write to the properties array.
546 int offset = index * kPointerSize + FixedArray::kHeaderSize;
547 // Get the properties array.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000548 __ lw(scratch1,
549 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
550 __ sw(a0, FieldMemOperand(scratch1, offset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000551
552 // Skip updating write barrier if storing a smi.
553 __ JumpIfSmi(a0, &exit);
554
555 // Update the write barrier for the array address.
556 // Ok to clobber receiver_reg and name_reg, since we return.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000557 __ mov(name_reg, a0);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000558 __ RecordWriteField(scratch1,
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000559 offset,
560 name_reg,
561 receiver_reg,
562 kRAHasNotBeenSaved,
563 kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000564 }
565
566 // Return the value (register v0).
567 __ bind(&exit);
568 __ mov(v0, a0);
569 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000570}
571
572
573void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000574 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000575 Handle<Code> code = (kind == Code::LOAD_IC)
576 ? masm->isolate()->builtins()->LoadIC_Miss()
577 : masm->isolate()->builtins()->KeyedLoadIC_Miss();
578 __ Jump(code, RelocInfo::CODE_TARGET);
ager@chromium.org5c838252010-02-19 08:53:10 +0000579}
580
581
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000582void StubCompiler::GenerateStoreMiss(MacroAssembler* masm, Code::Kind kind) {
583 ASSERT(kind == Code::STORE_IC || kind == Code::KEYED_STORE_IC);
584 Handle<Code> code = (kind == Code::STORE_IC)
585 ? masm->isolate()->builtins()->StoreIC_Miss()
586 : masm->isolate()->builtins()->KeyedStoreIC_Miss();
587 __ Jump(code, RelocInfo::CODE_TARGET);
588}
589
590
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000591static void GenerateCallFunction(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000592 Handle<Object> object,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000593 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000594 Label* miss,
595 Code::ExtraICState extra_ic_state) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000596 // ----------- S t a t e -------------
597 // -- a0: receiver
598 // -- a1: function to call
599 // -----------------------------------
600 // Check that the function really is a function.
601 __ JumpIfSmi(a1, miss);
602 __ GetObjectType(a1, a3, a3);
603 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
604
605 // Patch the receiver on the stack with the global proxy if
606 // necessary.
607 if (object->IsGlobalObject()) {
608 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
609 __ sw(a3, MemOperand(sp, arguments.immediate() * kPointerSize));
610 }
611
612 // Invoke the function.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000613 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
614 ? CALL_AS_FUNCTION
615 : CALL_AS_METHOD;
616 __ InvokeFunction(a1, arguments, JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000617}
618
619
620static void PushInterceptorArguments(MacroAssembler* masm,
621 Register receiver,
622 Register holder,
623 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000624 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000625 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000626 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
627 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000628 Register scratch = name;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000629 __ li(scratch, Operand(interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000630 __ Push(scratch, receiver, holder);
631 __ lw(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
632 __ push(scratch);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000633 __ li(scratch, Operand(ExternalReference::isolate_address()));
634 __ push(scratch);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000635}
636
637
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000638static void CompileCallLoadPropertyWithInterceptor(
639 MacroAssembler* masm,
640 Register receiver,
641 Register holder,
642 Register name,
643 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000644 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
645
646 ExternalReference ref =
647 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
648 masm->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000649 __ PrepareCEntryArgs(6);
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000650 __ PrepareCEntryFunction(ref);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000651
652 CEntryStub stub(1);
653 __ CallStub(&stub);
654}
655
656
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000657static const int kFastApiCallArguments = 4;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000658
659
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000660// Reserves space for the extra arguments to API function in the
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000661// caller's frame.
662//
663// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
664static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
665 Register scratch) {
666 ASSERT(Smi::FromInt(0) == 0);
667 for (int i = 0; i < kFastApiCallArguments; i++) {
668 __ push(zero_reg);
669 }
670}
671
672
673// Undoes the effects of ReserveSpaceForFastApiCall.
674static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
675 __ Drop(kFastApiCallArguments);
676}
677
678
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000679static void GenerateFastApiDirectCall(MacroAssembler* masm,
680 const CallOptimization& optimization,
681 int argc) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000682 // ----------- S t a t e -------------
683 // -- sp[0] : holder (set by CheckPrototypes)
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000684 // -- sp[4] : callee JS function
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000685 // -- sp[8] : call data
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000686 // -- sp[12] : isolate
687 // -- sp[16] : last JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000688 // -- ...
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000689 // -- sp[(argc + 3) * 4] : first JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000690 // -- sp[(argc + 4) * 4] : receiver
691 // -----------------------------------
692 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000693 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000694 __ LoadHeapObject(t1, function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000695 __ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset));
696
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000697 // Pass the additional arguments.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000698 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000699 Handle<Object> call_data(api_call_info->data(), masm->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000700 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
701 __ li(a0, api_call_info);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000702 __ lw(t2, FieldMemOperand(a0, CallHandlerInfo::kDataOffset));
703 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000704 __ li(t2, call_data);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000705 }
706
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000707 __ li(t3, Operand(ExternalReference::isolate_address()));
708 // Store JS function, call data and isolate.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000709 __ sw(t1, MemOperand(sp, 1 * kPointerSize));
710 __ sw(t2, MemOperand(sp, 2 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000711 __ sw(t3, MemOperand(sp, 3 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000712
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000713 // Prepare arguments.
714 __ Addu(a2, sp, Operand(3 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000715
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000716 // Allocate the v8::Arguments structure in the arguments' space since
717 // it's not controlled by GC.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000718 const int kApiStackSpace = 4;
719
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000720 FrameScope frame_scope(masm, StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000721 __ EnterExitFrame(false, kApiStackSpace);
722
723 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
724 // struct from the function (which is currently the case). This means we pass
725 // the first argument in a1 instead of a0. TryCallApiFunctionAndReturn
726 // will handle setting up a0.
727
728 // a1 = v8::Arguments&
729 // Arguments is built at sp + 1 (sp is a reserved spot for ra).
730 __ Addu(a1, sp, kPointerSize);
731
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000732 // v8::Arguments::implicit_args_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000733 __ sw(a2, MemOperand(a1, 0 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000734 // v8::Arguments::values_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000735 __ Addu(t0, a2, Operand(argc * kPointerSize));
736 __ sw(t0, MemOperand(a1, 1 * kPointerSize));
737 // v8::Arguments::length_ = argc
738 __ li(t0, Operand(argc));
739 __ sw(t0, MemOperand(a1, 2 * kPointerSize));
740 // v8::Arguments::is_construct_call = 0
741 __ sw(zero_reg, MemOperand(a1, 3 * kPointerSize));
742
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000743 const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000744 Address function_address = v8::ToCData<Address>(api_call_info->callback());
745 ApiFunction fun(function_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000746 ExternalReference ref =
747 ExternalReference(&fun,
748 ExternalReference::DIRECT_API_CALL,
749 masm->isolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000750 AllowExternalCallThatCantCauseGC scope(masm);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000751 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000752}
753
lrn@chromium.org7516f052011-03-30 08:52:27 +0000754class CallInterceptorCompiler BASE_EMBEDDED {
755 public:
756 CallInterceptorCompiler(StubCompiler* stub_compiler,
757 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000758 Register name,
759 Code::ExtraICState extra_ic_state)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000760 : stub_compiler_(stub_compiler),
761 arguments_(arguments),
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000762 name_(name),
763 extra_ic_state_(extra_ic_state) {}
lrn@chromium.org7516f052011-03-30 08:52:27 +0000764
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000765 void Compile(MacroAssembler* masm,
766 Handle<JSObject> object,
767 Handle<JSObject> holder,
768 Handle<String> name,
769 LookupResult* lookup,
770 Register receiver,
771 Register scratch1,
772 Register scratch2,
773 Register scratch3,
774 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000775 ASSERT(holder->HasNamedInterceptor());
776 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
777
778 // Check that the receiver isn't a smi.
779 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000780 CallOptimization optimization(lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000781 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000782 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
783 holder, lookup, name, optimization, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000784 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000785 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
786 name, holder, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000787 }
788 }
789
790 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000791 void CompileCacheable(MacroAssembler* masm,
792 Handle<JSObject> object,
793 Register receiver,
794 Register scratch1,
795 Register scratch2,
796 Register scratch3,
797 Handle<JSObject> interceptor_holder,
798 LookupResult* lookup,
799 Handle<String> name,
800 const CallOptimization& optimization,
801 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000802 ASSERT(optimization.is_constant_call());
803 ASSERT(!lookup->holder()->IsGlobalObject());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000804 Counters* counters = masm->isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000805 int depth1 = kInvalidProtoDepth;
806 int depth2 = kInvalidProtoDepth;
807 bool can_do_fast_api_call = false;
808 if (optimization.is_simple_api_call() &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000809 !lookup->holder()->IsGlobalObject()) {
810 depth1 = optimization.GetPrototypeDepthOfExpectedType(
811 object, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000812 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000813 depth2 = optimization.GetPrototypeDepthOfExpectedType(
814 interceptor_holder, Handle<JSObject>(lookup->holder()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000815 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000816 can_do_fast_api_call =
817 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000818 }
819
820 __ IncrementCounter(counters->call_const_interceptor(), 1,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000821 scratch1, scratch2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000822
823 if (can_do_fast_api_call) {
824 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
825 scratch1, scratch2);
826 ReserveSpaceForFastApiCall(masm, scratch1);
827 }
828
829 // Check that the maps from receiver to interceptor's holder
830 // haven't changed and thus we can invoke interceptor.
831 Label miss_cleanup;
832 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
833 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000834 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
835 scratch1, scratch2, scratch3,
836 name, depth1, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000837
838 // Invoke an interceptor and if it provides a value,
839 // branch to |regular_invoke|.
840 Label regular_invoke;
841 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
842 &regular_invoke);
843
844 // Interceptor returned nothing for this property. Try to use cached
845 // constant function.
846
847 // Check that the maps from interceptor's holder to constant function's
848 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000849 if (*interceptor_holder != lookup->holder()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000850 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000851 Handle<JSObject>(lookup->holder()),
852 scratch1, scratch2, scratch3,
853 name, depth2, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000854 } else {
855 // CheckPrototypes has a side effect of fetching a 'holder'
856 // for API (object which is instanceof for the signature). It's
857 // safe to omit it here, as if present, it should be fetched
858 // by the previous CheckPrototypes.
859 ASSERT(depth2 == kInvalidProtoDepth);
860 }
861
862 // Invoke function.
863 if (can_do_fast_api_call) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000864 GenerateFastApiDirectCall(masm, optimization, arguments_.immediate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000865 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000866 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
867 ? CALL_AS_FUNCTION
868 : CALL_AS_METHOD;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000869 __ InvokeFunction(optimization.constant_function(), arguments_,
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000870 JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000871 }
872
873 // Deferred code for fast API call case---clean preallocated space.
874 if (can_do_fast_api_call) {
875 __ bind(&miss_cleanup);
876 FreeSpaceForFastApiCall(masm);
877 __ Branch(miss_label);
878 }
879
880 // Invoke a regular function.
881 __ bind(&regular_invoke);
882 if (can_do_fast_api_call) {
883 FreeSpaceForFastApiCall(masm);
884 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000885 }
886
887 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000888 Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000889 Register receiver,
890 Register scratch1,
891 Register scratch2,
892 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000893 Handle<String> name,
894 Handle<JSObject> interceptor_holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000895 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000896 Register holder =
897 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000898 scratch1, scratch2, scratch3,
899 name, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000900
901 // Call a runtime function to load the interceptor property.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000902 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000903 // Save the name_ register across the call.
904 __ push(name_);
905
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000906 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000907
908 __ CallExternalReference(
909 ExternalReference(
910 IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
911 masm->isolate()),
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000912 6);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000913 // Restore the name_ register.
914 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000915 // Leave the internal frame.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000916 }
917
918 void LoadWithInterceptor(MacroAssembler* masm,
919 Register receiver,
920 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000921 Handle<JSObject> holder_obj,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000922 Register scratch,
923 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000924 {
925 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000926
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000927 __ Push(holder, name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000928 CompileCallLoadPropertyWithInterceptor(masm,
929 receiver,
930 holder,
931 name_,
932 holder_obj);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000933 __ pop(name_); // Restore the name.
934 __ pop(receiver); // Restore the holder.
935 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000936 // If interceptor returns no-result sentinel, call the constant function.
937 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
938 __ Branch(interceptor_succeeded, ne, v0, Operand(scratch));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000939 }
940
941 StubCompiler* stub_compiler_;
942 const ParameterCount& arguments_;
943 Register name_;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000944 Code::ExtraICState extra_ic_state_;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000945};
946
947
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000948
949// Generate code to check that a global property cell is empty. Create
950// the property cell at compilation time if no cell exists for the
951// property.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000952static void GenerateCheckPropertyCell(MacroAssembler* masm,
953 Handle<GlobalObject> global,
954 Handle<String> name,
955 Register scratch,
956 Label* miss) {
957 Handle<JSGlobalPropertyCell> cell =
958 GlobalObject::EnsurePropertyCell(global, name);
959 ASSERT(cell->value()->IsTheHole());
960 __ li(scratch, Operand(cell));
961 __ lw(scratch,
962 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
963 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
964 __ Branch(miss, ne, scratch, Operand(at));
965}
966
967
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000968// Calls GenerateCheckPropertyCell for each global object in the prototype chain
969// from object to (but not including) holder.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000970static void GenerateCheckPropertyCells(MacroAssembler* masm,
971 Handle<JSObject> object,
972 Handle<JSObject> holder,
973 Handle<String> name,
974 Register scratch,
975 Label* miss) {
976 Handle<JSObject> current = object;
977 while (!current.is_identical_to(holder)) {
978 if (current->IsGlobalObject()) {
979 GenerateCheckPropertyCell(masm,
980 Handle<GlobalObject>::cast(current),
981 name,
982 scratch,
983 miss);
984 }
985 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
986 }
987}
988
989
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000990// Convert and store int passed in register ival to IEEE 754 single precision
991// floating point value at memory location (dst + 4 * wordoffset)
992// If FPU is available use it for conversion.
993static void StoreIntAsFloat(MacroAssembler* masm,
994 Register dst,
995 Register wordoffset,
996 Register ival,
997 Register fval,
998 Register scratch1,
999 Register scratch2) {
1000 if (CpuFeatures::IsSupported(FPU)) {
1001 CpuFeatures::Scope scope(FPU);
1002 __ mtc1(ival, f0);
1003 __ cvt_s_w(f0, f0);
1004 __ sll(scratch1, wordoffset, 2);
1005 __ addu(scratch1, dst, scratch1);
1006 __ swc1(f0, MemOperand(scratch1, 0));
1007 } else {
1008 // FPU is not available, do manual conversions.
1009
1010 Label not_special, done;
1011 // Move sign bit from source to destination. This works because the sign
1012 // bit in the exponent word of the double has the same position and polarity
1013 // as the 2's complement sign bit in a Smi.
1014 ASSERT(kBinary32SignMask == 0x80000000u);
1015
1016 __ And(fval, ival, Operand(kBinary32SignMask));
1017 // Negate value if it is negative.
1018 __ subu(scratch1, zero_reg, ival);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001019 __ Movn(ival, scratch1, fval);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001020
1021 // We have -1, 0 or 1, which we treat specially. Register ival contains
1022 // absolute value: it is either equal to 1 (special case of -1 and 1),
1023 // greater than 1 (not a special case) or less than 1 (special case of 0).
1024 __ Branch(&not_special, gt, ival, Operand(1));
1025
1026 // For 1 or -1 we need to or in the 0 exponent (biased).
1027 static const uint32_t exponent_word_for_1 =
1028 kBinary32ExponentBias << kBinary32ExponentShift;
1029
1030 __ Xor(scratch1, ival, Operand(1));
1031 __ li(scratch2, exponent_word_for_1);
1032 __ or_(scratch2, fval, scratch2);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001033 __ Movz(fval, scratch2, scratch1); // Only if ival is equal to 1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001034 __ Branch(&done);
1035
1036 __ bind(&not_special);
1037 // Count leading zeros.
1038 // Gets the wrong answer for 0, but we already checked for that case above.
1039 Register zeros = scratch2;
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001040 __ Clz(zeros, ival);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001041
1042 // Compute exponent and or it into the exponent register.
1043 __ li(scratch1, (kBitsPerInt - 1) + kBinary32ExponentBias);
1044 __ subu(scratch1, scratch1, zeros);
1045
1046 __ sll(scratch1, scratch1, kBinary32ExponentShift);
1047 __ or_(fval, fval, scratch1);
1048
1049 // Shift up the source chopping the top bit off.
1050 __ Addu(zeros, zeros, Operand(1));
1051 // This wouldn't work for 1 and -1 as the shift would be 32 which means 0.
1052 __ sllv(ival, ival, zeros);
1053 // And the top (top 20 bits).
1054 __ srl(scratch1, ival, kBitsPerInt - kBinary32MantissaBits);
1055 __ or_(fval, fval, scratch1);
1056
1057 __ bind(&done);
1058
1059 __ sll(scratch1, wordoffset, 2);
1060 __ addu(scratch1, dst, scratch1);
1061 __ sw(fval, MemOperand(scratch1, 0));
1062 }
1063}
1064
1065
ager@chromium.org5c838252010-02-19 08:53:10 +00001066#undef __
1067#define __ ACCESS_MASM(masm())
1068
1069
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001070Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
1071 Register object_reg,
1072 Handle<JSObject> holder,
1073 Register holder_reg,
1074 Register scratch1,
1075 Register scratch2,
1076 Handle<String> name,
1077 int save_at_depth,
1078 Label* miss) {
1079 // Make sure there's no overlap between holder and object registers.
1080 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1081 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1082 && !scratch2.is(scratch1));
1083
1084 // Keep track of the current object in register reg.
1085 Register reg = object_reg;
1086 int depth = 0;
1087
1088 if (save_at_depth == depth) {
1089 __ sw(reg, MemOperand(sp));
1090 }
1091
1092 // Check the maps in the prototype chain.
1093 // Traverse the prototype chain from the object and do map checks.
1094 Handle<JSObject> current = object;
1095 while (!current.is_identical_to(holder)) {
1096 ++depth;
1097
1098 // Only global objects and objects that do not require access
1099 // checks are allowed in stubs.
1100 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1101
1102 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
1103 if (!current->HasFastProperties() &&
1104 !current->IsJSGlobalObject() &&
1105 !current->IsJSGlobalProxy()) {
1106 if (!name->IsSymbol()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001107 name = factory()->InternalizeString(name);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001108 }
1109 ASSERT(current->property_dictionary()->FindEntry(*name) ==
1110 StringDictionary::kNotFound);
1111
1112 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1113 scratch1, scratch2);
1114
1115 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1116 reg = holder_reg; // From now on the object will be in holder_reg.
1117 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1118 } else {
1119 Handle<Map> current_map(current->map());
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001120 __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK,
1121 ALLOW_ELEMENT_TRANSITION_MAPS);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001122 // Check access rights to the global object. This has to happen after
1123 // the map check so that we know that the object is actually a global
1124 // object.
1125 if (current->IsJSGlobalProxy()) {
1126 __ CheckAccessGlobalProxy(reg, scratch2, miss);
1127 }
1128 reg = holder_reg; // From now on the object will be in holder_reg.
1129
1130 if (heap()->InNewSpace(*prototype)) {
1131 // The prototype is in new space; we cannot store a reference to it
1132 // in the code. Load it from the map.
1133 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1134 } else {
1135 // The prototype is in old space; load it directly.
1136 __ li(reg, Operand(prototype));
1137 }
1138 }
1139
1140 if (save_at_depth == depth) {
1141 __ sw(reg, MemOperand(sp));
1142 }
1143
1144 // Go to the next object in the prototype chain.
1145 current = prototype;
1146 }
1147
1148 // Log the check depth.
1149 LOG(masm()->isolate(), IntEvent("check-maps-depth", depth + 1));
1150
1151 // Check the holder map.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001152 __ CheckMap(reg, scratch1, Handle<Map>(current->map()), miss,
1153 DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001154
1155 // Perform security check for access to the global object.
1156 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1157 if (holder->IsJSGlobalProxy()) {
1158 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1159 }
1160
1161 // If we've skipped any global objects, it's not enough to verify that
1162 // their maps haven't changed. We also need to check that the property
1163 // cell for the property is still empty.
1164 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1165
1166 // Return the register containing the holder.
1167 return reg;
1168}
1169
1170
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001171void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success,
1172 Label* miss) {
1173 __ Branch(success);
1174 __ bind(miss);
1175 GenerateLoadMiss(masm(), kind());
1176}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001177
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001178
1179Register BaseLoadStubCompiler::CallbackHandlerFrontend(
1180 Handle<JSObject> object,
1181 Register object_reg,
1182 Handle<JSObject> holder,
1183 Handle<String> name,
1184 Label* success,
1185 FrontendCheckType check,
1186 Handle<ExecutableAccessorInfo> callback) {
1187 Label miss;
1188
1189 Register reg = HandlerFrontendHeader(
1190 object, object_reg, holder, name, &miss, check);
1191
1192 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
1193 ASSERT(!reg.is(scratch2()));
1194 ASSERT(!reg.is(scratch3()));
1195 ASSERT(!reg.is(scratch4()));
1196
1197 // Load the properties dictionary.
1198 Register dictionary = scratch4();
1199 __ lw(dictionary, FieldMemOperand(reg, JSObject::kPropertiesOffset));
1200
1201 // Probe the dictionary.
1202 Label probe_done;
1203 StringDictionaryLookupStub::GeneratePositiveLookup(masm(),
1204 &miss,
1205 &probe_done,
1206 dictionary,
1207 this->name(),
1208 scratch2(),
1209 scratch3());
1210 __ bind(&probe_done);
1211
1212 // If probing finds an entry in the dictionary, scratch3 contains the
1213 // pointer into the dictionary. Check that the value is the callback.
1214 Register pointer = scratch3();
1215 const int kElementsStartOffset = StringDictionary::kHeaderSize +
1216 StringDictionary::kElementsStartIndex * kPointerSize;
1217 const int kValueOffset = kElementsStartOffset + kPointerSize;
1218 __ lw(scratch2(), FieldMemOperand(pointer, kValueOffset));
1219 __ Branch(&miss, ne, scratch2(), Operand(callback));
1220 }
1221
1222 HandlerFrontendFooter(success, &miss);
1223 return reg;
1224}
1225
1226
1227void BaseLoadStubCompiler::NonexistentHandlerFrontend(
1228 Handle<JSObject> object,
1229 Handle<JSObject> last,
1230 Handle<String> name,
1231 Label* success,
1232 Handle<GlobalObject> global) {
1233 Label miss;
1234
1235 Register reg = HandlerFrontendHeader(
1236 object, receiver(), last, name, &miss, PERFORM_INITIAL_CHECKS);
1237
1238 // If the last object in the prototype chain is a global object,
1239 // check that the global property cell is empty.
1240 if (!global.is_null()) {
1241 GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
1242 }
1243
1244 if (!last->HasFastProperties()) {
1245 __ lw(scratch2(), FieldMemOperand(reg, HeapObject::kMapOffset));
1246 __ lw(scratch2(), FieldMemOperand(scratch2(), Map::kPrototypeOffset));
1247 __ Branch(&miss, ne, scratch2(),
1248 Operand(isolate()->factory()->null_value()));
1249 }
1250
1251 HandlerFrontendFooter(success, &miss);
1252}
1253
1254
1255void BaseLoadStubCompiler::GenerateLoadField(Register reg,
1256 Handle<JSObject> holder,
1257 PropertyIndex index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001258 GenerateFastPropertyLoad(masm(), v0, reg, holder, index);
1259 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001260}
1261
1262
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001263void BaseLoadStubCompiler::GenerateLoadConstant(Handle<JSFunction> value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001264 // Return the constant value.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001265 __ LoadHeapObject(v0, value);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001266 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001267}
1268
1269
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001270void BaseLoadStubCompiler::GenerateLoadCallback(
1271 Register reg,
1272 Handle<ExecutableAccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001273 // Build AccessorInfo::args_ list on the stack and push property name below
1274 // the exit frame to make GC aware of them and store pointers to them.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001275 __ push(receiver());
1276 __ mov(scratch2(), sp); // scratch2 = AccessorInfo::args_
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001277 if (heap()->InNewSpace(callback->data())) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001278 __ li(scratch3(), callback);
1279 __ lw(scratch3(), FieldMemOperand(scratch3(),
1280 ExecutableAccessorInfo::kDataOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001281 } else {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001282 __ li(scratch3(), Handle<Object>(callback->data(),
1283 callback->GetIsolate()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001284 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001285 __ Subu(sp, sp, 4 * kPointerSize);
1286 __ sw(reg, MemOperand(sp, 3 * kPointerSize));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001287 __ sw(scratch3(), MemOperand(sp, 2 * kPointerSize));
1288 __ li(scratch3(), Operand(ExternalReference::isolate_address()));
1289 __ sw(scratch3(), MemOperand(sp, 1 * kPointerSize));
1290 __ sw(name(), MemOperand(sp, 0 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001291
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001292 __ mov(a2, scratch2()); // Saved in case scratch2 == a1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001293 __ mov(a1, sp); // a1 (first argument - see note below) = Handle<String>
1294
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001295 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
1296 // struct from the function (which is currently the case). This means we pass
1297 // the arguments in a1-a2 instead of a0-a1. TryCallApiFunctionAndReturn
1298 // will handle setting up a0.
1299
1300 const int kApiStackSpace = 1;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001301 FrameScope frame_scope(masm(), StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001302 __ EnterExitFrame(false, kApiStackSpace);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001303
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001304 // Create AccessorInfo instance on the stack above the exit frame with
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001305 // scratch2 (internal::Object** args_) as the data.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001306 __ sw(a2, MemOperand(sp, kPointerSize));
1307 // a2 (second argument - see note above) = AccessorInfo&
1308 __ Addu(a2, sp, kPointerSize);
1309
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001310 const int kStackUnwindSpace = 5;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001311 Address getter_address = v8::ToCData<Address>(callback->getter());
1312 ApiFunction fun(getter_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001313 ExternalReference ref =
1314 ExternalReference(&fun,
1315 ExternalReference::DIRECT_GETTER_CALL,
1316 masm()->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001317 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
ager@chromium.org5c838252010-02-19 08:53:10 +00001318}
1319
1320
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001321void BaseLoadStubCompiler::GenerateLoadInterceptor(
1322 Register holder_reg,
1323 Handle<JSObject> object,
1324 Handle<JSObject> interceptor_holder,
1325 LookupResult* lookup,
1326 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001327 ASSERT(interceptor_holder->HasNamedInterceptor());
1328 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1329
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001330 // So far the most popular follow ups for interceptor loads are FIELD
1331 // and CALLBACKS, so inline only them, other cases may be added
1332 // later.
1333 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001334 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001335 if (lookup->IsField()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001336 compile_followup_inline = true;
1337 } else if (lookup->type() == CALLBACKS &&
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001338 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
1339 ExecutableAccessorInfo* callback =
1340 ExecutableAccessorInfo::cast(lookup->GetCallbackObject());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001341 compile_followup_inline = callback->getter() != NULL &&
1342 callback->IsCompatibleReceiver(*object);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001343 }
1344 }
1345
1346 if (compile_followup_inline) {
1347 // Compile the interceptor call, followed by inline code to load the
1348 // property from further up the prototype chain if the call fails.
1349 // Check that the maps haven't changed.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001350 ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001351
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001352 // Preserve the receiver register explicitly whenever it is different from
1353 // the holder and it is needed should the interceptor return without any
1354 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1355 // the FIELD case might cause a miss during the prototype check.
1356 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001357 bool must_preserve_receiver_reg = !receiver().is(holder_reg) &&
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001358 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1359
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001360 // Save necessary data before invoking an interceptor.
1361 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001362 {
1363 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001364 if (must_preserve_receiver_reg) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001365 __ Push(receiver(), holder_reg, this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001366 } else {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001367 __ Push(holder_reg, this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001368 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001369 // Invoke an interceptor. Note: map checks from receiver to
1370 // interceptor's holder has been compiled before (see a caller
1371 // of this method).
1372 CompileCallLoadPropertyWithInterceptor(masm(),
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001373 receiver(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001374 holder_reg,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001375 this->name(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001376 interceptor_holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001377 // Check if interceptor provided a value for property. If it's
1378 // the case, return immediately.
1379 Label interceptor_failed;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001380 __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
1381 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001382 frame_scope.GenerateLeaveFrame();
1383 __ Ret();
1384
1385 __ bind(&interceptor_failed);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001386 __ pop(this->name());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001387 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001388 if (must_preserve_receiver_reg) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001389 __ pop(receiver());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001390 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001391 // Leave the internal frame.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001392 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001393 GenerateLoadPostInterceptor(holder_reg, interceptor_holder, name, lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001394 } else { // !compile_followup_inline
1395 // Call the runtime system to load the interceptor.
1396 // Check that the maps haven't changed.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001397 PushInterceptorArguments(masm(), receiver(), holder_reg,
1398 this->name(), interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001399
1400 ExternalReference ref = ExternalReference(
1401 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), masm()->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001402 __ TailCallExternalReference(ref, 6, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001403 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001404}
1405
1406
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001407void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001408 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001409 __ Branch(miss, ne, a2, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001410 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001411}
1412
1413
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001414void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1415 Handle<JSObject> holder,
1416 Handle<String> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001417 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001418 ASSERT(holder->IsGlobalObject());
1419
1420 // Get the number of arguments.
1421 const int argc = arguments().immediate();
1422
1423 // Get the receiver from the stack.
1424 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1425
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001426 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001427 __ JumpIfSmi(a0, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001428 CheckPrototypes(object, a0, holder, a3, a1, t0, name, miss);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001429}
1430
1431
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001432void CallStubCompiler::GenerateLoadFunctionFromCell(
1433 Handle<JSGlobalPropertyCell> cell,
1434 Handle<JSFunction> function,
1435 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001436 // Get the value from the cell.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001437 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001438 __ lw(a1, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
1439
1440 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001441 if (heap()->InNewSpace(*function)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001442 // We can't embed a pointer to a function in new space so we have
1443 // to verify that the shared function info is unchanged. This has
1444 // the nice side effect that multiple closures based on the same
1445 // function can all use this call IC. Before we load through the
1446 // function, we have to verify that it still is a function.
1447 __ JumpIfSmi(a1, miss);
1448 __ GetObjectType(a1, a3, a3);
1449 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
1450
1451 // Check the shared function info. Make sure it hasn't changed.
1452 __ li(a3, Handle<SharedFunctionInfo>(function->shared()));
1453 __ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
1454 __ Branch(miss, ne, t0, Operand(a3));
1455 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001456 __ Branch(miss, ne, a1, Operand(function));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001457 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001458}
1459
1460
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001461void CallStubCompiler::GenerateMissBranch() {
1462 Handle<Code> code =
danno@chromium.org40cb8782011-05-25 07:58:50 +00001463 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1464 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001465 extra_state_);
1466 __ Jump(code, RelocInfo::CODE_TARGET);
1467}
1468
1469
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001470Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1471 Handle<JSObject> holder,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001472 PropertyIndex index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001473 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001474 // ----------- S t a t e -------------
1475 // -- a2 : name
1476 // -- ra : return address
1477 // -----------------------------------
1478 Label miss;
1479
1480 GenerateNameCheck(name, &miss);
1481
1482 const int argc = arguments().immediate();
1483
1484 // Get the receiver of the function from the stack into a0.
1485 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1486 // Check that the receiver isn't a smi.
1487 __ JumpIfSmi(a0, &miss, t0);
1488
1489 // Do the right check and compute the holder register.
1490 Register reg = CheckPrototypes(object, a0, holder, a1, a3, t0, name, &miss);
1491 GenerateFastPropertyLoad(masm(), a1, reg, holder, index);
1492
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001493 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001494
1495 // Handle call cache miss.
1496 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001497 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001498
1499 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001500 return GetCode(Code::FIELD, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001501}
1502
1503
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001504Handle<Code> CallStubCompiler::CompileArrayPushCall(
1505 Handle<Object> object,
1506 Handle<JSObject> holder,
1507 Handle<JSGlobalPropertyCell> cell,
1508 Handle<JSFunction> function,
1509 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001510 // ----------- S t a t e -------------
1511 // -- a2 : name
1512 // -- ra : return address
1513 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1514 // -- ...
1515 // -- sp[argc * 4] : receiver
1516 // -----------------------------------
1517
1518 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001519 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001520
1521 Label miss;
1522
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001523 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001524
1525 Register receiver = a1;
1526
1527 // Get the receiver from the stack.
1528 const int argc = arguments().immediate();
1529 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1530
1531 // Check that the receiver isn't a smi.
1532 __ JumpIfSmi(receiver, &miss);
1533
1534 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001535 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, a3, v0, t0,
1536 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001537
1538 if (argc == 0) {
1539 // Nothing to do, just return the length.
1540 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1541 __ Drop(argc + 1);
1542 __ Ret();
1543 } else {
1544 Label call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001545 if (argc == 1) { // Otherwise fall through to call the builtin.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001546 Label attempt_to_grow_elements, with_write_barrier, check_double;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001547
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001548 Register elements = t2;
1549 Register end_elements = t1;
1550 // Get the elements array of the object.
1551 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1552
1553 // Check that the elements are in fast mode and writable.
1554 __ CheckMap(elements,
1555 v0,
1556 Heap::kFixedArrayMapRootIndex,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001557 &check_double,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001558 DONT_DO_SMI_CHECK);
1559
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001560 // Get the array's length into v0 and calculate new length.
1561 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1562 STATIC_ASSERT(kSmiTagSize == 1);
1563 STATIC_ASSERT(kSmiTag == 0);
1564 __ Addu(v0, v0, Operand(Smi::FromInt(argc)));
1565
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001566 // Get the elements' length.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001567 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1568
1569 // Check if we could survive without allocation.
1570 __ Branch(&attempt_to_grow_elements, gt, v0, Operand(t0));
1571
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001572 // Check if value is a smi.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001573 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1574 __ JumpIfNotSmi(t0, &with_write_barrier);
1575
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001576 // Save new length.
1577 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1578
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001579 // Store the value.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001580 // We may need a register containing the address end_elements below,
1581 // so write back the value in end_elements.
1582 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1583 __ Addu(end_elements, elements, end_elements);
1584 const int kEndElementsOffset =
1585 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001586 __ Addu(end_elements, end_elements, kEndElementsOffset);
1587 __ sw(t0, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001588
1589 // Check for a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001590 __ Drop(argc + 1);
1591 __ Ret();
1592
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001593 __ bind(&check_double);
1594
1595 // Check that the elements are in fast mode and writable.
1596 __ CheckMap(elements,
1597 a0,
1598 Heap::kFixedDoubleArrayMapRootIndex,
1599 &call_builtin,
1600 DONT_DO_SMI_CHECK);
1601
1602 // Get the array's length into r0 and calculate new length.
1603 __ lw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1604 STATIC_ASSERT(kSmiTagSize == 1);
1605 STATIC_ASSERT(kSmiTag == 0);
1606 __ Addu(a0, a0, Operand(Smi::FromInt(argc)));
1607
1608 // Get the elements' length.
1609 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1610
1611 // Check if we could survive without allocation.
1612 __ Branch(&call_builtin, gt, a0, Operand(t0));
1613
1614 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1615 __ StoreNumberToDoubleElements(
1616 t0, a0, elements, a3, t1, a2, t5,
1617 &call_builtin, argc * kDoubleSize);
1618
1619 // Save new length.
1620 __ sw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1621
1622 // Check for a smi.
1623 __ Drop(argc + 1);
1624 __ Ret();
1625
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001626 __ bind(&with_write_barrier);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001627
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001628 __ lw(a3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1629
1630 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
1631 Label fast_object, not_fast_object;
1632 __ CheckFastObjectElements(a3, t3, &not_fast_object);
1633 __ jmp(&fast_object);
1634 // In case of fast smi-only, convert to fast object, otherwise bail out.
1635 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001636 __ CheckFastSmiElements(a3, t3, &call_builtin);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001637
1638 __ lw(t3, FieldMemOperand(t0, HeapObject::kMapOffset));
1639 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
1640 __ Branch(&call_builtin, eq, t3, Operand(at));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001641 // edx: receiver
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001642 // a3: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001643 Label try_holey_map;
1644 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001645 FAST_ELEMENTS,
1646 a3,
1647 t3,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001648 &try_holey_map);
1649 __ mov(a2, receiver);
1650 ElementsTransitionGenerator::
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001651 GenerateMapChangeElementsTransition(masm(),
1652 DONT_TRACK_ALLOCATION_SITE,
1653 NULL);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001654 __ jmp(&fast_object);
1655
1656 __ bind(&try_holey_map);
1657 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1658 FAST_HOLEY_ELEMENTS,
1659 a3,
1660 t3,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001661 &call_builtin);
1662 __ mov(a2, receiver);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001663 ElementsTransitionGenerator::
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001664 GenerateMapChangeElementsTransition(masm(),
1665 DONT_TRACK_ALLOCATION_SITE,
1666 NULL);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001667 __ bind(&fast_object);
1668 } else {
1669 __ CheckFastObjectElements(a3, a3, &call_builtin);
1670 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001671
1672 // Save new length.
1673 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1674
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001675 // Store the value.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001676 // We may need a register containing the address end_elements below,
1677 // so write back the value in end_elements.
1678 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1679 __ Addu(end_elements, elements, end_elements);
1680 __ Addu(end_elements, end_elements, kEndElementsOffset);
1681 __ sw(t0, MemOperand(end_elements));
1682
1683 __ RecordWrite(elements,
1684 end_elements,
1685 t0,
1686 kRAHasNotBeenSaved,
1687 kDontSaveFPRegs,
1688 EMIT_REMEMBERED_SET,
1689 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001690 __ Drop(argc + 1);
1691 __ Ret();
1692
1693 __ bind(&attempt_to_grow_elements);
1694 // v0: array's length + 1.
1695 // t0: elements' length.
1696
1697 if (!FLAG_inline_new) {
1698 __ Branch(&call_builtin);
1699 }
1700
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001701 __ lw(a2, MemOperand(sp, (argc - 1) * kPointerSize));
1702 // Growing elements that are SMI-only requires special handling in case
1703 // the new element is non-Smi. For now, delegate to the builtin.
1704 Label no_fast_elements_check;
1705 __ JumpIfSmi(a2, &no_fast_elements_check);
1706 __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1707 __ CheckFastObjectElements(t3, t3, &call_builtin);
1708 __ bind(&no_fast_elements_check);
1709
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001710 ExternalReference new_space_allocation_top =
1711 ExternalReference::new_space_allocation_top_address(
1712 masm()->isolate());
1713 ExternalReference new_space_allocation_limit =
1714 ExternalReference::new_space_allocation_limit_address(
1715 masm()->isolate());
1716
1717 const int kAllocationDelta = 4;
1718 // Load top and check if it is the end of elements.
1719 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1720 __ Addu(end_elements, elements, end_elements);
1721 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset));
1722 __ li(t3, Operand(new_space_allocation_top));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001723 __ lw(a3, MemOperand(t3));
1724 __ Branch(&call_builtin, ne, end_elements, Operand(a3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001725
1726 __ li(t5, Operand(new_space_allocation_limit));
1727 __ lw(t5, MemOperand(t5));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001728 __ Addu(a3, a3, Operand(kAllocationDelta * kPointerSize));
1729 __ Branch(&call_builtin, hi, a3, Operand(t5));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001730
1731 // We fit and could grow elements.
1732 // Update new_space_allocation_top.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001733 __ sw(a3, MemOperand(t3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001734 // Push the argument.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001735 __ sw(a2, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001736 // Fill the rest with holes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001737 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001738 for (int i = 1; i < kAllocationDelta; i++) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001739 __ sw(a3, MemOperand(end_elements, i * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001740 }
1741
1742 // Update elements' and array's sizes.
1743 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1744 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta)));
1745 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1746
1747 // Elements are in new space, so write barrier is not required.
1748 __ Drop(argc + 1);
1749 __ Ret();
1750 }
1751 __ bind(&call_builtin);
1752 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
1753 masm()->isolate()),
1754 argc + 1,
1755 1);
1756 }
1757
1758 // Handle call cache miss.
1759 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001760 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001761
1762 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001763 return GetCode(function);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001764}
1765
1766
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001767Handle<Code> CallStubCompiler::CompileArrayPopCall(
1768 Handle<Object> object,
1769 Handle<JSObject> holder,
1770 Handle<JSGlobalPropertyCell> cell,
1771 Handle<JSFunction> function,
1772 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001773 // ----------- S t a t e -------------
1774 // -- a2 : name
1775 // -- ra : return address
1776 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1777 // -- ...
1778 // -- sp[argc * 4] : receiver
1779 // -----------------------------------
1780
1781 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001782 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001783
1784 Label miss, return_undefined, call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001785 Register receiver = a1;
1786 Register elements = a3;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001787 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001788
1789 // Get the receiver from the stack.
1790 const int argc = arguments().immediate();
1791 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001792 // Check that the receiver isn't a smi.
1793 __ JumpIfSmi(receiver, &miss);
1794
1795 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001796 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, elements,
1797 t0, v0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001798
1799 // Get the elements array of the object.
1800 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1801
1802 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001803 __ CheckMap(elements,
1804 v0,
1805 Heap::kFixedArrayMapRootIndex,
1806 &call_builtin,
1807 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001808
1809 // Get the array's length into t0 and calculate new length.
1810 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1811 __ Subu(t0, t0, Operand(Smi::FromInt(1)));
1812 __ Branch(&return_undefined, lt, t0, Operand(zero_reg));
1813
1814 // Get the last element.
1815 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1816 STATIC_ASSERT(kSmiTagSize == 1);
1817 STATIC_ASSERT(kSmiTag == 0);
1818 // We can't address the last element in one operation. Compute the more
1819 // expensive shift first, and use an offset later on.
1820 __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize);
1821 __ Addu(elements, elements, t1);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001822 __ lw(v0, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001823 __ Branch(&call_builtin, eq, v0, Operand(t2));
1824
1825 // Set the array's length.
1826 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1827
1828 // Fill with the hole.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001829 __ sw(t2, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001830 __ Drop(argc + 1);
1831 __ Ret();
1832
1833 __ bind(&return_undefined);
1834 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
1835 __ Drop(argc + 1);
1836 __ Ret();
1837
1838 __ bind(&call_builtin);
1839 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop,
1840 masm()->isolate()),
1841 argc + 1,
1842 1);
1843
1844 // Handle call cache miss.
1845 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001846 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001847
1848 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001849 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001850}
1851
1852
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001853Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1854 Handle<Object> object,
1855 Handle<JSObject> holder,
1856 Handle<JSGlobalPropertyCell> cell,
1857 Handle<JSFunction> function,
1858 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001859 // ----------- S t a t e -------------
1860 // -- a2 : function name
1861 // -- ra : return address
1862 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1863 // -- ...
1864 // -- sp[argc * 4] : receiver
1865 // -----------------------------------
1866
1867 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001868 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001869
1870 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001871 Label miss;
1872 Label name_miss;
1873 Label index_out_of_range;
1874
1875 Label* index_out_of_range_label = &index_out_of_range;
1876
danno@chromium.org40cb8782011-05-25 07:58:50 +00001877 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001878 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001879 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001880 index_out_of_range_label = &miss;
1881 }
1882
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001883 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001884
1885 // Check that the maps starting from the prototype haven't changed.
1886 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1887 Context::STRING_FUNCTION_INDEX,
1888 v0,
1889 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001890 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001891 CheckPrototypes(
1892 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
1893 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001894
1895 Register receiver = a1;
1896 Register index = t1;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001897 Register result = v0;
1898 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1899 if (argc > 0) {
1900 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1901 } else {
1902 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1903 }
1904
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001905 StringCharCodeAtGenerator generator(receiver,
1906 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001907 result,
1908 &miss, // When not a string.
1909 &miss, // When not a number.
1910 index_out_of_range_label,
1911 STRING_INDEX_IS_NUMBER);
1912 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001913 __ Drop(argc + 1);
1914 __ Ret();
1915
1916 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001917 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001918
1919 if (index_out_of_range.is_linked()) {
1920 __ bind(&index_out_of_range);
1921 __ LoadRoot(v0, Heap::kNanValueRootIndex);
1922 __ Drop(argc + 1);
1923 __ Ret();
1924 }
1925
1926 __ bind(&miss);
1927 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001928 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001929 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001930 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001931
1932 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001933 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001934}
1935
1936
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001937Handle<Code> CallStubCompiler::CompileStringCharAtCall(
1938 Handle<Object> object,
1939 Handle<JSObject> holder,
1940 Handle<JSGlobalPropertyCell> cell,
1941 Handle<JSFunction> function,
1942 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001943 // ----------- S t a t e -------------
1944 // -- a2 : function name
1945 // -- ra : return address
1946 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1947 // -- ...
1948 // -- sp[argc * 4] : receiver
1949 // -----------------------------------
1950
1951 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001952 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001953
1954 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001955 Label miss;
1956 Label name_miss;
1957 Label index_out_of_range;
1958 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00001959 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001960 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001961 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001962 index_out_of_range_label = &miss;
1963 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001964 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001965
1966 // Check that the maps starting from the prototype haven't changed.
1967 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1968 Context::STRING_FUNCTION_INDEX,
1969 v0,
1970 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001971 ASSERT(!object.is_identical_to(holder));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001972 CheckPrototypes(
1973 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
1974 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001975
1976 Register receiver = v0;
1977 Register index = t1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001978 Register scratch = a3;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001979 Register result = v0;
1980 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1981 if (argc > 0) {
1982 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1983 } else {
1984 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1985 }
1986
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001987 StringCharAtGenerator generator(receiver,
1988 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00001989 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001990 result,
1991 &miss, // When not a string.
1992 &miss, // When not a number.
1993 index_out_of_range_label,
1994 STRING_INDEX_IS_NUMBER);
1995 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001996 __ Drop(argc + 1);
1997 __ Ret();
1998
1999 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002000 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002001
2002 if (index_out_of_range.is_linked()) {
2003 __ bind(&index_out_of_range);
2004 __ LoadRoot(v0, Heap::kEmptyStringRootIndex);
2005 __ Drop(argc + 1);
2006 __ Ret();
2007 }
2008
2009 __ bind(&miss);
2010 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002011 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002012 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002013 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002014
2015 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002016 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002017}
2018
2019
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002020Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
2021 Handle<Object> object,
2022 Handle<JSObject> holder,
2023 Handle<JSGlobalPropertyCell> cell,
2024 Handle<JSFunction> function,
2025 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002026 // ----------- S t a t e -------------
2027 // -- a2 : function name
2028 // -- ra : return address
2029 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2030 // -- ...
2031 // -- sp[argc * 4] : receiver
2032 // -----------------------------------
2033
2034 const int argc = arguments().immediate();
2035
2036 // If the object is not a JSObject or we got an unexpected number of
2037 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002038 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002039
2040 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002041 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002042
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002043 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002044 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
2045
2046 STATIC_ASSERT(kSmiTag == 0);
2047 __ JumpIfSmi(a1, &miss);
2048
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002049 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2050 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002051 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002052 ASSERT(cell->value() == *function);
2053 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2054 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002055 GenerateLoadFunctionFromCell(cell, function, &miss);
2056 }
2057
2058 // Load the char code argument.
2059 Register code = a1;
2060 __ lw(code, MemOperand(sp, 0 * kPointerSize));
2061
2062 // Check the code is a smi.
2063 Label slow;
2064 STATIC_ASSERT(kSmiTag == 0);
2065 __ JumpIfNotSmi(code, &slow);
2066
2067 // Convert the smi code to uint16.
2068 __ And(code, code, Operand(Smi::FromInt(0xffff)));
2069
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002070 StringCharFromCodeGenerator generator(code, v0);
2071 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002072 __ Drop(argc + 1);
2073 __ Ret();
2074
2075 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002076 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002077
2078 // Tail call the full function. We do not have to patch the receiver
2079 // because the function makes no use of it.
2080 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002081 __ InvokeFunction(
2082 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002083
2084 __ bind(&miss);
2085 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002086 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002087
2088 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002089 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002090}
2091
2092
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002093Handle<Code> CallStubCompiler::CompileMathFloorCall(
2094 Handle<Object> object,
2095 Handle<JSObject> holder,
2096 Handle<JSGlobalPropertyCell> cell,
2097 Handle<JSFunction> function,
2098 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002099 // ----------- S t a t e -------------
2100 // -- a2 : function name
2101 // -- ra : return address
2102 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2103 // -- ...
2104 // -- sp[argc * 4] : receiver
2105 // -----------------------------------
2106
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002107 if (!CpuFeatures::IsSupported(FPU)) {
2108 return Handle<Code>::null();
2109 }
2110
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002111 CpuFeatures::Scope scope_fpu(FPU);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002112 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002113 // If the object is not a JSObject or we got an unexpected number of
2114 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002115 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002116
2117 Label miss, slow;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002118 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002119
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002120 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002121 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002122 STATIC_ASSERT(kSmiTag == 0);
2123 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002124 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2125 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002126 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002127 ASSERT(cell->value() == *function);
2128 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2129 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002130 GenerateLoadFunctionFromCell(cell, function, &miss);
2131 }
2132
2133 // Load the (only) argument into v0.
2134 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2135
2136 // If the argument is a smi, just return.
2137 STATIC_ASSERT(kSmiTag == 0);
2138 __ And(t0, v0, Operand(kSmiTagMask));
2139 __ Drop(argc + 1, eq, t0, Operand(zero_reg));
2140 __ Ret(eq, t0, Operand(zero_reg));
2141
danno@chromium.org40cb8782011-05-25 07:58:50 +00002142 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002143
2144 Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return;
2145
2146 // If fpu is enabled, we use the floor instruction.
2147
2148 // Load the HeapNumber value.
2149 __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2150
2151 // Backup FCSR.
2152 __ cfc1(a3, FCSR);
2153 // Clearing FCSR clears the exception mask with no side-effects.
2154 __ ctc1(zero_reg, FCSR);
2155 // Convert the argument to an integer.
2156 __ floor_w_d(f0, f0);
2157
2158 // Start checking for special cases.
2159 // Get the argument exponent and clear the sign bit.
2160 __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize));
2161 __ And(t2, t1, Operand(~HeapNumber::kSignMask));
2162 __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord);
2163
2164 // Retrieve FCSR and check for fpu errors.
2165 __ cfc1(t5, FCSR);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002166 __ And(t5, t5, Operand(kFCSRExceptionFlagMask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002167 __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));
2168
2169 // Check for NaN, Infinity, and -Infinity.
2170 // They are invariant through a Math.Floor call, so just
2171 // return the original argument.
2172 __ Subu(t3, t2, Operand(HeapNumber::kExponentMask
2173 >> HeapNumber::kMantissaBitsInTopWord));
2174 __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg));
2175 // We had an overflow or underflow in the conversion. Check if we
2176 // have a big exponent.
2177 // If greater or equal, the argument is already round and in v0.
2178 __ Branch(&restore_fcsr_and_return, ge, t3,
2179 Operand(HeapNumber::kMantissaBits));
2180 __ Branch(&wont_fit_smi);
2181
2182 __ bind(&no_fpu_error);
2183 // Move the result back to v0.
2184 __ mfc1(v0, f0);
2185 // Check if the result fits into a smi.
2186 __ Addu(a1, v0, Operand(0x40000000));
2187 __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg));
2188 // Tag the result.
2189 STATIC_ASSERT(kSmiTag == 0);
2190 __ sll(v0, v0, kSmiTagSize);
2191
2192 // Check for -0.
2193 __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg));
2194 // t1 already holds the HeapNumber exponent.
2195 __ And(t0, t1, Operand(HeapNumber::kSignMask));
2196 // If our HeapNumber is negative it was -0, so load its address and return.
2197 // Else v0 is loaded with 0, so we can also just return.
2198 __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg));
2199 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2200
2201 __ bind(&restore_fcsr_and_return);
2202 // Restore FCSR and return.
2203 __ ctc1(a3, FCSR);
2204
2205 __ Drop(argc + 1);
2206 __ Ret();
2207
2208 __ bind(&wont_fit_smi);
2209 // Restore FCSR and fall to slow case.
2210 __ ctc1(a3, FCSR);
2211
2212 __ bind(&slow);
2213 // Tail call the full function. We do not have to patch the receiver
2214 // because the function makes no use of it.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002215 __ InvokeFunction(
2216 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002217
2218 __ bind(&miss);
2219 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002220 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002221
2222 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002223 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002224}
2225
2226
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002227Handle<Code> CallStubCompiler::CompileMathAbsCall(
2228 Handle<Object> object,
2229 Handle<JSObject> holder,
2230 Handle<JSGlobalPropertyCell> cell,
2231 Handle<JSFunction> function,
2232 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002233 // ----------- S t a t e -------------
2234 // -- a2 : function name
2235 // -- ra : return address
2236 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2237 // -- ...
2238 // -- sp[argc * 4] : receiver
2239 // -----------------------------------
2240
2241 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002242 // If the object is not a JSObject or we got an unexpected number of
2243 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002244 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002245
2246 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002247
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002248 GenerateNameCheck(name, &miss);
2249 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002250 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002251 STATIC_ASSERT(kSmiTag == 0);
2252 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002253 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2254 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002255 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002256 ASSERT(cell->value() == *function);
2257 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2258 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002259 GenerateLoadFunctionFromCell(cell, function, &miss);
2260 }
2261
2262 // Load the (only) argument into v0.
2263 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2264
2265 // Check if the argument is a smi.
2266 Label not_smi;
2267 STATIC_ASSERT(kSmiTag == 0);
2268 __ JumpIfNotSmi(v0, &not_smi);
2269
2270 // Do bitwise not or do nothing depending on the sign of the
2271 // argument.
2272 __ sra(t0, v0, kBitsPerInt - 1);
2273 __ Xor(a1, v0, t0);
2274
2275 // Add 1 or do nothing depending on the sign of the argument.
2276 __ Subu(v0, a1, t0);
2277
2278 // If the result is still negative, go to the slow case.
2279 // This only happens for the most negative smi.
2280 Label slow;
2281 __ Branch(&slow, lt, v0, Operand(zero_reg));
2282
2283 // Smi case done.
2284 __ Drop(argc + 1);
2285 __ Ret();
2286
2287 // Check if the argument is a heap number and load its exponent and
2288 // sign.
2289 __ bind(&not_smi);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002290 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002291 __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2292
2293 // Check the sign of the argument. If the argument is positive,
2294 // just return it.
2295 Label negative_sign;
2296 __ And(t0, a1, Operand(HeapNumber::kSignMask));
2297 __ Branch(&negative_sign, ne, t0, Operand(zero_reg));
2298 __ Drop(argc + 1);
2299 __ Ret();
2300
2301 // If the argument is negative, clear the sign, and return a new
2302 // number.
2303 __ bind(&negative_sign);
2304 __ Xor(a1, a1, Operand(HeapNumber::kSignMask));
2305 __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2306 __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
2307 __ AllocateHeapNumber(v0, t0, t1, t2, &slow);
2308 __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2309 __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2310 __ Drop(argc + 1);
2311 __ Ret();
2312
2313 // Tail call the full function. We do not have to patch the receiver
2314 // because the function makes no use of it.
2315 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002316 __ InvokeFunction(
2317 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002318
2319 __ bind(&miss);
2320 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002321 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002322
2323 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002324 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002325}
2326
2327
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002328Handle<Code> CallStubCompiler::CompileFastApiCall(
lrn@chromium.org7516f052011-03-30 08:52:27 +00002329 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002330 Handle<Object> object,
2331 Handle<JSObject> holder,
2332 Handle<JSGlobalPropertyCell> cell,
2333 Handle<JSFunction> function,
2334 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002335
danno@chromium.org40cb8782011-05-25 07:58:50 +00002336 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002337
2338 ASSERT(optimization.is_simple_api_call());
2339 // Bail out if object is a global object as we don't want to
2340 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002341 if (object->IsGlobalObject()) return Handle<Code>::null();
2342 if (!cell.is_null()) return Handle<Code>::null();
2343 if (!object->IsJSObject()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002344 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002345 Handle<JSObject>::cast(object), holder);
2346 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002347
2348 Label miss, miss_before_stack_reserved;
2349
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002350 GenerateNameCheck(name, &miss_before_stack_reserved);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002351
2352 // Get the receiver from the stack.
2353 const int argc = arguments().immediate();
2354 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2355
2356 // Check that the receiver isn't a smi.
2357 __ JumpIfSmi(a1, &miss_before_stack_reserved);
2358
2359 __ IncrementCounter(counters->call_const(), 1, a0, a3);
2360 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2361
2362 ReserveSpaceForFastApiCall(masm(), a0);
2363
2364 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002365 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002366 depth, &miss);
2367
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002368 GenerateFastApiDirectCall(masm(), optimization, argc);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002369
2370 __ bind(&miss);
2371 FreeSpaceForFastApiCall(masm());
2372
2373 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002374 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002375
2376 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002377 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002378}
2379
2380
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002381void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
2382 Handle<JSObject> holder,
2383 Handle<String> name,
2384 CheckType check,
2385 Label* success) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002386 // ----------- S t a t e -------------
2387 // -- a2 : name
2388 // -- ra : return address
2389 // -----------------------------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002390 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002391 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002392
2393 // Get the receiver from the stack.
2394 const int argc = arguments().immediate();
2395 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2396
2397 // Check that the receiver isn't a smi.
2398 if (check != NUMBER_CHECK) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002399 __ JumpIfSmi(a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002400 }
2401
2402 // Make sure that it's okay not to patch the on stack receiver
2403 // unless we're doing a receiver map check.
2404 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002405 switch (check) {
2406 case RECEIVER_MAP_CHECK:
2407 __ IncrementCounter(masm()->isolate()->counters()->call_const(),
2408 1, a0, a3);
2409
2410 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002411 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2412 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002413
2414 // Patch the receiver on the stack with the global proxy if
2415 // necessary.
2416 if (object->IsGlobalObject()) {
2417 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2418 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2419 }
2420 break;
2421
2422 case STRING_CHECK:
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002423 // Check that the object is a two-byte string or a symbol.
2424 __ GetObjectType(a1, a3, a3);
2425 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2426 // Check that the maps starting from the prototype haven't changed.
2427 GenerateDirectLoadGlobalFunctionPrototype(
2428 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
2429 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002430 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002431 a0, holder, a3, a1, t0, name, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002432 break;
2433
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002434 case NUMBER_CHECK: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002435 Label fast;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002436 // Check that the object is a smi or a heap number.
2437 __ JumpIfSmi(a1, &fast);
2438 __ GetObjectType(a1, a0, a0);
2439 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
2440 __ bind(&fast);
2441 // Check that the maps starting from the prototype haven't changed.
2442 GenerateDirectLoadGlobalFunctionPrototype(
2443 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
2444 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002445 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002446 a0, holder, a3, a1, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002447 break;
2448 }
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002449 case BOOLEAN_CHECK: {
2450 Label fast;
2451 // Check that the object is a boolean.
2452 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
2453 __ Branch(&fast, eq, a1, Operand(t0));
2454 __ LoadRoot(t0, Heap::kFalseValueRootIndex);
2455 __ Branch(&miss, ne, a1, Operand(t0));
2456 __ bind(&fast);
2457 // Check that the maps starting from the prototype haven't changed.
2458 GenerateDirectLoadGlobalFunctionPrototype(
2459 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
2460 CheckPrototypes(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002461 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002462 a0, holder, a3, a1, t0, name, &miss);
2463 break;
2464 }
2465 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002466
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002467 __ jmp(success);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002468
2469 // Handle call cache miss.
2470 __ bind(&miss);
2471
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002472 GenerateMissBranch();
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002473}
2474
2475
2476void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) {
2477 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
2478 ? CALL_AS_FUNCTION
2479 : CALL_AS_METHOD;
2480 __ InvokeFunction(
2481 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), call_kind);
2482}
2483
2484
2485Handle<Code> CallStubCompiler::CompileCallConstant(
2486 Handle<Object> object,
2487 Handle<JSObject> holder,
2488 Handle<String> name,
2489 CheckType check,
2490 Handle<JSFunction> function) {
2491 if (HasCustomCallGenerator(function)) {
2492 Handle<Code> code = CompileCustomCall(object, holder,
2493 Handle<JSGlobalPropertyCell>::null(),
2494 function, name);
2495 // A null handle means bail out to the regular compiler code below.
2496 if (!code.is_null()) return code;
2497 }
2498
2499 Label success;
2500
2501 CompileHandlerFrontend(object, holder, name, check, &success);
2502 __ bind(&success);
2503 CompileHandlerBackend(function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002504
2505 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002506 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002507}
2508
2509
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002510Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2511 Handle<JSObject> holder,
2512 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002513 // ----------- S t a t e -------------
2514 // -- a2 : name
2515 // -- ra : return address
2516 // -----------------------------------
2517
2518 Label miss;
2519
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002520 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002521
2522 // Get the number of arguments.
2523 const int argc = arguments().immediate();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002524 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002525 LookupPostInterceptor(holder, name, &lookup);
2526
2527 // Get the receiver from the stack.
2528 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2529
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002530 CallInterceptorCompiler compiler(this, arguments(), a2, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002531 compiler.Compile(masm(), object, holder, name, &lookup, a1, a3, t0, a0,
2532 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002533
2534 // Move returned value, the function to call, to a1.
2535 __ mov(a1, v0);
2536 // Restore receiver.
2537 __ lw(a0, MemOperand(sp, argc * kPointerSize));
2538
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002539 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002540
2541 // Handle call cache miss.
2542 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002543 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002544
2545 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002546 return GetCode(Code::INTERCEPTOR, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002547}
2548
2549
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002550Handle<Code> CallStubCompiler::CompileCallGlobal(
2551 Handle<JSObject> object,
2552 Handle<GlobalObject> holder,
2553 Handle<JSGlobalPropertyCell> cell,
2554 Handle<JSFunction> function,
2555 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002556 // ----------- S t a t e -------------
2557 // -- a2 : name
2558 // -- ra : return address
2559 // -----------------------------------
2560
2561 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002562 Handle<Code> code = CompileCustomCall(object, holder, cell, function, name);
2563 // A null handle means bail out to the regular compiler code below.
2564 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002565 }
2566
2567 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002568 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002569
2570 // Get the number of arguments.
2571 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002572 GenerateGlobalReceiverCheck(object, holder, name, &miss);
2573 GenerateLoadFunctionFromCell(cell, function, &miss);
2574
2575 // Patch the receiver on the stack with the global proxy if
2576 // necessary.
2577 if (object->IsGlobalObject()) {
2578 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
2579 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2580 }
2581
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002582 // Set up the context (function already in r1).
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002583 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
2584
2585 // Jump to the cached code (tail call).
2586 Counters* counters = masm()->isolate()->counters();
2587 __ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002588 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002589 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002590 ? CALL_AS_FUNCTION
2591 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002592 // We call indirectly through the code field in the function to
2593 // allow recompilation to take effect without changing any of the
2594 // call sites.
2595 __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
2596 __ InvokeCode(a3, expected, arguments(), JUMP_FUNCTION,
2597 NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002598
2599 // Handle call cache miss.
2600 __ bind(&miss);
2601 __ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002602 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002603
2604 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002605 return GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002606}
2607
2608
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002609Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +00002610 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002611 Handle<Map> transition,
2612 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002613 // ----------- S t a t e -------------
2614 // -- a0 : value
2615 // -- a1 : receiver
2616 // -- a2 : name
2617 // -- ra : return address
2618 // -----------------------------------
2619 Label miss;
2620
2621 // Name register might be clobbered.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002622 GenerateStoreField(masm(),
2623 object,
2624 index,
2625 transition,
2626 name,
2627 a1, a2, a3, t0,
2628 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002629 __ bind(&miss);
2630 __ li(a2, Operand(Handle<String>(name))); // Restore name.
2631 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2632 __ Jump(ic, RelocInfo::CODE_TARGET);
2633
2634 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002635 return GetCode(transition.is_null()
2636 ? Code::FIELD
2637 : Code::MAP_TRANSITION, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002638}
2639
2640
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002641Handle<Code> StoreStubCompiler::CompileStoreCallback(
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002642 Handle<String> name,
2643 Handle<JSObject> receiver,
2644 Handle<JSObject> holder,
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002645 Handle<ExecutableAccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002646 // ----------- S t a t e -------------
2647 // -- a0 : value
2648 // -- a1 : receiver
2649 // -- a2 : name
2650 // -- ra : return address
2651 // -----------------------------------
2652 Label miss;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002653 // Check that the maps haven't changed.
2654 __ JumpIfSmi(a1, &miss, a3);
2655 CheckPrototypes(receiver, a1, holder, a3, t0, t1, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002656
2657 // Stub never generated for non-global objects that require access
2658 // checks.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002659 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002660
2661 __ push(a1); // Receiver.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002662 __ li(a3, Operand(callback)); // Callback info.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002663 __ Push(a3, a2, a0);
2664
2665 // Do tail-call to the runtime system.
2666 ExternalReference store_callback_property =
2667 ExternalReference(IC_Utility(IC::kStoreCallbackProperty),
2668 masm()->isolate());
2669 __ TailCallExternalReference(store_callback_property, 4, 1);
2670
2671 // Handle store cache miss.
2672 __ bind(&miss);
2673 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2674 __ Jump(ic, RelocInfo::CODE_TARGET);
2675
2676 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002677 return GetCode(Code::CALLBACKS, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002678}
2679
2680
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002681#undef __
2682#define __ ACCESS_MASM(masm)
2683
2684
2685void StoreStubCompiler::GenerateStoreViaSetter(
2686 MacroAssembler* masm,
2687 Handle<JSFunction> setter) {
2688 // ----------- S t a t e -------------
2689 // -- a0 : value
2690 // -- a1 : receiver
2691 // -- a2 : name
2692 // -- ra : return address
2693 // -----------------------------------
2694 {
2695 FrameScope scope(masm, StackFrame::INTERNAL);
2696
2697 // Save value register, so we can restore it later.
2698 __ push(a0);
2699
2700 if (!setter.is_null()) {
2701 // Call the JavaScript setter with receiver and value on the stack.
2702 __ push(a1);
2703 __ push(a0);
2704 ParameterCount actual(1);
2705 __ InvokeFunction(setter, actual, CALL_FUNCTION, NullCallWrapper(),
2706 CALL_AS_METHOD);
2707 } else {
2708 // If we generate a global code snippet for deoptimization only, remember
2709 // the place to continue after deoptimization.
2710 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2711 }
2712
2713 // We have to return the passed value, not the return value of the setter.
2714 __ pop(v0);
2715
2716 // Restore context register.
2717 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2718 }
2719 __ Ret();
2720}
2721
2722
2723#undef __
2724#define __ ACCESS_MASM(masm())
2725
2726
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002727Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002728 Handle<String> name,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002729 Handle<JSObject> receiver,
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002730 Handle<JSObject> holder,
2731 Handle<JSFunction> setter) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002732 // ----------- S t a t e -------------
2733 // -- a0 : value
2734 // -- a1 : receiver
2735 // -- a2 : name
2736 // -- ra : return address
2737 // -----------------------------------
2738 Label miss;
2739
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002740 // Check that the maps haven't changed.
2741 __ JumpIfSmi(a1, &miss);
2742 CheckPrototypes(receiver, a1, holder, a3, t0, t1, name, &miss);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002743
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002744 GenerateStoreViaSetter(masm(), setter);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002745
2746 __ bind(&miss);
2747 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2748 __ Jump(ic, RelocInfo::CODE_TARGET);
2749
2750 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002751 return GetCode(Code::CALLBACKS, name);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002752}
2753
2754
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002755Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
2756 Handle<JSObject> receiver,
2757 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002758 // ----------- S t a t e -------------
2759 // -- a0 : value
2760 // -- a1 : receiver
2761 // -- a2 : name
2762 // -- ra : return address
2763 // -----------------------------------
2764 Label miss;
2765
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002766 // Check that the map of the object hasn't changed.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002767 __ CheckMap(a1, a3, Handle<Map>(receiver->map()), &miss,
2768 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002769
2770 // Perform global security token check if needed.
2771 if (receiver->IsJSGlobalProxy()) {
2772 __ CheckAccessGlobalProxy(a1, a3, &miss);
2773 }
2774
2775 // Stub is never generated for non-global objects that require access
2776 // checks.
2777 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2778
2779 __ Push(a1, a2, a0); // Receiver, name, value.
2780
2781 __ li(a0, Operand(Smi::FromInt(strict_mode_)));
2782 __ push(a0); // Strict mode.
2783
2784 // Do tail-call to the runtime system.
2785 ExternalReference store_ic_property =
2786 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty),
2787 masm()->isolate());
2788 __ TailCallExternalReference(store_ic_property, 4, 1);
2789
2790 // Handle store cache miss.
2791 __ bind(&miss);
2792 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2793 __ Jump(ic, RelocInfo::CODE_TARGET);
2794
2795 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002796 return GetCode(Code::INTERCEPTOR, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002797}
2798
2799
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002800Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2801 Handle<GlobalObject> object,
2802 Handle<JSGlobalPropertyCell> cell,
2803 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002804 // ----------- S t a t e -------------
2805 // -- a0 : value
2806 // -- a1 : receiver
2807 // -- a2 : name
2808 // -- ra : return address
2809 // -----------------------------------
2810 Label miss;
2811
2812 // Check that the map of the global has not changed.
2813 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2814 __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map())));
2815
2816 // Check that the value in the cell is not the hole. If it is, this
2817 // cell could have been deleted and reintroducing the global needs
2818 // to update the property details in the property dictionary of the
2819 // global object. We bail out to the runtime system to do that.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002820 __ li(t0, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002821 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
2822 __ lw(t2, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2823 __ Branch(&miss, eq, t1, Operand(t2));
2824
2825 // Store the value in the cell.
2826 __ sw(a0, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2827 __ mov(v0, a0); // Stored value must be returned in v0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002828 // Cells are always rescanned, so no write barrier here.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002829
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002830 Counters* counters = masm()->isolate()->counters();
2831 __ IncrementCounter(counters->named_store_global_inline(), 1, a1, a3);
2832 __ Ret();
2833
2834 // Handle store cache miss.
2835 __ bind(&miss);
2836 __ IncrementCounter(counters->named_store_global_inline_miss(), 1, a1, a3);
2837 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2838 __ Jump(ic, RelocInfo::CODE_TARGET);
2839
2840 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002841 return GetCode(Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002842}
2843
2844
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002845Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
2846 Handle<JSObject> object,
2847 Handle<JSObject> last,
2848 Handle<String> name,
2849 Handle<GlobalObject> global) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002850 Label success;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002851
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002852 NonexistentHandlerFrontend(object, last, name, &success, global);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002853
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002854 __ bind(&success);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002855 // Return undefined if maps of the full prototype chain is still the same.
2856 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2857 __ Ret();
2858
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002859 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002860 return GetCode(Code::NONEXISTENT, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00002861}
2862
2863
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002864Register* LoadStubCompiler::registers() {
2865 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2866 static Register registers[] = { a0, a2, a3, a1, t0, t1 };
2867 return registers;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002868}
2869
2870
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002871Register* KeyedLoadStubCompiler::registers() {
2872 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2873 static Register registers[] = { a1, a0, a2, a3, t0, t1 };
2874 return registers;
2875}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002876
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002877
2878void KeyedLoadStubCompiler::GenerateNameCheck(Handle<String> name,
2879 Register name_reg,
2880 Label* miss) {
2881 __ Branch(miss, ne, name_reg, Operand(name));
lrn@chromium.org7516f052011-03-30 08:52:27 +00002882}
2883
2884
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002885#undef __
2886#define __ ACCESS_MASM(masm)
2887
2888
2889void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
2890 Handle<JSFunction> getter) {
2891 // ----------- S t a t e -------------
2892 // -- a0 : receiver
2893 // -- a2 : name
2894 // -- ra : return address
2895 // -----------------------------------
2896 {
2897 FrameScope scope(masm, StackFrame::INTERNAL);
2898
2899 if (!getter.is_null()) {
2900 // Call the JavaScript getter with the receiver on the stack.
2901 __ push(a0);
2902 ParameterCount actual(0);
2903 __ InvokeFunction(getter, actual, CALL_FUNCTION, NullCallWrapper(),
2904 CALL_AS_METHOD);
2905 } else {
2906 // If we generate a global code snippet for deoptimization only, remember
2907 // the place to continue after deoptimization.
2908 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
2909 }
2910
2911 // Restore context register.
2912 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2913 }
2914 __ Ret();
2915}
2916
2917
2918#undef __
2919#define __ ACCESS_MASM(masm())
2920
2921
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002922Handle<Code> LoadStubCompiler::CompileLoadGlobal(
2923 Handle<JSObject> object,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002924 Handle<GlobalObject> global,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002925 Handle<JSGlobalPropertyCell> cell,
2926 Handle<String> name,
2927 bool is_dont_delete) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002928 Label success, miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002929
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002930 HandlerFrontendHeader(object, receiver(), Handle<JSObject>::cast(global),
2931 name, &miss, PERFORM_INITIAL_CHECKS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002932
2933 // Get the value from the cell.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002934 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002935 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
2936
2937 // Check for deleted property if property can actually be deleted.
2938 if (!is_dont_delete) {
2939 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
2940 __ Branch(&miss, eq, t0, Operand(at));
2941 }
2942
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002943 HandlerFrontendFooter(&success, &miss);
2944 __ bind(&success);
2945
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002946 Counters* counters = masm()->isolate()->counters();
2947 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002948 __ mov(v0, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002949 __ Ret();
2950
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002951 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002952 return GetCode(Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002953}
2954
2955
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002956Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
2957 Handle<Map> receiver_map) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00002958 // ----------- S t a t e -------------
2959 // -- ra : return address
2960 // -- a0 : key
2961 // -- a1 : receiver
2962 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002963 ElementsKind elements_kind = receiver_map->elements_kind();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002964 if (receiver_map->has_fast_elements() ||
2965 receiver_map->has_external_array_elements()) {
2966 Handle<Code> stub = KeyedLoadFastElementStub(
2967 receiver_map->instance_type() == JS_ARRAY_TYPE,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002968 elements_kind).GetCode(isolate());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002969 __ DispatchMap(a1, a2, receiver_map, stub, DO_SMI_CHECK);
2970 } else {
2971 Handle<Code> stub =
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002972 KeyedLoadDictionaryElementStub().GetCode(isolate());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002973 __ DispatchMap(a1, a2, receiver_map, stub, DO_SMI_CHECK);
2974 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00002975
2976 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
2977 __ Jump(ic, RelocInfo::CODE_TARGET);
2978
2979 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002980 return GetCode(Code::NORMAL, factory()->empty_string());
danno@chromium.org40cb8782011-05-25 07:58:50 +00002981}
2982
2983
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002984Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002985 MapHandleList* receiver_maps,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002986 CodeHandleList* handlers) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002987 // ----------- S t a t e -------------
2988 // -- ra : return address
2989 // -- a0 : key
2990 // -- a1 : receiver
2991 // -----------------------------------
2992 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002993 __ JumpIfSmi(a1, &miss);
2994
danno@chromium.org40cb8782011-05-25 07:58:50 +00002995 int receiver_count = receiver_maps->length();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002996 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00002997 for (int current = 0; current < receiver_count; ++current) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002998 __ Jump(handlers->at(current), RelocInfo::CODE_TARGET,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002999 eq, a2, Operand(receiver_maps->at(current)));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003000 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003001
3002 __ bind(&miss);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003003 GenerateLoadMiss(masm(), kind());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003004
3005 // Return the generated code.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003006 return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003007}
3008
3009
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003010Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +00003011 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003012 Handle<Map> transition,
3013 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003014 // ----------- S t a t e -------------
3015 // -- a0 : value
3016 // -- a1 : key
3017 // -- a2 : receiver
3018 // -- ra : return address
3019 // -----------------------------------
3020
3021 Label miss;
3022
3023 Counters* counters = masm()->isolate()->counters();
3024 __ IncrementCounter(counters->keyed_store_field(), 1, a3, t0);
3025
3026 // Check that the name has not changed.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003027 __ Branch(&miss, ne, a1, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003028
3029 // a3 is used as scratch register. a1 and a2 keep their values if a jump to
3030 // the miss label is generated.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003031 GenerateStoreField(masm(),
3032 object,
3033 index,
3034 transition,
3035 name,
3036 a2, a1, a3, t0,
3037 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003038 __ bind(&miss);
3039
3040 __ DecrementCounter(counters->keyed_store_field(), 1, a3, t0);
3041 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss();
3042 __ Jump(ic, RelocInfo::CODE_TARGET);
3043
3044 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003045 return GetCode(transition.is_null()
3046 ? Code::FIELD
3047 : Code::MAP_TRANSITION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003048}
3049
3050
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003051Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
3052 Handle<Map> receiver_map) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003053 // ----------- S t a t e -------------
3054 // -- a0 : value
3055 // -- a1 : key
3056 // -- a2 : receiver
3057 // -- ra : return address
3058 // -- a3 : scratch
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003059 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003060 ElementsKind elements_kind = receiver_map->elements_kind();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003061 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003062 Handle<Code> stub =
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003063 KeyedStoreElementStub(is_js_array,
3064 elements_kind,
3065 grow_mode_).GetCode(isolate());
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003066
3067 __ DispatchMap(a2, a3, receiver_map, stub, DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003068
danno@chromium.org40cb8782011-05-25 07:58:50 +00003069 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003070 __ Jump(ic, RelocInfo::CODE_TARGET);
3071
3072 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003073 return GetCode(Code::NORMAL, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00003074}
3075
3076
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003077Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
3078 MapHandleList* receiver_maps,
3079 CodeHandleList* handler_stubs,
3080 MapHandleList* transitioned_maps) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003081 // ----------- S t a t e -------------
3082 // -- a0 : value
3083 // -- a1 : key
3084 // -- a2 : receiver
3085 // -- ra : return address
3086 // -- a3 : scratch
3087 // -----------------------------------
3088 Label miss;
3089 __ JumpIfSmi(a2, &miss);
3090
3091 int receiver_count = receiver_maps->length();
3092 __ lw(a3, FieldMemOperand(a2, HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003093 for (int i = 0; i < receiver_count; ++i) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003094 if (transitioned_maps->at(i).is_null()) {
3095 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq,
3096 a3, Operand(receiver_maps->at(i)));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003097 } else {
3098 Label next_map;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003099 __ Branch(&next_map, ne, a3, Operand(receiver_maps->at(i)));
3100 __ li(a3, Operand(transitioned_maps->at(i)));
3101 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003102 __ bind(&next_map);
3103 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003104 }
3105
3106 __ bind(&miss);
3107 Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
3108 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3109
3110 // Return the generated code.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003111 return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003112}
3113
3114
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003115Handle<Code> ConstructStubCompiler::CompileConstructStub(
3116 Handle<JSFunction> function) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003117 // a0 : argc
3118 // a1 : constructor
3119 // ra : return address
3120 // [sp] : last argument
3121 Label generic_stub_call;
3122
3123 // Use t7 for holding undefined which is used in several places below.
3124 __ LoadRoot(t7, Heap::kUndefinedValueRootIndex);
3125
3126#ifdef ENABLE_DEBUGGER_SUPPORT
3127 // Check to see whether there are any break points in the function code. If
3128 // there are jump to the generic constructor stub which calls the actual
3129 // code for the function thereby hitting the break points.
3130 __ lw(t5, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3131 __ lw(a2, FieldMemOperand(t5, SharedFunctionInfo::kDebugInfoOffset));
3132 __ Branch(&generic_stub_call, ne, a2, Operand(t7));
3133#endif
3134
3135 // Load the initial map and verify that it is in fact a map.
3136 // a1: constructor function
3137 // t7: undefined
3138 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003139 __ JumpIfSmi(a2, &generic_stub_call);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003140 __ GetObjectType(a2, a3, t0);
3141 __ Branch(&generic_stub_call, ne, t0, Operand(MAP_TYPE));
3142
3143#ifdef DEBUG
3144 // Cannot construct functions this way.
3145 // a0: argc
3146 // a1: constructor function
3147 // a2: initial map
3148 // t7: undefined
3149 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
3150 __ Check(ne, "Function constructed by construct stub.",
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003151 a3, Operand(JS_FUNCTION_TYPE));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003152#endif
3153
3154 // Now allocate the JSObject in new space.
3155 // a0: argc
3156 // a1: constructor function
3157 // a2: initial map
3158 // t7: undefined
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003159 ASSERT(function->has_initial_map());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003160 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003161#ifdef DEBUG
3162 int instance_size = function->initial_map()->instance_size();
3163 __ Check(eq, "Instance size of initial map changed.",
3164 a3, Operand(instance_size >> kPointerSizeLog2));
3165#endif
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003166 __ AllocateInNewSpace(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003167
3168 // Allocated the JSObject, now initialize the fields. Map is set to initial
3169 // map and properties and elements are set to empty fixed array.
3170 // a0: argc
3171 // a1: constructor function
3172 // a2: initial map
3173 // a3: object size (in words)
3174 // t4: JSObject (not tagged)
3175 // t7: undefined
3176 __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex);
3177 __ mov(t5, t4);
3178 __ sw(a2, MemOperand(t5, JSObject::kMapOffset));
3179 __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset));
3180 __ sw(t6, MemOperand(t5, JSObject::kElementsOffset));
3181 __ Addu(t5, t5, Operand(3 * kPointerSize));
3182 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
3183 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
3184 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
3185
3186
3187 // Calculate the location of the first argument. The stack contains only the
3188 // argc arguments.
3189 __ sll(a1, a0, kPointerSizeLog2);
3190 __ Addu(a1, a1, sp);
3191
3192 // Fill all the in-object properties with undefined.
3193 // a0: argc
3194 // a1: first argument
3195 // a3: object size (in words)
3196 // t4: JSObject (not tagged)
3197 // t5: First in-object property of JSObject (not tagged)
3198 // t7: undefined
3199 // Fill the initialized properties with a constant value or a passed argument
3200 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003201 Handle<SharedFunctionInfo> shared(function->shared());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003202 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3203 if (shared->IsThisPropertyAssignmentArgument(i)) {
3204 Label not_passed, next;
3205 // Check if the argument assigned to the property is actually passed.
3206 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3207 __ Branch(&not_passed, less_equal, a0, Operand(arg_number));
3208 // Argument passed - find it on the stack.
3209 __ lw(a2, MemOperand(a1, (arg_number + 1) * -kPointerSize));
3210 __ sw(a2, MemOperand(t5));
3211 __ Addu(t5, t5, kPointerSize);
3212 __ jmp(&next);
3213 __ bind(&not_passed);
3214 // Set the property to undefined.
3215 __ sw(t7, MemOperand(t5));
3216 __ Addu(t5, t5, Operand(kPointerSize));
3217 __ bind(&next);
3218 } else {
3219 // Set the property to the constant value.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003220 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i),
3221 masm()->isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003222 __ li(a2, Operand(constant));
3223 __ sw(a2, MemOperand(t5));
3224 __ Addu(t5, t5, kPointerSize);
3225 }
3226 }
3227
3228 // Fill the unused in-object property fields with undefined.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003229 for (int i = shared->this_property_assignments_count();
3230 i < function->initial_map()->inobject_properties();
3231 i++) {
3232 __ sw(t7, MemOperand(t5));
3233 __ Addu(t5, t5, kPointerSize);
3234 }
3235
3236 // a0: argc
3237 // t4: JSObject (not tagged)
3238 // Move argc to a1 and the JSObject to return to v0 and tag it.
3239 __ mov(a1, a0);
3240 __ mov(v0, t4);
3241 __ Or(v0, v0, Operand(kHeapObjectTag));
3242
3243 // v0: JSObject
3244 // a1: argc
3245 // Remove caller arguments and receiver from the stack and return.
3246 __ sll(t0, a1, kPointerSizeLog2);
3247 __ Addu(sp, sp, t0);
3248 __ Addu(sp, sp, Operand(kPointerSize));
3249 Counters* counters = masm()->isolate()->counters();
3250 __ IncrementCounter(counters->constructed_objects(), 1, a1, a2);
3251 __ IncrementCounter(counters->constructed_objects_stub(), 1, a1, a2);
3252 __ Ret();
3253
3254 // Jump to the generic stub in case the specialized code cannot handle the
3255 // construction.
3256 __ bind(&generic_stub_call);
3257 Handle<Code> generic_construct_stub =
3258 masm()->isolate()->builtins()->JSConstructStubGeneric();
3259 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
3260
3261 // Return the generated code.
3262 return GetCode();
3263}
3264
3265
danno@chromium.org40cb8782011-05-25 07:58:50 +00003266#undef __
3267#define __ ACCESS_MASM(masm)
3268
3269
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003270void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3271 MacroAssembler* masm) {
3272 // ---------- S t a t e --------------
3273 // -- ra : return address
3274 // -- a0 : key
3275 // -- a1 : receiver
3276 // -----------------------------------
3277 Label slow, miss_force_generic;
3278
3279 Register key = a0;
3280 Register receiver = a1;
3281
3282 __ JumpIfNotSmi(key, &miss_force_generic);
3283 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
3284 __ sra(a2, a0, kSmiTagSize);
3285 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
3286 __ Ret();
3287
3288 // Slow case, key and receiver still in a0 and a1.
3289 __ bind(&slow);
3290 __ IncrementCounter(
3291 masm->isolate()->counters()->keyed_load_external_array_slow(),
3292 1, a2, a3);
3293 // Entry registers are intact.
3294 // ---------- S t a t e --------------
3295 // -- ra : return address
3296 // -- a0 : key
3297 // -- a1 : receiver
3298 // -----------------------------------
3299 Handle<Code> slow_ic =
3300 masm->isolate()->builtins()->KeyedLoadIC_Slow();
3301 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
3302
3303 // Miss case, call the runtime.
3304 __ bind(&miss_force_generic);
3305
3306 // ---------- S t a t e --------------
3307 // -- ra : return address
3308 // -- a0 : key
3309 // -- a1 : receiver
3310 // -----------------------------------
3311
3312 Handle<Code> miss_ic =
3313 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3314 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3315}
3316
3317
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003318static bool IsElementTypeSigned(ElementsKind elements_kind) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003319 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003320 case EXTERNAL_BYTE_ELEMENTS:
3321 case EXTERNAL_SHORT_ELEMENTS:
3322 case EXTERNAL_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003323 return true;
3324
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003325 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3326 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3327 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3328 case EXTERNAL_PIXEL_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003329 return false;
3330
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003331 case EXTERNAL_FLOAT_ELEMENTS:
3332 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003333 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003334 case FAST_ELEMENTS:
3335 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003336 case FAST_HOLEY_SMI_ELEMENTS:
3337 case FAST_HOLEY_ELEMENTS:
3338 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003339 case DICTIONARY_ELEMENTS:
3340 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003341 UNREACHABLE();
3342 return false;
3343 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003344 return false;
lrn@chromium.org7516f052011-03-30 08:52:27 +00003345}
3346
3347
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003348static void GenerateSmiKeyCheck(MacroAssembler* masm,
3349 Register key,
3350 Register scratch0,
3351 Register scratch1,
3352 FPURegister double_scratch0,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003353 FPURegister double_scratch1,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003354 Label* fail) {
3355 if (CpuFeatures::IsSupported(FPU)) {
3356 CpuFeatures::Scope scope(FPU);
3357 Label key_ok;
3358 // Check for smi or a smi inside a heap number. We convert the heap
3359 // number and check if the conversion is exact and fits into the smi
3360 // range.
3361 __ JumpIfSmi(key, &key_ok);
3362 __ CheckMap(key,
3363 scratch0,
3364 Heap::kHeapNumberMapRootIndex,
3365 fail,
3366 DONT_DO_SMI_CHECK);
3367 __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
3368 __ EmitFPUTruncate(kRoundToZero,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003369 scratch0,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003370 double_scratch0,
3371 at,
3372 double_scratch1,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003373 scratch1,
3374 kCheckForInexactConversion);
3375
3376 __ Branch(fail, ne, scratch1, Operand(zero_reg));
3377
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003378 __ SmiTagCheckOverflow(key, scratch0, scratch1);
3379 __ BranchOnOverflow(fail, scratch1);
3380 __ bind(&key_ok);
3381 } else {
3382 // Check that the key is a smi.
3383 __ JumpIfNotSmi(key, fail);
3384 }
3385}
3386
3387
danno@chromium.org40cb8782011-05-25 07:58:50 +00003388void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3389 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003390 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003391 // ---------- S t a t e --------------
3392 // -- a0 : value
3393 // -- a1 : key
3394 // -- a2 : receiver
3395 // -- ra : return address
3396 // -----------------------------------
3397
danno@chromium.org40cb8782011-05-25 07:58:50 +00003398 Label slow, check_heap_number, miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003399
3400 // Register usage.
3401 Register value = a0;
3402 Register key = a1;
3403 Register receiver = a2;
3404 // a3 mostly holds the elements array or the destination external array.
3405
danno@chromium.org40cb8782011-05-25 07:58:50 +00003406 // This stub is meant to be tail-jumped to, the receiver must already
3407 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003408
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003409 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003410 GenerateSmiKeyCheck(masm, key, t0, t1, f2, f4, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003411
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003412 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3413
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003414 // Check that the index is in range.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003415 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3416 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003417 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003418
3419 // Handle both smis and HeapNumbers in the fast path. Go to the
3420 // runtime for all other kinds of values.
3421 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003422
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003423 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003424 // Double to pixel conversion is only implemented in the runtime for now.
3425 __ JumpIfNotSmi(value, &slow);
3426 } else {
3427 __ JumpIfNotSmi(value, &check_heap_number);
3428 }
3429 __ SmiUntag(t1, value);
3430 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3431
3432 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003433 // t1: value (integer).
3434
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003435 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003436 case EXTERNAL_PIXEL_ELEMENTS: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003437 // Clamp the value to [0..255].
3438 // v0 is used as a scratch register here.
3439 Label done;
3440 __ li(v0, Operand(255));
3441 // Normal branch: nop in delay slot.
3442 __ Branch(&done, gt, t1, Operand(v0));
3443 // Use delay slot in this branch.
3444 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg));
3445 __ mov(v0, zero_reg); // In delay slot.
3446 __ mov(v0, t1); // Value is in range 0..255.
3447 __ bind(&done);
3448 __ mov(t1, v0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003449
3450 __ srl(t8, key, 1);
3451 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003452 __ sb(t1, MemOperand(t8, 0));
3453 }
3454 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003455 case EXTERNAL_BYTE_ELEMENTS:
3456 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003457 __ srl(t8, key, 1);
3458 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003459 __ sb(t1, MemOperand(t8, 0));
3460 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003461 case EXTERNAL_SHORT_ELEMENTS:
3462 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003463 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003464 __ sh(t1, MemOperand(t8, 0));
3465 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003466 case EXTERNAL_INT_ELEMENTS:
3467 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003468 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003469 __ addu(t8, a3, t8);
3470 __ sw(t1, MemOperand(t8, 0));
3471 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003472 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003473 // Perform int-to-float conversion and store to memory.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003474 __ SmiUntag(t0, key);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003475 StoreIntAsFloat(masm, a3, t0, t1, t2, t3, t4);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003476 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003477 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003478 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003479 __ addu(a3, a3, t8);
3480 // a3: effective address of the double element
3481 FloatingPointHelper::Destination destination;
3482 if (CpuFeatures::IsSupported(FPU)) {
3483 destination = FloatingPointHelper::kFPURegisters;
3484 } else {
3485 destination = FloatingPointHelper::kCoreRegisters;
3486 }
3487 FloatingPointHelper::ConvertIntToDouble(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003488 masm, t1, destination,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003489 f0, t2, t3, // These are: double_dst, dst_mantissa, dst_exponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003490 t0, f2); // These are: scratch2, single_scratch.
3491 if (destination == FloatingPointHelper::kFPURegisters) {
3492 CpuFeatures::Scope scope(FPU);
3493 __ sdc1(f0, MemOperand(a3, 0));
3494 } else {
3495 __ sw(t2, MemOperand(a3, 0));
3496 __ sw(t3, MemOperand(a3, Register::kSizeInBytes));
3497 }
3498 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003499 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003500 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003501 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003502 case FAST_HOLEY_ELEMENTS:
3503 case FAST_HOLEY_SMI_ELEMENTS:
3504 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003505 case DICTIONARY_ELEMENTS:
3506 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003507 UNREACHABLE();
3508 break;
3509 }
3510
3511 // Entry registers are intact, a0 holds the value which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003512 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003513 __ Ret();
3514
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003515 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003516 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003517 __ bind(&check_heap_number);
3518 __ GetObjectType(value, t1, t2);
3519 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE));
3520
3521 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3522
3523 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003524
3525 // The WebGL specification leaves the behavior of storing NaN and
3526 // +/-Infinity into integer arrays basically undefined. For more
3527 // reproducible behavior, convert these to zero.
3528
3529 if (CpuFeatures::IsSupported(FPU)) {
3530 CpuFeatures::Scope scope(FPU);
3531
3532 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
3533
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003534 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003535 __ cvt_s_d(f0, f0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003536 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003537 __ addu(t8, a3, t8);
3538 __ swc1(f0, MemOperand(t8, 0));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003539 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003540 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003541 __ addu(t8, a3, t8);
3542 __ sdc1(f0, MemOperand(t8, 0));
3543 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003544 __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003545
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003546 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003547 case EXTERNAL_BYTE_ELEMENTS:
3548 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003549 __ srl(t8, key, 1);
3550 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003551 __ sb(t3, MemOperand(t8, 0));
3552 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003553 case EXTERNAL_SHORT_ELEMENTS:
3554 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003555 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003556 __ sh(t3, MemOperand(t8, 0));
3557 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003558 case EXTERNAL_INT_ELEMENTS:
3559 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003560 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003561 __ addu(t8, a3, t8);
3562 __ sw(t3, MemOperand(t8, 0));
3563 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003564 case EXTERNAL_PIXEL_ELEMENTS:
3565 case EXTERNAL_FLOAT_ELEMENTS:
3566 case EXTERNAL_DOUBLE_ELEMENTS:
3567 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003568 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003569 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003570 case FAST_HOLEY_ELEMENTS:
3571 case FAST_HOLEY_SMI_ELEMENTS:
3572 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003573 case DICTIONARY_ELEMENTS:
3574 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003575 UNREACHABLE();
3576 break;
3577 }
3578 }
3579
3580 // Entry registers are intact, a0 holds the value
3581 // which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003582 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003583 __ Ret();
3584 } else {
3585 // FPU is not available, do manual conversions.
3586
3587 __ lw(t3, FieldMemOperand(value, HeapNumber::kExponentOffset));
3588 __ lw(t4, FieldMemOperand(value, HeapNumber::kMantissaOffset));
3589
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003590 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003591 Label done, nan_or_infinity_or_zero;
3592 static const int kMantissaInHiWordShift =
3593 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3594
3595 static const int kMantissaInLoWordShift =
3596 kBitsPerInt - kMantissaInHiWordShift;
3597
3598 // Test for all special exponent values: zeros, subnormal numbers, NaNs
3599 // and infinities. All these should be converted to 0.
3600 __ li(t5, HeapNumber::kExponentMask);
3601 __ and_(t6, t3, t5);
3602 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(zero_reg));
3603
3604 __ xor_(t1, t6, t5);
3605 __ li(t2, kBinary32ExponentMask);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003606 __ Movz(t6, t2, t1); // Only if t6 is equal to t5.
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003607 __ Branch(&nan_or_infinity_or_zero, eq, t1, Operand(zero_reg));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003608
3609 // Rebias exponent.
3610 __ srl(t6, t6, HeapNumber::kExponentShift);
3611 __ Addu(t6,
3612 t6,
3613 Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
3614
3615 __ li(t1, Operand(kBinary32MaxExponent));
3616 __ Slt(t1, t1, t6);
3617 __ And(t2, t3, Operand(HeapNumber::kSignMask));
3618 __ Or(t2, t2, Operand(kBinary32ExponentMask));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003619 __ Movn(t3, t2, t1); // Only if t6 is gt kBinary32MaxExponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003620 __ Branch(&done, gt, t6, Operand(kBinary32MaxExponent));
3621
3622 __ Slt(t1, t6, Operand(kBinary32MinExponent));
3623 __ And(t2, t3, Operand(HeapNumber::kSignMask));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003624 __ Movn(t3, t2, t1); // Only if t6 is lt kBinary32MinExponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003625 __ Branch(&done, lt, t6, Operand(kBinary32MinExponent));
3626
3627 __ And(t7, t3, Operand(HeapNumber::kSignMask));
3628 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3629 __ sll(t3, t3, kMantissaInHiWordShift);
3630 __ or_(t7, t7, t3);
3631 __ srl(t4, t4, kMantissaInLoWordShift);
3632 __ or_(t7, t7, t4);
3633 __ sll(t6, t6, kBinary32ExponentShift);
3634 __ or_(t3, t7, t6);
3635
3636 __ bind(&done);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003637 __ sll(t9, key, 1);
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003638 __ addu(t9, a3, t9);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003639 __ sw(t3, MemOperand(t9, 0));
3640
3641 // Entry registers are intact, a0 holds the value which is the return
3642 // value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003643 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003644 __ Ret();
3645
3646 __ bind(&nan_or_infinity_or_zero);
3647 __ And(t7, t3, Operand(HeapNumber::kSignMask));
3648 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3649 __ or_(t6, t6, t7);
3650 __ sll(t3, t3, kMantissaInHiWordShift);
3651 __ or_(t6, t6, t3);
3652 __ srl(t4, t4, kMantissaInLoWordShift);
3653 __ or_(t3, t6, t4);
3654 __ Branch(&done);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003655 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003656 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003657 __ addu(t8, a3, t8);
3658 // t8: effective address of destination element.
3659 __ sw(t4, MemOperand(t8, 0));
3660 __ sw(t3, MemOperand(t8, Register::kSizeInBytes));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003661 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003662 __ Ret();
3663 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003664 bool is_signed_type = IsElementTypeSigned(elements_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003665 int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
3666 int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
3667
3668 Label done, sign;
3669
3670 // Test for all special exponent values: zeros, subnormal numbers, NaNs
3671 // and infinities. All these should be converted to 0.
3672 __ li(t5, HeapNumber::kExponentMask);
3673 __ and_(t6, t3, t5);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003674 __ Movz(t3, zero_reg, t6); // Only if t6 is equal to zero.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003675 __ Branch(&done, eq, t6, Operand(zero_reg));
3676
3677 __ xor_(t2, t6, t5);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003678 __ Movz(t3, zero_reg, t2); // Only if t6 is equal to t5.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003679 __ Branch(&done, eq, t6, Operand(t5));
3680
3681 // Unbias exponent.
3682 __ srl(t6, t6, HeapNumber::kExponentShift);
3683 __ Subu(t6, t6, Operand(HeapNumber::kExponentBias));
3684 // If exponent is negative then result is 0.
3685 __ slt(t2, t6, zero_reg);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003686 __ Movn(t3, zero_reg, t2); // Only if exponent is negative.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003687 __ Branch(&done, lt, t6, Operand(zero_reg));
3688
3689 // If exponent is too big then result is minimal value.
3690 __ slti(t1, t6, meaningfull_bits - 1);
3691 __ li(t2, min_value);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003692 __ Movz(t3, t2, t1); // Only if t6 is ge meaningfull_bits - 1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003693 __ Branch(&done, ge, t6, Operand(meaningfull_bits - 1));
3694
3695 __ And(t5, t3, Operand(HeapNumber::kSignMask));
3696 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3697 __ Or(t3, t3, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
3698
3699 __ li(t9, HeapNumber::kMantissaBitsInTopWord);
3700 __ subu(t6, t9, t6);
3701 __ slt(t1, t6, zero_reg);
3702 __ srlv(t2, t3, t6);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003703 __ Movz(t3, t2, t1); // Only if t6 is positive.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003704 __ Branch(&sign, ge, t6, Operand(zero_reg));
3705
3706 __ subu(t6, zero_reg, t6);
3707 __ sllv(t3, t3, t6);
3708 __ li(t9, meaningfull_bits);
3709 __ subu(t6, t9, t6);
3710 __ srlv(t4, t4, t6);
3711 __ or_(t3, t3, t4);
3712
3713 __ bind(&sign);
3714 __ subu(t2, t3, zero_reg);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003715 __ Movz(t3, t2, t5); // Only if t5 is zero.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003716
3717 __ bind(&done);
3718
3719 // Result is in t3.
3720 // This switch block should be exactly the same as above (FPU mode).
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003721 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003722 case EXTERNAL_BYTE_ELEMENTS:
3723 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003724 __ srl(t8, key, 1);
3725 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003726 __ sb(t3, MemOperand(t8, 0));
3727 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003728 case EXTERNAL_SHORT_ELEMENTS:
3729 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003730 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003731 __ sh(t3, MemOperand(t8, 0));
3732 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003733 case EXTERNAL_INT_ELEMENTS:
3734 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003735 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003736 __ addu(t8, a3, t8);
3737 __ sw(t3, MemOperand(t8, 0));
3738 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003739 case EXTERNAL_PIXEL_ELEMENTS:
3740 case EXTERNAL_FLOAT_ELEMENTS:
3741 case EXTERNAL_DOUBLE_ELEMENTS:
3742 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003743 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003744 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003745 case FAST_HOLEY_ELEMENTS:
3746 case FAST_HOLEY_SMI_ELEMENTS:
3747 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003748 case DICTIONARY_ELEMENTS:
3749 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003750 UNREACHABLE();
3751 break;
3752 }
3753 }
3754 }
3755 }
3756
danno@chromium.org40cb8782011-05-25 07:58:50 +00003757 // Slow case, key and receiver still in a0 and a1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003758 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003759 __ IncrementCounter(
3760 masm->isolate()->counters()->keyed_load_external_array_slow(),
3761 1, a2, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003762 // Entry registers are intact.
3763 // ---------- S t a t e --------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003764 // -- ra : return address
danno@chromium.org40cb8782011-05-25 07:58:50 +00003765 // -- a0 : key
3766 // -- a1 : receiver
3767 // -----------------------------------
3768 Handle<Code> slow_ic =
3769 masm->isolate()->builtins()->KeyedStoreIC_Slow();
3770 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
3771
3772 // Miss case, call the runtime.
3773 __ bind(&miss_force_generic);
3774
3775 // ---------- S t a t e --------------
3776 // -- ra : return address
3777 // -- a0 : key
3778 // -- a1 : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003779 // -----------------------------------
3780
danno@chromium.org40cb8782011-05-25 07:58:50 +00003781 Handle<Code> miss_ic =
3782 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
3783 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3784}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003785
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003786
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003787void KeyedStoreStubCompiler::GenerateStoreFastElement(
3788 MacroAssembler* masm,
3789 bool is_js_array,
yangguo@chromium.org56454712012-02-16 15:33:53 +00003790 ElementsKind elements_kind,
3791 KeyedAccessGrowMode grow_mode) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003792 // ----------- S t a t e -------------
3793 // -- a0 : value
3794 // -- a1 : key
3795 // -- a2 : receiver
3796 // -- ra : return address
3797 // -- a3 : scratch
3798 // -- a4 : scratch (elements)
3799 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00003800 Label miss_force_generic, transition_elements_kind, grow, slow;
3801 Label finish_store, check_capacity;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003802
3803 Register value_reg = a0;
3804 Register key_reg = a1;
3805 Register receiver_reg = a2;
yangguo@chromium.org56454712012-02-16 15:33:53 +00003806 Register scratch = t0;
3807 Register elements_reg = a3;
3808 Register length_reg = t1;
3809 Register scratch2 = t2;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003810
3811 // This stub is meant to be tail-jumped to, the receiver must already
3812 // have been verified by the caller to not be a smi.
3813
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003814 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003815 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003816
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003817 if (IsFastSmiElementsKind(elements_kind)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003818 __ JumpIfNotSmi(value_reg, &transition_elements_kind);
3819 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003820
3821 // Check that the key is within bounds.
yangguo@chromium.org56454712012-02-16 15:33:53 +00003822 __ lw(elements_reg,
3823 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003824 if (is_js_array) {
3825 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3826 } else {
3827 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3828 }
3829 // Compare smis.
yangguo@chromium.org56454712012-02-16 15:33:53 +00003830 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
3831 __ Branch(&grow, hs, key_reg, Operand(scratch));
3832 } else {
3833 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
3834 }
3835
3836 // Make sure elements is a fast element array, not 'cow'.
3837 __ CheckMap(elements_reg,
3838 scratch,
3839 Heap::kFixedArrayMapRootIndex,
3840 &miss_force_generic,
3841 DONT_DO_SMI_CHECK);
3842
3843 __ bind(&finish_store);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003844
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003845 if (IsFastSmiElementsKind(elements_kind)) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003846 __ Addu(scratch,
3847 elements_reg,
3848 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3849 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
3850 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
3851 __ Addu(scratch, scratch, scratch2);
3852 __ sw(value_reg, MemOperand(scratch));
3853 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003854 ASSERT(IsFastObjectElementsKind(elements_kind));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003855 __ Addu(scratch,
3856 elements_reg,
3857 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3858 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
3859 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
3860 __ Addu(scratch, scratch, scratch2);
3861 __ sw(value_reg, MemOperand(scratch));
3862 __ mov(receiver_reg, value_reg);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003863 __ RecordWrite(elements_reg, // Object.
3864 scratch, // Address.
3865 receiver_reg, // Value.
3866 kRAHasNotBeenSaved,
3867 kDontSaveFPRegs);
3868 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003869 // value_reg (a0) is preserved.
3870 // Done.
3871 __ Ret();
3872
3873 __ bind(&miss_force_generic);
3874 Handle<Code> ic =
3875 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
3876 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003877
3878 __ bind(&transition_elements_kind);
3879 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
3880 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003881
3882 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
3883 // Grow the array by a single element if possible.
3884 __ bind(&grow);
3885
3886 // Make sure the array is only growing by a single element, anything else
3887 // must be handled by the runtime.
3888 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch));
3889
3890 // Check for the empty array, and preallocate a small backing store if
3891 // possible.
3892 __ lw(length_reg,
3893 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3894 __ lw(elements_reg,
3895 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3896 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
3897 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
3898
3899 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
3900 __ AllocateInNewSpace(size, elements_reg, scratch, scratch2, &slow,
3901 TAG_OBJECT);
3902
3903 __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex);
3904 __ sw(scratch, FieldMemOperand(elements_reg, JSObject::kMapOffset));
3905 __ li(scratch, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
3906 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3907 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
3908 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
3909 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::SizeFor(i)));
3910 }
3911
3912 // Store the element at index zero.
3913 __ sw(value_reg, FieldMemOperand(elements_reg, FixedArray::SizeFor(0)));
3914
3915 // Install the new backing store in the JSArray.
3916 __ sw(elements_reg,
3917 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3918 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
3919 scratch, kRAHasNotBeenSaved, kDontSaveFPRegs,
3920 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
3921
3922 // Increment the length of the array.
3923 __ li(length_reg, Operand(Smi::FromInt(1)));
3924 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3925 __ Ret();
3926
3927 __ bind(&check_capacity);
3928 // Check for cow elements, in general they are not handled by this stub
3929 __ CheckMap(elements_reg,
3930 scratch,
3931 Heap::kFixedCOWArrayMapRootIndex,
3932 &miss_force_generic,
3933 DONT_DO_SMI_CHECK);
3934
3935 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3936 __ Branch(&slow, hs, length_reg, Operand(scratch));
3937
3938 // Grow the array and finish the store.
3939 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
3940 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3941 __ jmp(&finish_store);
3942
3943 __ bind(&slow);
3944 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
3945 __ Jump(ic_slow, RelocInfo::CODE_TARGET);
3946 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003947}
3948
3949
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003950void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
3951 MacroAssembler* masm,
yangguo@chromium.org56454712012-02-16 15:33:53 +00003952 bool is_js_array,
3953 KeyedAccessGrowMode grow_mode) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003954 // ----------- S t a t e -------------
3955 // -- a0 : value
3956 // -- a1 : key
3957 // -- a2 : receiver
3958 // -- ra : return address
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003959 // -- a3 : scratch (elements backing store)
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003960 // -- t0 : scratch (elements_reg)
3961 // -- t1 : scratch (mantissa_reg)
3962 // -- t2 : scratch (exponent_reg)
3963 // -- t3 : scratch4
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003964 // -- t4 : scratch
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003965 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00003966 Label miss_force_generic, transition_elements_kind, grow, slow;
3967 Label finish_store, check_capacity;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003968
3969 Register value_reg = a0;
3970 Register key_reg = a1;
3971 Register receiver_reg = a2;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003972 Register elements_reg = a3;
3973 Register scratch1 = t0;
3974 Register scratch2 = t1;
3975 Register scratch3 = t2;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003976 Register scratch4 = t3;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003977 Register scratch5 = t4;
yangguo@chromium.org56454712012-02-16 15:33:53 +00003978 Register length_reg = t3;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003979
3980 // This stub is meant to be tail-jumped to, the receiver must already
3981 // have been verified by the caller to not be a smi.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003982
3983 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003984 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003985
3986 __ lw(elements_reg,
3987 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3988
3989 // Check that the key is within bounds.
3990 if (is_js_array) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003991 __ lw(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003992 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003993 __ lw(scratch1,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003994 FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3995 }
3996 // Compare smis, unsigned compare catches both negative and out-of-bound
3997 // indexes.
yangguo@chromium.org56454712012-02-16 15:33:53 +00003998 if (grow_mode == ALLOW_JSARRAY_GROWTH) {
3999 __ Branch(&grow, hs, key_reg, Operand(scratch1));
4000 } else {
4001 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch1));
4002 }
4003
4004 __ bind(&finish_store);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004005
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004006 __ StoreNumberToDoubleElements(value_reg,
4007 key_reg,
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004008 // All registers after this are overwritten.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004009 elements_reg,
4010 scratch1,
4011 scratch2,
4012 scratch3,
4013 scratch4,
4014 &transition_elements_kind);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004015
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004016 __ Ret(USE_DELAY_SLOT);
4017 __ mov(v0, value_reg); // In delay slot.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004018
4019 // Handle store cache miss, replacing the ic with the generic stub.
4020 __ bind(&miss_force_generic);
4021 Handle<Code> ic =
4022 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4023 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004024
4025 __ bind(&transition_elements_kind);
4026 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4027 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
yangguo@chromium.org56454712012-02-16 15:33:53 +00004028
4029 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4030 // Grow the array by a single element if possible.
4031 __ bind(&grow);
4032
4033 // Make sure the array is only growing by a single element, anything else
4034 // must be handled by the runtime.
4035 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch1));
4036
4037 // Transition on values that can't be stored in a FixedDoubleArray.
4038 Label value_is_smi;
4039 __ JumpIfSmi(value_reg, &value_is_smi);
4040 __ lw(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
4041 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
4042 __ Branch(&transition_elements_kind, ne, scratch1, Operand(at));
4043 __ bind(&value_is_smi);
4044
4045 // Check for the empty array, and preallocate a small backing store if
4046 // possible.
4047 __ lw(length_reg,
4048 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4049 __ lw(elements_reg,
4050 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4051 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
4052 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
4053
4054 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
4055 __ AllocateInNewSpace(size, elements_reg, scratch1, scratch2, &slow,
4056 TAG_OBJECT);
4057
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004058 // Initialize the new FixedDoubleArray.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004059 __ LoadRoot(scratch1, Heap::kFixedDoubleArrayMapRootIndex);
4060 __ sw(scratch1, FieldMemOperand(elements_reg, JSObject::kMapOffset));
4061 __ li(scratch1, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4062 __ sw(scratch1,
4063 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
4064
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004065 __ mov(scratch1, elements_reg);
4066 __ StoreNumberToDoubleElements(value_reg,
4067 key_reg,
4068 // All registers after this are overwritten.
4069 scratch1,
4070 scratch2,
4071 scratch3,
4072 scratch4,
4073 scratch5,
4074 &transition_elements_kind);
4075
4076 __ li(scratch1, Operand(kHoleNanLower32));
4077 __ li(scratch2, Operand(kHoleNanUpper32));
4078 for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) {
4079 int offset = FixedDoubleArray::OffsetOfElementAt(i);
4080 __ sw(scratch1, FieldMemOperand(elements_reg, offset));
4081 __ sw(scratch2, FieldMemOperand(elements_reg, offset + kPointerSize));
4082 }
4083
yangguo@chromium.org56454712012-02-16 15:33:53 +00004084 // Install the new backing store in the JSArray.
4085 __ sw(elements_reg,
4086 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4087 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
4088 scratch1, kRAHasNotBeenSaved, kDontSaveFPRegs,
4089 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4090
4091 // Increment the length of the array.
4092 __ li(length_reg, Operand(Smi::FromInt(1)));
4093 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
danno@chromium.org00379b82012-05-04 09:16:29 +00004094 __ lw(elements_reg,
4095 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004096 __ Ret();
yangguo@chromium.org56454712012-02-16 15:33:53 +00004097
4098 __ bind(&check_capacity);
4099 // Make sure that the backing store can hold additional elements.
4100 __ lw(scratch1,
4101 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
4102 __ Branch(&slow, hs, length_reg, Operand(scratch1));
4103
4104 // Grow the array and finish the store.
4105 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
4106 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4107 __ jmp(&finish_store);
4108
4109 __ bind(&slow);
4110 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4111 __ Jump(ic_slow, RelocInfo::CODE_TARGET);
4112 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004113}
4114
4115
ager@chromium.org5c838252010-02-19 08:53:10 +00004116#undef __
4117
4118} } // namespace v8::internal
4119
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004120#endif // V8_TARGET_ARCH_MIPS