blob: 323933b5de4cd10657a6a8f6b12dd16bb1293222 [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
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000582static void GenerateCallFunction(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000583 Handle<Object> object,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000584 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000585 Label* miss,
586 Code::ExtraICState extra_ic_state) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000587 // ----------- S t a t e -------------
588 // -- a0: receiver
589 // -- a1: function to call
590 // -----------------------------------
591 // Check that the function really is a function.
592 __ JumpIfSmi(a1, miss);
593 __ GetObjectType(a1, a3, a3);
594 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
595
596 // Patch the receiver on the stack with the global proxy if
597 // necessary.
598 if (object->IsGlobalObject()) {
599 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
600 __ sw(a3, MemOperand(sp, arguments.immediate() * kPointerSize));
601 }
602
603 // Invoke the function.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000604 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
605 ? CALL_AS_FUNCTION
606 : CALL_AS_METHOD;
607 __ InvokeFunction(a1, arguments, JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000608}
609
610
611static void PushInterceptorArguments(MacroAssembler* masm,
612 Register receiver,
613 Register holder,
614 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000615 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000616 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000617 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
618 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000619 Register scratch = name;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000620 __ li(scratch, Operand(interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000621 __ Push(scratch, receiver, holder);
622 __ lw(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
623 __ push(scratch);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000624 __ li(scratch, Operand(ExternalReference::isolate_address()));
625 __ push(scratch);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000626}
627
628
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000629static void CompileCallLoadPropertyWithInterceptor(
630 MacroAssembler* masm,
631 Register receiver,
632 Register holder,
633 Register name,
634 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000635 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
636
637 ExternalReference ref =
638 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
639 masm->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000640 __ PrepareCEntryArgs(6);
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000641 __ PrepareCEntryFunction(ref);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000642
643 CEntryStub stub(1);
644 __ CallStub(&stub);
645}
646
647
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000648static const int kFastApiCallArguments = 4;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000649
650
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000651// Reserves space for the extra arguments to API function in the
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000652// caller's frame.
653//
654// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
655static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
656 Register scratch) {
657 ASSERT(Smi::FromInt(0) == 0);
658 for (int i = 0; i < kFastApiCallArguments; i++) {
659 __ push(zero_reg);
660 }
661}
662
663
664// Undoes the effects of ReserveSpaceForFastApiCall.
665static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
666 __ Drop(kFastApiCallArguments);
667}
668
669
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000670static void GenerateFastApiDirectCall(MacroAssembler* masm,
671 const CallOptimization& optimization,
672 int argc) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000673 // ----------- S t a t e -------------
674 // -- sp[0] : holder (set by CheckPrototypes)
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000675 // -- sp[4] : callee JS function
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000676 // -- sp[8] : call data
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000677 // -- sp[12] : isolate
678 // -- sp[16] : last JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000679 // -- ...
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000680 // -- sp[(argc + 3) * 4] : first JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000681 // -- sp[(argc + 4) * 4] : receiver
682 // -----------------------------------
683 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000684 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000685 __ LoadHeapObject(t1, function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000686 __ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset));
687
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000688 // Pass the additional arguments.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000689 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
690 Handle<Object> call_data(api_call_info->data());
691 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
692 __ li(a0, api_call_info);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000693 __ lw(t2, FieldMemOperand(a0, CallHandlerInfo::kDataOffset));
694 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000695 __ li(t2, call_data);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000696 }
697
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000698 __ li(t3, Operand(ExternalReference::isolate_address()));
699 // Store JS function, call data and isolate.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000700 __ sw(t1, MemOperand(sp, 1 * kPointerSize));
701 __ sw(t2, MemOperand(sp, 2 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000702 __ sw(t3, MemOperand(sp, 3 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000703
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000704 // Prepare arguments.
705 __ Addu(a2, sp, Operand(3 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000706
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000707 // Allocate the v8::Arguments structure in the arguments' space since
708 // it's not controlled by GC.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000709 const int kApiStackSpace = 4;
710
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000711 FrameScope frame_scope(masm, StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000712 __ EnterExitFrame(false, kApiStackSpace);
713
714 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
715 // struct from the function (which is currently the case). This means we pass
716 // the first argument in a1 instead of a0. TryCallApiFunctionAndReturn
717 // will handle setting up a0.
718
719 // a1 = v8::Arguments&
720 // Arguments is built at sp + 1 (sp is a reserved spot for ra).
721 __ Addu(a1, sp, kPointerSize);
722
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000723 // v8::Arguments::implicit_args_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000724 __ sw(a2, MemOperand(a1, 0 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000725 // v8::Arguments::values_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000726 __ Addu(t0, a2, Operand(argc * kPointerSize));
727 __ sw(t0, MemOperand(a1, 1 * kPointerSize));
728 // v8::Arguments::length_ = argc
729 __ li(t0, Operand(argc));
730 __ sw(t0, MemOperand(a1, 2 * kPointerSize));
731 // v8::Arguments::is_construct_call = 0
732 __ sw(zero_reg, MemOperand(a1, 3 * kPointerSize));
733
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000734 const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000735 Address function_address = v8::ToCData<Address>(api_call_info->callback());
736 ApiFunction fun(function_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000737 ExternalReference ref =
738 ExternalReference(&fun,
739 ExternalReference::DIRECT_API_CALL,
740 masm->isolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000741 AllowExternalCallThatCantCauseGC scope(masm);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000742 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000743}
744
lrn@chromium.org7516f052011-03-30 08:52:27 +0000745class CallInterceptorCompiler BASE_EMBEDDED {
746 public:
747 CallInterceptorCompiler(StubCompiler* stub_compiler,
748 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000749 Register name,
750 Code::ExtraICState extra_ic_state)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000751 : stub_compiler_(stub_compiler),
752 arguments_(arguments),
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000753 name_(name),
754 extra_ic_state_(extra_ic_state) {}
lrn@chromium.org7516f052011-03-30 08:52:27 +0000755
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000756 void Compile(MacroAssembler* masm,
757 Handle<JSObject> object,
758 Handle<JSObject> holder,
759 Handle<String> name,
760 LookupResult* lookup,
761 Register receiver,
762 Register scratch1,
763 Register scratch2,
764 Register scratch3,
765 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000766 ASSERT(holder->HasNamedInterceptor());
767 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
768
769 // Check that the receiver isn't a smi.
770 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000771 CallOptimization optimization(lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000772 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000773 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
774 holder, lookup, name, optimization, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000775 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000776 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
777 name, holder, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000778 }
779 }
780
781 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000782 void CompileCacheable(MacroAssembler* masm,
783 Handle<JSObject> object,
784 Register receiver,
785 Register scratch1,
786 Register scratch2,
787 Register scratch3,
788 Handle<JSObject> interceptor_holder,
789 LookupResult* lookup,
790 Handle<String> name,
791 const CallOptimization& optimization,
792 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000793 ASSERT(optimization.is_constant_call());
794 ASSERT(!lookup->holder()->IsGlobalObject());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000795 Counters* counters = masm->isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000796 int depth1 = kInvalidProtoDepth;
797 int depth2 = kInvalidProtoDepth;
798 bool can_do_fast_api_call = false;
799 if (optimization.is_simple_api_call() &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000800 !lookup->holder()->IsGlobalObject()) {
801 depth1 = optimization.GetPrototypeDepthOfExpectedType(
802 object, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000803 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000804 depth2 = optimization.GetPrototypeDepthOfExpectedType(
805 interceptor_holder, Handle<JSObject>(lookup->holder()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000806 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000807 can_do_fast_api_call =
808 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000809 }
810
811 __ IncrementCounter(counters->call_const_interceptor(), 1,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000812 scratch1, scratch2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000813
814 if (can_do_fast_api_call) {
815 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
816 scratch1, scratch2);
817 ReserveSpaceForFastApiCall(masm, scratch1);
818 }
819
820 // Check that the maps from receiver to interceptor's holder
821 // haven't changed and thus we can invoke interceptor.
822 Label miss_cleanup;
823 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
824 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000825 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
826 scratch1, scratch2, scratch3,
827 name, depth1, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000828
829 // Invoke an interceptor and if it provides a value,
830 // branch to |regular_invoke|.
831 Label regular_invoke;
832 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
833 &regular_invoke);
834
835 // Interceptor returned nothing for this property. Try to use cached
836 // constant function.
837
838 // Check that the maps from interceptor's holder to constant function's
839 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000840 if (*interceptor_holder != lookup->holder()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000841 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000842 Handle<JSObject>(lookup->holder()),
843 scratch1, scratch2, scratch3,
844 name, depth2, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000845 } else {
846 // CheckPrototypes has a side effect of fetching a 'holder'
847 // for API (object which is instanceof for the signature). It's
848 // safe to omit it here, as if present, it should be fetched
849 // by the previous CheckPrototypes.
850 ASSERT(depth2 == kInvalidProtoDepth);
851 }
852
853 // Invoke function.
854 if (can_do_fast_api_call) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000855 GenerateFastApiDirectCall(masm, optimization, arguments_.immediate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000856 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000857 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
858 ? CALL_AS_FUNCTION
859 : CALL_AS_METHOD;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000860 __ InvokeFunction(optimization.constant_function(), arguments_,
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000861 JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000862 }
863
864 // Deferred code for fast API call case---clean preallocated space.
865 if (can_do_fast_api_call) {
866 __ bind(&miss_cleanup);
867 FreeSpaceForFastApiCall(masm);
868 __ Branch(miss_label);
869 }
870
871 // Invoke a regular function.
872 __ bind(&regular_invoke);
873 if (can_do_fast_api_call) {
874 FreeSpaceForFastApiCall(masm);
875 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000876 }
877
878 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000879 Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000880 Register receiver,
881 Register scratch1,
882 Register scratch2,
883 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000884 Handle<String> name,
885 Handle<JSObject> interceptor_holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000886 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000887 Register holder =
888 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000889 scratch1, scratch2, scratch3,
890 name, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000891
892 // Call a runtime function to load the interceptor property.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000893 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000894 // Save the name_ register across the call.
895 __ push(name_);
896
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000897 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000898
899 __ CallExternalReference(
900 ExternalReference(
901 IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
902 masm->isolate()),
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000903 6);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000904 // Restore the name_ register.
905 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000906 // Leave the internal frame.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000907 }
908
909 void LoadWithInterceptor(MacroAssembler* masm,
910 Register receiver,
911 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000912 Handle<JSObject> holder_obj,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000913 Register scratch,
914 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000915 {
916 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000917
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000918 __ Push(holder, name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000919 CompileCallLoadPropertyWithInterceptor(masm,
920 receiver,
921 holder,
922 name_,
923 holder_obj);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000924 __ pop(name_); // Restore the name.
925 __ pop(receiver); // Restore the holder.
926 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000927 // If interceptor returns no-result sentinel, call the constant function.
928 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
929 __ Branch(interceptor_succeeded, ne, v0, Operand(scratch));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000930 }
931
932 StubCompiler* stub_compiler_;
933 const ParameterCount& arguments_;
934 Register name_;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000935 Code::ExtraICState extra_ic_state_;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000936};
937
938
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000939
940// Generate code to check that a global property cell is empty. Create
941// the property cell at compilation time if no cell exists for the
942// property.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000943static void GenerateCheckPropertyCell(MacroAssembler* masm,
944 Handle<GlobalObject> global,
945 Handle<String> name,
946 Register scratch,
947 Label* miss) {
948 Handle<JSGlobalPropertyCell> cell =
949 GlobalObject::EnsurePropertyCell(global, name);
950 ASSERT(cell->value()->IsTheHole());
951 __ li(scratch, Operand(cell));
952 __ lw(scratch,
953 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
954 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
955 __ Branch(miss, ne, scratch, Operand(at));
956}
957
958
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000959// Calls GenerateCheckPropertyCell for each global object in the prototype chain
960// from object to (but not including) holder.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000961static void GenerateCheckPropertyCells(MacroAssembler* masm,
962 Handle<JSObject> object,
963 Handle<JSObject> holder,
964 Handle<String> name,
965 Register scratch,
966 Label* miss) {
967 Handle<JSObject> current = object;
968 while (!current.is_identical_to(holder)) {
969 if (current->IsGlobalObject()) {
970 GenerateCheckPropertyCell(masm,
971 Handle<GlobalObject>::cast(current),
972 name,
973 scratch,
974 miss);
975 }
976 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
977 }
978}
979
980
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000981// Convert and store int passed in register ival to IEEE 754 single precision
982// floating point value at memory location (dst + 4 * wordoffset)
983// If FPU is available use it for conversion.
984static void StoreIntAsFloat(MacroAssembler* masm,
985 Register dst,
986 Register wordoffset,
987 Register ival,
988 Register fval,
989 Register scratch1,
990 Register scratch2) {
991 if (CpuFeatures::IsSupported(FPU)) {
992 CpuFeatures::Scope scope(FPU);
993 __ mtc1(ival, f0);
994 __ cvt_s_w(f0, f0);
995 __ sll(scratch1, wordoffset, 2);
996 __ addu(scratch1, dst, scratch1);
997 __ swc1(f0, MemOperand(scratch1, 0));
998 } else {
999 // FPU is not available, do manual conversions.
1000
1001 Label not_special, done;
1002 // Move sign bit from source to destination. This works because the sign
1003 // bit in the exponent word of the double has the same position and polarity
1004 // as the 2's complement sign bit in a Smi.
1005 ASSERT(kBinary32SignMask == 0x80000000u);
1006
1007 __ And(fval, ival, Operand(kBinary32SignMask));
1008 // Negate value if it is negative.
1009 __ subu(scratch1, zero_reg, ival);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001010 __ Movn(ival, scratch1, fval);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001011
1012 // We have -1, 0 or 1, which we treat specially. Register ival contains
1013 // absolute value: it is either equal to 1 (special case of -1 and 1),
1014 // greater than 1 (not a special case) or less than 1 (special case of 0).
1015 __ Branch(&not_special, gt, ival, Operand(1));
1016
1017 // For 1 or -1 we need to or in the 0 exponent (biased).
1018 static const uint32_t exponent_word_for_1 =
1019 kBinary32ExponentBias << kBinary32ExponentShift;
1020
1021 __ Xor(scratch1, ival, Operand(1));
1022 __ li(scratch2, exponent_word_for_1);
1023 __ or_(scratch2, fval, scratch2);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001024 __ Movz(fval, scratch2, scratch1); // Only if ival is equal to 1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001025 __ Branch(&done);
1026
1027 __ bind(&not_special);
1028 // Count leading zeros.
1029 // Gets the wrong answer for 0, but we already checked for that case above.
1030 Register zeros = scratch2;
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001031 __ Clz(zeros, ival);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001032
1033 // Compute exponent and or it into the exponent register.
1034 __ li(scratch1, (kBitsPerInt - 1) + kBinary32ExponentBias);
1035 __ subu(scratch1, scratch1, zeros);
1036
1037 __ sll(scratch1, scratch1, kBinary32ExponentShift);
1038 __ or_(fval, fval, scratch1);
1039
1040 // Shift up the source chopping the top bit off.
1041 __ Addu(zeros, zeros, Operand(1));
1042 // This wouldn't work for 1 and -1 as the shift would be 32 which means 0.
1043 __ sllv(ival, ival, zeros);
1044 // And the top (top 20 bits).
1045 __ srl(scratch1, ival, kBitsPerInt - kBinary32MantissaBits);
1046 __ or_(fval, fval, scratch1);
1047
1048 __ bind(&done);
1049
1050 __ sll(scratch1, wordoffset, 2);
1051 __ addu(scratch1, dst, scratch1);
1052 __ sw(fval, MemOperand(scratch1, 0));
1053 }
1054}
1055
1056
1057// Convert unsigned integer with specified number of leading zeroes in binary
1058// representation to IEEE 754 double.
1059// Integer to convert is passed in register hiword.
1060// Resulting double is returned in registers hiword:loword.
1061// This functions does not work correctly for 0.
1062static void GenerateUInt2Double(MacroAssembler* masm,
1063 Register hiword,
1064 Register loword,
1065 Register scratch,
1066 int leading_zeroes) {
1067 const int meaningful_bits = kBitsPerInt - leading_zeroes - 1;
1068 const int biased_exponent = HeapNumber::kExponentBias + meaningful_bits;
1069
1070 const int mantissa_shift_for_hi_word =
1071 meaningful_bits - HeapNumber::kMantissaBitsInTopWord;
1072
1073 const int mantissa_shift_for_lo_word =
1074 kBitsPerInt - mantissa_shift_for_hi_word;
1075
1076 __ li(scratch, biased_exponent << HeapNumber::kExponentShift);
1077 if (mantissa_shift_for_hi_word > 0) {
1078 __ sll(loword, hiword, mantissa_shift_for_lo_word);
1079 __ srl(hiword, hiword, mantissa_shift_for_hi_word);
1080 __ or_(hiword, scratch, hiword);
1081 } else {
1082 __ mov(loword, zero_reg);
1083 __ sll(hiword, hiword, mantissa_shift_for_hi_word);
1084 __ or_(hiword, scratch, hiword);
1085 }
1086
1087 // If least significant bit of biased exponent was not 1 it was corrupted
1088 // by most significant bit of mantissa so we should fix that.
1089 if (!(biased_exponent & 1)) {
1090 __ li(scratch, 1 << HeapNumber::kExponentShift);
1091 __ nor(scratch, scratch, scratch);
1092 __ and_(hiword, hiword, scratch);
1093 }
1094}
1095
1096
ager@chromium.org5c838252010-02-19 08:53:10 +00001097#undef __
1098#define __ ACCESS_MASM(masm())
1099
1100
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001101Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
1102 Register object_reg,
1103 Handle<JSObject> holder,
1104 Register holder_reg,
1105 Register scratch1,
1106 Register scratch2,
1107 Handle<String> name,
1108 int save_at_depth,
1109 Label* miss) {
1110 // Make sure there's no overlap between holder and object registers.
1111 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1112 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1113 && !scratch2.is(scratch1));
1114
1115 // Keep track of the current object in register reg.
1116 Register reg = object_reg;
1117 int depth = 0;
1118
1119 if (save_at_depth == depth) {
1120 __ sw(reg, MemOperand(sp));
1121 }
1122
1123 // Check the maps in the prototype chain.
1124 // Traverse the prototype chain from the object and do map checks.
1125 Handle<JSObject> current = object;
1126 while (!current.is_identical_to(holder)) {
1127 ++depth;
1128
1129 // Only global objects and objects that do not require access
1130 // checks are allowed in stubs.
1131 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1132
1133 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
1134 if (!current->HasFastProperties() &&
1135 !current->IsJSGlobalObject() &&
1136 !current->IsJSGlobalProxy()) {
1137 if (!name->IsSymbol()) {
1138 name = factory()->LookupSymbol(name);
1139 }
1140 ASSERT(current->property_dictionary()->FindEntry(*name) ==
1141 StringDictionary::kNotFound);
1142
1143 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1144 scratch1, scratch2);
1145
1146 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1147 reg = holder_reg; // From now on the object will be in holder_reg.
1148 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1149 } else {
1150 Handle<Map> current_map(current->map());
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001151 __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK,
1152 ALLOW_ELEMENT_TRANSITION_MAPS);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001153 // Check access rights to the global object. This has to happen after
1154 // the map check so that we know that the object is actually a global
1155 // object.
1156 if (current->IsJSGlobalProxy()) {
1157 __ CheckAccessGlobalProxy(reg, scratch2, miss);
1158 }
1159 reg = holder_reg; // From now on the object will be in holder_reg.
1160
1161 if (heap()->InNewSpace(*prototype)) {
1162 // The prototype is in new space; we cannot store a reference to it
1163 // in the code. Load it from the map.
1164 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1165 } else {
1166 // The prototype is in old space; load it directly.
1167 __ li(reg, Operand(prototype));
1168 }
1169 }
1170
1171 if (save_at_depth == depth) {
1172 __ sw(reg, MemOperand(sp));
1173 }
1174
1175 // Go to the next object in the prototype chain.
1176 current = prototype;
1177 }
1178
1179 // Log the check depth.
1180 LOG(masm()->isolate(), IntEvent("check-maps-depth", depth + 1));
1181
1182 // Check the holder map.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001183 __ CheckMap(reg, scratch1, Handle<Map>(current->map()), miss,
1184 DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001185
1186 // Perform security check for access to the global object.
1187 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1188 if (holder->IsJSGlobalProxy()) {
1189 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1190 }
1191
1192 // If we've skipped any global objects, it's not enough to verify that
1193 // their maps haven't changed. We also need to check that the property
1194 // cell for the property is still empty.
1195 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1196
1197 // Return the register containing the holder.
1198 return reg;
1199}
1200
1201
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001202void StubCompiler::GenerateLoadField(Handle<JSObject> object,
1203 Handle<JSObject> holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001204 Register receiver,
1205 Register scratch1,
1206 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001207 Register scratch3,
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00001208 PropertyIndex index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001209 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001210 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001211 // Check that the receiver isn't a smi.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001212 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001213
1214 // Check that the maps haven't changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001215 Register reg = CheckPrototypes(
1216 object, receiver, holder, scratch1, scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001217 GenerateFastPropertyLoad(masm(), v0, reg, holder, index);
1218 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001219}
1220
1221
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001222void StubCompiler::GenerateLoadConstant(Handle<JSObject> object,
1223 Handle<JSObject> holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001224 Register receiver,
1225 Register scratch1,
1226 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001227 Register scratch3,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001228 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001229 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001230 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001231 // Check that the receiver isn't a smi.
1232 __ JumpIfSmi(receiver, miss, scratch1);
1233
1234 // Check that the maps haven't changed.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001235 CheckPrototypes(object, receiver, holder,
1236 scratch1, scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001237
1238 // Return the constant value.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001239 __ LoadHeapObject(v0, value);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001240 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001241}
1242
1243
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001244void StubCompiler::GenerateDictionaryLoadCallback(Register receiver,
1245 Register name_reg,
1246 Register scratch1,
1247 Register scratch2,
1248 Register scratch3,
1249 Handle<AccessorInfo> callback,
1250 Handle<String> name,
1251 Label* miss) {
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001252 ASSERT(!receiver.is(scratch1));
1253 ASSERT(!receiver.is(scratch2));
1254 ASSERT(!receiver.is(scratch3));
1255
1256 // Load the properties dictionary.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001257 Register dictionary = scratch1;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001258 __ lw(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
1259
1260 // Probe the dictionary.
1261 Label probe_done;
1262 StringDictionaryLookupStub::GeneratePositiveLookup(masm(),
1263 miss,
1264 &probe_done,
1265 dictionary,
1266 name_reg,
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001267 scratch2,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001268 scratch3);
1269 __ bind(&probe_done);
1270
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001271 // If probing finds an entry in the dictionary, scratch3 contains the
1272 // pointer into the dictionary. Check that the value is the callback.
1273 Register pointer = scratch3;
1274 const int kElementsStartOffset = StringDictionary::kHeaderSize +
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001275 StringDictionary::kElementsStartIndex * kPointerSize;
1276 const int kValueOffset = kElementsStartOffset + kPointerSize;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001277 __ lw(scratch2, FieldMemOperand(pointer, kValueOffset));
1278 __ Branch(miss, ne, scratch2, Operand(callback));
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001279}
1280
1281
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001282void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
1283 Handle<JSObject> holder,
1284 Register receiver,
1285 Register name_reg,
1286 Register scratch1,
1287 Register scratch2,
1288 Register scratch3,
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001289 Register scratch4,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001290 Handle<AccessorInfo> callback,
1291 Handle<String> name,
1292 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001293 // Check that the receiver isn't a smi.
1294 __ JumpIfSmi(receiver, miss, scratch1);
1295
1296 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001297 Register reg = CheckPrototypes(object, receiver, holder, scratch1,
1298 scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001299
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001300 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
1301 GenerateDictionaryLoadCallback(
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001302 reg, name_reg, scratch2, scratch3, scratch4, callback, name, miss);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001303 }
1304
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001305 // Build AccessorInfo::args_ list on the stack and push property name below
1306 // the exit frame to make GC aware of them and store pointers to them.
1307 __ push(receiver);
1308 __ mov(scratch2, sp); // scratch2 = AccessorInfo::args_
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001309 if (heap()->InNewSpace(callback->data())) {
1310 __ li(scratch3, callback);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001311 __ lw(scratch3, FieldMemOperand(scratch3, AccessorInfo::kDataOffset));
1312 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001313 __ li(scratch3, Handle<Object>(callback->data()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001314 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001315 __ Subu(sp, sp, 4 * kPointerSize);
1316 __ sw(reg, MemOperand(sp, 3 * kPointerSize));
1317 __ sw(scratch3, MemOperand(sp, 2 * kPointerSize));
1318 __ li(scratch3, Operand(ExternalReference::isolate_address()));
1319 __ sw(scratch3, MemOperand(sp, 1 * kPointerSize));
1320 __ sw(name_reg, MemOperand(sp, 0 * kPointerSize));
1321
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001322 __ mov(a2, scratch2); // Saved in case scratch2 == a1.
1323 __ mov(a1, sp); // a1 (first argument - see note below) = Handle<String>
1324
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001325 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
1326 // struct from the function (which is currently the case). This means we pass
1327 // the arguments in a1-a2 instead of a0-a1. TryCallApiFunctionAndReturn
1328 // will handle setting up a0.
1329
1330 const int kApiStackSpace = 1;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001331 FrameScope frame_scope(masm(), StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001332 __ EnterExitFrame(false, kApiStackSpace);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001333
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001334 // Create AccessorInfo instance on the stack above the exit frame with
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001335 // scratch2 (internal::Object** args_) as the data.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001336 __ sw(a2, MemOperand(sp, kPointerSize));
1337 // a2 (second argument - see note above) = AccessorInfo&
1338 __ Addu(a2, sp, kPointerSize);
1339
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001340 const int kStackUnwindSpace = 5;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001341 Address getter_address = v8::ToCData<Address>(callback->getter());
1342 ApiFunction fun(getter_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001343 ExternalReference ref =
1344 ExternalReference(&fun,
1345 ExternalReference::DIRECT_GETTER_CALL,
1346 masm()->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001347 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
ager@chromium.org5c838252010-02-19 08:53:10 +00001348}
1349
1350
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001351void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
1352 Handle<JSObject> interceptor_holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001353 LookupResult* lookup,
1354 Register receiver,
1355 Register name_reg,
1356 Register scratch1,
1357 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001358 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001359 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001360 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001361 ASSERT(interceptor_holder->HasNamedInterceptor());
1362 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1363
1364 // Check that the receiver isn't a smi.
1365 __ JumpIfSmi(receiver, miss);
1366
1367 // So far the most popular follow ups for interceptor loads are FIELD
1368 // and CALLBACKS, so inline only them, other cases may be added
1369 // later.
1370 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001371 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001372 if (lookup->IsField()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001373 compile_followup_inline = true;
1374 } else if (lookup->type() == CALLBACKS &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001375 lookup->GetCallbackObject()->IsAccessorInfo()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001376 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
1377 compile_followup_inline = callback->getter() != NULL &&
1378 callback->IsCompatibleReceiver(*object);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001379 }
1380 }
1381
1382 if (compile_followup_inline) {
1383 // Compile the interceptor call, followed by inline code to load the
1384 // property from further up the prototype chain if the call fails.
1385 // Check that the maps haven't changed.
1386 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1387 scratch1, scratch2, scratch3,
1388 name, miss);
1389 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
1390
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001391 // Preserve the receiver register explicitly whenever it is different from
1392 // the holder and it is needed should the interceptor return without any
1393 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1394 // the FIELD case might cause a miss during the prototype check.
1395 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
1396 bool must_preserve_receiver_reg = !receiver.is(holder_reg) &&
1397 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1398
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001399 // Save necessary data before invoking an interceptor.
1400 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001401 {
1402 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001403 if (must_preserve_receiver_reg) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001404 __ Push(receiver, holder_reg, name_reg);
1405 } else {
1406 __ Push(holder_reg, name_reg);
1407 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001408 // Invoke an interceptor. Note: map checks from receiver to
1409 // interceptor's holder has been compiled before (see a caller
1410 // of this method).
1411 CompileCallLoadPropertyWithInterceptor(masm(),
1412 receiver,
1413 holder_reg,
1414 name_reg,
1415 interceptor_holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001416 // Check if interceptor provided a value for property. If it's
1417 // the case, return immediately.
1418 Label interceptor_failed;
1419 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
1420 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1));
1421 frame_scope.GenerateLeaveFrame();
1422 __ Ret();
1423
1424 __ bind(&interceptor_failed);
1425 __ pop(name_reg);
1426 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001427 if (must_preserve_receiver_reg) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001428 __ pop(receiver);
1429 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001430 // Leave the internal frame.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001431 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001432 // Check that the maps from interceptor's holder to lookup's holder
1433 // haven't changed. And load lookup's holder into |holder| register.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001434 if (must_perfrom_prototype_check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001435 holder_reg = CheckPrototypes(interceptor_holder,
1436 holder_reg,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001437 Handle<JSObject>(lookup->holder()),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001438 scratch1,
1439 scratch2,
1440 scratch3,
1441 name,
1442 miss);
1443 }
1444
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001445 if (lookup->IsField()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001446 // We found FIELD property in prototype chain of interceptor's holder.
1447 // Retrieve a field from field's holder.
1448 GenerateFastPropertyLoad(masm(), v0, holder_reg,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001449 Handle<JSObject>(lookup->holder()),
1450 lookup->GetFieldIndex());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001451 __ Ret();
1452 } else {
1453 // We found CALLBACKS property in prototype chain of interceptor's
1454 // holder.
1455 ASSERT(lookup->type() == CALLBACKS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001456 Handle<AccessorInfo> callback(
1457 AccessorInfo::cast(lookup->GetCallbackObject()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001458 ASSERT(callback->getter() != NULL);
1459
1460 // Tail call to runtime.
1461 // Important invariant in CALLBACKS case: the code above must be
1462 // structured to never clobber |receiver| register.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001463 __ li(scratch2, callback);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001464
1465 __ Push(receiver, holder_reg);
1466 __ lw(scratch3,
1467 FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
1468 __ li(scratch1, Operand(ExternalReference::isolate_address()));
1469 __ Push(scratch3, scratch1, scratch2, name_reg);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001470
1471 ExternalReference ref =
1472 ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
1473 masm()->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001474 __ TailCallExternalReference(ref, 6, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001475 }
1476 } else { // !compile_followup_inline
1477 // Call the runtime system to load the interceptor.
1478 // Check that the maps haven't changed.
1479 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1480 scratch1, scratch2, scratch3,
1481 name, miss);
1482 PushInterceptorArguments(masm(), receiver, holder_reg,
1483 name_reg, interceptor_holder);
1484
1485 ExternalReference ref = ExternalReference(
1486 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), masm()->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001487 __ TailCallExternalReference(ref, 6, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001488 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001489}
1490
1491
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001492void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001493 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001494 __ Branch(miss, ne, a2, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001495 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001496}
1497
1498
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001499void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1500 Handle<JSObject> holder,
1501 Handle<String> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001502 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001503 ASSERT(holder->IsGlobalObject());
1504
1505 // Get the number of arguments.
1506 const int argc = arguments().immediate();
1507
1508 // Get the receiver from the stack.
1509 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1510
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001511 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001512 __ JumpIfSmi(a0, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001513 CheckPrototypes(object, a0, holder, a3, a1, t0, name, miss);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001514}
1515
1516
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001517void CallStubCompiler::GenerateLoadFunctionFromCell(
1518 Handle<JSGlobalPropertyCell> cell,
1519 Handle<JSFunction> function,
1520 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001521 // Get the value from the cell.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001522 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001523 __ lw(a1, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
1524
1525 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001526 if (heap()->InNewSpace(*function)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001527 // We can't embed a pointer to a function in new space so we have
1528 // to verify that the shared function info is unchanged. This has
1529 // the nice side effect that multiple closures based on the same
1530 // function can all use this call IC. Before we load through the
1531 // function, we have to verify that it still is a function.
1532 __ JumpIfSmi(a1, miss);
1533 __ GetObjectType(a1, a3, a3);
1534 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
1535
1536 // Check the shared function info. Make sure it hasn't changed.
1537 __ li(a3, Handle<SharedFunctionInfo>(function->shared()));
1538 __ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
1539 __ Branch(miss, ne, t0, Operand(a3));
1540 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001541 __ Branch(miss, ne, a1, Operand(function));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001542 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001543}
1544
1545
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001546void CallStubCompiler::GenerateMissBranch() {
1547 Handle<Code> code =
danno@chromium.org40cb8782011-05-25 07:58:50 +00001548 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1549 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001550 extra_state_);
1551 __ Jump(code, RelocInfo::CODE_TARGET);
1552}
1553
1554
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001555Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1556 Handle<JSObject> holder,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001557 PropertyIndex index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001558 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001559 // ----------- S t a t e -------------
1560 // -- a2 : name
1561 // -- ra : return address
1562 // -----------------------------------
1563 Label miss;
1564
1565 GenerateNameCheck(name, &miss);
1566
1567 const int argc = arguments().immediate();
1568
1569 // Get the receiver of the function from the stack into a0.
1570 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1571 // Check that the receiver isn't a smi.
1572 __ JumpIfSmi(a0, &miss, t0);
1573
1574 // Do the right check and compute the holder register.
1575 Register reg = CheckPrototypes(object, a0, holder, a1, a3, t0, name, &miss);
1576 GenerateFastPropertyLoad(masm(), a1, reg, holder, index);
1577
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001578 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001579
1580 // Handle call cache miss.
1581 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001582 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001583
1584 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001585 return GetCode(Code::FIELD, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001586}
1587
1588
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001589Handle<Code> CallStubCompiler::CompileArrayPushCall(
1590 Handle<Object> object,
1591 Handle<JSObject> holder,
1592 Handle<JSGlobalPropertyCell> cell,
1593 Handle<JSFunction> function,
1594 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001595 // ----------- S t a t e -------------
1596 // -- a2 : name
1597 // -- ra : return address
1598 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1599 // -- ...
1600 // -- sp[argc * 4] : receiver
1601 // -----------------------------------
1602
1603 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001604 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001605
1606 Label miss;
1607
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001608 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001609
1610 Register receiver = a1;
1611
1612 // Get the receiver from the stack.
1613 const int argc = arguments().immediate();
1614 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1615
1616 // Check that the receiver isn't a smi.
1617 __ JumpIfSmi(receiver, &miss);
1618
1619 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001620 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, a3, v0, t0,
1621 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001622
1623 if (argc == 0) {
1624 // Nothing to do, just return the length.
1625 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1626 __ Drop(argc + 1);
1627 __ Ret();
1628 } else {
1629 Label call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001630 if (argc == 1) { // Otherwise fall through to call the builtin.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001631 Label attempt_to_grow_elements, with_write_barrier, check_double;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001632
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001633 Register elements = t2;
1634 Register end_elements = t1;
1635 // Get the elements array of the object.
1636 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1637
1638 // Check that the elements are in fast mode and writable.
1639 __ CheckMap(elements,
1640 v0,
1641 Heap::kFixedArrayMapRootIndex,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001642 &check_double,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001643 DONT_DO_SMI_CHECK);
1644
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001645 // Get the array's length into v0 and calculate new length.
1646 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1647 STATIC_ASSERT(kSmiTagSize == 1);
1648 STATIC_ASSERT(kSmiTag == 0);
1649 __ Addu(v0, v0, Operand(Smi::FromInt(argc)));
1650
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001651 // Get the elements' length.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001652 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1653
1654 // Check if we could survive without allocation.
1655 __ Branch(&attempt_to_grow_elements, gt, v0, Operand(t0));
1656
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001657 // Check if value is a smi.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001658 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1659 __ JumpIfNotSmi(t0, &with_write_barrier);
1660
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001661 // Save new length.
1662 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1663
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001664 // Store the value.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001665 // We may need a register containing the address end_elements below,
1666 // so write back the value in end_elements.
1667 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1668 __ Addu(end_elements, elements, end_elements);
1669 const int kEndElementsOffset =
1670 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001671 __ Addu(end_elements, end_elements, kEndElementsOffset);
1672 __ sw(t0, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001673
1674 // Check for a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001675 __ Drop(argc + 1);
1676 __ Ret();
1677
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001678 __ bind(&check_double);
1679
1680 // Check that the elements are in fast mode and writable.
1681 __ CheckMap(elements,
1682 a0,
1683 Heap::kFixedDoubleArrayMapRootIndex,
1684 &call_builtin,
1685 DONT_DO_SMI_CHECK);
1686
1687 // Get the array's length into r0 and calculate new length.
1688 __ lw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1689 STATIC_ASSERT(kSmiTagSize == 1);
1690 STATIC_ASSERT(kSmiTag == 0);
1691 __ Addu(a0, a0, Operand(Smi::FromInt(argc)));
1692
1693 // Get the elements' length.
1694 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1695
1696 // Check if we could survive without allocation.
1697 __ Branch(&call_builtin, gt, a0, Operand(t0));
1698
1699 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1700 __ StoreNumberToDoubleElements(
1701 t0, a0, elements, a3, t1, a2, t5,
1702 &call_builtin, argc * kDoubleSize);
1703
1704 // Save new length.
1705 __ sw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1706
1707 // Check for a smi.
1708 __ Drop(argc + 1);
1709 __ Ret();
1710
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001711 __ bind(&with_write_barrier);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001712
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001713 __ lw(a3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1714
1715 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
1716 Label fast_object, not_fast_object;
1717 __ CheckFastObjectElements(a3, t3, &not_fast_object);
1718 __ jmp(&fast_object);
1719 // In case of fast smi-only, convert to fast object, otherwise bail out.
1720 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001721 __ CheckFastSmiElements(a3, t3, &call_builtin);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001722
1723 __ lw(t3, FieldMemOperand(t0, HeapObject::kMapOffset));
1724 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
1725 __ Branch(&call_builtin, eq, t3, Operand(at));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001726 // edx: receiver
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001727 // a3: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001728 Label try_holey_map;
1729 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001730 FAST_ELEMENTS,
1731 a3,
1732 t3,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001733 &try_holey_map);
1734 __ mov(a2, receiver);
1735 ElementsTransitionGenerator::
1736 GenerateMapChangeElementsTransition(masm());
1737 __ jmp(&fast_object);
1738
1739 __ bind(&try_holey_map);
1740 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1741 FAST_HOLEY_ELEMENTS,
1742 a3,
1743 t3,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001744 &call_builtin);
1745 __ mov(a2, receiver);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001746 ElementsTransitionGenerator::
1747 GenerateMapChangeElementsTransition(masm());
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001748 __ bind(&fast_object);
1749 } else {
1750 __ CheckFastObjectElements(a3, a3, &call_builtin);
1751 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001752
1753 // Save new length.
1754 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1755
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001756 // Store the value.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001757 // We may need a register containing the address end_elements below,
1758 // so write back the value in end_elements.
1759 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1760 __ Addu(end_elements, elements, end_elements);
1761 __ Addu(end_elements, end_elements, kEndElementsOffset);
1762 __ sw(t0, MemOperand(end_elements));
1763
1764 __ RecordWrite(elements,
1765 end_elements,
1766 t0,
1767 kRAHasNotBeenSaved,
1768 kDontSaveFPRegs,
1769 EMIT_REMEMBERED_SET,
1770 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001771 __ Drop(argc + 1);
1772 __ Ret();
1773
1774 __ bind(&attempt_to_grow_elements);
1775 // v0: array's length + 1.
1776 // t0: elements' length.
1777
1778 if (!FLAG_inline_new) {
1779 __ Branch(&call_builtin);
1780 }
1781
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001782 __ lw(a2, MemOperand(sp, (argc - 1) * kPointerSize));
1783 // Growing elements that are SMI-only requires special handling in case
1784 // the new element is non-Smi. For now, delegate to the builtin.
1785 Label no_fast_elements_check;
1786 __ JumpIfSmi(a2, &no_fast_elements_check);
1787 __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1788 __ CheckFastObjectElements(t3, t3, &call_builtin);
1789 __ bind(&no_fast_elements_check);
1790
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001791 ExternalReference new_space_allocation_top =
1792 ExternalReference::new_space_allocation_top_address(
1793 masm()->isolate());
1794 ExternalReference new_space_allocation_limit =
1795 ExternalReference::new_space_allocation_limit_address(
1796 masm()->isolate());
1797
1798 const int kAllocationDelta = 4;
1799 // Load top and check if it is the end of elements.
1800 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1801 __ Addu(end_elements, elements, end_elements);
1802 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset));
1803 __ li(t3, Operand(new_space_allocation_top));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001804 __ lw(a3, MemOperand(t3));
1805 __ Branch(&call_builtin, ne, end_elements, Operand(a3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001806
1807 __ li(t5, Operand(new_space_allocation_limit));
1808 __ lw(t5, MemOperand(t5));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001809 __ Addu(a3, a3, Operand(kAllocationDelta * kPointerSize));
1810 __ Branch(&call_builtin, hi, a3, Operand(t5));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001811
1812 // We fit and could grow elements.
1813 // Update new_space_allocation_top.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001814 __ sw(a3, MemOperand(t3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001815 // Push the argument.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001816 __ sw(a2, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001817 // Fill the rest with holes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001818 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001819 for (int i = 1; i < kAllocationDelta; i++) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001820 __ sw(a3, MemOperand(end_elements, i * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001821 }
1822
1823 // Update elements' and array's sizes.
1824 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1825 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta)));
1826 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1827
1828 // Elements are in new space, so write barrier is not required.
1829 __ Drop(argc + 1);
1830 __ Ret();
1831 }
1832 __ bind(&call_builtin);
1833 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
1834 masm()->isolate()),
1835 argc + 1,
1836 1);
1837 }
1838
1839 // Handle call cache miss.
1840 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001841 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001842
1843 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001844 return GetCode(function);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001845}
1846
1847
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001848Handle<Code> CallStubCompiler::CompileArrayPopCall(
1849 Handle<Object> object,
1850 Handle<JSObject> holder,
1851 Handle<JSGlobalPropertyCell> cell,
1852 Handle<JSFunction> function,
1853 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001854 // ----------- S t a t e -------------
1855 // -- a2 : name
1856 // -- ra : return address
1857 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1858 // -- ...
1859 // -- sp[argc * 4] : receiver
1860 // -----------------------------------
1861
1862 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001863 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001864
1865 Label miss, return_undefined, call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001866 Register receiver = a1;
1867 Register elements = a3;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001868 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001869
1870 // Get the receiver from the stack.
1871 const int argc = arguments().immediate();
1872 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001873 // Check that the receiver isn't a smi.
1874 __ JumpIfSmi(receiver, &miss);
1875
1876 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001877 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, elements,
1878 t0, v0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001879
1880 // Get the elements array of the object.
1881 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1882
1883 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001884 __ CheckMap(elements,
1885 v0,
1886 Heap::kFixedArrayMapRootIndex,
1887 &call_builtin,
1888 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001889
1890 // Get the array's length into t0 and calculate new length.
1891 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1892 __ Subu(t0, t0, Operand(Smi::FromInt(1)));
1893 __ Branch(&return_undefined, lt, t0, Operand(zero_reg));
1894
1895 // Get the last element.
1896 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1897 STATIC_ASSERT(kSmiTagSize == 1);
1898 STATIC_ASSERT(kSmiTag == 0);
1899 // We can't address the last element in one operation. Compute the more
1900 // expensive shift first, and use an offset later on.
1901 __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize);
1902 __ Addu(elements, elements, t1);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001903 __ lw(v0, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001904 __ Branch(&call_builtin, eq, v0, Operand(t2));
1905
1906 // Set the array's length.
1907 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1908
1909 // Fill with the hole.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001910 __ sw(t2, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001911 __ Drop(argc + 1);
1912 __ Ret();
1913
1914 __ bind(&return_undefined);
1915 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
1916 __ Drop(argc + 1);
1917 __ Ret();
1918
1919 __ bind(&call_builtin);
1920 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop,
1921 masm()->isolate()),
1922 argc + 1,
1923 1);
1924
1925 // Handle call cache miss.
1926 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001927 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001928
1929 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001930 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001931}
1932
1933
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001934Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1935 Handle<Object> object,
1936 Handle<JSObject> holder,
1937 Handle<JSGlobalPropertyCell> cell,
1938 Handle<JSFunction> function,
1939 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001940 // ----------- S t a t e -------------
1941 // -- a2 : function name
1942 // -- ra : return address
1943 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1944 // -- ...
1945 // -- sp[argc * 4] : receiver
1946 // -----------------------------------
1947
1948 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001949 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001950
1951 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001952 Label miss;
1953 Label name_miss;
1954 Label index_out_of_range;
1955
1956 Label* index_out_of_range_label = &index_out_of_range;
1957
danno@chromium.org40cb8782011-05-25 07:58:50 +00001958 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001959 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001960 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001961 index_out_of_range_label = &miss;
1962 }
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));
1972 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1973 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001974
1975 Register receiver = a1;
1976 Register index = t1;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001977 Register result = v0;
1978 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1979 if (argc > 0) {
1980 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1981 } else {
1982 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1983 }
1984
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001985 StringCharCodeAtGenerator generator(receiver,
1986 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001987 result,
1988 &miss, // When not a string.
1989 &miss, // When not a number.
1990 index_out_of_range_label,
1991 STRING_INDEX_IS_NUMBER);
1992 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001993 __ Drop(argc + 1);
1994 __ Ret();
1995
1996 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001997 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001998
1999 if (index_out_of_range.is_linked()) {
2000 __ bind(&index_out_of_range);
2001 __ LoadRoot(v0, Heap::kNanValueRootIndex);
2002 __ Drop(argc + 1);
2003 __ Ret();
2004 }
2005
2006 __ bind(&miss);
2007 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002008 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002009 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002010 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002011
2012 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002013 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002014}
2015
2016
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002017Handle<Code> CallStubCompiler::CompileStringCharAtCall(
2018 Handle<Object> object,
2019 Handle<JSObject> holder,
2020 Handle<JSGlobalPropertyCell> cell,
2021 Handle<JSFunction> function,
2022 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002023 // ----------- S t a t e -------------
2024 // -- a2 : function name
2025 // -- ra : return address
2026 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2027 // -- ...
2028 // -- sp[argc * 4] : receiver
2029 // -----------------------------------
2030
2031 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002032 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002033
2034 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002035 Label miss;
2036 Label name_miss;
2037 Label index_out_of_range;
2038 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00002039 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002040 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002041 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002042 index_out_of_range_label = &miss;
2043 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002044 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002045
2046 // Check that the maps starting from the prototype haven't changed.
2047 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2048 Context::STRING_FUNCTION_INDEX,
2049 v0,
2050 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002051 ASSERT(!object.is_identical_to(holder));
2052 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2053 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002054
2055 Register receiver = v0;
2056 Register index = t1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00002057 Register scratch = a3;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002058 Register result = v0;
2059 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
2060 if (argc > 0) {
2061 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
2062 } else {
2063 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
2064 }
2065
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002066 StringCharAtGenerator generator(receiver,
2067 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00002068 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002069 result,
2070 &miss, // When not a string.
2071 &miss, // When not a number.
2072 index_out_of_range_label,
2073 STRING_INDEX_IS_NUMBER);
2074 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002075 __ Drop(argc + 1);
2076 __ Ret();
2077
2078 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002079 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002080
2081 if (index_out_of_range.is_linked()) {
2082 __ bind(&index_out_of_range);
2083 __ LoadRoot(v0, Heap::kEmptyStringRootIndex);
2084 __ Drop(argc + 1);
2085 __ Ret();
2086 }
2087
2088 __ bind(&miss);
2089 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002090 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002091 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002092 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002093
2094 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002095 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002096}
2097
2098
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002099Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
2100 Handle<Object> object,
2101 Handle<JSObject> holder,
2102 Handle<JSGlobalPropertyCell> cell,
2103 Handle<JSFunction> function,
2104 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002105 // ----------- S t a t e -------------
2106 // -- a2 : function name
2107 // -- ra : return address
2108 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2109 // -- ...
2110 // -- sp[argc * 4] : receiver
2111 // -----------------------------------
2112
2113 const int argc = arguments().immediate();
2114
2115 // If the object is not a JSObject or we got an unexpected number of
2116 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002117 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002118
2119 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002120 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002121
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002122 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002123 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
2124
2125 STATIC_ASSERT(kSmiTag == 0);
2126 __ JumpIfSmi(a1, &miss);
2127
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002128 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2129 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002130 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002131 ASSERT(cell->value() == *function);
2132 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2133 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002134 GenerateLoadFunctionFromCell(cell, function, &miss);
2135 }
2136
2137 // Load the char code argument.
2138 Register code = a1;
2139 __ lw(code, MemOperand(sp, 0 * kPointerSize));
2140
2141 // Check the code is a smi.
2142 Label slow;
2143 STATIC_ASSERT(kSmiTag == 0);
2144 __ JumpIfNotSmi(code, &slow);
2145
2146 // Convert the smi code to uint16.
2147 __ And(code, code, Operand(Smi::FromInt(0xffff)));
2148
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002149 StringCharFromCodeGenerator generator(code, v0);
2150 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002151 __ Drop(argc + 1);
2152 __ Ret();
2153
2154 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002155 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002156
2157 // Tail call the full function. We do not have to patch the receiver
2158 // because the function makes no use of it.
2159 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002160 __ InvokeFunction(
2161 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002162
2163 __ bind(&miss);
2164 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002165 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002166
2167 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002168 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002169}
2170
2171
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002172Handle<Code> CallStubCompiler::CompileMathFloorCall(
2173 Handle<Object> object,
2174 Handle<JSObject> holder,
2175 Handle<JSGlobalPropertyCell> cell,
2176 Handle<JSFunction> function,
2177 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002178 // ----------- S t a t e -------------
2179 // -- a2 : function name
2180 // -- ra : return address
2181 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2182 // -- ...
2183 // -- sp[argc * 4] : receiver
2184 // -----------------------------------
2185
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002186 if (!CpuFeatures::IsSupported(FPU)) {
2187 return Handle<Code>::null();
2188 }
2189
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002190 CpuFeatures::Scope scope_fpu(FPU);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002191 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002192 // If the object is not a JSObject or we got an unexpected number of
2193 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002194 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002195
2196 Label miss, slow;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002197 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002198
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002199 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002200 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002201 STATIC_ASSERT(kSmiTag == 0);
2202 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002203 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2204 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002205 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002206 ASSERT(cell->value() == *function);
2207 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2208 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002209 GenerateLoadFunctionFromCell(cell, function, &miss);
2210 }
2211
2212 // Load the (only) argument into v0.
2213 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2214
2215 // If the argument is a smi, just return.
2216 STATIC_ASSERT(kSmiTag == 0);
2217 __ And(t0, v0, Operand(kSmiTagMask));
2218 __ Drop(argc + 1, eq, t0, Operand(zero_reg));
2219 __ Ret(eq, t0, Operand(zero_reg));
2220
danno@chromium.org40cb8782011-05-25 07:58:50 +00002221 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002222
2223 Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return;
2224
2225 // If fpu is enabled, we use the floor instruction.
2226
2227 // Load the HeapNumber value.
2228 __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2229
2230 // Backup FCSR.
2231 __ cfc1(a3, FCSR);
2232 // Clearing FCSR clears the exception mask with no side-effects.
2233 __ ctc1(zero_reg, FCSR);
2234 // Convert the argument to an integer.
2235 __ floor_w_d(f0, f0);
2236
2237 // Start checking for special cases.
2238 // Get the argument exponent and clear the sign bit.
2239 __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize));
2240 __ And(t2, t1, Operand(~HeapNumber::kSignMask));
2241 __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord);
2242
2243 // Retrieve FCSR and check for fpu errors.
2244 __ cfc1(t5, FCSR);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002245 __ And(t5, t5, Operand(kFCSRExceptionFlagMask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002246 __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));
2247
2248 // Check for NaN, Infinity, and -Infinity.
2249 // They are invariant through a Math.Floor call, so just
2250 // return the original argument.
2251 __ Subu(t3, t2, Operand(HeapNumber::kExponentMask
2252 >> HeapNumber::kMantissaBitsInTopWord));
2253 __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg));
2254 // We had an overflow or underflow in the conversion. Check if we
2255 // have a big exponent.
2256 // If greater or equal, the argument is already round and in v0.
2257 __ Branch(&restore_fcsr_and_return, ge, t3,
2258 Operand(HeapNumber::kMantissaBits));
2259 __ Branch(&wont_fit_smi);
2260
2261 __ bind(&no_fpu_error);
2262 // Move the result back to v0.
2263 __ mfc1(v0, f0);
2264 // Check if the result fits into a smi.
2265 __ Addu(a1, v0, Operand(0x40000000));
2266 __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg));
2267 // Tag the result.
2268 STATIC_ASSERT(kSmiTag == 0);
2269 __ sll(v0, v0, kSmiTagSize);
2270
2271 // Check for -0.
2272 __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg));
2273 // t1 already holds the HeapNumber exponent.
2274 __ And(t0, t1, Operand(HeapNumber::kSignMask));
2275 // If our HeapNumber is negative it was -0, so load its address and return.
2276 // Else v0 is loaded with 0, so we can also just return.
2277 __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg));
2278 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2279
2280 __ bind(&restore_fcsr_and_return);
2281 // Restore FCSR and return.
2282 __ ctc1(a3, FCSR);
2283
2284 __ Drop(argc + 1);
2285 __ Ret();
2286
2287 __ bind(&wont_fit_smi);
2288 // Restore FCSR and fall to slow case.
2289 __ ctc1(a3, FCSR);
2290
2291 __ bind(&slow);
2292 // Tail call the full function. We do not have to patch the receiver
2293 // because the function makes no use of it.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002294 __ InvokeFunction(
2295 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002296
2297 __ bind(&miss);
2298 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002299 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002300
2301 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002302 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002303}
2304
2305
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002306Handle<Code> CallStubCompiler::CompileMathAbsCall(
2307 Handle<Object> object,
2308 Handle<JSObject> holder,
2309 Handle<JSGlobalPropertyCell> cell,
2310 Handle<JSFunction> function,
2311 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002312 // ----------- S t a t e -------------
2313 // -- a2 : function name
2314 // -- ra : return address
2315 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2316 // -- ...
2317 // -- sp[argc * 4] : receiver
2318 // -----------------------------------
2319
2320 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002321 // If the object is not a JSObject or we got an unexpected number of
2322 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002323 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002324
2325 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002326
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002327 GenerateNameCheck(name, &miss);
2328 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002329 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002330 STATIC_ASSERT(kSmiTag == 0);
2331 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002332 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2333 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002334 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002335 ASSERT(cell->value() == *function);
2336 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2337 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002338 GenerateLoadFunctionFromCell(cell, function, &miss);
2339 }
2340
2341 // Load the (only) argument into v0.
2342 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2343
2344 // Check if the argument is a smi.
2345 Label not_smi;
2346 STATIC_ASSERT(kSmiTag == 0);
2347 __ JumpIfNotSmi(v0, &not_smi);
2348
2349 // Do bitwise not or do nothing depending on the sign of the
2350 // argument.
2351 __ sra(t0, v0, kBitsPerInt - 1);
2352 __ Xor(a1, v0, t0);
2353
2354 // Add 1 or do nothing depending on the sign of the argument.
2355 __ Subu(v0, a1, t0);
2356
2357 // If the result is still negative, go to the slow case.
2358 // This only happens for the most negative smi.
2359 Label slow;
2360 __ Branch(&slow, lt, v0, Operand(zero_reg));
2361
2362 // Smi case done.
2363 __ Drop(argc + 1);
2364 __ Ret();
2365
2366 // Check if the argument is a heap number and load its exponent and
2367 // sign.
2368 __ bind(&not_smi);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002369 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002370 __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2371
2372 // Check the sign of the argument. If the argument is positive,
2373 // just return it.
2374 Label negative_sign;
2375 __ And(t0, a1, Operand(HeapNumber::kSignMask));
2376 __ Branch(&negative_sign, ne, t0, Operand(zero_reg));
2377 __ Drop(argc + 1);
2378 __ Ret();
2379
2380 // If the argument is negative, clear the sign, and return a new
2381 // number.
2382 __ bind(&negative_sign);
2383 __ Xor(a1, a1, Operand(HeapNumber::kSignMask));
2384 __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2385 __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
2386 __ AllocateHeapNumber(v0, t0, t1, t2, &slow);
2387 __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2388 __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2389 __ Drop(argc + 1);
2390 __ Ret();
2391
2392 // Tail call the full function. We do not have to patch the receiver
2393 // because the function makes no use of it.
2394 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002395 __ InvokeFunction(
2396 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002397
2398 __ bind(&miss);
2399 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002400 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002401
2402 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002403 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002404}
2405
2406
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002407Handle<Code> CallStubCompiler::CompileFastApiCall(
lrn@chromium.org7516f052011-03-30 08:52:27 +00002408 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002409 Handle<Object> object,
2410 Handle<JSObject> holder,
2411 Handle<JSGlobalPropertyCell> cell,
2412 Handle<JSFunction> function,
2413 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002414
danno@chromium.org40cb8782011-05-25 07:58:50 +00002415 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002416
2417 ASSERT(optimization.is_simple_api_call());
2418 // Bail out if object is a global object as we don't want to
2419 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002420 if (object->IsGlobalObject()) return Handle<Code>::null();
2421 if (!cell.is_null()) return Handle<Code>::null();
2422 if (!object->IsJSObject()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002423 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002424 Handle<JSObject>::cast(object), holder);
2425 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002426
2427 Label miss, miss_before_stack_reserved;
2428
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002429 GenerateNameCheck(name, &miss_before_stack_reserved);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002430
2431 // Get the receiver from the stack.
2432 const int argc = arguments().immediate();
2433 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2434
2435 // Check that the receiver isn't a smi.
2436 __ JumpIfSmi(a1, &miss_before_stack_reserved);
2437
2438 __ IncrementCounter(counters->call_const(), 1, a0, a3);
2439 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2440
2441 ReserveSpaceForFastApiCall(masm(), a0);
2442
2443 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002444 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002445 depth, &miss);
2446
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002447 GenerateFastApiDirectCall(masm(), optimization, argc);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002448
2449 __ bind(&miss);
2450 FreeSpaceForFastApiCall(masm());
2451
2452 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002453 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002454
2455 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002456 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002457}
2458
2459
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002460Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object,
2461 Handle<JSObject> holder,
2462 Handle<JSFunction> function,
2463 Handle<String> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002464 CheckType check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002465 // ----------- S t a t e -------------
2466 // -- a2 : name
2467 // -- ra : return address
2468 // -----------------------------------
2469 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002470 Handle<Code> code = CompileCustomCall(object, holder,
2471 Handle<JSGlobalPropertyCell>::null(),
2472 function, name);
2473 // A null handle means bail out to the regular compiler code below.
2474 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002475 }
2476
2477 Label miss;
2478
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002479 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002480
2481 // Get the receiver from the stack.
2482 const int argc = arguments().immediate();
2483 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2484
2485 // Check that the receiver isn't a smi.
2486 if (check != NUMBER_CHECK) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002487 __ JumpIfSmi(a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002488 }
2489
2490 // Make sure that it's okay not to patch the on stack receiver
2491 // unless we're doing a receiver map check.
2492 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002493 switch (check) {
2494 case RECEIVER_MAP_CHECK:
2495 __ IncrementCounter(masm()->isolate()->counters()->call_const(),
2496 1, a0, a3);
2497
2498 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002499 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2500 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002501
2502 // Patch the receiver on the stack with the global proxy if
2503 // necessary.
2504 if (object->IsGlobalObject()) {
2505 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2506 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2507 }
2508 break;
2509
2510 case STRING_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002511 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002512 // Check that the object is a two-byte string or a symbol.
2513 __ GetObjectType(a1, a3, a3);
2514 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2515 // Check that the maps starting from the prototype haven't changed.
2516 GenerateDirectLoadGlobalFunctionPrototype(
2517 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002518 CheckPrototypes(
2519 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2520 a0, holder, a3, a1, t0, name, &miss);
2521 } else {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002522 // Calling non-strict non-builtins with a value as the receiver
2523 // requires boxing.
2524 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002525 }
2526 break;
2527
2528 case NUMBER_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002529 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002530 Label fast;
2531 // Check that the object is a smi or a heap number.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002532 __ JumpIfSmi(a1, &fast);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002533 __ GetObjectType(a1, a0, a0);
2534 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
2535 __ bind(&fast);
2536 // Check that the maps starting from the prototype haven't changed.
2537 GenerateDirectLoadGlobalFunctionPrototype(
2538 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002539 CheckPrototypes(
2540 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2541 a0, holder, a3, a1, t0, name, &miss);
2542 } else {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002543 // Calling non-strict non-builtins with a value as the receiver
2544 // requires boxing.
2545 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002546 }
2547 break;
2548
2549 case BOOLEAN_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002550 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002551 Label fast;
2552 // Check that the object is a boolean.
2553 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
2554 __ Branch(&fast, eq, a1, Operand(t0));
2555 __ LoadRoot(t0, Heap::kFalseValueRootIndex);
2556 __ Branch(&miss, ne, a1, Operand(t0));
2557 __ bind(&fast);
2558 // Check that the maps starting from the prototype haven't changed.
2559 GenerateDirectLoadGlobalFunctionPrototype(
2560 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002561 CheckPrototypes(
2562 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2563 a0, holder, a3, a1, t0, name, &miss);
2564 } else {
2565 // Calling non-strict non-builtins with a value as the receiver
2566 // requires boxing.
2567 __ jmp(&miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002568 }
2569 break;
2570 }
2571
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002572 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002573 ? CALL_AS_FUNCTION
2574 : CALL_AS_METHOD;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002575 __ InvokeFunction(
2576 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002577
2578 // Handle call cache miss.
2579 __ bind(&miss);
2580
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002581 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002582
2583 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002584 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002585}
2586
2587
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002588Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2589 Handle<JSObject> holder,
2590 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002591 // ----------- S t a t e -------------
2592 // -- a2 : name
2593 // -- ra : return address
2594 // -----------------------------------
2595
2596 Label miss;
2597
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002598 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002599
2600 // Get the number of arguments.
2601 const int argc = arguments().immediate();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002602 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002603 LookupPostInterceptor(holder, name, &lookup);
2604
2605 // Get the receiver from the stack.
2606 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2607
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002608 CallInterceptorCompiler compiler(this, arguments(), a2, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002609 compiler.Compile(masm(), object, holder, name, &lookup, a1, a3, t0, a0,
2610 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002611
2612 // Move returned value, the function to call, to a1.
2613 __ mov(a1, v0);
2614 // Restore receiver.
2615 __ lw(a0, MemOperand(sp, argc * kPointerSize));
2616
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002617 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002618
2619 // Handle call cache miss.
2620 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002621 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002622
2623 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002624 return GetCode(Code::INTERCEPTOR, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002625}
2626
2627
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002628Handle<Code> CallStubCompiler::CompileCallGlobal(
2629 Handle<JSObject> object,
2630 Handle<GlobalObject> holder,
2631 Handle<JSGlobalPropertyCell> cell,
2632 Handle<JSFunction> function,
2633 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002634 // ----------- S t a t e -------------
2635 // -- a2 : name
2636 // -- ra : return address
2637 // -----------------------------------
2638
2639 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002640 Handle<Code> code = CompileCustomCall(object, holder, cell, function, name);
2641 // A null handle means bail out to the regular compiler code below.
2642 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002643 }
2644
2645 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002646 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002647
2648 // Get the number of arguments.
2649 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002650 GenerateGlobalReceiverCheck(object, holder, name, &miss);
2651 GenerateLoadFunctionFromCell(cell, function, &miss);
2652
2653 // Patch the receiver on the stack with the global proxy if
2654 // necessary.
2655 if (object->IsGlobalObject()) {
2656 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
2657 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2658 }
2659
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002660 // Set up the context (function already in r1).
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002661 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
2662
2663 // Jump to the cached code (tail call).
2664 Counters* counters = masm()->isolate()->counters();
2665 __ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002666 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002667 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002668 ? CALL_AS_FUNCTION
2669 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002670 // We call indirectly through the code field in the function to
2671 // allow recompilation to take effect without changing any of the
2672 // call sites.
2673 __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
2674 __ InvokeCode(a3, expected, arguments(), JUMP_FUNCTION,
2675 NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002676
2677 // Handle call cache miss.
2678 __ bind(&miss);
2679 __ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002680 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002681
2682 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002683 return GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002684}
2685
2686
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002687Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +00002688 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002689 Handle<Map> transition,
2690 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002691 // ----------- S t a t e -------------
2692 // -- a0 : value
2693 // -- a1 : receiver
2694 // -- a2 : name
2695 // -- ra : return address
2696 // -----------------------------------
2697 Label miss;
2698
2699 // Name register might be clobbered.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002700 GenerateStoreField(masm(),
2701 object,
2702 index,
2703 transition,
2704 name,
2705 a1, a2, a3, t0,
2706 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002707 __ bind(&miss);
2708 __ li(a2, Operand(Handle<String>(name))); // Restore name.
2709 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2710 __ Jump(ic, RelocInfo::CODE_TARGET);
2711
2712 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002713 return GetCode(transition.is_null()
2714 ? Code::FIELD
2715 : Code::MAP_TRANSITION, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002716}
2717
2718
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002719Handle<Code> StoreStubCompiler::CompileStoreCallback(
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002720 Handle<String> name,
2721 Handle<JSObject> receiver,
2722 Handle<JSObject> holder,
2723 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002724 // ----------- S t a t e -------------
2725 // -- a0 : value
2726 // -- a1 : receiver
2727 // -- a2 : name
2728 // -- ra : return address
2729 // -----------------------------------
2730 Label miss;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002731 // Check that the maps haven't changed.
2732 __ JumpIfSmi(a1, &miss, a3);
2733 CheckPrototypes(receiver, a1, holder, a3, t0, t1, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002734
2735 // Stub never generated for non-global objects that require access
2736 // checks.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002737 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002738
2739 __ push(a1); // Receiver.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002740 __ li(a3, Operand(callback)); // Callback info.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002741 __ Push(a3, a2, a0);
2742
2743 // Do tail-call to the runtime system.
2744 ExternalReference store_callback_property =
2745 ExternalReference(IC_Utility(IC::kStoreCallbackProperty),
2746 masm()->isolate());
2747 __ TailCallExternalReference(store_callback_property, 4, 1);
2748
2749 // Handle store cache miss.
2750 __ bind(&miss);
2751 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2752 __ Jump(ic, RelocInfo::CODE_TARGET);
2753
2754 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002755 return GetCode(Code::CALLBACKS, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002756}
2757
2758
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002759#undef __
2760#define __ ACCESS_MASM(masm)
2761
2762
2763void StoreStubCompiler::GenerateStoreViaSetter(
2764 MacroAssembler* masm,
2765 Handle<JSFunction> setter) {
2766 // ----------- S t a t e -------------
2767 // -- a0 : value
2768 // -- a1 : receiver
2769 // -- a2 : name
2770 // -- ra : return address
2771 // -----------------------------------
2772 {
2773 FrameScope scope(masm, StackFrame::INTERNAL);
2774
2775 // Save value register, so we can restore it later.
2776 __ push(a0);
2777
2778 if (!setter.is_null()) {
2779 // Call the JavaScript setter with receiver and value on the stack.
2780 __ push(a1);
2781 __ push(a0);
2782 ParameterCount actual(1);
2783 __ InvokeFunction(setter, actual, CALL_FUNCTION, NullCallWrapper(),
2784 CALL_AS_METHOD);
2785 } else {
2786 // If we generate a global code snippet for deoptimization only, remember
2787 // the place to continue after deoptimization.
2788 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2789 }
2790
2791 // We have to return the passed value, not the return value of the setter.
2792 __ pop(v0);
2793
2794 // Restore context register.
2795 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2796 }
2797 __ Ret();
2798}
2799
2800
2801#undef __
2802#define __ ACCESS_MASM(masm())
2803
2804
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002805Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002806 Handle<String> name,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002807 Handle<JSObject> receiver,
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002808 Handle<JSObject> holder,
2809 Handle<JSFunction> setter) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002810 // ----------- S t a t e -------------
2811 // -- a0 : value
2812 // -- a1 : receiver
2813 // -- a2 : name
2814 // -- ra : return address
2815 // -----------------------------------
2816 Label miss;
2817
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002818 // Check that the maps haven't changed.
2819 __ JumpIfSmi(a1, &miss);
2820 CheckPrototypes(receiver, a1, holder, a3, t0, t1, name, &miss);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002821
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002822 GenerateStoreViaSetter(masm(), setter);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002823
2824 __ bind(&miss);
2825 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2826 __ Jump(ic, RelocInfo::CODE_TARGET);
2827
2828 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002829 return GetCode(Code::CALLBACKS, name);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002830}
2831
2832
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002833Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
2834 Handle<JSObject> receiver,
2835 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002836 // ----------- S t a t e -------------
2837 // -- a0 : value
2838 // -- a1 : receiver
2839 // -- a2 : name
2840 // -- ra : return address
2841 // -----------------------------------
2842 Label miss;
2843
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002844 // Check that the map of the object hasn't changed.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002845 __ CheckMap(a1, a3, Handle<Map>(receiver->map()), &miss,
2846 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002847
2848 // Perform global security token check if needed.
2849 if (receiver->IsJSGlobalProxy()) {
2850 __ CheckAccessGlobalProxy(a1, a3, &miss);
2851 }
2852
2853 // Stub is never generated for non-global objects that require access
2854 // checks.
2855 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2856
2857 __ Push(a1, a2, a0); // Receiver, name, value.
2858
2859 __ li(a0, Operand(Smi::FromInt(strict_mode_)));
2860 __ push(a0); // Strict mode.
2861
2862 // Do tail-call to the runtime system.
2863 ExternalReference store_ic_property =
2864 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty),
2865 masm()->isolate());
2866 __ TailCallExternalReference(store_ic_property, 4, 1);
2867
2868 // Handle store cache miss.
2869 __ bind(&miss);
2870 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2871 __ Jump(ic, RelocInfo::CODE_TARGET);
2872
2873 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002874 return GetCode(Code::INTERCEPTOR, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002875}
2876
2877
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002878Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2879 Handle<GlobalObject> object,
2880 Handle<JSGlobalPropertyCell> cell,
2881 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002882 // ----------- S t a t e -------------
2883 // -- a0 : value
2884 // -- a1 : receiver
2885 // -- a2 : name
2886 // -- ra : return address
2887 // -----------------------------------
2888 Label miss;
2889
2890 // Check that the map of the global has not changed.
2891 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2892 __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map())));
2893
2894 // Check that the value in the cell is not the hole. If it is, this
2895 // cell could have been deleted and reintroducing the global needs
2896 // to update the property details in the property dictionary of the
2897 // global object. We bail out to the runtime system to do that.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002898 __ li(t0, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002899 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
2900 __ lw(t2, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2901 __ Branch(&miss, eq, t1, Operand(t2));
2902
2903 // Store the value in the cell.
2904 __ sw(a0, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2905 __ mov(v0, a0); // Stored value must be returned in v0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002906 // Cells are always rescanned, so no write barrier here.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002907
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002908 Counters* counters = masm()->isolate()->counters();
2909 __ IncrementCounter(counters->named_store_global_inline(), 1, a1, a3);
2910 __ Ret();
2911
2912 // Handle store cache miss.
2913 __ bind(&miss);
2914 __ IncrementCounter(counters->named_store_global_inline_miss(), 1, a1, a3);
2915 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2916 __ Jump(ic, RelocInfo::CODE_TARGET);
2917
2918 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002919 return GetCode(Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002920}
2921
2922
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002923Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
2924 Handle<JSObject> object,
2925 Handle<JSObject> last) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002926 // ----------- S t a t e -------------
2927 // -- a0 : receiver
2928 // -- ra : return address
2929 // -----------------------------------
2930 Label miss;
2931
2932 // Check that the receiver is not a smi.
2933 __ JumpIfSmi(a0, &miss);
2934
2935 // Check the maps of the full prototype chain.
2936 CheckPrototypes(object, a0, last, a3, a1, t0, name, &miss);
2937
2938 // If the last object in the prototype chain is a global object,
2939 // check that the global property cell is empty.
2940 if (last->IsGlobalObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002941 GenerateCheckPropertyCell(
2942 masm(), Handle<GlobalObject>::cast(last), name, a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002943 }
2944
2945 // Return undefined if maps of the full prototype chain is still the same.
2946 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2947 __ Ret();
2948
2949 __ bind(&miss);
2950 GenerateLoadMiss(masm(), Code::LOAD_IC);
2951
2952 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002953 return GetCode(Code::NONEXISTENT, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00002954}
2955
2956
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002957Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object,
2958 Handle<JSObject> holder,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002959 PropertyIndex index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002960 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002961 // ----------- S t a t e -------------
2962 // -- a0 : receiver
2963 // -- a2 : name
2964 // -- ra : return address
2965 // -----------------------------------
2966 Label miss;
2967
2968 __ mov(v0, a0);
2969
2970 GenerateLoadField(object, holder, v0, a3, a1, t0, index, name, &miss);
2971 __ bind(&miss);
2972 GenerateLoadMiss(masm(), Code::LOAD_IC);
2973
2974 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002975 return GetCode(Code::FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002976}
2977
2978
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002979Handle<Code> LoadStubCompiler::CompileLoadCallback(
2980 Handle<String> name,
2981 Handle<JSObject> object,
2982 Handle<JSObject> holder,
2983 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002984 // ----------- S t a t e -------------
2985 // -- a0 : receiver
2986 // -- a2 : name
2987 // -- ra : return address
2988 // -----------------------------------
2989 Label miss;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00002990 GenerateLoadCallback(object, holder, a0, a2, a3, a1, t0, t1, callback, name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002991 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002992 __ bind(&miss);
2993 GenerateLoadMiss(masm(), Code::LOAD_IC);
2994
2995 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002996 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002997}
2998
2999
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003000#undef __
3001#define __ ACCESS_MASM(masm)
3002
3003
3004void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
3005 Handle<JSFunction> getter) {
3006 // ----------- S t a t e -------------
3007 // -- a0 : receiver
3008 // -- a2 : name
3009 // -- ra : return address
3010 // -----------------------------------
3011 {
3012 FrameScope scope(masm, StackFrame::INTERNAL);
3013
3014 if (!getter.is_null()) {
3015 // Call the JavaScript getter with the receiver on the stack.
3016 __ push(a0);
3017 ParameterCount actual(0);
3018 __ InvokeFunction(getter, actual, CALL_FUNCTION, NullCallWrapper(),
3019 CALL_AS_METHOD);
3020 } else {
3021 // If we generate a global code snippet for deoptimization only, remember
3022 // the place to continue after deoptimization.
3023 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
3024 }
3025
3026 // Restore context register.
3027 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
3028 }
3029 __ Ret();
3030}
3031
3032
3033#undef __
3034#define __ ACCESS_MASM(masm())
3035
3036
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003037Handle<Code> LoadStubCompiler::CompileLoadViaGetter(
3038 Handle<String> name,
3039 Handle<JSObject> receiver,
3040 Handle<JSObject> holder,
3041 Handle<JSFunction> getter) {
3042 // ----------- S t a t e -------------
3043 // -- a0 : receiver
3044 // -- a2 : name
3045 // -- ra : return address
3046 // -----------------------------------
3047 Label miss;
3048
3049 // Check that the maps haven't changed.
3050 __ JumpIfSmi(a0, &miss);
3051 CheckPrototypes(receiver, a0, holder, a3, t0, a1, name, &miss);
3052
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003053 GenerateLoadViaGetter(masm(), getter);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003054
3055 __ bind(&miss);
3056 GenerateLoadMiss(masm(), Code::LOAD_IC);
3057
3058 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003059 return GetCode(Code::CALLBACKS, name);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003060}
3061
3062
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003063Handle<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object,
3064 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003065 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003066 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003067 // ----------- S t a t e -------------
3068 // -- a0 : receiver
3069 // -- a2 : name
3070 // -- ra : return address
3071 // -----------------------------------
3072 Label miss;
3073
3074 GenerateLoadConstant(object, holder, a0, a3, a1, t0, value, name, &miss);
3075 __ bind(&miss);
3076 GenerateLoadMiss(masm(), Code::LOAD_IC);
3077
3078 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003079 return GetCode(Code::CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003080}
3081
3082
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003083Handle<Code> LoadStubCompiler::CompileLoadInterceptor(Handle<JSObject> object,
3084 Handle<JSObject> holder,
3085 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003086 // ----------- S t a t e -------------
3087 // -- a0 : receiver
3088 // -- a2 : name
3089 // -- ra : return address
3090 // -- [sp] : receiver
3091 // -----------------------------------
3092 Label miss;
3093
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003094 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003095 LookupPostInterceptor(holder, name, &lookup);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003096 GenerateLoadInterceptor(object, holder, &lookup, a0, a2, a3, a1, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003097 &miss);
3098 __ bind(&miss);
3099 GenerateLoadMiss(masm(), Code::LOAD_IC);
3100
3101 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003102 return GetCode(Code::INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003103}
3104
3105
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003106Handle<Code> LoadStubCompiler::CompileLoadGlobal(
3107 Handle<JSObject> object,
3108 Handle<GlobalObject> holder,
3109 Handle<JSGlobalPropertyCell> cell,
3110 Handle<String> name,
3111 bool is_dont_delete) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003112 // ----------- S t a t e -------------
3113 // -- a0 : receiver
3114 // -- a2 : name
3115 // -- ra : return address
3116 // -----------------------------------
3117 Label miss;
3118
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003119 // Check that the map of the global has not changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003120 __ JumpIfSmi(a0, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003121 CheckPrototypes(object, a0, holder, a3, t0, a1, name, &miss);
3122
3123 // Get the value from the cell.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003124 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003125 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
3126
3127 // Check for deleted property if property can actually be deleted.
3128 if (!is_dont_delete) {
3129 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
3130 __ Branch(&miss, eq, t0, Operand(at));
3131 }
3132
3133 __ mov(v0, t0);
3134 Counters* counters = masm()->isolate()->counters();
3135 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
3136 __ Ret();
3137
3138 __ bind(&miss);
3139 __ IncrementCounter(counters->named_load_global_stub_miss(), 1, a1, a3);
3140 GenerateLoadMiss(masm(), Code::LOAD_IC);
3141
3142 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003143 return GetCode(Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003144}
3145
3146
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003147Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
3148 Handle<JSObject> receiver,
3149 Handle<JSObject> holder,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003150 PropertyIndex index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003151 // ----------- S t a t e -------------
3152 // -- ra : return address
3153 // -- a0 : key
3154 // -- a1 : receiver
3155 // -----------------------------------
3156 Label miss;
3157
3158 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003159 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003160
3161 GenerateLoadField(receiver, holder, a1, a2, a3, t0, index, name, &miss);
3162 __ bind(&miss);
3163 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3164
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003165 return GetCode(Code::FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003166}
3167
3168
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003169Handle<Code> KeyedLoadStubCompiler::CompileLoadCallback(
3170 Handle<String> name,
3171 Handle<JSObject> receiver,
3172 Handle<JSObject> holder,
3173 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003174 // ----------- S t a t e -------------
3175 // -- ra : return address
3176 // -- a0 : key
3177 // -- a1 : receiver
3178 // -----------------------------------
3179 Label miss;
3180
3181 // Check the key is the cached one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003182 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003183
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00003184 GenerateLoadCallback(receiver, holder, a1, a0, a2, a3, t0, t1, callback,
3185 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003186 __ bind(&miss);
3187 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3188
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003189 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003190}
3191
3192
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003193Handle<Code> KeyedLoadStubCompiler::CompileLoadConstant(
3194 Handle<String> name,
3195 Handle<JSObject> receiver,
3196 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003197 Handle<JSFunction> value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003198 // ----------- S t a t e -------------
3199 // -- ra : return address
3200 // -- a0 : key
3201 // -- a1 : receiver
3202 // -----------------------------------
3203 Label miss;
3204
3205 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003206 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003207
3208 GenerateLoadConstant(receiver, holder, a1, a2, a3, t0, value, name, &miss);
3209 __ bind(&miss);
3210 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3211
3212 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003213 return GetCode(Code::CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003214}
3215
3216
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003217Handle<Code> KeyedLoadStubCompiler::CompileLoadInterceptor(
3218 Handle<JSObject> receiver,
3219 Handle<JSObject> holder,
3220 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003221 // ----------- S t a t e -------------
3222 // -- ra : return address
3223 // -- a0 : key
3224 // -- a1 : receiver
3225 // -----------------------------------
3226 Label miss;
3227
3228 // Check the key is the cached one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003229 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003230
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003231 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003232 LookupPostInterceptor(holder, name, &lookup);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003233 GenerateLoadInterceptor(receiver, holder, &lookup, a1, a0, a2, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003234 &miss);
3235 __ bind(&miss);
3236 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3237
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003238 return GetCode(Code::INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003239}
3240
3241
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003242Handle<Code> KeyedLoadStubCompiler::CompileLoadArrayLength(
3243 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003244 // ----------- S t a t e -------------
3245 // -- ra : return address
3246 // -- a0 : key
3247 // -- a1 : receiver
3248 // -----------------------------------
3249 Label miss;
3250
3251 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003252 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003253
3254 GenerateLoadArrayLength(masm(), a1, a2, &miss);
3255 __ bind(&miss);
3256 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3257
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003258 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003259}
3260
3261
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003262Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength(
3263 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003264 // ----------- S t a t e -------------
3265 // -- ra : return address
3266 // -- a0 : key
3267 // -- a1 : receiver
3268 // -----------------------------------
3269 Label miss;
3270
3271 Counters* counters = masm()->isolate()->counters();
3272 __ IncrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
3273
3274 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003275 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003276
3277 GenerateLoadStringLength(masm(), a1, a2, a3, &miss, true);
3278 __ bind(&miss);
3279 __ DecrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
3280
3281 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3282
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003283 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003284}
3285
3286
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003287Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype(
3288 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003289 // ----------- S t a t e -------------
3290 // -- ra : return address
3291 // -- a0 : key
3292 // -- a1 : receiver
3293 // -----------------------------------
3294 Label miss;
3295
3296 Counters* counters = masm()->isolate()->counters();
3297 __ IncrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
3298
3299 // Check the name hasn't changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003300 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003301
3302 GenerateLoadFunctionPrototype(masm(), a1, a2, a3, &miss);
3303 __ bind(&miss);
3304 __ DecrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
3305 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3306
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003307 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003308}
3309
3310
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003311Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
3312 Handle<Map> receiver_map) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003313 // ----------- S t a t e -------------
3314 // -- ra : return address
3315 // -- a0 : key
3316 // -- a1 : receiver
3317 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003318 ElementsKind elements_kind = receiver_map->elements_kind();
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003319 Handle<Code> stub = KeyedLoadElementStub(elements_kind).GetCode();
3320
3321 __ DispatchMap(a1, a2, receiver_map, stub, DO_SMI_CHECK);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003322
3323 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
3324 __ Jump(ic, RelocInfo::CODE_TARGET);
3325
3326 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003327 return GetCode(Code::NORMAL, factory()->empty_string());
danno@chromium.org40cb8782011-05-25 07:58:50 +00003328}
3329
3330
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003331Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
3332 MapHandleList* receiver_maps,
3333 CodeHandleList* handler_ics) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003334 // ----------- S t a t e -------------
3335 // -- ra : return address
3336 // -- a0 : key
3337 // -- a1 : receiver
3338 // -----------------------------------
3339 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003340 __ JumpIfSmi(a1, &miss);
3341
danno@chromium.org40cb8782011-05-25 07:58:50 +00003342 int receiver_count = receiver_maps->length();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003343 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003344 for (int current = 0; current < receiver_count; ++current) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003345 __ Jump(handler_ics->at(current), RelocInfo::CODE_TARGET,
3346 eq, a2, Operand(receiver_maps->at(current)));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003347 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003348
3349 __ bind(&miss);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003350 Handle<Code> miss_ic = isolate()->builtins()->KeyedLoadIC_Miss();
3351 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003352
3353 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003354 return GetCode(Code::NORMAL, factory()->empty_string(), MEGAMORPHIC);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003355}
3356
3357
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003358Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +00003359 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003360 Handle<Map> transition,
3361 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003362 // ----------- S t a t e -------------
3363 // -- a0 : value
3364 // -- a1 : key
3365 // -- a2 : receiver
3366 // -- ra : return address
3367 // -----------------------------------
3368
3369 Label miss;
3370
3371 Counters* counters = masm()->isolate()->counters();
3372 __ IncrementCounter(counters->keyed_store_field(), 1, a3, t0);
3373
3374 // Check that the name has not changed.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003375 __ Branch(&miss, ne, a1, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003376
3377 // a3 is used as scratch register. a1 and a2 keep their values if a jump to
3378 // the miss label is generated.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003379 GenerateStoreField(masm(),
3380 object,
3381 index,
3382 transition,
3383 name,
3384 a2, a1, a3, t0,
3385 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003386 __ bind(&miss);
3387
3388 __ DecrementCounter(counters->keyed_store_field(), 1, a3, t0);
3389 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss();
3390 __ Jump(ic, RelocInfo::CODE_TARGET);
3391
3392 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003393 return GetCode(transition.is_null()
3394 ? Code::FIELD
3395 : Code::MAP_TRANSITION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003396}
3397
3398
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003399Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
3400 Handle<Map> receiver_map) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003401 // ----------- S t a t e -------------
3402 // -- a0 : value
3403 // -- a1 : key
3404 // -- a2 : receiver
3405 // -- ra : return address
3406 // -- a3 : scratch
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003407 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003408 ElementsKind elements_kind = receiver_map->elements_kind();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003409 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003410 Handle<Code> stub =
yangguo@chromium.org56454712012-02-16 15:33:53 +00003411 KeyedStoreElementStub(is_js_array, elements_kind, grow_mode_).GetCode();
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003412
3413 __ DispatchMap(a2, a3, receiver_map, stub, DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003414
danno@chromium.org40cb8782011-05-25 07:58:50 +00003415 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003416 __ Jump(ic, RelocInfo::CODE_TARGET);
3417
3418 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003419 return GetCode(Code::NORMAL, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00003420}
3421
3422
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003423Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
3424 MapHandleList* receiver_maps,
3425 CodeHandleList* handler_stubs,
3426 MapHandleList* transitioned_maps) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003427 // ----------- S t a t e -------------
3428 // -- a0 : value
3429 // -- a1 : key
3430 // -- a2 : receiver
3431 // -- ra : return address
3432 // -- a3 : scratch
3433 // -----------------------------------
3434 Label miss;
3435 __ JumpIfSmi(a2, &miss);
3436
3437 int receiver_count = receiver_maps->length();
3438 __ lw(a3, FieldMemOperand(a2, HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003439 for (int i = 0; i < receiver_count; ++i) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003440 if (transitioned_maps->at(i).is_null()) {
3441 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq,
3442 a3, Operand(receiver_maps->at(i)));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003443 } else {
3444 Label next_map;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003445 __ Branch(&next_map, ne, a3, Operand(receiver_maps->at(i)));
3446 __ li(a3, Operand(transitioned_maps->at(i)));
3447 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003448 __ bind(&next_map);
3449 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003450 }
3451
3452 __ bind(&miss);
3453 Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
3454 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3455
3456 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003457 return GetCode(Code::NORMAL, factory()->empty_string(), MEGAMORPHIC);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003458}
3459
3460
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003461Handle<Code> ConstructStubCompiler::CompileConstructStub(
3462 Handle<JSFunction> function) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003463 // a0 : argc
3464 // a1 : constructor
3465 // ra : return address
3466 // [sp] : last argument
3467 Label generic_stub_call;
3468
3469 // Use t7 for holding undefined which is used in several places below.
3470 __ LoadRoot(t7, Heap::kUndefinedValueRootIndex);
3471
3472#ifdef ENABLE_DEBUGGER_SUPPORT
3473 // Check to see whether there are any break points in the function code. If
3474 // there are jump to the generic constructor stub which calls the actual
3475 // code for the function thereby hitting the break points.
3476 __ lw(t5, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3477 __ lw(a2, FieldMemOperand(t5, SharedFunctionInfo::kDebugInfoOffset));
3478 __ Branch(&generic_stub_call, ne, a2, Operand(t7));
3479#endif
3480
3481 // Load the initial map and verify that it is in fact a map.
3482 // a1: constructor function
3483 // t7: undefined
3484 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003485 __ JumpIfSmi(a2, &generic_stub_call);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003486 __ GetObjectType(a2, a3, t0);
3487 __ Branch(&generic_stub_call, ne, t0, Operand(MAP_TYPE));
3488
3489#ifdef DEBUG
3490 // Cannot construct functions this way.
3491 // a0: argc
3492 // a1: constructor function
3493 // a2: initial map
3494 // t7: undefined
3495 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
3496 __ Check(ne, "Function constructed by construct stub.",
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003497 a3, Operand(JS_FUNCTION_TYPE));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003498#endif
3499
3500 // Now allocate the JSObject in new space.
3501 // a0: argc
3502 // a1: constructor function
3503 // a2: initial map
3504 // t7: undefined
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003505 ASSERT(function->has_initial_map());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003506 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003507#ifdef DEBUG
3508 int instance_size = function->initial_map()->instance_size();
3509 __ Check(eq, "Instance size of initial map changed.",
3510 a3, Operand(instance_size >> kPointerSizeLog2));
3511#endif
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003512 __ AllocateInNewSpace(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003513
3514 // Allocated the JSObject, now initialize the fields. Map is set to initial
3515 // map and properties and elements are set to empty fixed array.
3516 // a0: argc
3517 // a1: constructor function
3518 // a2: initial map
3519 // a3: object size (in words)
3520 // t4: JSObject (not tagged)
3521 // t7: undefined
3522 __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex);
3523 __ mov(t5, t4);
3524 __ sw(a2, MemOperand(t5, JSObject::kMapOffset));
3525 __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset));
3526 __ sw(t6, MemOperand(t5, JSObject::kElementsOffset));
3527 __ Addu(t5, t5, Operand(3 * kPointerSize));
3528 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
3529 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
3530 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
3531
3532
3533 // Calculate the location of the first argument. The stack contains only the
3534 // argc arguments.
3535 __ sll(a1, a0, kPointerSizeLog2);
3536 __ Addu(a1, a1, sp);
3537
3538 // Fill all the in-object properties with undefined.
3539 // a0: argc
3540 // a1: first argument
3541 // a3: object size (in words)
3542 // t4: JSObject (not tagged)
3543 // t5: First in-object property of JSObject (not tagged)
3544 // t7: undefined
3545 // Fill the initialized properties with a constant value or a passed argument
3546 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003547 Handle<SharedFunctionInfo> shared(function->shared());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003548 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3549 if (shared->IsThisPropertyAssignmentArgument(i)) {
3550 Label not_passed, next;
3551 // Check if the argument assigned to the property is actually passed.
3552 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3553 __ Branch(&not_passed, less_equal, a0, Operand(arg_number));
3554 // Argument passed - find it on the stack.
3555 __ lw(a2, MemOperand(a1, (arg_number + 1) * -kPointerSize));
3556 __ sw(a2, MemOperand(t5));
3557 __ Addu(t5, t5, kPointerSize);
3558 __ jmp(&next);
3559 __ bind(&not_passed);
3560 // Set the property to undefined.
3561 __ sw(t7, MemOperand(t5));
3562 __ Addu(t5, t5, Operand(kPointerSize));
3563 __ bind(&next);
3564 } else {
3565 // Set the property to the constant value.
3566 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
3567 __ li(a2, Operand(constant));
3568 __ sw(a2, MemOperand(t5));
3569 __ Addu(t5, t5, kPointerSize);
3570 }
3571 }
3572
3573 // Fill the unused in-object property fields with undefined.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003574 for (int i = shared->this_property_assignments_count();
3575 i < function->initial_map()->inobject_properties();
3576 i++) {
3577 __ sw(t7, MemOperand(t5));
3578 __ Addu(t5, t5, kPointerSize);
3579 }
3580
3581 // a0: argc
3582 // t4: JSObject (not tagged)
3583 // Move argc to a1 and the JSObject to return to v0 and tag it.
3584 __ mov(a1, a0);
3585 __ mov(v0, t4);
3586 __ Or(v0, v0, Operand(kHeapObjectTag));
3587
3588 // v0: JSObject
3589 // a1: argc
3590 // Remove caller arguments and receiver from the stack and return.
3591 __ sll(t0, a1, kPointerSizeLog2);
3592 __ Addu(sp, sp, t0);
3593 __ Addu(sp, sp, Operand(kPointerSize));
3594 Counters* counters = masm()->isolate()->counters();
3595 __ IncrementCounter(counters->constructed_objects(), 1, a1, a2);
3596 __ IncrementCounter(counters->constructed_objects_stub(), 1, a1, a2);
3597 __ Ret();
3598
3599 // Jump to the generic stub in case the specialized code cannot handle the
3600 // construction.
3601 __ bind(&generic_stub_call);
3602 Handle<Code> generic_construct_stub =
3603 masm()->isolate()->builtins()->JSConstructStubGeneric();
3604 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
3605
3606 // Return the generated code.
3607 return GetCode();
3608}
3609
3610
danno@chromium.org40cb8782011-05-25 07:58:50 +00003611#undef __
3612#define __ ACCESS_MASM(masm)
3613
3614
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003615void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3616 MacroAssembler* masm) {
3617 // ---------- S t a t e --------------
3618 // -- ra : return address
3619 // -- a0 : key
3620 // -- a1 : receiver
3621 // -----------------------------------
3622 Label slow, miss_force_generic;
3623
3624 Register key = a0;
3625 Register receiver = a1;
3626
3627 __ JumpIfNotSmi(key, &miss_force_generic);
3628 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
3629 __ sra(a2, a0, kSmiTagSize);
3630 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
3631 __ Ret();
3632
3633 // Slow case, key and receiver still in a0 and a1.
3634 __ bind(&slow);
3635 __ IncrementCounter(
3636 masm->isolate()->counters()->keyed_load_external_array_slow(),
3637 1, a2, a3);
3638 // Entry registers are intact.
3639 // ---------- S t a t e --------------
3640 // -- ra : return address
3641 // -- a0 : key
3642 // -- a1 : receiver
3643 // -----------------------------------
3644 Handle<Code> slow_ic =
3645 masm->isolate()->builtins()->KeyedLoadIC_Slow();
3646 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
3647
3648 // Miss case, call the runtime.
3649 __ bind(&miss_force_generic);
3650
3651 // ---------- S t a t e --------------
3652 // -- ra : return address
3653 // -- a0 : key
3654 // -- a1 : receiver
3655 // -----------------------------------
3656
3657 Handle<Code> miss_ic =
3658 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3659 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3660}
3661
3662
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003663static bool IsElementTypeSigned(ElementsKind elements_kind) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003664 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003665 case EXTERNAL_BYTE_ELEMENTS:
3666 case EXTERNAL_SHORT_ELEMENTS:
3667 case EXTERNAL_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003668 return true;
3669
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003670 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3671 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3672 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3673 case EXTERNAL_PIXEL_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003674 return false;
3675
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003676 case EXTERNAL_FLOAT_ELEMENTS:
3677 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003678 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003679 case FAST_ELEMENTS:
3680 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003681 case FAST_HOLEY_SMI_ELEMENTS:
3682 case FAST_HOLEY_ELEMENTS:
3683 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003684 case DICTIONARY_ELEMENTS:
3685 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003686 UNREACHABLE();
3687 return false;
3688 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003689 return false;
lrn@chromium.org7516f052011-03-30 08:52:27 +00003690}
3691
3692
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003693static void GenerateSmiKeyCheck(MacroAssembler* masm,
3694 Register key,
3695 Register scratch0,
3696 Register scratch1,
3697 FPURegister double_scratch0,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003698 FPURegister double_scratch1,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003699 Label* fail) {
3700 if (CpuFeatures::IsSupported(FPU)) {
3701 CpuFeatures::Scope scope(FPU);
3702 Label key_ok;
3703 // Check for smi or a smi inside a heap number. We convert the heap
3704 // number and check if the conversion is exact and fits into the smi
3705 // range.
3706 __ JumpIfSmi(key, &key_ok);
3707 __ CheckMap(key,
3708 scratch0,
3709 Heap::kHeapNumberMapRootIndex,
3710 fail,
3711 DONT_DO_SMI_CHECK);
3712 __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
3713 __ EmitFPUTruncate(kRoundToZero,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003714 scratch0,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003715 double_scratch0,
3716 at,
3717 double_scratch1,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003718 scratch1,
3719 kCheckForInexactConversion);
3720
3721 __ Branch(fail, ne, scratch1, Operand(zero_reg));
3722
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003723 __ SmiTagCheckOverflow(key, scratch0, scratch1);
3724 __ BranchOnOverflow(fail, scratch1);
3725 __ bind(&key_ok);
3726 } else {
3727 // Check that the key is a smi.
3728 __ JumpIfNotSmi(key, fail);
3729 }
3730}
3731
3732
danno@chromium.org40cb8782011-05-25 07:58:50 +00003733void KeyedLoadStubCompiler::GenerateLoadExternalArray(
3734 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003735 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003736 // ---------- S t a t e --------------
3737 // -- ra : return address
3738 // -- a0 : key
3739 // -- a1 : receiver
3740 // -----------------------------------
danno@chromium.org40cb8782011-05-25 07:58:50 +00003741 Label miss_force_generic, slow, failed_allocation;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003742
3743 Register key = a0;
3744 Register receiver = a1;
3745
danno@chromium.org40cb8782011-05-25 07:58:50 +00003746 // This stub is meant to be tail-jumped to, the receiver must already
3747 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003748
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003749 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003750 GenerateSmiKeyCheck(masm, key, t0, t1, f2, f4, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003751
3752 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3753 // a3: elements array
3754
3755 // Check that the index is in range.
3756 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3757 __ sra(t2, key, kSmiTagSize);
3758 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003759 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003760
3761 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3762 // a3: base pointer of external storage
3763
3764 // We are not untagging smi key and instead work with it
3765 // as if it was premultiplied by 2.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003766 STATIC_ASSERT((kSmiTag == 0) && (kSmiTagSize == 1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003767
3768 Register value = a2;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003769 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003770 case EXTERNAL_BYTE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003771 __ srl(t2, key, 1);
3772 __ addu(t3, a3, t2);
3773 __ lb(value, MemOperand(t3, 0));
3774 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003775 case EXTERNAL_PIXEL_ELEMENTS:
3776 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003777 __ srl(t2, key, 1);
3778 __ addu(t3, a3, t2);
3779 __ lbu(value, MemOperand(t3, 0));
3780 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003781 case EXTERNAL_SHORT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003782 __ addu(t3, a3, key);
3783 __ lh(value, MemOperand(t3, 0));
3784 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003785 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003786 __ addu(t3, a3, key);
3787 __ lhu(value, MemOperand(t3, 0));
3788 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003789 case EXTERNAL_INT_ELEMENTS:
3790 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003791 __ sll(t2, key, 1);
3792 __ addu(t3, a3, t2);
3793 __ lw(value, MemOperand(t3, 0));
3794 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003795 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003796 __ sll(t3, t2, 2);
3797 __ addu(t3, a3, t3);
3798 if (CpuFeatures::IsSupported(FPU)) {
3799 CpuFeatures::Scope scope(FPU);
3800 __ lwc1(f0, MemOperand(t3, 0));
3801 } else {
3802 __ lw(value, MemOperand(t3, 0));
3803 }
3804 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003805 case EXTERNAL_DOUBLE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003806 __ sll(t2, key, 2);
3807 __ addu(t3, a3, t2);
3808 if (CpuFeatures::IsSupported(FPU)) {
3809 CpuFeatures::Scope scope(FPU);
3810 __ ldc1(f0, MemOperand(t3, 0));
3811 } else {
3812 // t3: pointer to the beginning of the double we want to load.
3813 __ lw(a2, MemOperand(t3, 0));
3814 __ lw(a3, MemOperand(t3, Register::kSizeInBytes));
3815 }
3816 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003817 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003818 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003819 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003820 case FAST_HOLEY_ELEMENTS:
3821 case FAST_HOLEY_SMI_ELEMENTS:
3822 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003823 case DICTIONARY_ELEMENTS:
3824 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003825 UNREACHABLE();
3826 break;
3827 }
3828
3829 // For integer array types:
3830 // a2: value
3831 // For float array type:
3832 // f0: value (if FPU is supported)
3833 // a2: value (if FPU is not supported)
3834 // For double array type:
3835 // f0: value (if FPU is supported)
3836 // a2/a3: value (if FPU is not supported)
3837
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003838 if (elements_kind == EXTERNAL_INT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003839 // For the Int and UnsignedInt array types, we need to see whether
3840 // the value can be represented in a Smi. If not, we need to convert
3841 // it to a HeapNumber.
3842 Label box_int;
3843 __ Subu(t3, value, Operand(0xC0000000)); // Non-smi value gives neg result.
3844 __ Branch(&box_int, lt, t3, Operand(zero_reg));
3845 // Tag integer as smi and return it.
3846 __ sll(v0, value, kSmiTagSize);
3847 __ Ret();
3848
3849 __ bind(&box_int);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003850
3851 if (CpuFeatures::IsSupported(FPU)) {
3852 CpuFeatures::Scope scope(FPU);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003853 // Allocate a HeapNumber for the result and perform int-to-double
3854 // conversion.
3855 // The arm version uses a temporary here to save r0, but we don't need to
3856 // (a0 is not modified).
3857 __ LoadRoot(t1, Heap::kHeapNumberMapRootIndex);
3858 __ AllocateHeapNumber(v0, a3, t0, t1, &slow, DONT_TAG_RESULT);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003859 __ mtc1(value, f0);
3860 __ cvt_d_w(f0, f0);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003861 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset));
3862 __ Addu(v0, v0, kHeapObjectTag);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003863 __ Ret();
3864 } else {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003865 // Allocate a HeapNumber for the result and perform int-to-double
3866 // conversion.
3867 // The arm version uses a temporary here to save r0, but we don't need to
3868 // (a0 is not modified).
3869 __ LoadRoot(t1, Heap::kHeapNumberMapRootIndex);
3870 __ AllocateHeapNumber(v0, a3, t0, t1, &slow, TAG_RESULT);
3871 Register dst_mantissa = t2;
3872 Register dst_exponent = t3;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003873 FloatingPointHelper::Destination dest =
3874 FloatingPointHelper::kCoreRegisters;
3875 FloatingPointHelper::ConvertIntToDouble(masm,
3876 value,
3877 dest,
3878 f0,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003879 dst_mantissa,
3880 dst_exponent,
danno@chromium.org40cb8782011-05-25 07:58:50 +00003881 t1,
3882 f2);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003883 __ sw(dst_mantissa, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3884 __ sw(dst_exponent, FieldMemOperand(v0, HeapNumber::kExponentOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003885 __ Ret();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003886 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003887 } else if (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003888 // The test is different for unsigned int values. Since we need
3889 // the value to be in the range of a positive smi, we can't
3890 // handle either of the top two bits being set in the value.
3891 if (CpuFeatures::IsSupported(FPU)) {
3892 CpuFeatures::Scope scope(FPU);
3893 Label pl_box_int;
3894 __ And(t2, value, Operand(0xC0000000));
3895 __ Branch(&pl_box_int, ne, t2, Operand(zero_reg));
3896
3897 // It can fit in an Smi.
3898 // Tag integer as smi and return it.
3899 __ sll(v0, value, kSmiTagSize);
3900 __ Ret();
3901
3902 __ bind(&pl_box_int);
3903 // Allocate a HeapNumber for the result and perform int-to-double
3904 // conversion. Don't use a0 and a1 as AllocateHeapNumber clobbers all
3905 // registers - also when jumping due to exhausted young space.
3906 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003907 __ AllocateHeapNumber(v0, t2, t3, t6, &slow, DONT_TAG_RESULT);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003908
3909 // This is replaced by a macro:
3910 // __ mtc1(value, f0); // LS 32-bits.
3911 // __ mtc1(zero_reg, f1); // MS 32-bits are all zero.
3912 // __ cvt_d_l(f0, f0); // Use 64 bit conv to get correct unsigned 32-bit.
3913
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003914 __ Cvt_d_uw(f0, value, f22);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003915
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003916 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003917
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003918 __ Addu(v0, v0, kHeapObjectTag);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003919 __ Ret();
3920 } else {
3921 // Check whether unsigned integer fits into smi.
3922 Label box_int_0, box_int_1, done;
3923 __ And(t2, value, Operand(0x80000000));
3924 __ Branch(&box_int_0, ne, t2, Operand(zero_reg));
3925 __ And(t2, value, Operand(0x40000000));
3926 __ Branch(&box_int_1, ne, t2, Operand(zero_reg));
3927
3928 // Tag integer as smi and return it.
3929 __ sll(v0, value, kSmiTagSize);
3930 __ Ret();
3931
3932 Register hiword = value; // a2.
3933 Register loword = a3;
3934
3935 __ bind(&box_int_0);
3936 // Integer does not have leading zeros.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003937 GenerateUInt2Double(masm, hiword, loword, t0, 0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003938 __ Branch(&done);
3939
3940 __ bind(&box_int_1);
3941 // Integer has one leading zero.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003942 GenerateUInt2Double(masm, hiword, loword, t0, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003943
3944
3945 __ bind(&done);
3946 // Integer was converted to double in registers hiword:loword.
3947 // Wrap it into a HeapNumber. Don't use a0 and a1 as AllocateHeapNumber
3948 // clobbers all registers - also when jumping due to exhausted young
3949 // space.
3950 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003951 __ AllocateHeapNumber(t2, t3, t5, t6, &slow, TAG_RESULT);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003952
3953 __ sw(hiword, FieldMemOperand(t2, HeapNumber::kExponentOffset));
3954 __ sw(loword, FieldMemOperand(t2, HeapNumber::kMantissaOffset));
3955
3956 __ mov(v0, t2);
3957 __ Ret();
3958 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003959 } else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003960 // For the floating-point array type, we need to always allocate a
3961 // HeapNumber.
3962 if (CpuFeatures::IsSupported(FPU)) {
3963 CpuFeatures::Scope scope(FPU);
3964 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3965 // AllocateHeapNumber clobbers all registers - also when jumping due to
3966 // exhausted young space.
3967 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003968 __ AllocateHeapNumber(v0, t3, t5, t6, &slow, DONT_TAG_RESULT);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003969 // The float (single) value is already in fpu reg f0 (if we use float).
3970 __ cvt_d_s(f0, f0);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003971 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset));
3972
3973 __ Addu(v0, v0, kHeapObjectTag);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003974 __ Ret();
3975 } else {
3976 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3977 // AllocateHeapNumber clobbers all registers - also when jumping due to
3978 // exhausted young space.
3979 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003980 __ AllocateHeapNumber(v0, t3, t5, t6, &slow, TAG_RESULT);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003981 // FPU is not available, do manual single to double conversion.
3982
3983 // a2: floating point value (binary32).
3984 // v0: heap number for result
3985
3986 // Extract mantissa to t4.
3987 __ And(t4, value, Operand(kBinary32MantissaMask));
3988
3989 // Extract exponent to t5.
3990 __ srl(t5, value, kBinary32MantissaBits);
3991 __ And(t5, t5, Operand(kBinary32ExponentMask >> kBinary32MantissaBits));
3992
3993 Label exponent_rebiased;
3994 __ Branch(&exponent_rebiased, eq, t5, Operand(zero_reg));
3995
3996 __ li(t0, 0x7ff);
3997 __ Xor(t1, t5, Operand(0xFF));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003998 __ Movz(t5, t0, t1); // Set t5 to 0x7ff only if t5 is equal to 0xff.
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003999 __ Branch(&exponent_rebiased, eq, t1, Operand(zero_reg));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004000
4001 // Rebias exponent.
4002 __ Addu(t5,
4003 t5,
4004 Operand(-kBinary32ExponentBias + HeapNumber::kExponentBias));
4005
4006 __ bind(&exponent_rebiased);
4007 __ And(a2, value, Operand(kBinary32SignMask));
4008 value = no_reg;
4009 __ sll(t0, t5, HeapNumber::kMantissaBitsInTopWord);
4010 __ or_(a2, a2, t0);
4011
4012 // Shift mantissa.
4013 static const int kMantissaShiftForHiWord =
4014 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
4015
4016 static const int kMantissaShiftForLoWord =
4017 kBitsPerInt - kMantissaShiftForHiWord;
4018
4019 __ srl(t0, t4, kMantissaShiftForHiWord);
4020 __ or_(a2, a2, t0);
4021 __ sll(a0, t4, kMantissaShiftForLoWord);
4022
4023 __ sw(a2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
4024 __ sw(a0, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
4025 __ Ret();
4026 }
4027
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004028 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004029 if (CpuFeatures::IsSupported(FPU)) {
4030 CpuFeatures::Scope scope(FPU);
4031 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
4032 // AllocateHeapNumber clobbers all registers - also when jumping due to
4033 // exhausted young space.
4034 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004035 __ AllocateHeapNumber(v0, t3, t5, t6, &slow, DONT_TAG_RESULT);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004036 // The double value is already in f0
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004037 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset));
4038
4039 __ Addu(v0, v0, kHeapObjectTag);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004040 __ Ret();
4041 } else {
4042 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
4043 // AllocateHeapNumber clobbers all registers - also when jumping due to
4044 // exhausted young space.
4045 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004046 __ AllocateHeapNumber(v0, t3, t5, t6, &slow, TAG_RESULT);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004047
4048 __ sw(a2, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
4049 __ sw(a3, FieldMemOperand(v0, HeapNumber::kExponentOffset));
4050 __ Ret();
4051 }
4052
4053 } else {
4054 // Tag integer as smi and return it.
4055 __ sll(v0, value, kSmiTagSize);
4056 __ Ret();
4057 }
4058
4059 // Slow case, key and receiver still in a0 and a1.
4060 __ bind(&slow);
4061 __ IncrementCounter(
danno@chromium.org40cb8782011-05-25 07:58:50 +00004062 masm->isolate()->counters()->keyed_load_external_array_slow(),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004063 1, a2, a3);
4064
4065 // ---------- S t a t e --------------
4066 // -- ra : return address
4067 // -- a0 : key
4068 // -- a1 : receiver
4069 // -----------------------------------
4070
4071 __ Push(a1, a0);
4072
4073 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
4074
danno@chromium.org40cb8782011-05-25 07:58:50 +00004075 __ bind(&miss_force_generic);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004076 Handle<Code> stub =
4077 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4078 __ Jump(stub, RelocInfo::CODE_TARGET);
lrn@chromium.org7516f052011-03-30 08:52:27 +00004079}
4080
4081
danno@chromium.org40cb8782011-05-25 07:58:50 +00004082void KeyedStoreStubCompiler::GenerateStoreExternalArray(
4083 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004084 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004085 // ---------- S t a t e --------------
4086 // -- a0 : value
4087 // -- a1 : key
4088 // -- a2 : receiver
4089 // -- ra : return address
4090 // -----------------------------------
4091
danno@chromium.org40cb8782011-05-25 07:58:50 +00004092 Label slow, check_heap_number, miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004093
4094 // Register usage.
4095 Register value = a0;
4096 Register key = a1;
4097 Register receiver = a2;
4098 // a3 mostly holds the elements array or the destination external array.
4099
danno@chromium.org40cb8782011-05-25 07:58:50 +00004100 // This stub is meant to be tail-jumped to, the receiver must already
4101 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004102
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004103 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004104 GenerateSmiKeyCheck(masm, key, t0, t1, f2, f4, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004105
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004106 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
4107
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004108 // Check that the index is in range.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004109 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
4110 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004111 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004112
4113 // Handle both smis and HeapNumbers in the fast path. Go to the
4114 // runtime for all other kinds of values.
4115 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004116
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004117 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004118 // Double to pixel conversion is only implemented in the runtime for now.
4119 __ JumpIfNotSmi(value, &slow);
4120 } else {
4121 __ JumpIfNotSmi(value, &check_heap_number);
4122 }
4123 __ SmiUntag(t1, value);
4124 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
4125
4126 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004127 // t1: value (integer).
4128
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004129 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004130 case EXTERNAL_PIXEL_ELEMENTS: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004131 // Clamp the value to [0..255].
4132 // v0 is used as a scratch register here.
4133 Label done;
4134 __ li(v0, Operand(255));
4135 // Normal branch: nop in delay slot.
4136 __ Branch(&done, gt, t1, Operand(v0));
4137 // Use delay slot in this branch.
4138 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg));
4139 __ mov(v0, zero_reg); // In delay slot.
4140 __ mov(v0, t1); // Value is in range 0..255.
4141 __ bind(&done);
4142 __ mov(t1, v0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004143
4144 __ srl(t8, key, 1);
4145 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004146 __ sb(t1, MemOperand(t8, 0));
4147 }
4148 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004149 case EXTERNAL_BYTE_ELEMENTS:
4150 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004151 __ srl(t8, key, 1);
4152 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004153 __ sb(t1, MemOperand(t8, 0));
4154 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004155 case EXTERNAL_SHORT_ELEMENTS:
4156 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004157 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004158 __ sh(t1, MemOperand(t8, 0));
4159 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004160 case EXTERNAL_INT_ELEMENTS:
4161 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004162 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004163 __ addu(t8, a3, t8);
4164 __ sw(t1, MemOperand(t8, 0));
4165 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004166 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004167 // Perform int-to-float conversion and store to memory.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004168 __ SmiUntag(t0, key);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004169 StoreIntAsFloat(masm, a3, t0, t1, t2, t3, t4);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004170 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004171 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004172 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004173 __ addu(a3, a3, t8);
4174 // a3: effective address of the double element
4175 FloatingPointHelper::Destination destination;
4176 if (CpuFeatures::IsSupported(FPU)) {
4177 destination = FloatingPointHelper::kFPURegisters;
4178 } else {
4179 destination = FloatingPointHelper::kCoreRegisters;
4180 }
4181 FloatingPointHelper::ConvertIntToDouble(
danno@chromium.org40cb8782011-05-25 07:58:50 +00004182 masm, t1, destination,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004183 f0, t2, t3, // These are: double_dst, dst_mantissa, dst_exponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004184 t0, f2); // These are: scratch2, single_scratch.
4185 if (destination == FloatingPointHelper::kFPURegisters) {
4186 CpuFeatures::Scope scope(FPU);
4187 __ sdc1(f0, MemOperand(a3, 0));
4188 } else {
4189 __ sw(t2, MemOperand(a3, 0));
4190 __ sw(t3, MemOperand(a3, Register::kSizeInBytes));
4191 }
4192 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004193 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004194 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004195 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004196 case FAST_HOLEY_ELEMENTS:
4197 case FAST_HOLEY_SMI_ELEMENTS:
4198 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004199 case DICTIONARY_ELEMENTS:
4200 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004201 UNREACHABLE();
4202 break;
4203 }
4204
4205 // Entry registers are intact, a0 holds the value which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004206 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004207 __ Ret();
4208
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004209 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004210 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004211 __ bind(&check_heap_number);
4212 __ GetObjectType(value, t1, t2);
4213 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE));
4214
4215 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
4216
4217 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004218
4219 // The WebGL specification leaves the behavior of storing NaN and
4220 // +/-Infinity into integer arrays basically undefined. For more
4221 // reproducible behavior, convert these to zero.
4222
4223 if (CpuFeatures::IsSupported(FPU)) {
4224 CpuFeatures::Scope scope(FPU);
4225
4226 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
4227
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004228 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004229 __ cvt_s_d(f0, f0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004230 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004231 __ addu(t8, a3, t8);
4232 __ swc1(f0, MemOperand(t8, 0));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004233 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004234 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004235 __ addu(t8, a3, t8);
4236 __ sdc1(f0, MemOperand(t8, 0));
4237 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00004238 __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004239
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004240 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004241 case EXTERNAL_BYTE_ELEMENTS:
4242 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004243 __ srl(t8, key, 1);
4244 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004245 __ sb(t3, MemOperand(t8, 0));
4246 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004247 case EXTERNAL_SHORT_ELEMENTS:
4248 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004249 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004250 __ sh(t3, MemOperand(t8, 0));
4251 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004252 case EXTERNAL_INT_ELEMENTS:
4253 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004254 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004255 __ addu(t8, a3, t8);
4256 __ sw(t3, MemOperand(t8, 0));
4257 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004258 case EXTERNAL_PIXEL_ELEMENTS:
4259 case EXTERNAL_FLOAT_ELEMENTS:
4260 case EXTERNAL_DOUBLE_ELEMENTS:
4261 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004262 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004263 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004264 case FAST_HOLEY_ELEMENTS:
4265 case FAST_HOLEY_SMI_ELEMENTS:
4266 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004267 case DICTIONARY_ELEMENTS:
4268 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004269 UNREACHABLE();
4270 break;
4271 }
4272 }
4273
4274 // Entry registers are intact, a0 holds the value
4275 // which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004276 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004277 __ Ret();
4278 } else {
4279 // FPU is not available, do manual conversions.
4280
4281 __ lw(t3, FieldMemOperand(value, HeapNumber::kExponentOffset));
4282 __ lw(t4, FieldMemOperand(value, HeapNumber::kMantissaOffset));
4283
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004284 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004285 Label done, nan_or_infinity_or_zero;
4286 static const int kMantissaInHiWordShift =
4287 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
4288
4289 static const int kMantissaInLoWordShift =
4290 kBitsPerInt - kMantissaInHiWordShift;
4291
4292 // Test for all special exponent values: zeros, subnormal numbers, NaNs
4293 // and infinities. All these should be converted to 0.
4294 __ li(t5, HeapNumber::kExponentMask);
4295 __ and_(t6, t3, t5);
4296 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(zero_reg));
4297
4298 __ xor_(t1, t6, t5);
4299 __ li(t2, kBinary32ExponentMask);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004300 __ Movz(t6, t2, t1); // Only if t6 is equal to t5.
rossberg@chromium.org400388e2012-06-06 09:29:22 +00004301 __ Branch(&nan_or_infinity_or_zero, eq, t1, Operand(zero_reg));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004302
4303 // Rebias exponent.
4304 __ srl(t6, t6, HeapNumber::kExponentShift);
4305 __ Addu(t6,
4306 t6,
4307 Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
4308
4309 __ li(t1, Operand(kBinary32MaxExponent));
4310 __ Slt(t1, t1, t6);
4311 __ And(t2, t3, Operand(HeapNumber::kSignMask));
4312 __ Or(t2, t2, Operand(kBinary32ExponentMask));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004313 __ Movn(t3, t2, t1); // Only if t6 is gt kBinary32MaxExponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004314 __ Branch(&done, gt, t6, Operand(kBinary32MaxExponent));
4315
4316 __ Slt(t1, t6, Operand(kBinary32MinExponent));
4317 __ And(t2, t3, Operand(HeapNumber::kSignMask));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004318 __ Movn(t3, t2, t1); // Only if t6 is lt kBinary32MinExponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004319 __ Branch(&done, lt, t6, Operand(kBinary32MinExponent));
4320
4321 __ And(t7, t3, Operand(HeapNumber::kSignMask));
4322 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4323 __ sll(t3, t3, kMantissaInHiWordShift);
4324 __ or_(t7, t7, t3);
4325 __ srl(t4, t4, kMantissaInLoWordShift);
4326 __ or_(t7, t7, t4);
4327 __ sll(t6, t6, kBinary32ExponentShift);
4328 __ or_(t3, t7, t6);
4329
4330 __ bind(&done);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004331 __ sll(t9, key, 1);
rossberg@chromium.org400388e2012-06-06 09:29:22 +00004332 __ addu(t9, a3, t9);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004333 __ sw(t3, MemOperand(t9, 0));
4334
4335 // Entry registers are intact, a0 holds the value which is the return
4336 // value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004337 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004338 __ Ret();
4339
4340 __ bind(&nan_or_infinity_or_zero);
4341 __ And(t7, t3, Operand(HeapNumber::kSignMask));
4342 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4343 __ or_(t6, t6, t7);
4344 __ sll(t3, t3, kMantissaInHiWordShift);
4345 __ or_(t6, t6, t3);
4346 __ srl(t4, t4, kMantissaInLoWordShift);
4347 __ or_(t3, t6, t4);
4348 __ Branch(&done);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004349 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00004350 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004351 __ addu(t8, a3, t8);
4352 // t8: effective address of destination element.
4353 __ sw(t4, MemOperand(t8, 0));
4354 __ sw(t3, MemOperand(t8, Register::kSizeInBytes));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004355 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004356 __ Ret();
4357 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004358 bool is_signed_type = IsElementTypeSigned(elements_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004359 int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
4360 int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
4361
4362 Label done, sign;
4363
4364 // Test for all special exponent values: zeros, subnormal numbers, NaNs
4365 // and infinities. All these should be converted to 0.
4366 __ li(t5, HeapNumber::kExponentMask);
4367 __ and_(t6, t3, t5);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004368 __ Movz(t3, zero_reg, t6); // Only if t6 is equal to zero.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004369 __ Branch(&done, eq, t6, Operand(zero_reg));
4370
4371 __ xor_(t2, t6, t5);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004372 __ Movz(t3, zero_reg, t2); // Only if t6 is equal to t5.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004373 __ Branch(&done, eq, t6, Operand(t5));
4374
4375 // Unbias exponent.
4376 __ srl(t6, t6, HeapNumber::kExponentShift);
4377 __ Subu(t6, t6, Operand(HeapNumber::kExponentBias));
4378 // If exponent is negative then result is 0.
4379 __ slt(t2, t6, zero_reg);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004380 __ Movn(t3, zero_reg, t2); // Only if exponent is negative.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004381 __ Branch(&done, lt, t6, Operand(zero_reg));
4382
4383 // If exponent is too big then result is minimal value.
4384 __ slti(t1, t6, meaningfull_bits - 1);
4385 __ li(t2, min_value);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004386 __ Movz(t3, t2, t1); // Only if t6 is ge meaningfull_bits - 1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004387 __ Branch(&done, ge, t6, Operand(meaningfull_bits - 1));
4388
4389 __ And(t5, t3, Operand(HeapNumber::kSignMask));
4390 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4391 __ Or(t3, t3, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
4392
4393 __ li(t9, HeapNumber::kMantissaBitsInTopWord);
4394 __ subu(t6, t9, t6);
4395 __ slt(t1, t6, zero_reg);
4396 __ srlv(t2, t3, t6);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004397 __ Movz(t3, t2, t1); // Only if t6 is positive.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004398 __ Branch(&sign, ge, t6, Operand(zero_reg));
4399
4400 __ subu(t6, zero_reg, t6);
4401 __ sllv(t3, t3, t6);
4402 __ li(t9, meaningfull_bits);
4403 __ subu(t6, t9, t6);
4404 __ srlv(t4, t4, t6);
4405 __ or_(t3, t3, t4);
4406
4407 __ bind(&sign);
4408 __ subu(t2, t3, zero_reg);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004409 __ Movz(t3, t2, t5); // Only if t5 is zero.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004410
4411 __ bind(&done);
4412
4413 // Result is in t3.
4414 // This switch block should be exactly the same as above (FPU mode).
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004415 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004416 case EXTERNAL_BYTE_ELEMENTS:
4417 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004418 __ srl(t8, key, 1);
4419 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004420 __ sb(t3, MemOperand(t8, 0));
4421 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004422 case EXTERNAL_SHORT_ELEMENTS:
4423 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004424 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004425 __ sh(t3, MemOperand(t8, 0));
4426 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004427 case EXTERNAL_INT_ELEMENTS:
4428 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004429 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004430 __ addu(t8, a3, t8);
4431 __ sw(t3, MemOperand(t8, 0));
4432 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004433 case EXTERNAL_PIXEL_ELEMENTS:
4434 case EXTERNAL_FLOAT_ELEMENTS:
4435 case EXTERNAL_DOUBLE_ELEMENTS:
4436 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004437 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004438 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004439 case FAST_HOLEY_ELEMENTS:
4440 case FAST_HOLEY_SMI_ELEMENTS:
4441 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004442 case DICTIONARY_ELEMENTS:
4443 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004444 UNREACHABLE();
4445 break;
4446 }
4447 }
4448 }
4449 }
4450
danno@chromium.org40cb8782011-05-25 07:58:50 +00004451 // Slow case, key and receiver still in a0 and a1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004452 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004453 __ IncrementCounter(
4454 masm->isolate()->counters()->keyed_load_external_array_slow(),
4455 1, a2, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004456 // Entry registers are intact.
4457 // ---------- S t a t e --------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004458 // -- ra : return address
danno@chromium.org40cb8782011-05-25 07:58:50 +00004459 // -- a0 : key
4460 // -- a1 : receiver
4461 // -----------------------------------
4462 Handle<Code> slow_ic =
4463 masm->isolate()->builtins()->KeyedStoreIC_Slow();
4464 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4465
4466 // Miss case, call the runtime.
4467 __ bind(&miss_force_generic);
4468
4469 // ---------- S t a t e --------------
4470 // -- ra : return address
4471 // -- a0 : key
4472 // -- a1 : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004473 // -----------------------------------
4474
danno@chromium.org40cb8782011-05-25 07:58:50 +00004475 Handle<Code> miss_ic =
4476 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4477 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
4478}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004479
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004480
danno@chromium.org40cb8782011-05-25 07:58:50 +00004481void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
4482 // ----------- S t a t e -------------
4483 // -- ra : return address
4484 // -- a0 : key
4485 // -- a1 : receiver
4486 // -----------------------------------
4487 Label miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004488
danno@chromium.org40cb8782011-05-25 07:58:50 +00004489 // This stub is meant to be tail-jumped to, the receiver must already
4490 // have been verified by the caller to not be a smi.
4491
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004492 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004493 GenerateSmiKeyCheck(masm, a0, t0, t1, f2, f4, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004494
4495 // Get the elements array.
4496 __ lw(a2, FieldMemOperand(a1, JSObject::kElementsOffset));
4497 __ AssertFastElements(a2);
4498
4499 // Check that the key is within bounds.
4500 __ lw(a3, FieldMemOperand(a2, FixedArray::kLengthOffset));
ulan@chromium.org6ff65142012-03-21 09:52:17 +00004501 __ Branch(USE_DELAY_SLOT, &miss_force_generic, hs, a0, Operand(a3));
danno@chromium.org40cb8782011-05-25 07:58:50 +00004502
4503 // Load the result and make sure it's not the hole.
4504 __ Addu(a3, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004505 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004506 __ sll(t0, a0, kPointerSizeLog2 - kSmiTagSize);
4507 __ Addu(t0, t0, a3);
4508 __ lw(t0, MemOperand(t0));
4509 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
4510 __ Branch(&miss_force_generic, eq, t0, Operand(t1));
ulan@chromium.org6ff65142012-03-21 09:52:17 +00004511 __ Ret(USE_DELAY_SLOT);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004512 __ mov(v0, t0);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004513
4514 __ bind(&miss_force_generic);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004515 Handle<Code> stub =
4516 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4517 __ Jump(stub, RelocInfo::CODE_TARGET);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004518}
4519
4520
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004521void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
4522 MacroAssembler* masm) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004523 // ----------- S t a t e -------------
4524 // -- ra : return address
4525 // -- a0 : key
4526 // -- a1 : receiver
4527 // -----------------------------------
4528 Label miss_force_generic, slow_allocate_heapnumber;
4529
4530 Register key_reg = a0;
4531 Register receiver_reg = a1;
4532 Register elements_reg = a2;
4533 Register heap_number_reg = a2;
4534 Register indexed_double_offset = a3;
4535 Register scratch = t0;
4536 Register scratch2 = t1;
4537 Register scratch3 = t2;
4538 Register heap_number_map = t3;
4539
4540 // This stub is meant to be tail-jumped to, the receiver must already
4541 // have been verified by the caller to not be a smi.
4542
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004543 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004544 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004545
4546 // Get the elements array.
4547 __ lw(elements_reg,
4548 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4549
4550 // Check that the key is within bounds.
4551 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4552 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4553
4554 // Load the upper word of the double in the fixed array and test for NaN.
4555 __ sll(scratch2, key_reg, kDoubleSizeLog2 - kSmiTagSize);
4556 __ Addu(indexed_double_offset, elements_reg, Operand(scratch2));
4557 uint32_t upper_32_offset = FixedArray::kHeaderSize + sizeof(kHoleNanLower32);
4558 __ lw(scratch, FieldMemOperand(indexed_double_offset, upper_32_offset));
4559 __ Branch(&miss_force_generic, eq, scratch, Operand(kHoleNanUpper32));
4560
4561 // Non-NaN. Allocate a new heap number and copy the double value into it.
4562 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
4563 __ AllocateHeapNumber(heap_number_reg, scratch2, scratch3,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004564 heap_number_map, &slow_allocate_heapnumber, TAG_RESULT);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004565
4566 // Don't need to reload the upper 32 bits of the double, it's already in
4567 // scratch.
4568 __ sw(scratch, FieldMemOperand(heap_number_reg,
4569 HeapNumber::kExponentOffset));
4570 __ lw(scratch, FieldMemOperand(indexed_double_offset,
4571 FixedArray::kHeaderSize));
4572 __ sw(scratch, FieldMemOperand(heap_number_reg,
4573 HeapNumber::kMantissaOffset));
4574
4575 __ mov(v0, heap_number_reg);
4576 __ Ret();
4577
4578 __ bind(&slow_allocate_heapnumber);
4579 Handle<Code> slow_ic =
4580 masm->isolate()->builtins()->KeyedLoadIC_Slow();
4581 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4582
4583 __ bind(&miss_force_generic);
4584 Handle<Code> miss_ic =
4585 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4586 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004587}
4588
4589
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004590void KeyedStoreStubCompiler::GenerateStoreFastElement(
4591 MacroAssembler* masm,
4592 bool is_js_array,
yangguo@chromium.org56454712012-02-16 15:33:53 +00004593 ElementsKind elements_kind,
4594 KeyedAccessGrowMode grow_mode) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00004595 // ----------- S t a t e -------------
4596 // -- a0 : value
4597 // -- a1 : key
4598 // -- a2 : receiver
4599 // -- ra : return address
4600 // -- a3 : scratch
4601 // -- a4 : scratch (elements)
4602 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00004603 Label miss_force_generic, transition_elements_kind, grow, slow;
4604 Label finish_store, check_capacity;
danno@chromium.org40cb8782011-05-25 07:58:50 +00004605
4606 Register value_reg = a0;
4607 Register key_reg = a1;
4608 Register receiver_reg = a2;
yangguo@chromium.org56454712012-02-16 15:33:53 +00004609 Register scratch = t0;
4610 Register elements_reg = a3;
4611 Register length_reg = t1;
4612 Register scratch2 = t2;
danno@chromium.org40cb8782011-05-25 07:58:50 +00004613
4614 // This stub is meant to be tail-jumped to, the receiver must already
4615 // have been verified by the caller to not be a smi.
4616
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004617 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004618 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004619
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004620 if (IsFastSmiElementsKind(elements_kind)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00004621 __ JumpIfNotSmi(value_reg, &transition_elements_kind);
4622 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004623
4624 // Check that the key is within bounds.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004625 __ lw(elements_reg,
4626 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00004627 if (is_js_array) {
4628 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4629 } else {
4630 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4631 }
4632 // Compare smis.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004633 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4634 __ Branch(&grow, hs, key_reg, Operand(scratch));
4635 } else {
4636 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4637 }
4638
4639 // Make sure elements is a fast element array, not 'cow'.
4640 __ CheckMap(elements_reg,
4641 scratch,
4642 Heap::kFixedArrayMapRootIndex,
4643 &miss_force_generic,
4644 DONT_DO_SMI_CHECK);
4645
4646 __ bind(&finish_store);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004647
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004648 if (IsFastSmiElementsKind(elements_kind)) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004649 __ Addu(scratch,
4650 elements_reg,
4651 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4652 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4653 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4654 __ Addu(scratch, scratch, scratch2);
4655 __ sw(value_reg, MemOperand(scratch));
4656 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004657 ASSERT(IsFastObjectElementsKind(elements_kind));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004658 __ Addu(scratch,
4659 elements_reg,
4660 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4661 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4662 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4663 __ Addu(scratch, scratch, scratch2);
4664 __ sw(value_reg, MemOperand(scratch));
4665 __ mov(receiver_reg, value_reg);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004666 __ RecordWrite(elements_reg, // Object.
4667 scratch, // Address.
4668 receiver_reg, // Value.
4669 kRAHasNotBeenSaved,
4670 kDontSaveFPRegs);
4671 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004672 // value_reg (a0) is preserved.
4673 // Done.
4674 __ Ret();
4675
4676 __ bind(&miss_force_generic);
4677 Handle<Code> ic =
4678 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4679 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004680
4681 __ bind(&transition_elements_kind);
4682 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4683 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
yangguo@chromium.org56454712012-02-16 15:33:53 +00004684
4685 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4686 // Grow the array by a single element if possible.
4687 __ bind(&grow);
4688
4689 // Make sure the array is only growing by a single element, anything else
4690 // must be handled by the runtime.
4691 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch));
4692
4693 // Check for the empty array, and preallocate a small backing store if
4694 // possible.
4695 __ lw(length_reg,
4696 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4697 __ lw(elements_reg,
4698 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4699 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
4700 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
4701
4702 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
4703 __ AllocateInNewSpace(size, elements_reg, scratch, scratch2, &slow,
4704 TAG_OBJECT);
4705
4706 __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex);
4707 __ sw(scratch, FieldMemOperand(elements_reg, JSObject::kMapOffset));
4708 __ li(scratch, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4709 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4710 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
4711 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
4712 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::SizeFor(i)));
4713 }
4714
4715 // Store the element at index zero.
4716 __ sw(value_reg, FieldMemOperand(elements_reg, FixedArray::SizeFor(0)));
4717
4718 // Install the new backing store in the JSArray.
4719 __ sw(elements_reg,
4720 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4721 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
4722 scratch, kRAHasNotBeenSaved, kDontSaveFPRegs,
4723 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4724
4725 // Increment the length of the array.
4726 __ li(length_reg, Operand(Smi::FromInt(1)));
4727 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4728 __ Ret();
4729
4730 __ bind(&check_capacity);
4731 // Check for cow elements, in general they are not handled by this stub
4732 __ CheckMap(elements_reg,
4733 scratch,
4734 Heap::kFixedCOWArrayMapRootIndex,
4735 &miss_force_generic,
4736 DONT_DO_SMI_CHECK);
4737
4738 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4739 __ Branch(&slow, hs, length_reg, Operand(scratch));
4740
4741 // Grow the array and finish the store.
4742 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
4743 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4744 __ jmp(&finish_store);
4745
4746 __ bind(&slow);
4747 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4748 __ Jump(ic_slow, RelocInfo::CODE_TARGET);
4749 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004750}
4751
4752
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004753void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
4754 MacroAssembler* masm,
yangguo@chromium.org56454712012-02-16 15:33:53 +00004755 bool is_js_array,
4756 KeyedAccessGrowMode grow_mode) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004757 // ----------- S t a t e -------------
4758 // -- a0 : value
4759 // -- a1 : key
4760 // -- a2 : receiver
4761 // -- ra : return address
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004762 // -- a3 : scratch (elements backing store)
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004763 // -- t0 : scratch (elements_reg)
4764 // -- t1 : scratch (mantissa_reg)
4765 // -- t2 : scratch (exponent_reg)
4766 // -- t3 : scratch4
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004767 // -- t4 : scratch
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004768 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00004769 Label miss_force_generic, transition_elements_kind, grow, slow;
4770 Label finish_store, check_capacity;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004771
4772 Register value_reg = a0;
4773 Register key_reg = a1;
4774 Register receiver_reg = a2;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004775 Register elements_reg = a3;
4776 Register scratch1 = t0;
4777 Register scratch2 = t1;
4778 Register scratch3 = t2;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004779 Register scratch4 = t3;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004780 Register scratch5 = t4;
yangguo@chromium.org56454712012-02-16 15:33:53 +00004781 Register length_reg = t3;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004782
4783 // This stub is meant to be tail-jumped to, the receiver must already
4784 // have been verified by the caller to not be a smi.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004785
4786 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004787 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004788
4789 __ lw(elements_reg,
4790 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4791
4792 // Check that the key is within bounds.
4793 if (is_js_array) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004794 __ lw(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004795 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004796 __ lw(scratch1,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004797 FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4798 }
4799 // Compare smis, unsigned compare catches both negative and out-of-bound
4800 // indexes.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004801 if (grow_mode == ALLOW_JSARRAY_GROWTH) {
4802 __ Branch(&grow, hs, key_reg, Operand(scratch1));
4803 } else {
4804 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch1));
4805 }
4806
4807 __ bind(&finish_store);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004808
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004809 __ StoreNumberToDoubleElements(value_reg,
4810 key_reg,
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004811 // All registers after this are overwritten.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004812 elements_reg,
4813 scratch1,
4814 scratch2,
4815 scratch3,
4816 scratch4,
4817 &transition_elements_kind);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004818
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004819 __ Ret(USE_DELAY_SLOT);
4820 __ mov(v0, value_reg); // In delay slot.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004821
4822 // Handle store cache miss, replacing the ic with the generic stub.
4823 __ bind(&miss_force_generic);
4824 Handle<Code> ic =
4825 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4826 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004827
4828 __ bind(&transition_elements_kind);
4829 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4830 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
yangguo@chromium.org56454712012-02-16 15:33:53 +00004831
4832 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4833 // Grow the array by a single element if possible.
4834 __ bind(&grow);
4835
4836 // Make sure the array is only growing by a single element, anything else
4837 // must be handled by the runtime.
4838 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch1));
4839
4840 // Transition on values that can't be stored in a FixedDoubleArray.
4841 Label value_is_smi;
4842 __ JumpIfSmi(value_reg, &value_is_smi);
4843 __ lw(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
4844 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
4845 __ Branch(&transition_elements_kind, ne, scratch1, Operand(at));
4846 __ bind(&value_is_smi);
4847
4848 // Check for the empty array, and preallocate a small backing store if
4849 // possible.
4850 __ lw(length_reg,
4851 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4852 __ lw(elements_reg,
4853 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4854 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
4855 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
4856
4857 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
4858 __ AllocateInNewSpace(size, elements_reg, scratch1, scratch2, &slow,
4859 TAG_OBJECT);
4860
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004861 // Initialize the new FixedDoubleArray.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004862 __ LoadRoot(scratch1, Heap::kFixedDoubleArrayMapRootIndex);
4863 __ sw(scratch1, FieldMemOperand(elements_reg, JSObject::kMapOffset));
4864 __ li(scratch1, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4865 __ sw(scratch1,
4866 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
4867
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004868 __ mov(scratch1, elements_reg);
4869 __ StoreNumberToDoubleElements(value_reg,
4870 key_reg,
4871 // All registers after this are overwritten.
4872 scratch1,
4873 scratch2,
4874 scratch3,
4875 scratch4,
4876 scratch5,
4877 &transition_elements_kind);
4878
4879 __ li(scratch1, Operand(kHoleNanLower32));
4880 __ li(scratch2, Operand(kHoleNanUpper32));
4881 for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) {
4882 int offset = FixedDoubleArray::OffsetOfElementAt(i);
4883 __ sw(scratch1, FieldMemOperand(elements_reg, offset));
4884 __ sw(scratch2, FieldMemOperand(elements_reg, offset + kPointerSize));
4885 }
4886
yangguo@chromium.org56454712012-02-16 15:33:53 +00004887 // Install the new backing store in the JSArray.
4888 __ sw(elements_reg,
4889 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4890 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
4891 scratch1, kRAHasNotBeenSaved, kDontSaveFPRegs,
4892 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4893
4894 // Increment the length of the array.
4895 __ li(length_reg, Operand(Smi::FromInt(1)));
4896 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
danno@chromium.org00379b82012-05-04 09:16:29 +00004897 __ lw(elements_reg,
4898 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004899 __ Ret();
yangguo@chromium.org56454712012-02-16 15:33:53 +00004900
4901 __ bind(&check_capacity);
4902 // Make sure that the backing store can hold additional elements.
4903 __ lw(scratch1,
4904 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
4905 __ Branch(&slow, hs, length_reg, Operand(scratch1));
4906
4907 // Grow the array and finish the store.
4908 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
4909 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4910 __ jmp(&finish_store);
4911
4912 __ bind(&slow);
4913 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4914 __ Jump(ic_slow, RelocInfo::CODE_TARGET);
4915 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004916}
4917
4918
ager@chromium.org5c838252010-02-19 08:53:10 +00004919#undef __
4920
4921} } // namespace v8::internal
4922
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004923#endif // V8_TARGET_ARCH_MIPS