blob: 8325afe2f9a471906d22fbbd7325652a565b8528 [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.
273 __ lw(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
274 // Load the global context from the global or builtins object.
275 __ lw(prototype,
276 FieldMemOperand(prototype, GlobalObject::kGlobalContextOffset));
277 // Load the function from the global context.
278 __ lw(prototype, MemOperand(prototype, Context::SlotOffset(index)));
279 // Load the initial map. The global functions all have initial maps.
280 __ lw(prototype,
281 FieldMemOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
282 // Load the prototype from the initial map.
283 __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000284}
285
286
lrn@chromium.org7516f052011-03-30 08:52:27 +0000287void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000288 MacroAssembler* masm,
289 int index,
290 Register prototype,
291 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000292 Isolate* isolate = masm->isolate();
293 // Check we're still in the same context.
294 __ lw(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
295 ASSERT(!prototype.is(at));
296 __ li(at, isolate->global());
297 __ Branch(miss, ne, prototype, Operand(at));
298 // Get the global function with the given index.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000299 Handle<JSFunction> function(
300 JSFunction::cast(isolate->global_context()->get(index)));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000301 // Load its initial map. The global functions all have initial maps.
302 __ li(prototype, Handle<Map>(function->initial_map()));
303 // Load the prototype from the initial map.
304 __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000305}
306
307
ager@chromium.org5c838252010-02-19 08:53:10 +0000308// Load a fast property out of a holder object (src). In-object properties
309// are loaded directly otherwise the property is loaded from the properties
310// fixed array.
311void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000312 Register dst,
313 Register src,
314 Handle<JSObject> holder,
315 int index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000316 // Adjust for the number of properties stored in the holder.
317 index -= holder->map()->inobject_properties();
318 if (index < 0) {
319 // Get the property straight out of the holder.
320 int offset = holder->map()->instance_size() + (index * kPointerSize);
321 __ lw(dst, FieldMemOperand(src, offset));
322 } else {
323 // Calculate the offset into the properties array.
324 int offset = index * kPointerSize + FixedArray::kHeaderSize;
325 __ lw(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
326 __ lw(dst, FieldMemOperand(dst, offset));
327 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000328}
329
330
331void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
332 Register receiver,
333 Register scratch,
334 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000335 // Check that the receiver isn't a smi.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000336 __ JumpIfSmi(receiver, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000337
338 // Check that the object is a JS array.
339 __ GetObjectType(receiver, scratch, scratch);
340 __ Branch(miss_label, ne, scratch, Operand(JS_ARRAY_TYPE));
341
342 // Load length directly from the JS array.
343 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
344 __ Ret();
345}
346
347
348// Generate code to check if an object is a string. If the object is a
349// heap object, its map's instance type is left in the scratch1 register.
350// If this is not needed, scratch1 and scratch2 may be the same register.
351static void GenerateStringCheck(MacroAssembler* masm,
352 Register receiver,
353 Register scratch1,
354 Register scratch2,
355 Label* smi,
356 Label* non_string_object) {
357 // Check that the receiver isn't a smi.
358 __ JumpIfSmi(receiver, smi, t0);
359
360 // Check that the object is a string.
361 __ lw(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
362 __ lbu(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
363 __ And(scratch2, scratch1, Operand(kIsNotStringMask));
364 // The cast is to resolve the overload for the argument of 0x0.
365 __ Branch(non_string_object,
366 ne,
367 scratch2,
368 Operand(static_cast<int32_t>(kStringTag)));
ager@chromium.org5c838252010-02-19 08:53:10 +0000369}
370
371
lrn@chromium.org7516f052011-03-30 08:52:27 +0000372// Generate code to load the length from a string object and return the length.
373// If the receiver object is not a string or a wrapped string object the
374// execution continues at the miss label. The register containing the
375// receiver is potentially clobbered.
376void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
377 Register receiver,
378 Register scratch1,
379 Register scratch2,
380 Label* miss,
381 bool support_wrappers) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000382 Label check_wrapper;
383
384 // Check if the object is a string leaving the instance type in the
385 // scratch1 register.
386 GenerateStringCheck(masm, receiver, scratch1, scratch2, miss,
387 support_wrappers ? &check_wrapper : miss);
388
389 // Load length directly from the string.
390 __ lw(v0, FieldMemOperand(receiver, String::kLengthOffset));
391 __ Ret();
392
393 if (support_wrappers) {
394 // Check if the object is a JSValue wrapper.
395 __ bind(&check_wrapper);
396 __ Branch(miss, ne, scratch1, Operand(JS_VALUE_TYPE));
397
398 // Unwrap the value and check if the wrapped value is a string.
399 __ lw(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
400 GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
401 __ lw(v0, FieldMemOperand(scratch1, String::kLengthOffset));
402 __ Ret();
403 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000404}
405
406
ager@chromium.org5c838252010-02-19 08:53:10 +0000407void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
408 Register receiver,
409 Register scratch1,
410 Register scratch2,
411 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000412 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
413 __ mov(v0, scratch1);
414 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000415}
416
417
lrn@chromium.org7516f052011-03-30 08:52:27 +0000418// Generate StoreField code, value is passed in a0 register.
ager@chromium.org5c838252010-02-19 08:53:10 +0000419// After executing generated code, the receiver_reg and name_reg
420// may be clobbered.
421void StubCompiler::GenerateStoreField(MacroAssembler* masm,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000422 Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +0000423 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000424 Handle<Map> transition,
ager@chromium.org5c838252010-02-19 08:53:10 +0000425 Register receiver_reg,
426 Register name_reg,
427 Register scratch,
428 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000429 // a0 : value.
430 Label exit;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000431 // Check that the map of the object hasn't changed.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000432 CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
433 : REQUIRE_EXACT_MAP;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000434 __ CheckMap(receiver_reg, scratch, Handle<Map>(object->map()), miss_label,
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000435 DO_SMI_CHECK, mode);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000436
437 // Perform global security token check if needed.
438 if (object->IsJSGlobalProxy()) {
439 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
440 }
441
442 // Stub never generated for non-global objects that require access
443 // checks.
444 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
445
446 // Perform map transition for the receiver if necessary.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000447 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000448 // The properties must be extended before we can store the value.
449 // We jump to a runtime call that extends the properties array.
450 __ push(receiver_reg);
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000451 __ li(a2, Operand(transition));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000452 __ Push(a2, a0);
453 __ TailCallExternalReference(
454 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
455 masm->isolate()),
456 3, 1);
457 return;
458 }
459
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000460 if (!transition.is_null()) {
verwaest@chromium.org37141392012-05-31 13:27:02 +0000461 // Update the map of the object.
462 __ li(scratch, Operand(transition));
463 __ sw(scratch, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
464
465 // Update the write barrier for the map field and pass the now unused
466 // name_reg as scratch register.
467 __ RecordWriteField(receiver_reg,
468 HeapObject::kMapOffset,
469 scratch,
470 name_reg,
471 kRAHasNotBeenSaved,
472 kDontSaveFPRegs,
473 OMIT_REMEMBERED_SET,
474 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000475 }
476
477 // Adjust for the number of properties stored in the object. Even in the
478 // face of a transition we can use the old map here because the size of the
479 // object and the number of in-object properties is not going to change.
480 index -= object->map()->inobject_properties();
481
482 if (index < 0) {
483 // Set the property straight into the object.
484 int offset = object->map()->instance_size() + (index * kPointerSize);
485 __ sw(a0, FieldMemOperand(receiver_reg, offset));
486
487 // Skip updating write barrier if storing a smi.
488 __ JumpIfSmi(a0, &exit, scratch);
489
490 // Update the write barrier for the array address.
491 // Pass the now unused name_reg as a scratch register.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000492 __ mov(name_reg, a0);
493 __ RecordWriteField(receiver_reg,
494 offset,
495 name_reg,
496 scratch,
497 kRAHasNotBeenSaved,
498 kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000499 } else {
500 // Write to the properties array.
501 int offset = index * kPointerSize + FixedArray::kHeaderSize;
502 // Get the properties array.
503 __ lw(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
504 __ sw(a0, FieldMemOperand(scratch, offset));
505
506 // Skip updating write barrier if storing a smi.
507 __ JumpIfSmi(a0, &exit);
508
509 // Update the write barrier for the array address.
510 // Ok to clobber receiver_reg and name_reg, since we return.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000511 __ mov(name_reg, a0);
512 __ RecordWriteField(scratch,
513 offset,
514 name_reg,
515 receiver_reg,
516 kRAHasNotBeenSaved,
517 kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000518 }
519
520 // Return the value (register v0).
521 __ bind(&exit);
522 __ mov(v0, a0);
523 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000524}
525
526
527void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000528 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000529 Handle<Code> code = (kind == Code::LOAD_IC)
530 ? masm->isolate()->builtins()->LoadIC_Miss()
531 : masm->isolate()->builtins()->KeyedLoadIC_Miss();
532 __ Jump(code, RelocInfo::CODE_TARGET);
ager@chromium.org5c838252010-02-19 08:53:10 +0000533}
534
535
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000536static void GenerateCallFunction(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000537 Handle<Object> object,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000538 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000539 Label* miss,
540 Code::ExtraICState extra_ic_state) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000541 // ----------- S t a t e -------------
542 // -- a0: receiver
543 // -- a1: function to call
544 // -----------------------------------
545 // Check that the function really is a function.
546 __ JumpIfSmi(a1, miss);
547 __ GetObjectType(a1, a3, a3);
548 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
549
550 // Patch the receiver on the stack with the global proxy if
551 // necessary.
552 if (object->IsGlobalObject()) {
553 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
554 __ sw(a3, MemOperand(sp, arguments.immediate() * kPointerSize));
555 }
556
557 // Invoke the function.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000558 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
559 ? CALL_AS_FUNCTION
560 : CALL_AS_METHOD;
561 __ InvokeFunction(a1, arguments, JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000562}
563
564
565static void PushInterceptorArguments(MacroAssembler* masm,
566 Register receiver,
567 Register holder,
568 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000569 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000570 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000571 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
572 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000573 Register scratch = name;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000574 __ li(scratch, Operand(interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000575 __ Push(scratch, receiver, holder);
576 __ lw(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
577 __ push(scratch);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000578 __ li(scratch, Operand(ExternalReference::isolate_address()));
579 __ push(scratch);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000580}
581
582
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000583static void CompileCallLoadPropertyWithInterceptor(
584 MacroAssembler* masm,
585 Register receiver,
586 Register holder,
587 Register name,
588 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000589 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
590
591 ExternalReference ref =
592 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
593 masm->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000594 __ PrepareCEntryArgs(6);
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000595 __ PrepareCEntryFunction(ref);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000596
597 CEntryStub stub(1);
598 __ CallStub(&stub);
599}
600
601
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000602static const int kFastApiCallArguments = 4;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000603
604
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000605// Reserves space for the extra arguments to API function in the
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000606// caller's frame.
607//
608// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
609static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
610 Register scratch) {
611 ASSERT(Smi::FromInt(0) == 0);
612 for (int i = 0; i < kFastApiCallArguments; i++) {
613 __ push(zero_reg);
614 }
615}
616
617
618// Undoes the effects of ReserveSpaceForFastApiCall.
619static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
620 __ Drop(kFastApiCallArguments);
621}
622
623
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000624static void GenerateFastApiDirectCall(MacroAssembler* masm,
625 const CallOptimization& optimization,
626 int argc) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000627 // ----------- S t a t e -------------
628 // -- sp[0] : holder (set by CheckPrototypes)
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000629 // -- sp[4] : callee JS function
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000630 // -- sp[8] : call data
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000631 // -- sp[12] : isolate
632 // -- sp[16] : last JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000633 // -- ...
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000634 // -- sp[(argc + 3) * 4] : first JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000635 // -- sp[(argc + 4) * 4] : receiver
636 // -----------------------------------
637 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000638 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000639 __ LoadHeapObject(t1, function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000640 __ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset));
641
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000642 // Pass the additional arguments.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000643 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
644 Handle<Object> call_data(api_call_info->data());
645 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
646 __ li(a0, api_call_info);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000647 __ lw(t2, FieldMemOperand(a0, CallHandlerInfo::kDataOffset));
648 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000649 __ li(t2, call_data);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000650 }
651
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000652 __ li(t3, Operand(ExternalReference::isolate_address()));
653 // Store JS function, call data and isolate.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000654 __ sw(t1, MemOperand(sp, 1 * kPointerSize));
655 __ sw(t2, MemOperand(sp, 2 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000656 __ sw(t3, MemOperand(sp, 3 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000657
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000658 // Prepare arguments.
659 __ Addu(a2, sp, Operand(3 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000660
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000661 // Allocate the v8::Arguments structure in the arguments' space since
662 // it's not controlled by GC.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000663 const int kApiStackSpace = 4;
664
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000665 FrameScope frame_scope(masm, StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000666 __ EnterExitFrame(false, kApiStackSpace);
667
668 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
669 // struct from the function (which is currently the case). This means we pass
670 // the first argument in a1 instead of a0. TryCallApiFunctionAndReturn
671 // will handle setting up a0.
672
673 // a1 = v8::Arguments&
674 // Arguments is built at sp + 1 (sp is a reserved spot for ra).
675 __ Addu(a1, sp, kPointerSize);
676
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000677 // v8::Arguments::implicit_args_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000678 __ sw(a2, MemOperand(a1, 0 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000679 // v8::Arguments::values_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000680 __ Addu(t0, a2, Operand(argc * kPointerSize));
681 __ sw(t0, MemOperand(a1, 1 * kPointerSize));
682 // v8::Arguments::length_ = argc
683 __ li(t0, Operand(argc));
684 __ sw(t0, MemOperand(a1, 2 * kPointerSize));
685 // v8::Arguments::is_construct_call = 0
686 __ sw(zero_reg, MemOperand(a1, 3 * kPointerSize));
687
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000688 const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000689 Address function_address = v8::ToCData<Address>(api_call_info->callback());
690 ApiFunction fun(function_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000691 ExternalReference ref =
692 ExternalReference(&fun,
693 ExternalReference::DIRECT_API_CALL,
694 masm->isolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000695 AllowExternalCallThatCantCauseGC scope(masm);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000696 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000697}
698
lrn@chromium.org7516f052011-03-30 08:52:27 +0000699class CallInterceptorCompiler BASE_EMBEDDED {
700 public:
701 CallInterceptorCompiler(StubCompiler* stub_compiler,
702 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000703 Register name,
704 Code::ExtraICState extra_ic_state)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000705 : stub_compiler_(stub_compiler),
706 arguments_(arguments),
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000707 name_(name),
708 extra_ic_state_(extra_ic_state) {}
lrn@chromium.org7516f052011-03-30 08:52:27 +0000709
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000710 void Compile(MacroAssembler* masm,
711 Handle<JSObject> object,
712 Handle<JSObject> holder,
713 Handle<String> name,
714 LookupResult* lookup,
715 Register receiver,
716 Register scratch1,
717 Register scratch2,
718 Register scratch3,
719 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000720 ASSERT(holder->HasNamedInterceptor());
721 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
722
723 // Check that the receiver isn't a smi.
724 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000725 CallOptimization optimization(lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000726 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000727 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
728 holder, lookup, name, optimization, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000729 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000730 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
731 name, holder, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000732 }
733 }
734
735 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000736 void CompileCacheable(MacroAssembler* masm,
737 Handle<JSObject> object,
738 Register receiver,
739 Register scratch1,
740 Register scratch2,
741 Register scratch3,
742 Handle<JSObject> interceptor_holder,
743 LookupResult* lookup,
744 Handle<String> name,
745 const CallOptimization& optimization,
746 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000747 ASSERT(optimization.is_constant_call());
748 ASSERT(!lookup->holder()->IsGlobalObject());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000749 Counters* counters = masm->isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000750 int depth1 = kInvalidProtoDepth;
751 int depth2 = kInvalidProtoDepth;
752 bool can_do_fast_api_call = false;
753 if (optimization.is_simple_api_call() &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000754 !lookup->holder()->IsGlobalObject()) {
755 depth1 = optimization.GetPrototypeDepthOfExpectedType(
756 object, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000757 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000758 depth2 = optimization.GetPrototypeDepthOfExpectedType(
759 interceptor_holder, Handle<JSObject>(lookup->holder()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000760 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000761 can_do_fast_api_call =
762 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000763 }
764
765 __ IncrementCounter(counters->call_const_interceptor(), 1,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000766 scratch1, scratch2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000767
768 if (can_do_fast_api_call) {
769 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
770 scratch1, scratch2);
771 ReserveSpaceForFastApiCall(masm, scratch1);
772 }
773
774 // Check that the maps from receiver to interceptor's holder
775 // haven't changed and thus we can invoke interceptor.
776 Label miss_cleanup;
777 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
778 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000779 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
780 scratch1, scratch2, scratch3,
781 name, depth1, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000782
783 // Invoke an interceptor and if it provides a value,
784 // branch to |regular_invoke|.
785 Label regular_invoke;
786 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
787 &regular_invoke);
788
789 // Interceptor returned nothing for this property. Try to use cached
790 // constant function.
791
792 // Check that the maps from interceptor's holder to constant function's
793 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000794 if (*interceptor_holder != lookup->holder()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000795 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000796 Handle<JSObject>(lookup->holder()),
797 scratch1, scratch2, scratch3,
798 name, depth2, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000799 } else {
800 // CheckPrototypes has a side effect of fetching a 'holder'
801 // for API (object which is instanceof for the signature). It's
802 // safe to omit it here, as if present, it should be fetched
803 // by the previous CheckPrototypes.
804 ASSERT(depth2 == kInvalidProtoDepth);
805 }
806
807 // Invoke function.
808 if (can_do_fast_api_call) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000809 GenerateFastApiDirectCall(masm, optimization, arguments_.immediate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000810 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000811 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
812 ? CALL_AS_FUNCTION
813 : CALL_AS_METHOD;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000814 __ InvokeFunction(optimization.constant_function(), arguments_,
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000815 JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000816 }
817
818 // Deferred code for fast API call case---clean preallocated space.
819 if (can_do_fast_api_call) {
820 __ bind(&miss_cleanup);
821 FreeSpaceForFastApiCall(masm);
822 __ Branch(miss_label);
823 }
824
825 // Invoke a regular function.
826 __ bind(&regular_invoke);
827 if (can_do_fast_api_call) {
828 FreeSpaceForFastApiCall(masm);
829 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000830 }
831
832 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000833 Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000834 Register receiver,
835 Register scratch1,
836 Register scratch2,
837 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000838 Handle<String> name,
839 Handle<JSObject> interceptor_holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000840 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000841 Register holder =
842 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000843 scratch1, scratch2, scratch3,
844 name, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000845
846 // Call a runtime function to load the interceptor property.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000847 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000848 // Save the name_ register across the call.
849 __ push(name_);
850
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000851 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000852
853 __ CallExternalReference(
854 ExternalReference(
855 IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
856 masm->isolate()),
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000857 6);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000858 // Restore the name_ register.
859 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000860 // Leave the internal frame.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000861 }
862
863 void LoadWithInterceptor(MacroAssembler* masm,
864 Register receiver,
865 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000866 Handle<JSObject> holder_obj,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000867 Register scratch,
868 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000869 {
870 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000871
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000872 __ Push(holder, name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000873 CompileCallLoadPropertyWithInterceptor(masm,
874 receiver,
875 holder,
876 name_,
877 holder_obj);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000878 __ pop(name_); // Restore the name.
879 __ pop(receiver); // Restore the holder.
880 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000881 // If interceptor returns no-result sentinel, call the constant function.
882 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
883 __ Branch(interceptor_succeeded, ne, v0, Operand(scratch));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000884 }
885
886 StubCompiler* stub_compiler_;
887 const ParameterCount& arguments_;
888 Register name_;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000889 Code::ExtraICState extra_ic_state_;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000890};
891
892
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000893
894// Generate code to check that a global property cell is empty. Create
895// the property cell at compilation time if no cell exists for the
896// property.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000897static void GenerateCheckPropertyCell(MacroAssembler* masm,
898 Handle<GlobalObject> global,
899 Handle<String> name,
900 Register scratch,
901 Label* miss) {
902 Handle<JSGlobalPropertyCell> cell =
903 GlobalObject::EnsurePropertyCell(global, name);
904 ASSERT(cell->value()->IsTheHole());
905 __ li(scratch, Operand(cell));
906 __ lw(scratch,
907 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
908 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
909 __ Branch(miss, ne, scratch, Operand(at));
910}
911
912
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000913// Calls GenerateCheckPropertyCell for each global object in the prototype chain
914// from object to (but not including) holder.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000915static void GenerateCheckPropertyCells(MacroAssembler* masm,
916 Handle<JSObject> object,
917 Handle<JSObject> holder,
918 Handle<String> name,
919 Register scratch,
920 Label* miss) {
921 Handle<JSObject> current = object;
922 while (!current.is_identical_to(holder)) {
923 if (current->IsGlobalObject()) {
924 GenerateCheckPropertyCell(masm,
925 Handle<GlobalObject>::cast(current),
926 name,
927 scratch,
928 miss);
929 }
930 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
931 }
932}
933
934
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000935// Convert and store int passed in register ival to IEEE 754 single precision
936// floating point value at memory location (dst + 4 * wordoffset)
937// If FPU is available use it for conversion.
938static void StoreIntAsFloat(MacroAssembler* masm,
939 Register dst,
940 Register wordoffset,
941 Register ival,
942 Register fval,
943 Register scratch1,
944 Register scratch2) {
945 if (CpuFeatures::IsSupported(FPU)) {
946 CpuFeatures::Scope scope(FPU);
947 __ mtc1(ival, f0);
948 __ cvt_s_w(f0, f0);
949 __ sll(scratch1, wordoffset, 2);
950 __ addu(scratch1, dst, scratch1);
951 __ swc1(f0, MemOperand(scratch1, 0));
952 } else {
953 // FPU is not available, do manual conversions.
954
955 Label not_special, done;
956 // Move sign bit from source to destination. This works because the sign
957 // bit in the exponent word of the double has the same position and polarity
958 // as the 2's complement sign bit in a Smi.
959 ASSERT(kBinary32SignMask == 0x80000000u);
960
961 __ And(fval, ival, Operand(kBinary32SignMask));
962 // Negate value if it is negative.
963 __ subu(scratch1, zero_reg, ival);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +0000964 __ Movn(ival, scratch1, fval);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000965
966 // We have -1, 0 or 1, which we treat specially. Register ival contains
967 // absolute value: it is either equal to 1 (special case of -1 and 1),
968 // greater than 1 (not a special case) or less than 1 (special case of 0).
969 __ Branch(&not_special, gt, ival, Operand(1));
970
971 // For 1 or -1 we need to or in the 0 exponent (biased).
972 static const uint32_t exponent_word_for_1 =
973 kBinary32ExponentBias << kBinary32ExponentShift;
974
975 __ Xor(scratch1, ival, Operand(1));
976 __ li(scratch2, exponent_word_for_1);
977 __ or_(scratch2, fval, scratch2);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +0000978 __ Movz(fval, scratch2, scratch1); // Only if ival is equal to 1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000979 __ Branch(&done);
980
981 __ bind(&not_special);
982 // Count leading zeros.
983 // Gets the wrong answer for 0, but we already checked for that case above.
984 Register zeros = scratch2;
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +0000985 __ Clz(zeros, ival);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000986
987 // Compute exponent and or it into the exponent register.
988 __ li(scratch1, (kBitsPerInt - 1) + kBinary32ExponentBias);
989 __ subu(scratch1, scratch1, zeros);
990
991 __ sll(scratch1, scratch1, kBinary32ExponentShift);
992 __ or_(fval, fval, scratch1);
993
994 // Shift up the source chopping the top bit off.
995 __ Addu(zeros, zeros, Operand(1));
996 // This wouldn't work for 1 and -1 as the shift would be 32 which means 0.
997 __ sllv(ival, ival, zeros);
998 // And the top (top 20 bits).
999 __ srl(scratch1, ival, kBitsPerInt - kBinary32MantissaBits);
1000 __ or_(fval, fval, scratch1);
1001
1002 __ bind(&done);
1003
1004 __ sll(scratch1, wordoffset, 2);
1005 __ addu(scratch1, dst, scratch1);
1006 __ sw(fval, MemOperand(scratch1, 0));
1007 }
1008}
1009
1010
1011// Convert unsigned integer with specified number of leading zeroes in binary
1012// representation to IEEE 754 double.
1013// Integer to convert is passed in register hiword.
1014// Resulting double is returned in registers hiword:loword.
1015// This functions does not work correctly for 0.
1016static void GenerateUInt2Double(MacroAssembler* masm,
1017 Register hiword,
1018 Register loword,
1019 Register scratch,
1020 int leading_zeroes) {
1021 const int meaningful_bits = kBitsPerInt - leading_zeroes - 1;
1022 const int biased_exponent = HeapNumber::kExponentBias + meaningful_bits;
1023
1024 const int mantissa_shift_for_hi_word =
1025 meaningful_bits - HeapNumber::kMantissaBitsInTopWord;
1026
1027 const int mantissa_shift_for_lo_word =
1028 kBitsPerInt - mantissa_shift_for_hi_word;
1029
1030 __ li(scratch, biased_exponent << HeapNumber::kExponentShift);
1031 if (mantissa_shift_for_hi_word > 0) {
1032 __ sll(loword, hiword, mantissa_shift_for_lo_word);
1033 __ srl(hiword, hiword, mantissa_shift_for_hi_word);
1034 __ or_(hiword, scratch, hiword);
1035 } else {
1036 __ mov(loword, zero_reg);
1037 __ sll(hiword, hiword, mantissa_shift_for_hi_word);
1038 __ or_(hiword, scratch, hiword);
1039 }
1040
1041 // If least significant bit of biased exponent was not 1 it was corrupted
1042 // by most significant bit of mantissa so we should fix that.
1043 if (!(biased_exponent & 1)) {
1044 __ li(scratch, 1 << HeapNumber::kExponentShift);
1045 __ nor(scratch, scratch, scratch);
1046 __ and_(hiword, hiword, scratch);
1047 }
1048}
1049
1050
ager@chromium.org5c838252010-02-19 08:53:10 +00001051#undef __
1052#define __ ACCESS_MASM(masm())
1053
1054
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001055Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
1056 Register object_reg,
1057 Handle<JSObject> holder,
1058 Register holder_reg,
1059 Register scratch1,
1060 Register scratch2,
1061 Handle<String> name,
1062 int save_at_depth,
1063 Label* miss) {
1064 // Make sure there's no overlap between holder and object registers.
1065 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1066 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1067 && !scratch2.is(scratch1));
1068
1069 // Keep track of the current object in register reg.
1070 Register reg = object_reg;
1071 int depth = 0;
1072
1073 if (save_at_depth == depth) {
1074 __ sw(reg, MemOperand(sp));
1075 }
1076
1077 // Check the maps in the prototype chain.
1078 // Traverse the prototype chain from the object and do map checks.
1079 Handle<JSObject> current = object;
1080 while (!current.is_identical_to(holder)) {
1081 ++depth;
1082
1083 // Only global objects and objects that do not require access
1084 // checks are allowed in stubs.
1085 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1086
1087 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
1088 if (!current->HasFastProperties() &&
1089 !current->IsJSGlobalObject() &&
1090 !current->IsJSGlobalProxy()) {
1091 if (!name->IsSymbol()) {
1092 name = factory()->LookupSymbol(name);
1093 }
1094 ASSERT(current->property_dictionary()->FindEntry(*name) ==
1095 StringDictionary::kNotFound);
1096
1097 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1098 scratch1, scratch2);
1099
1100 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1101 reg = holder_reg; // From now on the object will be in holder_reg.
1102 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1103 } else {
1104 Handle<Map> current_map(current->map());
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001105 __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK,
1106 ALLOW_ELEMENT_TRANSITION_MAPS);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001107 // Check access rights to the global object. This has to happen after
1108 // the map check so that we know that the object is actually a global
1109 // object.
1110 if (current->IsJSGlobalProxy()) {
1111 __ CheckAccessGlobalProxy(reg, scratch2, miss);
1112 }
1113 reg = holder_reg; // From now on the object will be in holder_reg.
1114
1115 if (heap()->InNewSpace(*prototype)) {
1116 // The prototype is in new space; we cannot store a reference to it
1117 // in the code. Load it from the map.
1118 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1119 } else {
1120 // The prototype is in old space; load it directly.
1121 __ li(reg, Operand(prototype));
1122 }
1123 }
1124
1125 if (save_at_depth == depth) {
1126 __ sw(reg, MemOperand(sp));
1127 }
1128
1129 // Go to the next object in the prototype chain.
1130 current = prototype;
1131 }
1132
1133 // Log the check depth.
1134 LOG(masm()->isolate(), IntEvent("check-maps-depth", depth + 1));
1135
1136 // Check the holder map.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001137 __ CheckMap(reg, scratch1, Handle<Map>(current->map()), miss,
1138 DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001139
1140 // Perform security check for access to the global object.
1141 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1142 if (holder->IsJSGlobalProxy()) {
1143 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1144 }
1145
1146 // If we've skipped any global objects, it's not enough to verify that
1147 // their maps haven't changed. We also need to check that the property
1148 // cell for the property is still empty.
1149 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1150
1151 // Return the register containing the holder.
1152 return reg;
1153}
1154
1155
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001156void StubCompiler::GenerateLoadField(Handle<JSObject> object,
1157 Handle<JSObject> holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001158 Register receiver,
1159 Register scratch1,
1160 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001161 Register scratch3,
ager@chromium.org5c838252010-02-19 08:53:10 +00001162 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001163 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001164 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001165 // Check that the receiver isn't a smi.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001166 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001167
1168 // Check that the maps haven't changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001169 Register reg = CheckPrototypes(
1170 object, receiver, holder, scratch1, scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001171 GenerateFastPropertyLoad(masm(), v0, reg, holder, index);
1172 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001173}
1174
1175
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001176void StubCompiler::GenerateLoadConstant(Handle<JSObject> object,
1177 Handle<JSObject> holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001178 Register receiver,
1179 Register scratch1,
1180 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001181 Register scratch3,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001182 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001183 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001184 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001185 // Check that the receiver isn't a smi.
1186 __ JumpIfSmi(receiver, miss, scratch1);
1187
1188 // Check that the maps haven't changed.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001189 CheckPrototypes(object, receiver, holder,
1190 scratch1, scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001191
1192 // Return the constant value.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001193 __ LoadHeapObject(v0, value);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001194 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001195}
1196
1197
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001198void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
1199 Handle<JSObject> holder,
1200 Register receiver,
1201 Register name_reg,
1202 Register scratch1,
1203 Register scratch2,
1204 Register scratch3,
1205 Handle<AccessorInfo> callback,
1206 Handle<String> name,
1207 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001208 // Check that the receiver isn't a smi.
1209 __ JumpIfSmi(receiver, miss, scratch1);
1210
1211 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001212 Register reg = CheckPrototypes(object, receiver, holder, scratch1,
1213 scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001214
1215 // Build AccessorInfo::args_ list on the stack and push property name below
1216 // the exit frame to make GC aware of them and store pointers to them.
1217 __ push(receiver);
1218 __ mov(scratch2, sp); // scratch2 = AccessorInfo::args_
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001219 if (heap()->InNewSpace(callback->data())) {
1220 __ li(scratch3, callback);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001221 __ lw(scratch3, FieldMemOperand(scratch3, AccessorInfo::kDataOffset));
1222 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001223 __ li(scratch3, Handle<Object>(callback->data()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001224 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001225 __ Subu(sp, sp, 4 * kPointerSize);
1226 __ sw(reg, MemOperand(sp, 3 * kPointerSize));
1227 __ sw(scratch3, MemOperand(sp, 2 * kPointerSize));
1228 __ li(scratch3, Operand(ExternalReference::isolate_address()));
1229 __ sw(scratch3, MemOperand(sp, 1 * kPointerSize));
1230 __ sw(name_reg, MemOperand(sp, 0 * kPointerSize));
1231
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001232 __ mov(a2, scratch2); // Saved in case scratch2 == a1.
1233 __ mov(a1, sp); // a1 (first argument - see note below) = Handle<String>
1234
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001235 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
1236 // struct from the function (which is currently the case). This means we pass
1237 // the arguments in a1-a2 instead of a0-a1. TryCallApiFunctionAndReturn
1238 // will handle setting up a0.
1239
1240 const int kApiStackSpace = 1;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001241 FrameScope frame_scope(masm(), StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001242 __ EnterExitFrame(false, kApiStackSpace);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001243
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001244 // Create AccessorInfo instance on the stack above the exit frame with
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001245 // scratch2 (internal::Object** args_) as the data.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001246 __ sw(a2, MemOperand(sp, kPointerSize));
1247 // a2 (second argument - see note above) = AccessorInfo&
1248 __ Addu(a2, sp, kPointerSize);
1249
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001250 const int kStackUnwindSpace = 5;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001251 Address getter_address = v8::ToCData<Address>(callback->getter());
1252 ApiFunction fun(getter_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001253 ExternalReference ref =
1254 ExternalReference(&fun,
1255 ExternalReference::DIRECT_GETTER_CALL,
1256 masm()->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001257 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
ager@chromium.org5c838252010-02-19 08:53:10 +00001258}
1259
1260
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001261void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
1262 Handle<JSObject> interceptor_holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001263 LookupResult* lookup,
1264 Register receiver,
1265 Register name_reg,
1266 Register scratch1,
1267 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001268 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001269 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001270 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001271 ASSERT(interceptor_holder->HasNamedInterceptor());
1272 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1273
1274 // Check that the receiver isn't a smi.
1275 __ JumpIfSmi(receiver, miss);
1276
1277 // So far the most popular follow ups for interceptor loads are FIELD
1278 // and CALLBACKS, so inline only them, other cases may be added
1279 // later.
1280 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001281 if (lookup->IsFound() && lookup->IsCacheable()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001282 if (lookup->type() == FIELD) {
1283 compile_followup_inline = true;
1284 } else if (lookup->type() == CALLBACKS &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001285 lookup->GetCallbackObject()->IsAccessorInfo()) {
1286 compile_followup_inline =
1287 AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001288 }
1289 }
1290
1291 if (compile_followup_inline) {
1292 // Compile the interceptor call, followed by inline code to load the
1293 // property from further up the prototype chain if the call fails.
1294 // Check that the maps haven't changed.
1295 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1296 scratch1, scratch2, scratch3,
1297 name, miss);
1298 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
1299
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001300 // Preserve the receiver register explicitly whenever it is different from
1301 // the holder and it is needed should the interceptor return without any
1302 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1303 // the FIELD case might cause a miss during the prototype check.
1304 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
1305 bool must_preserve_receiver_reg = !receiver.is(holder_reg) &&
1306 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1307
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001308 // Save necessary data before invoking an interceptor.
1309 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001310 {
1311 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001312 if (must_preserve_receiver_reg) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001313 __ Push(receiver, holder_reg, name_reg);
1314 } else {
1315 __ Push(holder_reg, name_reg);
1316 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001317 // Invoke an interceptor. Note: map checks from receiver to
1318 // interceptor's holder has been compiled before (see a caller
1319 // of this method).
1320 CompileCallLoadPropertyWithInterceptor(masm(),
1321 receiver,
1322 holder_reg,
1323 name_reg,
1324 interceptor_holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001325 // Check if interceptor provided a value for property. If it's
1326 // the case, return immediately.
1327 Label interceptor_failed;
1328 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
1329 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1));
1330 frame_scope.GenerateLeaveFrame();
1331 __ Ret();
1332
1333 __ bind(&interceptor_failed);
1334 __ pop(name_reg);
1335 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001336 if (must_preserve_receiver_reg) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001337 __ pop(receiver);
1338 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001339 // Leave the internal frame.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001340 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001341 // Check that the maps from interceptor's holder to lookup's holder
1342 // haven't changed. And load lookup's holder into |holder| register.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001343 if (must_perfrom_prototype_check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001344 holder_reg = CheckPrototypes(interceptor_holder,
1345 holder_reg,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001346 Handle<JSObject>(lookup->holder()),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001347 scratch1,
1348 scratch2,
1349 scratch3,
1350 name,
1351 miss);
1352 }
1353
1354 if (lookup->type() == FIELD) {
1355 // We found FIELD property in prototype chain of interceptor's holder.
1356 // Retrieve a field from field's holder.
1357 GenerateFastPropertyLoad(masm(), v0, holder_reg,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001358 Handle<JSObject>(lookup->holder()),
1359 lookup->GetFieldIndex());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001360 __ Ret();
1361 } else {
1362 // We found CALLBACKS property in prototype chain of interceptor's
1363 // holder.
1364 ASSERT(lookup->type() == CALLBACKS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001365 Handle<AccessorInfo> callback(
1366 AccessorInfo::cast(lookup->GetCallbackObject()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001367 ASSERT(callback->getter() != NULL);
1368
1369 // Tail call to runtime.
1370 // Important invariant in CALLBACKS case: the code above must be
1371 // structured to never clobber |receiver| register.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001372 __ li(scratch2, callback);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001373
1374 __ Push(receiver, holder_reg);
1375 __ lw(scratch3,
1376 FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
1377 __ li(scratch1, Operand(ExternalReference::isolate_address()));
1378 __ Push(scratch3, scratch1, scratch2, name_reg);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001379
1380 ExternalReference ref =
1381 ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
1382 masm()->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001383 __ TailCallExternalReference(ref, 6, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001384 }
1385 } else { // !compile_followup_inline
1386 // Call the runtime system to load the interceptor.
1387 // Check that the maps haven't changed.
1388 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1389 scratch1, scratch2, scratch3,
1390 name, miss);
1391 PushInterceptorArguments(masm(), receiver, holder_reg,
1392 name_reg, interceptor_holder);
1393
1394 ExternalReference ref = ExternalReference(
1395 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), masm()->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001396 __ TailCallExternalReference(ref, 6, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001397 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001398}
1399
1400
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001401void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001402 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001403 __ Branch(miss, ne, a2, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001404 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001405}
1406
1407
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001408void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1409 Handle<JSObject> holder,
1410 Handle<String> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001411 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001412 ASSERT(holder->IsGlobalObject());
1413
1414 // Get the number of arguments.
1415 const int argc = arguments().immediate();
1416
1417 // Get the receiver from the stack.
1418 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1419
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001420 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001421 __ JumpIfSmi(a0, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001422 CheckPrototypes(object, a0, holder, a3, a1, t0, name, miss);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001423}
1424
1425
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001426void CallStubCompiler::GenerateLoadFunctionFromCell(
1427 Handle<JSGlobalPropertyCell> cell,
1428 Handle<JSFunction> function,
1429 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001430 // Get the value from the cell.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001431 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001432 __ lw(a1, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
1433
1434 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001435 if (heap()->InNewSpace(*function)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001436 // We can't embed a pointer to a function in new space so we have
1437 // to verify that the shared function info is unchanged. This has
1438 // the nice side effect that multiple closures based on the same
1439 // function can all use this call IC. Before we load through the
1440 // function, we have to verify that it still is a function.
1441 __ JumpIfSmi(a1, miss);
1442 __ GetObjectType(a1, a3, a3);
1443 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
1444
1445 // Check the shared function info. Make sure it hasn't changed.
1446 __ li(a3, Handle<SharedFunctionInfo>(function->shared()));
1447 __ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
1448 __ Branch(miss, ne, t0, Operand(a3));
1449 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001450 __ Branch(miss, ne, a1, Operand(function));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001451 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001452}
1453
1454
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001455void CallStubCompiler::GenerateMissBranch() {
1456 Handle<Code> code =
danno@chromium.org40cb8782011-05-25 07:58:50 +00001457 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1458 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001459 extra_state_);
1460 __ Jump(code, RelocInfo::CODE_TARGET);
1461}
1462
1463
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001464Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1465 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001466 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001467 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001468 // ----------- S t a t e -------------
1469 // -- a2 : name
1470 // -- ra : return address
1471 // -----------------------------------
1472 Label miss;
1473
1474 GenerateNameCheck(name, &miss);
1475
1476 const int argc = arguments().immediate();
1477
1478 // Get the receiver of the function from the stack into a0.
1479 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1480 // Check that the receiver isn't a smi.
1481 __ JumpIfSmi(a0, &miss, t0);
1482
1483 // Do the right check and compute the holder register.
1484 Register reg = CheckPrototypes(object, a0, holder, a1, a3, t0, name, &miss);
1485 GenerateFastPropertyLoad(masm(), a1, reg, holder, index);
1486
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001487 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001488
1489 // Handle call cache miss.
1490 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001491 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001492
1493 // Return the generated code.
1494 return GetCode(FIELD, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001495}
1496
1497
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001498Handle<Code> CallStubCompiler::CompileArrayPushCall(
1499 Handle<Object> object,
1500 Handle<JSObject> holder,
1501 Handle<JSGlobalPropertyCell> cell,
1502 Handle<JSFunction> function,
1503 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001504 // ----------- S t a t e -------------
1505 // -- a2 : name
1506 // -- ra : return address
1507 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1508 // -- ...
1509 // -- sp[argc * 4] : receiver
1510 // -----------------------------------
1511
1512 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001513 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001514
1515 Label miss;
1516
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001517 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001518
1519 Register receiver = a1;
1520
1521 // Get the receiver from the stack.
1522 const int argc = arguments().immediate();
1523 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1524
1525 // Check that the receiver isn't a smi.
1526 __ JumpIfSmi(receiver, &miss);
1527
1528 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001529 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, a3, v0, t0,
1530 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001531
1532 if (argc == 0) {
1533 // Nothing to do, just return the length.
1534 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1535 __ Drop(argc + 1);
1536 __ Ret();
1537 } else {
1538 Label call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001539 if (argc == 1) { // Otherwise fall through to call the builtin.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001540 Label attempt_to_grow_elements;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001541
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001542 Register elements = t2;
1543 Register end_elements = t1;
1544 // Get the elements array of the object.
1545 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1546
1547 // Check that the elements are in fast mode and writable.
1548 __ CheckMap(elements,
1549 v0,
1550 Heap::kFixedArrayMapRootIndex,
1551 &call_builtin,
1552 DONT_DO_SMI_CHECK);
1553
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001554 // Get the array's length into v0 and calculate new length.
1555 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1556 STATIC_ASSERT(kSmiTagSize == 1);
1557 STATIC_ASSERT(kSmiTag == 0);
1558 __ Addu(v0, v0, Operand(Smi::FromInt(argc)));
1559
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001560 // Get the elements' length.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001561 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1562
1563 // Check if we could survive without allocation.
1564 __ Branch(&attempt_to_grow_elements, gt, v0, Operand(t0));
1565
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001566 // Check if value is a smi.
1567 Label with_write_barrier;
1568 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1569 __ JumpIfNotSmi(t0, &with_write_barrier);
1570
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001571 // Save new length.
1572 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1573
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001574 // Store the value.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001575 // We may need a register containing the address end_elements below,
1576 // so write back the value in end_elements.
1577 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1578 __ Addu(end_elements, elements, end_elements);
1579 const int kEndElementsOffset =
1580 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001581 __ Addu(end_elements, end_elements, kEndElementsOffset);
1582 __ sw(t0, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001583
1584 // Check for a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001585 __ Drop(argc + 1);
1586 __ Ret();
1587
1588 __ bind(&with_write_barrier);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001589
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001590 __ lw(a3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1591
1592 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
1593 Label fast_object, not_fast_object;
1594 __ CheckFastObjectElements(a3, t3, &not_fast_object);
1595 __ jmp(&fast_object);
1596 // In case of fast smi-only, convert to fast object, otherwise bail out.
1597 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001598 __ CheckFastSmiElements(a3, t3, &call_builtin);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001599 // edx: receiver
1600 // r3: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001601 Label try_holey_map;
1602 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001603 FAST_ELEMENTS,
1604 a3,
1605 t3,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001606 &try_holey_map);
1607 __ mov(a2, receiver);
1608 ElementsTransitionGenerator::
1609 GenerateMapChangeElementsTransition(masm());
1610 __ jmp(&fast_object);
1611
1612 __ bind(&try_holey_map);
1613 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1614 FAST_HOLEY_ELEMENTS,
1615 a3,
1616 t3,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001617 &call_builtin);
1618 __ mov(a2, receiver);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001619 ElementsTransitionGenerator::
1620 GenerateMapChangeElementsTransition(masm());
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001621 __ bind(&fast_object);
1622 } else {
1623 __ CheckFastObjectElements(a3, a3, &call_builtin);
1624 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001625
1626 // Save new length.
1627 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1628
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001629 // Store the value.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001630 // We may need a register containing the address end_elements below,
1631 // so write back the value in end_elements.
1632 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1633 __ Addu(end_elements, elements, end_elements);
1634 __ Addu(end_elements, end_elements, kEndElementsOffset);
1635 __ sw(t0, MemOperand(end_elements));
1636
1637 __ RecordWrite(elements,
1638 end_elements,
1639 t0,
1640 kRAHasNotBeenSaved,
1641 kDontSaveFPRegs,
1642 EMIT_REMEMBERED_SET,
1643 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001644 __ Drop(argc + 1);
1645 __ Ret();
1646
1647 __ bind(&attempt_to_grow_elements);
1648 // v0: array's length + 1.
1649 // t0: elements' length.
1650
1651 if (!FLAG_inline_new) {
1652 __ Branch(&call_builtin);
1653 }
1654
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001655 __ lw(a2, MemOperand(sp, (argc - 1) * kPointerSize));
1656 // Growing elements that are SMI-only requires special handling in case
1657 // the new element is non-Smi. For now, delegate to the builtin.
1658 Label no_fast_elements_check;
1659 __ JumpIfSmi(a2, &no_fast_elements_check);
1660 __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1661 __ CheckFastObjectElements(t3, t3, &call_builtin);
1662 __ bind(&no_fast_elements_check);
1663
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001664 ExternalReference new_space_allocation_top =
1665 ExternalReference::new_space_allocation_top_address(
1666 masm()->isolate());
1667 ExternalReference new_space_allocation_limit =
1668 ExternalReference::new_space_allocation_limit_address(
1669 masm()->isolate());
1670
1671 const int kAllocationDelta = 4;
1672 // Load top and check if it is the end of elements.
1673 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1674 __ Addu(end_elements, elements, end_elements);
1675 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset));
1676 __ li(t3, Operand(new_space_allocation_top));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001677 __ lw(a3, MemOperand(t3));
1678 __ Branch(&call_builtin, ne, end_elements, Operand(a3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001679
1680 __ li(t5, Operand(new_space_allocation_limit));
1681 __ lw(t5, MemOperand(t5));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001682 __ Addu(a3, a3, Operand(kAllocationDelta * kPointerSize));
1683 __ Branch(&call_builtin, hi, a3, Operand(t5));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001684
1685 // We fit and could grow elements.
1686 // Update new_space_allocation_top.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001687 __ sw(a3, MemOperand(t3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001688 // Push the argument.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001689 __ sw(a2, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001690 // Fill the rest with holes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001691 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001692 for (int i = 1; i < kAllocationDelta; i++) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001693 __ sw(a3, MemOperand(end_elements, i * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001694 }
1695
1696 // Update elements' and array's sizes.
1697 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1698 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta)));
1699 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1700
1701 // Elements are in new space, so write barrier is not required.
1702 __ Drop(argc + 1);
1703 __ Ret();
1704 }
1705 __ bind(&call_builtin);
1706 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
1707 masm()->isolate()),
1708 argc + 1,
1709 1);
1710 }
1711
1712 // Handle call cache miss.
1713 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001714 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001715
1716 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001717 return GetCode(function);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001718}
1719
1720
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001721Handle<Code> CallStubCompiler::CompileArrayPopCall(
1722 Handle<Object> object,
1723 Handle<JSObject> holder,
1724 Handle<JSGlobalPropertyCell> cell,
1725 Handle<JSFunction> function,
1726 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001727 // ----------- S t a t e -------------
1728 // -- a2 : name
1729 // -- ra : return address
1730 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1731 // -- ...
1732 // -- sp[argc * 4] : receiver
1733 // -----------------------------------
1734
1735 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001736 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001737
1738 Label miss, return_undefined, call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001739 Register receiver = a1;
1740 Register elements = a3;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001741 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001742
1743 // Get the receiver from the stack.
1744 const int argc = arguments().immediate();
1745 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001746 // Check that the receiver isn't a smi.
1747 __ JumpIfSmi(receiver, &miss);
1748
1749 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001750 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, elements,
1751 t0, v0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001752
1753 // Get the elements array of the object.
1754 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1755
1756 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001757 __ CheckMap(elements,
1758 v0,
1759 Heap::kFixedArrayMapRootIndex,
1760 &call_builtin,
1761 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001762
1763 // Get the array's length into t0 and calculate new length.
1764 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1765 __ Subu(t0, t0, Operand(Smi::FromInt(1)));
1766 __ Branch(&return_undefined, lt, t0, Operand(zero_reg));
1767
1768 // Get the last element.
1769 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1770 STATIC_ASSERT(kSmiTagSize == 1);
1771 STATIC_ASSERT(kSmiTag == 0);
1772 // We can't address the last element in one operation. Compute the more
1773 // expensive shift first, and use an offset later on.
1774 __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize);
1775 __ Addu(elements, elements, t1);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001776 __ lw(v0, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001777 __ Branch(&call_builtin, eq, v0, Operand(t2));
1778
1779 // Set the array's length.
1780 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1781
1782 // Fill with the hole.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001783 __ sw(t2, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001784 __ Drop(argc + 1);
1785 __ Ret();
1786
1787 __ bind(&return_undefined);
1788 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
1789 __ Drop(argc + 1);
1790 __ Ret();
1791
1792 __ bind(&call_builtin);
1793 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop,
1794 masm()->isolate()),
1795 argc + 1,
1796 1);
1797
1798 // Handle call cache miss.
1799 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001800 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001801
1802 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001803 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001804}
1805
1806
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001807Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1808 Handle<Object> object,
1809 Handle<JSObject> holder,
1810 Handle<JSGlobalPropertyCell> cell,
1811 Handle<JSFunction> function,
1812 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001813 // ----------- S t a t e -------------
1814 // -- a2 : function name
1815 // -- ra : return address
1816 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1817 // -- ...
1818 // -- sp[argc * 4] : receiver
1819 // -----------------------------------
1820
1821 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001822 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001823
1824 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001825 Label miss;
1826 Label name_miss;
1827 Label index_out_of_range;
1828
1829 Label* index_out_of_range_label = &index_out_of_range;
1830
danno@chromium.org40cb8782011-05-25 07:58:50 +00001831 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001832 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001833 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001834 index_out_of_range_label = &miss;
1835 }
1836
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001837 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001838
1839 // Check that the maps starting from the prototype haven't changed.
1840 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1841 Context::STRING_FUNCTION_INDEX,
1842 v0,
1843 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001844 ASSERT(!object.is_identical_to(holder));
1845 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1846 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001847
1848 Register receiver = a1;
1849 Register index = t1;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001850 Register result = v0;
1851 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1852 if (argc > 0) {
1853 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1854 } else {
1855 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1856 }
1857
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001858 StringCharCodeAtGenerator generator(receiver,
1859 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001860 result,
1861 &miss, // When not a string.
1862 &miss, // When not a number.
1863 index_out_of_range_label,
1864 STRING_INDEX_IS_NUMBER);
1865 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001866 __ Drop(argc + 1);
1867 __ Ret();
1868
1869 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001870 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001871
1872 if (index_out_of_range.is_linked()) {
1873 __ bind(&index_out_of_range);
1874 __ LoadRoot(v0, Heap::kNanValueRootIndex);
1875 __ Drop(argc + 1);
1876 __ Ret();
1877 }
1878
1879 __ bind(&miss);
1880 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001881 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001882 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001883 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001884
1885 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001886 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001887}
1888
1889
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001890Handle<Code> CallStubCompiler::CompileStringCharAtCall(
1891 Handle<Object> object,
1892 Handle<JSObject> holder,
1893 Handle<JSGlobalPropertyCell> cell,
1894 Handle<JSFunction> function,
1895 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001896 // ----------- S t a t e -------------
1897 // -- a2 : function name
1898 // -- ra : return address
1899 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1900 // -- ...
1901 // -- sp[argc * 4] : receiver
1902 // -----------------------------------
1903
1904 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001905 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001906
1907 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001908 Label miss;
1909 Label name_miss;
1910 Label index_out_of_range;
1911 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00001912 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001913 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001914 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001915 index_out_of_range_label = &miss;
1916 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001917 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001918
1919 // Check that the maps starting from the prototype haven't changed.
1920 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1921 Context::STRING_FUNCTION_INDEX,
1922 v0,
1923 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001924 ASSERT(!object.is_identical_to(holder));
1925 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1926 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001927
1928 Register receiver = v0;
1929 Register index = t1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001930 Register scratch = a3;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001931 Register result = v0;
1932 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1933 if (argc > 0) {
1934 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1935 } else {
1936 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1937 }
1938
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001939 StringCharAtGenerator generator(receiver,
1940 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00001941 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001942 result,
1943 &miss, // When not a string.
1944 &miss, // When not a number.
1945 index_out_of_range_label,
1946 STRING_INDEX_IS_NUMBER);
1947 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001948 __ Drop(argc + 1);
1949 __ Ret();
1950
1951 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001952 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001953
1954 if (index_out_of_range.is_linked()) {
1955 __ bind(&index_out_of_range);
1956 __ LoadRoot(v0, Heap::kEmptyStringRootIndex);
1957 __ Drop(argc + 1);
1958 __ Ret();
1959 }
1960
1961 __ bind(&miss);
1962 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001963 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001964 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001965 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001966
1967 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001968 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001969}
1970
1971
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001972Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
1973 Handle<Object> object,
1974 Handle<JSObject> holder,
1975 Handle<JSGlobalPropertyCell> cell,
1976 Handle<JSFunction> function,
1977 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001978 // ----------- S t a t e -------------
1979 // -- a2 : function name
1980 // -- ra : return address
1981 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1982 // -- ...
1983 // -- sp[argc * 4] : receiver
1984 // -----------------------------------
1985
1986 const int argc = arguments().immediate();
1987
1988 // If the object is not a JSObject or we got an unexpected number of
1989 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001990 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001991
1992 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001993 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001994
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001995 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001996 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
1997
1998 STATIC_ASSERT(kSmiTag == 0);
1999 __ JumpIfSmi(a1, &miss);
2000
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002001 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2002 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002003 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002004 ASSERT(cell->value() == *function);
2005 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2006 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002007 GenerateLoadFunctionFromCell(cell, function, &miss);
2008 }
2009
2010 // Load the char code argument.
2011 Register code = a1;
2012 __ lw(code, MemOperand(sp, 0 * kPointerSize));
2013
2014 // Check the code is a smi.
2015 Label slow;
2016 STATIC_ASSERT(kSmiTag == 0);
2017 __ JumpIfNotSmi(code, &slow);
2018
2019 // Convert the smi code to uint16.
2020 __ And(code, code, Operand(Smi::FromInt(0xffff)));
2021
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002022 StringCharFromCodeGenerator generator(code, v0);
2023 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002024 __ Drop(argc + 1);
2025 __ Ret();
2026
2027 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002028 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002029
2030 // Tail call the full function. We do not have to patch the receiver
2031 // because the function makes no use of it.
2032 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002033 __ InvokeFunction(
2034 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002035
2036 __ bind(&miss);
2037 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002038 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002039
2040 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002041 return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002042}
2043
2044
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002045Handle<Code> CallStubCompiler::CompileMathFloorCall(
2046 Handle<Object> object,
2047 Handle<JSObject> holder,
2048 Handle<JSGlobalPropertyCell> cell,
2049 Handle<JSFunction> function,
2050 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002051 // ----------- S t a t e -------------
2052 // -- a2 : function name
2053 // -- ra : return address
2054 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2055 // -- ...
2056 // -- sp[argc * 4] : receiver
2057 // -----------------------------------
2058
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002059 if (!CpuFeatures::IsSupported(FPU)) {
2060 return Handle<Code>::null();
2061 }
2062
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002063 CpuFeatures::Scope scope_fpu(FPU);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002064 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002065 // If the object is not a JSObject or we got an unexpected number of
2066 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002067 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002068
2069 Label miss, slow;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002070 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002071
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002072 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002073 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002074 STATIC_ASSERT(kSmiTag == 0);
2075 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002076 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2077 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002078 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002079 ASSERT(cell->value() == *function);
2080 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2081 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002082 GenerateLoadFunctionFromCell(cell, function, &miss);
2083 }
2084
2085 // Load the (only) argument into v0.
2086 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2087
2088 // If the argument is a smi, just return.
2089 STATIC_ASSERT(kSmiTag == 0);
2090 __ And(t0, v0, Operand(kSmiTagMask));
2091 __ Drop(argc + 1, eq, t0, Operand(zero_reg));
2092 __ Ret(eq, t0, Operand(zero_reg));
2093
danno@chromium.org40cb8782011-05-25 07:58:50 +00002094 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002095
2096 Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return;
2097
2098 // If fpu is enabled, we use the floor instruction.
2099
2100 // Load the HeapNumber value.
2101 __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2102
2103 // Backup FCSR.
2104 __ cfc1(a3, FCSR);
2105 // Clearing FCSR clears the exception mask with no side-effects.
2106 __ ctc1(zero_reg, FCSR);
2107 // Convert the argument to an integer.
2108 __ floor_w_d(f0, f0);
2109
2110 // Start checking for special cases.
2111 // Get the argument exponent and clear the sign bit.
2112 __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize));
2113 __ And(t2, t1, Operand(~HeapNumber::kSignMask));
2114 __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord);
2115
2116 // Retrieve FCSR and check for fpu errors.
2117 __ cfc1(t5, FCSR);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002118 __ And(t5, t5, Operand(kFCSRExceptionFlagMask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002119 __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));
2120
2121 // Check for NaN, Infinity, and -Infinity.
2122 // They are invariant through a Math.Floor call, so just
2123 // return the original argument.
2124 __ Subu(t3, t2, Operand(HeapNumber::kExponentMask
2125 >> HeapNumber::kMantissaBitsInTopWord));
2126 __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg));
2127 // We had an overflow or underflow in the conversion. Check if we
2128 // have a big exponent.
2129 // If greater or equal, the argument is already round and in v0.
2130 __ Branch(&restore_fcsr_and_return, ge, t3,
2131 Operand(HeapNumber::kMantissaBits));
2132 __ Branch(&wont_fit_smi);
2133
2134 __ bind(&no_fpu_error);
2135 // Move the result back to v0.
2136 __ mfc1(v0, f0);
2137 // Check if the result fits into a smi.
2138 __ Addu(a1, v0, Operand(0x40000000));
2139 __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg));
2140 // Tag the result.
2141 STATIC_ASSERT(kSmiTag == 0);
2142 __ sll(v0, v0, kSmiTagSize);
2143
2144 // Check for -0.
2145 __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg));
2146 // t1 already holds the HeapNumber exponent.
2147 __ And(t0, t1, Operand(HeapNumber::kSignMask));
2148 // If our HeapNumber is negative it was -0, so load its address and return.
2149 // Else v0 is loaded with 0, so we can also just return.
2150 __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg));
2151 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2152
2153 __ bind(&restore_fcsr_and_return);
2154 // Restore FCSR and return.
2155 __ ctc1(a3, FCSR);
2156
2157 __ Drop(argc + 1);
2158 __ Ret();
2159
2160 __ bind(&wont_fit_smi);
2161 // Restore FCSR and fall to slow case.
2162 __ ctc1(a3, FCSR);
2163
2164 __ bind(&slow);
2165 // Tail call the full function. We do not have to patch the receiver
2166 // because the function makes no use of it.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002167 __ InvokeFunction(
2168 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002169
2170 __ bind(&miss);
2171 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002172 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002173
2174 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002175 return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002176}
2177
2178
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002179Handle<Code> CallStubCompiler::CompileMathAbsCall(
2180 Handle<Object> object,
2181 Handle<JSObject> holder,
2182 Handle<JSGlobalPropertyCell> cell,
2183 Handle<JSFunction> function,
2184 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002185 // ----------- S t a t e -------------
2186 // -- a2 : function name
2187 // -- ra : return address
2188 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2189 // -- ...
2190 // -- sp[argc * 4] : receiver
2191 // -----------------------------------
2192
2193 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002194 // If the object is not a JSObject or we got an unexpected number of
2195 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002196 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002197
2198 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002199
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002200 GenerateNameCheck(name, &miss);
2201 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002202 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002203 STATIC_ASSERT(kSmiTag == 0);
2204 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002205 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2206 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002207 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002208 ASSERT(cell->value() == *function);
2209 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2210 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002211 GenerateLoadFunctionFromCell(cell, function, &miss);
2212 }
2213
2214 // Load the (only) argument into v0.
2215 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2216
2217 // Check if the argument is a smi.
2218 Label not_smi;
2219 STATIC_ASSERT(kSmiTag == 0);
2220 __ JumpIfNotSmi(v0, &not_smi);
2221
2222 // Do bitwise not or do nothing depending on the sign of the
2223 // argument.
2224 __ sra(t0, v0, kBitsPerInt - 1);
2225 __ Xor(a1, v0, t0);
2226
2227 // Add 1 or do nothing depending on the sign of the argument.
2228 __ Subu(v0, a1, t0);
2229
2230 // If the result is still negative, go to the slow case.
2231 // This only happens for the most negative smi.
2232 Label slow;
2233 __ Branch(&slow, lt, v0, Operand(zero_reg));
2234
2235 // Smi case done.
2236 __ Drop(argc + 1);
2237 __ Ret();
2238
2239 // Check if the argument is a heap number and load its exponent and
2240 // sign.
2241 __ bind(&not_smi);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002242 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002243 __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2244
2245 // Check the sign of the argument. If the argument is positive,
2246 // just return it.
2247 Label negative_sign;
2248 __ And(t0, a1, Operand(HeapNumber::kSignMask));
2249 __ Branch(&negative_sign, ne, t0, Operand(zero_reg));
2250 __ Drop(argc + 1);
2251 __ Ret();
2252
2253 // If the argument is negative, clear the sign, and return a new
2254 // number.
2255 __ bind(&negative_sign);
2256 __ Xor(a1, a1, Operand(HeapNumber::kSignMask));
2257 __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2258 __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
2259 __ AllocateHeapNumber(v0, t0, t1, t2, &slow);
2260 __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2261 __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2262 __ Drop(argc + 1);
2263 __ Ret();
2264
2265 // Tail call the full function. We do not have to patch the receiver
2266 // because the function makes no use of it.
2267 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002268 __ InvokeFunction(
2269 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002270
2271 __ bind(&miss);
2272 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002273 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002274
2275 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002276 return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002277}
2278
2279
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002280Handle<Code> CallStubCompiler::CompileFastApiCall(
lrn@chromium.org7516f052011-03-30 08:52:27 +00002281 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002282 Handle<Object> object,
2283 Handle<JSObject> holder,
2284 Handle<JSGlobalPropertyCell> cell,
2285 Handle<JSFunction> function,
2286 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002287
danno@chromium.org40cb8782011-05-25 07:58:50 +00002288 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002289
2290 ASSERT(optimization.is_simple_api_call());
2291 // Bail out if object is a global object as we don't want to
2292 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002293 if (object->IsGlobalObject()) return Handle<Code>::null();
2294 if (!cell.is_null()) return Handle<Code>::null();
2295 if (!object->IsJSObject()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002296 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002297 Handle<JSObject>::cast(object), holder);
2298 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002299
2300 Label miss, miss_before_stack_reserved;
2301
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002302 GenerateNameCheck(name, &miss_before_stack_reserved);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002303
2304 // Get the receiver from the stack.
2305 const int argc = arguments().immediate();
2306 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2307
2308 // Check that the receiver isn't a smi.
2309 __ JumpIfSmi(a1, &miss_before_stack_reserved);
2310
2311 __ IncrementCounter(counters->call_const(), 1, a0, a3);
2312 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2313
2314 ReserveSpaceForFastApiCall(masm(), a0);
2315
2316 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002317 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002318 depth, &miss);
2319
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002320 GenerateFastApiDirectCall(masm(), optimization, argc);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002321
2322 __ bind(&miss);
2323 FreeSpaceForFastApiCall(masm());
2324
2325 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002326 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002327
2328 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002329 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002330}
2331
2332
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002333Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object,
2334 Handle<JSObject> holder,
2335 Handle<JSFunction> function,
2336 Handle<String> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002337 CheckType check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002338 // ----------- S t a t e -------------
2339 // -- a2 : name
2340 // -- ra : return address
2341 // -----------------------------------
2342 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002343 Handle<Code> code = CompileCustomCall(object, holder,
2344 Handle<JSGlobalPropertyCell>::null(),
2345 function, name);
2346 // A null handle means bail out to the regular compiler code below.
2347 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002348 }
2349
2350 Label miss;
2351
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002352 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002353
2354 // Get the receiver from the stack.
2355 const int argc = arguments().immediate();
2356 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2357
2358 // Check that the receiver isn't a smi.
2359 if (check != NUMBER_CHECK) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002360 __ JumpIfSmi(a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002361 }
2362
2363 // Make sure that it's okay not to patch the on stack receiver
2364 // unless we're doing a receiver map check.
2365 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002366 switch (check) {
2367 case RECEIVER_MAP_CHECK:
2368 __ IncrementCounter(masm()->isolate()->counters()->call_const(),
2369 1, a0, a3);
2370
2371 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002372 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2373 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002374
2375 // Patch the receiver on the stack with the global proxy if
2376 // necessary.
2377 if (object->IsGlobalObject()) {
2378 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2379 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2380 }
2381 break;
2382
2383 case STRING_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002384 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002385 // Check that the object is a two-byte string or a symbol.
2386 __ GetObjectType(a1, a3, a3);
2387 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2388 // Check that the maps starting from the prototype haven't changed.
2389 GenerateDirectLoadGlobalFunctionPrototype(
2390 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002391 CheckPrototypes(
2392 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2393 a0, holder, a3, a1, t0, name, &miss);
2394 } else {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002395 // Calling non-strict non-builtins with a value as the receiver
2396 // requires boxing.
2397 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002398 }
2399 break;
2400
2401 case NUMBER_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002402 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002403 Label fast;
2404 // Check that the object is a smi or a heap number.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002405 __ JumpIfSmi(a1, &fast);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002406 __ GetObjectType(a1, a0, a0);
2407 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
2408 __ bind(&fast);
2409 // Check that the maps starting from the prototype haven't changed.
2410 GenerateDirectLoadGlobalFunctionPrototype(
2411 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002412 CheckPrototypes(
2413 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2414 a0, holder, a3, a1, t0, name, &miss);
2415 } else {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002416 // Calling non-strict non-builtins with a value as the receiver
2417 // requires boxing.
2418 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002419 }
2420 break;
2421
2422 case BOOLEAN_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002423 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002424 Label fast;
2425 // Check that the object is a boolean.
2426 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
2427 __ Branch(&fast, eq, a1, Operand(t0));
2428 __ LoadRoot(t0, Heap::kFalseValueRootIndex);
2429 __ Branch(&miss, ne, a1, Operand(t0));
2430 __ bind(&fast);
2431 // Check that the maps starting from the prototype haven't changed.
2432 GenerateDirectLoadGlobalFunctionPrototype(
2433 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002434 CheckPrototypes(
2435 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2436 a0, holder, a3, a1, t0, name, &miss);
2437 } else {
2438 // Calling non-strict non-builtins with a value as the receiver
2439 // requires boxing.
2440 __ jmp(&miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002441 }
2442 break;
2443 }
2444
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002445 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002446 ? CALL_AS_FUNCTION
2447 : CALL_AS_METHOD;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002448 __ InvokeFunction(
2449 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002450
2451 // Handle call cache miss.
2452 __ bind(&miss);
2453
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002454 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002455
2456 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002457 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002458}
2459
2460
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002461Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2462 Handle<JSObject> holder,
2463 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002464 // ----------- S t a t e -------------
2465 // -- a2 : name
2466 // -- ra : return address
2467 // -----------------------------------
2468
2469 Label miss;
2470
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002471 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002472
2473 // Get the number of arguments.
2474 const int argc = arguments().immediate();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002475 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002476 LookupPostInterceptor(holder, name, &lookup);
2477
2478 // Get the receiver from the stack.
2479 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2480
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002481 CallInterceptorCompiler compiler(this, arguments(), a2, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002482 compiler.Compile(masm(), object, holder, name, &lookup, a1, a3, t0, a0,
2483 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002484
2485 // Move returned value, the function to call, to a1.
2486 __ mov(a1, v0);
2487 // Restore receiver.
2488 __ lw(a0, MemOperand(sp, argc * kPointerSize));
2489
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002490 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002491
2492 // Handle call cache miss.
2493 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002494 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002495
2496 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002497 return GetCode(INTERCEPTOR, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002498}
2499
2500
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002501Handle<Code> CallStubCompiler::CompileCallGlobal(
2502 Handle<JSObject> object,
2503 Handle<GlobalObject> holder,
2504 Handle<JSGlobalPropertyCell> cell,
2505 Handle<JSFunction> function,
2506 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002507 // ----------- S t a t e -------------
2508 // -- a2 : name
2509 // -- ra : return address
2510 // -----------------------------------
2511
2512 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002513 Handle<Code> code = CompileCustomCall(object, holder, cell, function, name);
2514 // A null handle means bail out to the regular compiler code below.
2515 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002516 }
2517
2518 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002519 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002520
2521 // Get the number of arguments.
2522 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002523 GenerateGlobalReceiverCheck(object, holder, name, &miss);
2524 GenerateLoadFunctionFromCell(cell, function, &miss);
2525
2526 // Patch the receiver on the stack with the global proxy if
2527 // necessary.
2528 if (object->IsGlobalObject()) {
2529 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
2530 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2531 }
2532
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002533 // Set up the context (function already in r1).
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002534 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
2535
2536 // Jump to the cached code (tail call).
2537 Counters* counters = masm()->isolate()->counters();
2538 __ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002539 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002540 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002541 ? CALL_AS_FUNCTION
2542 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002543 // We call indirectly through the code field in the function to
2544 // allow recompilation to take effect without changing any of the
2545 // call sites.
2546 __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
2547 __ InvokeCode(a3, expected, arguments(), JUMP_FUNCTION,
2548 NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002549
2550 // Handle call cache miss.
2551 __ bind(&miss);
2552 __ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002553 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002554
2555 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002556 return GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002557}
2558
2559
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002560Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +00002561 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002562 Handle<Map> transition,
2563 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002564 // ----------- S t a t e -------------
2565 // -- a0 : value
2566 // -- a1 : receiver
2567 // -- a2 : name
2568 // -- ra : return address
2569 // -----------------------------------
2570 Label miss;
2571
2572 // Name register might be clobbered.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002573 GenerateStoreField(masm(), object, index, transition, a1, a2, a3, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002574 __ bind(&miss);
2575 __ li(a2, Operand(Handle<String>(name))); // Restore name.
2576 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2577 __ Jump(ic, RelocInfo::CODE_TARGET);
2578
2579 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002580 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002581}
2582
2583
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002584Handle<Code> StoreStubCompiler::CompileStoreCallback(
2585 Handle<JSObject> object,
2586 Handle<AccessorInfo> callback,
2587 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002588 // ----------- S t a t e -------------
2589 // -- a0 : value
2590 // -- a1 : receiver
2591 // -- a2 : name
2592 // -- ra : return address
2593 // -----------------------------------
2594 Label miss;
2595
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002596 // Check that the map of the object hasn't changed.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002597 __ CheckMap(a1, a3, Handle<Map>(object->map()), &miss,
2598 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002599
2600 // Perform global security token check if needed.
2601 if (object->IsJSGlobalProxy()) {
2602 __ CheckAccessGlobalProxy(a1, a3, &miss);
2603 }
2604
2605 // Stub never generated for non-global objects that require access
2606 // checks.
2607 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
2608
2609 __ push(a1); // Receiver.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002610 __ li(a3, Operand(callback)); // Callback info.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002611 __ Push(a3, a2, a0);
2612
2613 // Do tail-call to the runtime system.
2614 ExternalReference store_callback_property =
2615 ExternalReference(IC_Utility(IC::kStoreCallbackProperty),
2616 masm()->isolate());
2617 __ TailCallExternalReference(store_callback_property, 4, 1);
2618
2619 // Handle store cache miss.
2620 __ bind(&miss);
2621 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2622 __ Jump(ic, RelocInfo::CODE_TARGET);
2623
2624 // Return the generated code.
2625 return GetCode(CALLBACKS, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002626}
2627
2628
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002629Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
2630 Handle<JSObject> receiver,
2631 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002632 // ----------- S t a t e -------------
2633 // -- a0 : value
2634 // -- a1 : receiver
2635 // -- a2 : name
2636 // -- ra : return address
2637 // -----------------------------------
2638 Label miss;
2639
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002640 // Check that the map of the object hasn't changed.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002641 __ CheckMap(a1, a3, Handle<Map>(receiver->map()), &miss,
2642 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002643
2644 // Perform global security token check if needed.
2645 if (receiver->IsJSGlobalProxy()) {
2646 __ CheckAccessGlobalProxy(a1, a3, &miss);
2647 }
2648
2649 // Stub is never generated for non-global objects that require access
2650 // checks.
2651 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2652
2653 __ Push(a1, a2, a0); // Receiver, name, value.
2654
2655 __ li(a0, Operand(Smi::FromInt(strict_mode_)));
2656 __ push(a0); // Strict mode.
2657
2658 // Do tail-call to the runtime system.
2659 ExternalReference store_ic_property =
2660 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty),
2661 masm()->isolate());
2662 __ TailCallExternalReference(store_ic_property, 4, 1);
2663
2664 // Handle store cache miss.
2665 __ bind(&miss);
2666 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2667 __ Jump(ic, RelocInfo::CODE_TARGET);
2668
2669 // Return the generated code.
2670 return GetCode(INTERCEPTOR, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002671}
2672
2673
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002674Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2675 Handle<GlobalObject> object,
2676 Handle<JSGlobalPropertyCell> cell,
2677 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002678 // ----------- S t a t e -------------
2679 // -- a0 : value
2680 // -- a1 : receiver
2681 // -- a2 : name
2682 // -- ra : return address
2683 // -----------------------------------
2684 Label miss;
2685
2686 // Check that the map of the global has not changed.
2687 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2688 __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map())));
2689
2690 // Check that the value in the cell is not the hole. If it is, this
2691 // cell could have been deleted and reintroducing the global needs
2692 // to update the property details in the property dictionary of the
2693 // global object. We bail out to the runtime system to do that.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002694 __ li(t0, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002695 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
2696 __ lw(t2, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2697 __ Branch(&miss, eq, t1, Operand(t2));
2698
2699 // Store the value in the cell.
2700 __ sw(a0, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2701 __ mov(v0, a0); // Stored value must be returned in v0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002702 // Cells are always rescanned, so no write barrier here.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002703
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002704 Counters* counters = masm()->isolate()->counters();
2705 __ IncrementCounter(counters->named_store_global_inline(), 1, a1, a3);
2706 __ Ret();
2707
2708 // Handle store cache miss.
2709 __ bind(&miss);
2710 __ IncrementCounter(counters->named_store_global_inline_miss(), 1, a1, a3);
2711 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2712 __ Jump(ic, RelocInfo::CODE_TARGET);
2713
2714 // Return the generated code.
2715 return GetCode(NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002716}
2717
2718
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002719Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
2720 Handle<JSObject> object,
2721 Handle<JSObject> last) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002722 // ----------- S t a t e -------------
2723 // -- a0 : receiver
2724 // -- ra : return address
2725 // -----------------------------------
2726 Label miss;
2727
2728 // Check that the receiver is not a smi.
2729 __ JumpIfSmi(a0, &miss);
2730
2731 // Check the maps of the full prototype chain.
2732 CheckPrototypes(object, a0, last, a3, a1, t0, name, &miss);
2733
2734 // If the last object in the prototype chain is a global object,
2735 // check that the global property cell is empty.
2736 if (last->IsGlobalObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002737 GenerateCheckPropertyCell(
2738 masm(), Handle<GlobalObject>::cast(last), name, a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002739 }
2740
2741 // Return undefined if maps of the full prototype chain is still the same.
2742 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2743 __ Ret();
2744
2745 __ bind(&miss);
2746 GenerateLoadMiss(masm(), Code::LOAD_IC);
2747
2748 // Return the generated code.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002749 return GetCode(NONEXISTENT, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00002750}
2751
2752
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002753Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object,
2754 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002755 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002756 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002757 // ----------- S t a t e -------------
2758 // -- a0 : receiver
2759 // -- a2 : name
2760 // -- ra : return address
2761 // -----------------------------------
2762 Label miss;
2763
2764 __ mov(v0, a0);
2765
2766 GenerateLoadField(object, holder, v0, a3, a1, t0, index, name, &miss);
2767 __ bind(&miss);
2768 GenerateLoadMiss(masm(), Code::LOAD_IC);
2769
2770 // Return the generated code.
2771 return GetCode(FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002772}
2773
2774
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002775Handle<Code> LoadStubCompiler::CompileLoadCallback(
2776 Handle<String> name,
2777 Handle<JSObject> object,
2778 Handle<JSObject> holder,
2779 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002780 // ----------- S t a t e -------------
2781 // -- a0 : receiver
2782 // -- a2 : name
2783 // -- ra : return address
2784 // -----------------------------------
2785 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002786 GenerateLoadCallback(object, holder, a0, a2, a3, a1, t0, callback, name,
2787 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002788 __ bind(&miss);
2789 GenerateLoadMiss(masm(), Code::LOAD_IC);
2790
2791 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002792 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002793}
2794
2795
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002796Handle<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object,
2797 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002798 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002799 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002800 // ----------- S t a t e -------------
2801 // -- a0 : receiver
2802 // -- a2 : name
2803 // -- ra : return address
2804 // -----------------------------------
2805 Label miss;
2806
2807 GenerateLoadConstant(object, holder, a0, a3, a1, t0, value, name, &miss);
2808 __ bind(&miss);
2809 GenerateLoadMiss(masm(), Code::LOAD_IC);
2810
2811 // Return the generated code.
2812 return GetCode(CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002813}
2814
2815
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002816Handle<Code> LoadStubCompiler::CompileLoadInterceptor(Handle<JSObject> object,
2817 Handle<JSObject> holder,
2818 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002819 // ----------- S t a t e -------------
2820 // -- a0 : receiver
2821 // -- a2 : name
2822 // -- ra : return address
2823 // -- [sp] : receiver
2824 // -----------------------------------
2825 Label miss;
2826
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002827 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002828 LookupPostInterceptor(holder, name, &lookup);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002829 GenerateLoadInterceptor(object, holder, &lookup, a0, a2, a3, a1, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002830 &miss);
2831 __ bind(&miss);
2832 GenerateLoadMiss(masm(), Code::LOAD_IC);
2833
2834 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002835 return GetCode(INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002836}
2837
2838
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002839Handle<Code> LoadStubCompiler::CompileLoadGlobal(
2840 Handle<JSObject> object,
2841 Handle<GlobalObject> holder,
2842 Handle<JSGlobalPropertyCell> cell,
2843 Handle<String> name,
2844 bool is_dont_delete) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002845 // ----------- S t a t e -------------
2846 // -- a0 : receiver
2847 // -- a2 : name
2848 // -- ra : return address
2849 // -----------------------------------
2850 Label miss;
2851
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002852 // Check that the map of the global has not changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00002853 __ JumpIfSmi(a0, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002854 CheckPrototypes(object, a0, holder, a3, t0, a1, name, &miss);
2855
2856 // Get the value from the cell.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002857 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002858 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
2859
2860 // Check for deleted property if property can actually be deleted.
2861 if (!is_dont_delete) {
2862 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
2863 __ Branch(&miss, eq, t0, Operand(at));
2864 }
2865
2866 __ mov(v0, t0);
2867 Counters* counters = masm()->isolate()->counters();
2868 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
2869 __ Ret();
2870
2871 __ bind(&miss);
2872 __ IncrementCounter(counters->named_load_global_stub_miss(), 1, a1, a3);
2873 GenerateLoadMiss(masm(), Code::LOAD_IC);
2874
2875 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002876 return GetCode(NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002877}
2878
2879
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002880Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
2881 Handle<JSObject> receiver,
2882 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002883 int index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002884 // ----------- S t a t e -------------
2885 // -- ra : return address
2886 // -- a0 : key
2887 // -- a1 : receiver
2888 // -----------------------------------
2889 Label miss;
2890
2891 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002892 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002893
2894 GenerateLoadField(receiver, holder, a1, a2, a3, t0, index, name, &miss);
2895 __ bind(&miss);
2896 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2897
2898 return GetCode(FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002899}
2900
2901
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002902Handle<Code> KeyedLoadStubCompiler::CompileLoadCallback(
2903 Handle<String> name,
2904 Handle<JSObject> receiver,
2905 Handle<JSObject> holder,
2906 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002907 // ----------- S t a t e -------------
2908 // -- ra : return address
2909 // -- a0 : key
2910 // -- a1 : receiver
2911 // -----------------------------------
2912 Label miss;
2913
2914 // Check the key is the cached one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002915 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002916
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002917 GenerateLoadCallback(receiver, holder, a1, a0, a2, a3, t0, callback, name,
2918 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002919 __ bind(&miss);
2920 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2921
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002922 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002923}
2924
2925
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002926Handle<Code> KeyedLoadStubCompiler::CompileLoadConstant(
2927 Handle<String> name,
2928 Handle<JSObject> receiver,
2929 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002930 Handle<JSFunction> value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002931 // ----------- S t a t e -------------
2932 // -- ra : return address
2933 // -- a0 : key
2934 // -- a1 : receiver
2935 // -----------------------------------
2936 Label miss;
2937
2938 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002939 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002940
2941 GenerateLoadConstant(receiver, holder, a1, a2, a3, t0, value, name, &miss);
2942 __ bind(&miss);
2943 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2944
2945 // Return the generated code.
2946 return GetCode(CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002947}
2948
2949
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002950Handle<Code> KeyedLoadStubCompiler::CompileLoadInterceptor(
2951 Handle<JSObject> receiver,
2952 Handle<JSObject> holder,
2953 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002954 // ----------- S t a t e -------------
2955 // -- ra : return address
2956 // -- a0 : key
2957 // -- a1 : receiver
2958 // -----------------------------------
2959 Label miss;
2960
2961 // Check the key is the cached one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002962 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002963
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002964 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002965 LookupPostInterceptor(holder, name, &lookup);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002966 GenerateLoadInterceptor(receiver, holder, &lookup, a1, a0, a2, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002967 &miss);
2968 __ bind(&miss);
2969 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2970
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002971 return GetCode(INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002972}
2973
2974
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002975Handle<Code> KeyedLoadStubCompiler::CompileLoadArrayLength(
2976 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002977 // ----------- S t a t e -------------
2978 // -- ra : return address
2979 // -- a0 : key
2980 // -- a1 : receiver
2981 // -----------------------------------
2982 Label miss;
2983
2984 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002985 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002986
2987 GenerateLoadArrayLength(masm(), a1, a2, &miss);
2988 __ bind(&miss);
2989 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2990
2991 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002992}
2993
2994
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002995Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength(
2996 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002997 // ----------- S t a t e -------------
2998 // -- ra : return address
2999 // -- a0 : key
3000 // -- a1 : receiver
3001 // -----------------------------------
3002 Label miss;
3003
3004 Counters* counters = masm()->isolate()->counters();
3005 __ IncrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
3006
3007 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003008 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003009
3010 GenerateLoadStringLength(masm(), a1, a2, a3, &miss, true);
3011 __ bind(&miss);
3012 __ DecrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
3013
3014 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3015
3016 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003017}
3018
3019
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003020Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype(
3021 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003022 // ----------- S t a t e -------------
3023 // -- ra : return address
3024 // -- a0 : key
3025 // -- a1 : receiver
3026 // -----------------------------------
3027 Label miss;
3028
3029 Counters* counters = masm()->isolate()->counters();
3030 __ IncrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
3031
3032 // Check the name hasn't changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003033 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003034
3035 GenerateLoadFunctionPrototype(masm(), a1, a2, a3, &miss);
3036 __ bind(&miss);
3037 __ DecrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
3038 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3039
3040 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003041}
3042
3043
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003044Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
3045 Handle<Map> receiver_map) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003046 // ----------- S t a t e -------------
3047 // -- ra : return address
3048 // -- a0 : key
3049 // -- a1 : receiver
3050 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003051 ElementsKind elements_kind = receiver_map->elements_kind();
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003052 Handle<Code> stub = KeyedLoadElementStub(elements_kind).GetCode();
3053
3054 __ DispatchMap(a1, a2, receiver_map, stub, DO_SMI_CHECK);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003055
3056 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
3057 __ Jump(ic, RelocInfo::CODE_TARGET);
3058
3059 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003060 return GetCode(NORMAL, factory()->empty_string());
danno@chromium.org40cb8782011-05-25 07:58:50 +00003061}
3062
3063
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003064Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
3065 MapHandleList* receiver_maps,
3066 CodeHandleList* handler_ics) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003067 // ----------- S t a t e -------------
3068 // -- ra : return address
3069 // -- a0 : key
3070 // -- a1 : receiver
3071 // -----------------------------------
3072 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003073 __ JumpIfSmi(a1, &miss);
3074
danno@chromium.org40cb8782011-05-25 07:58:50 +00003075 int receiver_count = receiver_maps->length();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003076 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003077 for (int current = 0; current < receiver_count; ++current) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003078 __ Jump(handler_ics->at(current), RelocInfo::CODE_TARGET,
3079 eq, a2, Operand(receiver_maps->at(current)));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003080 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003081
3082 __ bind(&miss);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003083 Handle<Code> miss_ic = isolate()->builtins()->KeyedLoadIC_Miss();
3084 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003085
3086 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003087 return GetCode(NORMAL, factory()->empty_string(), MEGAMORPHIC);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003088}
3089
3090
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003091Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +00003092 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003093 Handle<Map> transition,
3094 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003095 // ----------- S t a t e -------------
3096 // -- a0 : value
3097 // -- a1 : key
3098 // -- a2 : receiver
3099 // -- ra : return address
3100 // -----------------------------------
3101
3102 Label miss;
3103
3104 Counters* counters = masm()->isolate()->counters();
3105 __ IncrementCounter(counters->keyed_store_field(), 1, a3, t0);
3106
3107 // Check that the name has not changed.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003108 __ Branch(&miss, ne, a1, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003109
3110 // a3 is used as scratch register. a1 and a2 keep their values if a jump to
3111 // the miss label is generated.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003112 GenerateStoreField(masm(), object, index, transition, a2, a1, a3, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003113 __ bind(&miss);
3114
3115 __ DecrementCounter(counters->keyed_store_field(), 1, a3, t0);
3116 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss();
3117 __ Jump(ic, RelocInfo::CODE_TARGET);
3118
3119 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003120 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003121}
3122
3123
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003124Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
3125 Handle<Map> receiver_map) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003126 // ----------- S t a t e -------------
3127 // -- a0 : value
3128 // -- a1 : key
3129 // -- a2 : receiver
3130 // -- ra : return address
3131 // -- a3 : scratch
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003132 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003133 ElementsKind elements_kind = receiver_map->elements_kind();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003134 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003135 Handle<Code> stub =
yangguo@chromium.org56454712012-02-16 15:33:53 +00003136 KeyedStoreElementStub(is_js_array, elements_kind, grow_mode_).GetCode();
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003137
3138 __ DispatchMap(a2, a3, receiver_map, stub, DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003139
danno@chromium.org40cb8782011-05-25 07:58:50 +00003140 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003141 __ Jump(ic, RelocInfo::CODE_TARGET);
3142
3143 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003144 return GetCode(NORMAL, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00003145}
3146
3147
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003148Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
3149 MapHandleList* receiver_maps,
3150 CodeHandleList* handler_stubs,
3151 MapHandleList* transitioned_maps) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003152 // ----------- S t a t e -------------
3153 // -- a0 : value
3154 // -- a1 : key
3155 // -- a2 : receiver
3156 // -- ra : return address
3157 // -- a3 : scratch
3158 // -----------------------------------
3159 Label miss;
3160 __ JumpIfSmi(a2, &miss);
3161
3162 int receiver_count = receiver_maps->length();
3163 __ lw(a3, FieldMemOperand(a2, HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003164 for (int i = 0; i < receiver_count; ++i) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003165 if (transitioned_maps->at(i).is_null()) {
3166 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq,
3167 a3, Operand(receiver_maps->at(i)));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003168 } else {
3169 Label next_map;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003170 __ Branch(&next_map, ne, a3, Operand(receiver_maps->at(i)));
3171 __ li(a3, Operand(transitioned_maps->at(i)));
3172 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003173 __ bind(&next_map);
3174 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003175 }
3176
3177 __ bind(&miss);
3178 Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
3179 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3180
3181 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003182 return GetCode(NORMAL, factory()->empty_string(), MEGAMORPHIC);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003183}
3184
3185
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003186Handle<Code> ConstructStubCompiler::CompileConstructStub(
3187 Handle<JSFunction> function) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003188 // a0 : argc
3189 // a1 : constructor
3190 // ra : return address
3191 // [sp] : last argument
3192 Label generic_stub_call;
3193
3194 // Use t7 for holding undefined which is used in several places below.
3195 __ LoadRoot(t7, Heap::kUndefinedValueRootIndex);
3196
3197#ifdef ENABLE_DEBUGGER_SUPPORT
3198 // Check to see whether there are any break points in the function code. If
3199 // there are jump to the generic constructor stub which calls the actual
3200 // code for the function thereby hitting the break points.
3201 __ lw(t5, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3202 __ lw(a2, FieldMemOperand(t5, SharedFunctionInfo::kDebugInfoOffset));
3203 __ Branch(&generic_stub_call, ne, a2, Operand(t7));
3204#endif
3205
3206 // Load the initial map and verify that it is in fact a map.
3207 // a1: constructor function
3208 // t7: undefined
3209 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003210 __ JumpIfSmi(a2, &generic_stub_call);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003211 __ GetObjectType(a2, a3, t0);
3212 __ Branch(&generic_stub_call, ne, t0, Operand(MAP_TYPE));
3213
3214#ifdef DEBUG
3215 // Cannot construct functions this way.
3216 // a0: argc
3217 // a1: constructor function
3218 // a2: initial map
3219 // t7: undefined
3220 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
3221 __ Check(ne, "Function constructed by construct stub.",
3222 a3, Operand(JS_FUNCTION_TYPE));
3223#endif
3224
3225 // Now allocate the JSObject in new space.
3226 // a0: argc
3227 // a1: constructor function
3228 // a2: initial map
3229 // t7: undefined
3230 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003231 __ AllocateInNewSpace(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003232
3233 // Allocated the JSObject, now initialize the fields. Map is set to initial
3234 // map and properties and elements are set to empty fixed array.
3235 // a0: argc
3236 // a1: constructor function
3237 // a2: initial map
3238 // a3: object size (in words)
3239 // t4: JSObject (not tagged)
3240 // t7: undefined
3241 __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex);
3242 __ mov(t5, t4);
3243 __ sw(a2, MemOperand(t5, JSObject::kMapOffset));
3244 __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset));
3245 __ sw(t6, MemOperand(t5, JSObject::kElementsOffset));
3246 __ Addu(t5, t5, Operand(3 * kPointerSize));
3247 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
3248 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
3249 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
3250
3251
3252 // Calculate the location of the first argument. The stack contains only the
3253 // argc arguments.
3254 __ sll(a1, a0, kPointerSizeLog2);
3255 __ Addu(a1, a1, sp);
3256
3257 // Fill all the in-object properties with undefined.
3258 // a0: argc
3259 // a1: first argument
3260 // a3: object size (in words)
3261 // t4: JSObject (not tagged)
3262 // t5: First in-object property of JSObject (not tagged)
3263 // t7: undefined
3264 // Fill the initialized properties with a constant value or a passed argument
3265 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003266 Handle<SharedFunctionInfo> shared(function->shared());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003267 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3268 if (shared->IsThisPropertyAssignmentArgument(i)) {
3269 Label not_passed, next;
3270 // Check if the argument assigned to the property is actually passed.
3271 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3272 __ Branch(&not_passed, less_equal, a0, Operand(arg_number));
3273 // Argument passed - find it on the stack.
3274 __ lw(a2, MemOperand(a1, (arg_number + 1) * -kPointerSize));
3275 __ sw(a2, MemOperand(t5));
3276 __ Addu(t5, t5, kPointerSize);
3277 __ jmp(&next);
3278 __ bind(&not_passed);
3279 // Set the property to undefined.
3280 __ sw(t7, MemOperand(t5));
3281 __ Addu(t5, t5, Operand(kPointerSize));
3282 __ bind(&next);
3283 } else {
3284 // Set the property to the constant value.
3285 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
3286 __ li(a2, Operand(constant));
3287 __ sw(a2, MemOperand(t5));
3288 __ Addu(t5, t5, kPointerSize);
3289 }
3290 }
3291
3292 // Fill the unused in-object property fields with undefined.
3293 ASSERT(function->has_initial_map());
3294 for (int i = shared->this_property_assignments_count();
3295 i < function->initial_map()->inobject_properties();
3296 i++) {
3297 __ sw(t7, MemOperand(t5));
3298 __ Addu(t5, t5, kPointerSize);
3299 }
3300
3301 // a0: argc
3302 // t4: JSObject (not tagged)
3303 // Move argc to a1 and the JSObject to return to v0 and tag it.
3304 __ mov(a1, a0);
3305 __ mov(v0, t4);
3306 __ Or(v0, v0, Operand(kHeapObjectTag));
3307
3308 // v0: JSObject
3309 // a1: argc
3310 // Remove caller arguments and receiver from the stack and return.
3311 __ sll(t0, a1, kPointerSizeLog2);
3312 __ Addu(sp, sp, t0);
3313 __ Addu(sp, sp, Operand(kPointerSize));
3314 Counters* counters = masm()->isolate()->counters();
3315 __ IncrementCounter(counters->constructed_objects(), 1, a1, a2);
3316 __ IncrementCounter(counters->constructed_objects_stub(), 1, a1, a2);
3317 __ Ret();
3318
3319 // Jump to the generic stub in case the specialized code cannot handle the
3320 // construction.
3321 __ bind(&generic_stub_call);
3322 Handle<Code> generic_construct_stub =
3323 masm()->isolate()->builtins()->JSConstructStubGeneric();
3324 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
3325
3326 // Return the generated code.
3327 return GetCode();
3328}
3329
3330
danno@chromium.org40cb8782011-05-25 07:58:50 +00003331#undef __
3332#define __ ACCESS_MASM(masm)
3333
3334
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003335void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3336 MacroAssembler* masm) {
3337 // ---------- S t a t e --------------
3338 // -- ra : return address
3339 // -- a0 : key
3340 // -- a1 : receiver
3341 // -----------------------------------
3342 Label slow, miss_force_generic;
3343
3344 Register key = a0;
3345 Register receiver = a1;
3346
3347 __ JumpIfNotSmi(key, &miss_force_generic);
3348 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
3349 __ sra(a2, a0, kSmiTagSize);
3350 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
3351 __ Ret();
3352
3353 // Slow case, key and receiver still in a0 and a1.
3354 __ bind(&slow);
3355 __ IncrementCounter(
3356 masm->isolate()->counters()->keyed_load_external_array_slow(),
3357 1, a2, a3);
3358 // Entry registers are intact.
3359 // ---------- S t a t e --------------
3360 // -- ra : return address
3361 // -- a0 : key
3362 // -- a1 : receiver
3363 // -----------------------------------
3364 Handle<Code> slow_ic =
3365 masm->isolate()->builtins()->KeyedLoadIC_Slow();
3366 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
3367
3368 // Miss case, call the runtime.
3369 __ bind(&miss_force_generic);
3370
3371 // ---------- S t a t e --------------
3372 // -- ra : return address
3373 // -- a0 : key
3374 // -- a1 : receiver
3375 // -----------------------------------
3376
3377 Handle<Code> miss_ic =
3378 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3379 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3380}
3381
3382
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003383static bool IsElementTypeSigned(ElementsKind elements_kind) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003384 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003385 case EXTERNAL_BYTE_ELEMENTS:
3386 case EXTERNAL_SHORT_ELEMENTS:
3387 case EXTERNAL_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003388 return true;
3389
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003390 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3391 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3392 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3393 case EXTERNAL_PIXEL_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003394 return false;
3395
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003396 case EXTERNAL_FLOAT_ELEMENTS:
3397 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003398 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003399 case FAST_ELEMENTS:
3400 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003401 case FAST_HOLEY_SMI_ELEMENTS:
3402 case FAST_HOLEY_ELEMENTS:
3403 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003404 case DICTIONARY_ELEMENTS:
3405 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003406 UNREACHABLE();
3407 return false;
3408 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003409 return false;
lrn@chromium.org7516f052011-03-30 08:52:27 +00003410}
3411
3412
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003413static void GenerateSmiKeyCheck(MacroAssembler* masm,
3414 Register key,
3415 Register scratch0,
3416 Register scratch1,
3417 FPURegister double_scratch0,
3418 Label* fail) {
3419 if (CpuFeatures::IsSupported(FPU)) {
3420 CpuFeatures::Scope scope(FPU);
3421 Label key_ok;
3422 // Check for smi or a smi inside a heap number. We convert the heap
3423 // number and check if the conversion is exact and fits into the smi
3424 // range.
3425 __ JumpIfSmi(key, &key_ok);
3426 __ CheckMap(key,
3427 scratch0,
3428 Heap::kHeapNumberMapRootIndex,
3429 fail,
3430 DONT_DO_SMI_CHECK);
3431 __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
3432 __ EmitFPUTruncate(kRoundToZero,
3433 double_scratch0,
3434 double_scratch0,
3435 scratch0,
3436 scratch1,
3437 kCheckForInexactConversion);
3438
3439 __ Branch(fail, ne, scratch1, Operand(zero_reg));
3440
3441 __ mfc1(scratch0, double_scratch0);
3442 __ SmiTagCheckOverflow(key, scratch0, scratch1);
3443 __ BranchOnOverflow(fail, scratch1);
3444 __ bind(&key_ok);
3445 } else {
3446 // Check that the key is a smi.
3447 __ JumpIfNotSmi(key, fail);
3448 }
3449}
3450
3451
danno@chromium.org40cb8782011-05-25 07:58:50 +00003452void KeyedLoadStubCompiler::GenerateLoadExternalArray(
3453 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003454 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003455 // ---------- S t a t e --------------
3456 // -- ra : return address
3457 // -- a0 : key
3458 // -- a1 : receiver
3459 // -----------------------------------
danno@chromium.org40cb8782011-05-25 07:58:50 +00003460 Label miss_force_generic, slow, failed_allocation;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003461
3462 Register key = a0;
3463 Register receiver = a1;
3464
danno@chromium.org40cb8782011-05-25 07:58:50 +00003465 // This stub is meant to be tail-jumped to, the receiver must already
3466 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003467
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003468 // Check that the key is a smi or a heap number convertible to a smi.
3469 GenerateSmiKeyCheck(masm, key, t0, t1, f2, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003470
3471 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3472 // a3: elements array
3473
3474 // Check that the index is in range.
3475 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3476 __ sra(t2, key, kSmiTagSize);
3477 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003478 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003479
3480 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3481 // a3: base pointer of external storage
3482
3483 // We are not untagging smi key and instead work with it
3484 // as if it was premultiplied by 2.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003485 STATIC_ASSERT((kSmiTag == 0) && (kSmiTagSize == 1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003486
3487 Register value = a2;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003488 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003489 case EXTERNAL_BYTE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003490 __ srl(t2, key, 1);
3491 __ addu(t3, a3, t2);
3492 __ lb(value, MemOperand(t3, 0));
3493 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003494 case EXTERNAL_PIXEL_ELEMENTS:
3495 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003496 __ srl(t2, key, 1);
3497 __ addu(t3, a3, t2);
3498 __ lbu(value, MemOperand(t3, 0));
3499 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003500 case EXTERNAL_SHORT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003501 __ addu(t3, a3, key);
3502 __ lh(value, MemOperand(t3, 0));
3503 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003504 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003505 __ addu(t3, a3, key);
3506 __ lhu(value, MemOperand(t3, 0));
3507 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003508 case EXTERNAL_INT_ELEMENTS:
3509 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003510 __ sll(t2, key, 1);
3511 __ addu(t3, a3, t2);
3512 __ lw(value, MemOperand(t3, 0));
3513 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003514 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003515 __ sll(t3, t2, 2);
3516 __ addu(t3, a3, t3);
3517 if (CpuFeatures::IsSupported(FPU)) {
3518 CpuFeatures::Scope scope(FPU);
3519 __ lwc1(f0, MemOperand(t3, 0));
3520 } else {
3521 __ lw(value, MemOperand(t3, 0));
3522 }
3523 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003524 case EXTERNAL_DOUBLE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003525 __ sll(t2, key, 2);
3526 __ addu(t3, a3, t2);
3527 if (CpuFeatures::IsSupported(FPU)) {
3528 CpuFeatures::Scope scope(FPU);
3529 __ ldc1(f0, MemOperand(t3, 0));
3530 } else {
3531 // t3: pointer to the beginning of the double we want to load.
3532 __ lw(a2, MemOperand(t3, 0));
3533 __ lw(a3, MemOperand(t3, Register::kSizeInBytes));
3534 }
3535 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003536 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003537 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003538 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003539 case FAST_HOLEY_ELEMENTS:
3540 case FAST_HOLEY_SMI_ELEMENTS:
3541 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003542 case DICTIONARY_ELEMENTS:
3543 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003544 UNREACHABLE();
3545 break;
3546 }
3547
3548 // For integer array types:
3549 // a2: value
3550 // For float array type:
3551 // f0: value (if FPU is supported)
3552 // a2: value (if FPU is not supported)
3553 // For double array type:
3554 // f0: value (if FPU is supported)
3555 // a2/a3: value (if FPU is not supported)
3556
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003557 if (elements_kind == EXTERNAL_INT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003558 // For the Int and UnsignedInt array types, we need to see whether
3559 // the value can be represented in a Smi. If not, we need to convert
3560 // it to a HeapNumber.
3561 Label box_int;
3562 __ Subu(t3, value, Operand(0xC0000000)); // Non-smi value gives neg result.
3563 __ Branch(&box_int, lt, t3, Operand(zero_reg));
3564 // Tag integer as smi and return it.
3565 __ sll(v0, value, kSmiTagSize);
3566 __ Ret();
3567
3568 __ bind(&box_int);
3569 // Allocate a HeapNumber for the result and perform int-to-double
3570 // conversion.
3571 // The arm version uses a temporary here to save r0, but we don't need to
3572 // (a0 is not modified).
3573 __ LoadRoot(t1, Heap::kHeapNumberMapRootIndex);
3574 __ AllocateHeapNumber(v0, a3, t0, t1, &slow);
3575
3576 if (CpuFeatures::IsSupported(FPU)) {
3577 CpuFeatures::Scope scope(FPU);
3578 __ mtc1(value, f0);
3579 __ cvt_d_w(f0, f0);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00003580 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003581 __ Ret();
3582 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003583 Register dst1 = t2;
3584 Register dst2 = t3;
3585 FloatingPointHelper::Destination dest =
3586 FloatingPointHelper::kCoreRegisters;
3587 FloatingPointHelper::ConvertIntToDouble(masm,
3588 value,
3589 dest,
3590 f0,
3591 dst1,
3592 dst2,
3593 t1,
3594 f2);
3595 __ sw(dst1, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3596 __ sw(dst2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3597 __ Ret();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003598 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003599 } else if (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003600 // The test is different for unsigned int values. Since we need
3601 // the value to be in the range of a positive smi, we can't
3602 // handle either of the top two bits being set in the value.
3603 if (CpuFeatures::IsSupported(FPU)) {
3604 CpuFeatures::Scope scope(FPU);
3605 Label pl_box_int;
3606 __ And(t2, value, Operand(0xC0000000));
3607 __ Branch(&pl_box_int, ne, t2, Operand(zero_reg));
3608
3609 // It can fit in an Smi.
3610 // Tag integer as smi and return it.
3611 __ sll(v0, value, kSmiTagSize);
3612 __ Ret();
3613
3614 __ bind(&pl_box_int);
3615 // Allocate a HeapNumber for the result and perform int-to-double
3616 // conversion. Don't use a0 and a1 as AllocateHeapNumber clobbers all
3617 // registers - also when jumping due to exhausted young space.
3618 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3619 __ AllocateHeapNumber(v0, t2, t3, t6, &slow);
3620
3621 // This is replaced by a macro:
3622 // __ mtc1(value, f0); // LS 32-bits.
3623 // __ mtc1(zero_reg, f1); // MS 32-bits are all zero.
3624 // __ cvt_d_l(f0, f0); // Use 64 bit conv to get correct unsigned 32-bit.
3625
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003626 __ Cvt_d_uw(f0, value, f22);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003627
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00003628 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003629
3630 __ Ret();
3631 } else {
3632 // Check whether unsigned integer fits into smi.
3633 Label box_int_0, box_int_1, done;
3634 __ And(t2, value, Operand(0x80000000));
3635 __ Branch(&box_int_0, ne, t2, Operand(zero_reg));
3636 __ And(t2, value, Operand(0x40000000));
3637 __ Branch(&box_int_1, ne, t2, Operand(zero_reg));
3638
3639 // Tag integer as smi and return it.
3640 __ sll(v0, value, kSmiTagSize);
3641 __ Ret();
3642
3643 Register hiword = value; // a2.
3644 Register loword = a3;
3645
3646 __ bind(&box_int_0);
3647 // Integer does not have leading zeros.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003648 GenerateUInt2Double(masm, hiword, loword, t0, 0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003649 __ Branch(&done);
3650
3651 __ bind(&box_int_1);
3652 // Integer has one leading zero.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003653 GenerateUInt2Double(masm, hiword, loword, t0, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003654
3655
3656 __ bind(&done);
3657 // Integer was converted to double in registers hiword:loword.
3658 // Wrap it into a HeapNumber. Don't use a0 and a1 as AllocateHeapNumber
3659 // clobbers all registers - also when jumping due to exhausted young
3660 // space.
3661 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3662 __ AllocateHeapNumber(t2, t3, t5, t6, &slow);
3663
3664 __ sw(hiword, FieldMemOperand(t2, HeapNumber::kExponentOffset));
3665 __ sw(loword, FieldMemOperand(t2, HeapNumber::kMantissaOffset));
3666
3667 __ mov(v0, t2);
3668 __ Ret();
3669 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003670 } else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003671 // For the floating-point array type, we need to always allocate a
3672 // HeapNumber.
3673 if (CpuFeatures::IsSupported(FPU)) {
3674 CpuFeatures::Scope scope(FPU);
3675 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3676 // AllocateHeapNumber clobbers all registers - also when jumping due to
3677 // exhausted young space.
3678 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3679 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3680 // The float (single) value is already in fpu reg f0 (if we use float).
3681 __ cvt_d_s(f0, f0);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00003682 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003683 __ Ret();
3684 } else {
3685 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3686 // AllocateHeapNumber clobbers all registers - also when jumping due to
3687 // exhausted young space.
3688 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3689 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3690 // FPU is not available, do manual single to double conversion.
3691
3692 // a2: floating point value (binary32).
3693 // v0: heap number for result
3694
3695 // Extract mantissa to t4.
3696 __ And(t4, value, Operand(kBinary32MantissaMask));
3697
3698 // Extract exponent to t5.
3699 __ srl(t5, value, kBinary32MantissaBits);
3700 __ And(t5, t5, Operand(kBinary32ExponentMask >> kBinary32MantissaBits));
3701
3702 Label exponent_rebiased;
3703 __ Branch(&exponent_rebiased, eq, t5, Operand(zero_reg));
3704
3705 __ li(t0, 0x7ff);
3706 __ Xor(t1, t5, Operand(0xFF));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003707 __ Movz(t5, t0, t1); // Set t5 to 0x7ff only if t5 is equal to 0xff.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003708 __ Branch(&exponent_rebiased, eq, t0, Operand(0xff));
3709
3710 // Rebias exponent.
3711 __ Addu(t5,
3712 t5,
3713 Operand(-kBinary32ExponentBias + HeapNumber::kExponentBias));
3714
3715 __ bind(&exponent_rebiased);
3716 __ And(a2, value, Operand(kBinary32SignMask));
3717 value = no_reg;
3718 __ sll(t0, t5, HeapNumber::kMantissaBitsInTopWord);
3719 __ or_(a2, a2, t0);
3720
3721 // Shift mantissa.
3722 static const int kMantissaShiftForHiWord =
3723 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3724
3725 static const int kMantissaShiftForLoWord =
3726 kBitsPerInt - kMantissaShiftForHiWord;
3727
3728 __ srl(t0, t4, kMantissaShiftForHiWord);
3729 __ or_(a2, a2, t0);
3730 __ sll(a0, t4, kMantissaShiftForLoWord);
3731
3732 __ sw(a2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3733 __ sw(a0, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3734 __ Ret();
3735 }
3736
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003737 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003738 if (CpuFeatures::IsSupported(FPU)) {
3739 CpuFeatures::Scope scope(FPU);
3740 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3741 // AllocateHeapNumber clobbers all registers - also when jumping due to
3742 // exhausted young space.
3743 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3744 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3745 // The double value is already in f0
3746 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
3747 __ Ret();
3748 } else {
3749 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3750 // AllocateHeapNumber clobbers all registers - also when jumping due to
3751 // exhausted young space.
3752 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3753 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3754
3755 __ sw(a2, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3756 __ sw(a3, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3757 __ Ret();
3758 }
3759
3760 } else {
3761 // Tag integer as smi and return it.
3762 __ sll(v0, value, kSmiTagSize);
3763 __ Ret();
3764 }
3765
3766 // Slow case, key and receiver still in a0 and a1.
3767 __ bind(&slow);
3768 __ IncrementCounter(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003769 masm->isolate()->counters()->keyed_load_external_array_slow(),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003770 1, a2, a3);
3771
3772 // ---------- S t a t e --------------
3773 // -- ra : return address
3774 // -- a0 : key
3775 // -- a1 : receiver
3776 // -----------------------------------
3777
3778 __ Push(a1, a0);
3779
3780 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
3781
danno@chromium.org40cb8782011-05-25 07:58:50 +00003782 __ bind(&miss_force_generic);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003783 Handle<Code> stub =
3784 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3785 __ Jump(stub, RelocInfo::CODE_TARGET);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003786}
3787
3788
danno@chromium.org40cb8782011-05-25 07:58:50 +00003789void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3790 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003791 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003792 // ---------- S t a t e --------------
3793 // -- a0 : value
3794 // -- a1 : key
3795 // -- a2 : receiver
3796 // -- ra : return address
3797 // -----------------------------------
3798
danno@chromium.org40cb8782011-05-25 07:58:50 +00003799 Label slow, check_heap_number, miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003800
3801 // Register usage.
3802 Register value = a0;
3803 Register key = a1;
3804 Register receiver = a2;
3805 // a3 mostly holds the elements array or the destination external array.
3806
danno@chromium.org40cb8782011-05-25 07:58:50 +00003807 // This stub is meant to be tail-jumped to, the receiver must already
3808 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003809
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003810 // Check that the key is a smi or a heap number convertible to a smi.
3811 GenerateSmiKeyCheck(masm, key, t0, t1, f2, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003812
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003813 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3814
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003815 // Check that the index is in range.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003816 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3817 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003818 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003819
3820 // Handle both smis and HeapNumbers in the fast path. Go to the
3821 // runtime for all other kinds of values.
3822 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003823
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003824 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003825 // Double to pixel conversion is only implemented in the runtime for now.
3826 __ JumpIfNotSmi(value, &slow);
3827 } else {
3828 __ JumpIfNotSmi(value, &check_heap_number);
3829 }
3830 __ SmiUntag(t1, value);
3831 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3832
3833 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003834 // t1: value (integer).
3835
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003836 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003837 case EXTERNAL_PIXEL_ELEMENTS: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003838 // Clamp the value to [0..255].
3839 // v0 is used as a scratch register here.
3840 Label done;
3841 __ li(v0, Operand(255));
3842 // Normal branch: nop in delay slot.
3843 __ Branch(&done, gt, t1, Operand(v0));
3844 // Use delay slot in this branch.
3845 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg));
3846 __ mov(v0, zero_reg); // In delay slot.
3847 __ mov(v0, t1); // Value is in range 0..255.
3848 __ bind(&done);
3849 __ mov(t1, v0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003850
3851 __ srl(t8, key, 1);
3852 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003853 __ sb(t1, MemOperand(t8, 0));
3854 }
3855 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003856 case EXTERNAL_BYTE_ELEMENTS:
3857 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003858 __ srl(t8, key, 1);
3859 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003860 __ sb(t1, MemOperand(t8, 0));
3861 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003862 case EXTERNAL_SHORT_ELEMENTS:
3863 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003864 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003865 __ sh(t1, MemOperand(t8, 0));
3866 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003867 case EXTERNAL_INT_ELEMENTS:
3868 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003869 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003870 __ addu(t8, a3, t8);
3871 __ sw(t1, MemOperand(t8, 0));
3872 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003873 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003874 // Perform int-to-float conversion and store to memory.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003875 __ SmiUntag(t0, key);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003876 StoreIntAsFloat(masm, a3, t0, t1, t2, t3, t4);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003877 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003878 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003879 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003880 __ addu(a3, a3, t8);
3881 // a3: effective address of the double element
3882 FloatingPointHelper::Destination destination;
3883 if (CpuFeatures::IsSupported(FPU)) {
3884 destination = FloatingPointHelper::kFPURegisters;
3885 } else {
3886 destination = FloatingPointHelper::kCoreRegisters;
3887 }
3888 FloatingPointHelper::ConvertIntToDouble(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003889 masm, t1, destination,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003890 f0, t2, t3, // These are: double_dst, dst1, dst2.
3891 t0, f2); // These are: scratch2, single_scratch.
3892 if (destination == FloatingPointHelper::kFPURegisters) {
3893 CpuFeatures::Scope scope(FPU);
3894 __ sdc1(f0, MemOperand(a3, 0));
3895 } else {
3896 __ sw(t2, MemOperand(a3, 0));
3897 __ sw(t3, MemOperand(a3, Register::kSizeInBytes));
3898 }
3899 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003900 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003901 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003902 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003903 case FAST_HOLEY_ELEMENTS:
3904 case FAST_HOLEY_SMI_ELEMENTS:
3905 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003906 case DICTIONARY_ELEMENTS:
3907 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003908 UNREACHABLE();
3909 break;
3910 }
3911
3912 // Entry registers are intact, a0 holds the value which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003913 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003914 __ Ret();
3915
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003916 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003917 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003918 __ bind(&check_heap_number);
3919 __ GetObjectType(value, t1, t2);
3920 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE));
3921
3922 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3923
3924 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003925
3926 // The WebGL specification leaves the behavior of storing NaN and
3927 // +/-Infinity into integer arrays basically undefined. For more
3928 // reproducible behavior, convert these to zero.
3929
3930 if (CpuFeatures::IsSupported(FPU)) {
3931 CpuFeatures::Scope scope(FPU);
3932
3933 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
3934
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003935 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003936 __ cvt_s_d(f0, f0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003937 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003938 __ addu(t8, a3, t8);
3939 __ swc1(f0, MemOperand(t8, 0));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003940 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003941 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003942 __ addu(t8, a3, t8);
3943 __ sdc1(f0, MemOperand(t8, 0));
3944 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003945 __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003946
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003947 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003948 case EXTERNAL_BYTE_ELEMENTS:
3949 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003950 __ srl(t8, key, 1);
3951 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003952 __ sb(t3, MemOperand(t8, 0));
3953 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003954 case EXTERNAL_SHORT_ELEMENTS:
3955 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003956 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003957 __ sh(t3, MemOperand(t8, 0));
3958 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003959 case EXTERNAL_INT_ELEMENTS:
3960 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003961 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003962 __ addu(t8, a3, t8);
3963 __ sw(t3, MemOperand(t8, 0));
3964 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003965 case EXTERNAL_PIXEL_ELEMENTS:
3966 case EXTERNAL_FLOAT_ELEMENTS:
3967 case EXTERNAL_DOUBLE_ELEMENTS:
3968 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003969 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003970 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003971 case FAST_HOLEY_ELEMENTS:
3972 case FAST_HOLEY_SMI_ELEMENTS:
3973 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003974 case DICTIONARY_ELEMENTS:
3975 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003976 UNREACHABLE();
3977 break;
3978 }
3979 }
3980
3981 // Entry registers are intact, a0 holds the value
3982 // which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003983 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003984 __ Ret();
3985 } else {
3986 // FPU is not available, do manual conversions.
3987
3988 __ lw(t3, FieldMemOperand(value, HeapNumber::kExponentOffset));
3989 __ lw(t4, FieldMemOperand(value, HeapNumber::kMantissaOffset));
3990
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003991 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003992 Label done, nan_or_infinity_or_zero;
3993 static const int kMantissaInHiWordShift =
3994 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3995
3996 static const int kMantissaInLoWordShift =
3997 kBitsPerInt - kMantissaInHiWordShift;
3998
3999 // Test for all special exponent values: zeros, subnormal numbers, NaNs
4000 // and infinities. All these should be converted to 0.
4001 __ li(t5, HeapNumber::kExponentMask);
4002 __ and_(t6, t3, t5);
4003 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(zero_reg));
4004
4005 __ xor_(t1, t6, t5);
4006 __ li(t2, kBinary32ExponentMask);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004007 __ Movz(t6, t2, t1); // Only if t6 is equal to t5.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004008 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(t5));
4009
4010 // Rebias exponent.
4011 __ srl(t6, t6, HeapNumber::kExponentShift);
4012 __ Addu(t6,
4013 t6,
4014 Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
4015
4016 __ li(t1, Operand(kBinary32MaxExponent));
4017 __ Slt(t1, t1, t6);
4018 __ And(t2, t3, Operand(HeapNumber::kSignMask));
4019 __ Or(t2, t2, Operand(kBinary32ExponentMask));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004020 __ Movn(t3, t2, t1); // Only if t6 is gt kBinary32MaxExponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004021 __ Branch(&done, gt, t6, Operand(kBinary32MaxExponent));
4022
4023 __ Slt(t1, t6, Operand(kBinary32MinExponent));
4024 __ And(t2, t3, Operand(HeapNumber::kSignMask));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004025 __ Movn(t3, t2, t1); // Only if t6 is lt kBinary32MinExponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004026 __ Branch(&done, lt, t6, Operand(kBinary32MinExponent));
4027
4028 __ And(t7, t3, Operand(HeapNumber::kSignMask));
4029 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4030 __ sll(t3, t3, kMantissaInHiWordShift);
4031 __ or_(t7, t7, t3);
4032 __ srl(t4, t4, kMantissaInLoWordShift);
4033 __ or_(t7, t7, t4);
4034 __ sll(t6, t6, kBinary32ExponentShift);
4035 __ or_(t3, t7, t6);
4036
4037 __ bind(&done);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004038 __ sll(t9, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004039 __ addu(t9, a2, t9);
4040 __ sw(t3, MemOperand(t9, 0));
4041
4042 // Entry registers are intact, a0 holds the value which is the return
4043 // value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004044 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004045 __ Ret();
4046
4047 __ bind(&nan_or_infinity_or_zero);
4048 __ And(t7, t3, Operand(HeapNumber::kSignMask));
4049 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4050 __ or_(t6, t6, t7);
4051 __ sll(t3, t3, kMantissaInHiWordShift);
4052 __ or_(t6, t6, t3);
4053 __ srl(t4, t4, kMantissaInLoWordShift);
4054 __ or_(t3, t6, t4);
4055 __ Branch(&done);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004056 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004057 __ sll(t8, t0, 3);
4058 __ addu(t8, a3, t8);
4059 // t8: effective address of destination element.
4060 __ sw(t4, MemOperand(t8, 0));
4061 __ sw(t3, MemOperand(t8, Register::kSizeInBytes));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004062 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004063 __ Ret();
4064 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004065 bool is_signed_type = IsElementTypeSigned(elements_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004066 int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
4067 int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
4068
4069 Label done, sign;
4070
4071 // Test for all special exponent values: zeros, subnormal numbers, NaNs
4072 // and infinities. All these should be converted to 0.
4073 __ li(t5, HeapNumber::kExponentMask);
4074 __ and_(t6, t3, t5);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004075 __ Movz(t3, zero_reg, t6); // Only if t6 is equal to zero.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004076 __ Branch(&done, eq, t6, Operand(zero_reg));
4077
4078 __ xor_(t2, t6, t5);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004079 __ Movz(t3, zero_reg, t2); // Only if t6 is equal to t5.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004080 __ Branch(&done, eq, t6, Operand(t5));
4081
4082 // Unbias exponent.
4083 __ srl(t6, t6, HeapNumber::kExponentShift);
4084 __ Subu(t6, t6, Operand(HeapNumber::kExponentBias));
4085 // If exponent is negative then result is 0.
4086 __ slt(t2, t6, zero_reg);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004087 __ Movn(t3, zero_reg, t2); // Only if exponent is negative.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004088 __ Branch(&done, lt, t6, Operand(zero_reg));
4089
4090 // If exponent is too big then result is minimal value.
4091 __ slti(t1, t6, meaningfull_bits - 1);
4092 __ li(t2, min_value);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004093 __ Movz(t3, t2, t1); // Only if t6 is ge meaningfull_bits - 1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004094 __ Branch(&done, ge, t6, Operand(meaningfull_bits - 1));
4095
4096 __ And(t5, t3, Operand(HeapNumber::kSignMask));
4097 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4098 __ Or(t3, t3, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
4099
4100 __ li(t9, HeapNumber::kMantissaBitsInTopWord);
4101 __ subu(t6, t9, t6);
4102 __ slt(t1, t6, zero_reg);
4103 __ srlv(t2, t3, t6);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004104 __ Movz(t3, t2, t1); // Only if t6 is positive.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004105 __ Branch(&sign, ge, t6, Operand(zero_reg));
4106
4107 __ subu(t6, zero_reg, t6);
4108 __ sllv(t3, t3, t6);
4109 __ li(t9, meaningfull_bits);
4110 __ subu(t6, t9, t6);
4111 __ srlv(t4, t4, t6);
4112 __ or_(t3, t3, t4);
4113
4114 __ bind(&sign);
4115 __ subu(t2, t3, zero_reg);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004116 __ Movz(t3, t2, t5); // Only if t5 is zero.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004117
4118 __ bind(&done);
4119
4120 // Result is in t3.
4121 // This switch block should be exactly the same as above (FPU mode).
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004122 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004123 case EXTERNAL_BYTE_ELEMENTS:
4124 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004125 __ srl(t8, key, 1);
4126 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004127 __ sb(t3, MemOperand(t8, 0));
4128 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004129 case EXTERNAL_SHORT_ELEMENTS:
4130 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004131 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004132 __ sh(t3, MemOperand(t8, 0));
4133 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004134 case EXTERNAL_INT_ELEMENTS:
4135 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004136 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004137 __ addu(t8, a3, t8);
4138 __ sw(t3, MemOperand(t8, 0));
4139 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004140 case EXTERNAL_PIXEL_ELEMENTS:
4141 case EXTERNAL_FLOAT_ELEMENTS:
4142 case EXTERNAL_DOUBLE_ELEMENTS:
4143 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004144 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004145 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004146 case FAST_HOLEY_ELEMENTS:
4147 case FAST_HOLEY_SMI_ELEMENTS:
4148 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004149 case DICTIONARY_ELEMENTS:
4150 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004151 UNREACHABLE();
4152 break;
4153 }
4154 }
4155 }
4156 }
4157
danno@chromium.org40cb8782011-05-25 07:58:50 +00004158 // Slow case, key and receiver still in a0 and a1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004159 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004160 __ IncrementCounter(
4161 masm->isolate()->counters()->keyed_load_external_array_slow(),
4162 1, a2, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004163 // Entry registers are intact.
4164 // ---------- S t a t e --------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004165 // -- ra : return address
danno@chromium.org40cb8782011-05-25 07:58:50 +00004166 // -- a0 : key
4167 // -- a1 : receiver
4168 // -----------------------------------
4169 Handle<Code> slow_ic =
4170 masm->isolate()->builtins()->KeyedStoreIC_Slow();
4171 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4172
4173 // Miss case, call the runtime.
4174 __ bind(&miss_force_generic);
4175
4176 // ---------- S t a t e --------------
4177 // -- ra : return address
4178 // -- a0 : key
4179 // -- a1 : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004180 // -----------------------------------
4181
danno@chromium.org40cb8782011-05-25 07:58:50 +00004182 Handle<Code> miss_ic =
4183 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4184 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
4185}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004186
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004187
danno@chromium.org40cb8782011-05-25 07:58:50 +00004188void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
4189 // ----------- S t a t e -------------
4190 // -- ra : return address
4191 // -- a0 : key
4192 // -- a1 : receiver
4193 // -----------------------------------
4194 Label miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004195
danno@chromium.org40cb8782011-05-25 07:58:50 +00004196 // This stub is meant to be tail-jumped to, the receiver must already
4197 // have been verified by the caller to not be a smi.
4198
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004199 // Check that the key is a smi or a heap number convertible to a smi.
4200 GenerateSmiKeyCheck(masm, a0, t0, t1, f2, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004201
4202 // Get the elements array.
4203 __ lw(a2, FieldMemOperand(a1, JSObject::kElementsOffset));
4204 __ AssertFastElements(a2);
4205
4206 // Check that the key is within bounds.
4207 __ lw(a3, FieldMemOperand(a2, FixedArray::kLengthOffset));
ulan@chromium.org6ff65142012-03-21 09:52:17 +00004208 __ Branch(USE_DELAY_SLOT, &miss_force_generic, hs, a0, Operand(a3));
danno@chromium.org40cb8782011-05-25 07:58:50 +00004209
4210 // Load the result and make sure it's not the hole.
4211 __ Addu(a3, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004212 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004213 __ sll(t0, a0, kPointerSizeLog2 - kSmiTagSize);
4214 __ Addu(t0, t0, a3);
4215 __ lw(t0, MemOperand(t0));
4216 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
4217 __ Branch(&miss_force_generic, eq, t0, Operand(t1));
ulan@chromium.org6ff65142012-03-21 09:52:17 +00004218 __ Ret(USE_DELAY_SLOT);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004219 __ mov(v0, t0);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004220
4221 __ bind(&miss_force_generic);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004222 Handle<Code> stub =
4223 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4224 __ Jump(stub, RelocInfo::CODE_TARGET);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004225}
4226
4227
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004228void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
4229 MacroAssembler* masm) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004230 // ----------- S t a t e -------------
4231 // -- ra : return address
4232 // -- a0 : key
4233 // -- a1 : receiver
4234 // -----------------------------------
4235 Label miss_force_generic, slow_allocate_heapnumber;
4236
4237 Register key_reg = a0;
4238 Register receiver_reg = a1;
4239 Register elements_reg = a2;
4240 Register heap_number_reg = a2;
4241 Register indexed_double_offset = a3;
4242 Register scratch = t0;
4243 Register scratch2 = t1;
4244 Register scratch3 = t2;
4245 Register heap_number_map = t3;
4246
4247 // This stub is meant to be tail-jumped to, the receiver must already
4248 // have been verified by the caller to not be a smi.
4249
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004250 // Check that the key is a smi or a heap number convertible to a smi.
4251 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004252
4253 // Get the elements array.
4254 __ lw(elements_reg,
4255 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4256
4257 // Check that the key is within bounds.
4258 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4259 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4260
4261 // Load the upper word of the double in the fixed array and test for NaN.
4262 __ sll(scratch2, key_reg, kDoubleSizeLog2 - kSmiTagSize);
4263 __ Addu(indexed_double_offset, elements_reg, Operand(scratch2));
4264 uint32_t upper_32_offset = FixedArray::kHeaderSize + sizeof(kHoleNanLower32);
4265 __ lw(scratch, FieldMemOperand(indexed_double_offset, upper_32_offset));
4266 __ Branch(&miss_force_generic, eq, scratch, Operand(kHoleNanUpper32));
4267
4268 // Non-NaN. Allocate a new heap number and copy the double value into it.
4269 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
4270 __ AllocateHeapNumber(heap_number_reg, scratch2, scratch3,
4271 heap_number_map, &slow_allocate_heapnumber);
4272
4273 // Don't need to reload the upper 32 bits of the double, it's already in
4274 // scratch.
4275 __ sw(scratch, FieldMemOperand(heap_number_reg,
4276 HeapNumber::kExponentOffset));
4277 __ lw(scratch, FieldMemOperand(indexed_double_offset,
4278 FixedArray::kHeaderSize));
4279 __ sw(scratch, FieldMemOperand(heap_number_reg,
4280 HeapNumber::kMantissaOffset));
4281
4282 __ mov(v0, heap_number_reg);
4283 __ Ret();
4284
4285 __ bind(&slow_allocate_heapnumber);
4286 Handle<Code> slow_ic =
4287 masm->isolate()->builtins()->KeyedLoadIC_Slow();
4288 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4289
4290 __ bind(&miss_force_generic);
4291 Handle<Code> miss_ic =
4292 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4293 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004294}
4295
4296
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004297void KeyedStoreStubCompiler::GenerateStoreFastElement(
4298 MacroAssembler* masm,
4299 bool is_js_array,
yangguo@chromium.org56454712012-02-16 15:33:53 +00004300 ElementsKind elements_kind,
4301 KeyedAccessGrowMode grow_mode) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00004302 // ----------- S t a t e -------------
4303 // -- a0 : value
4304 // -- a1 : key
4305 // -- a2 : receiver
4306 // -- ra : return address
4307 // -- a3 : scratch
4308 // -- a4 : scratch (elements)
4309 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00004310 Label miss_force_generic, transition_elements_kind, grow, slow;
4311 Label finish_store, check_capacity;
danno@chromium.org40cb8782011-05-25 07:58:50 +00004312
4313 Register value_reg = a0;
4314 Register key_reg = a1;
4315 Register receiver_reg = a2;
yangguo@chromium.org56454712012-02-16 15:33:53 +00004316 Register scratch = t0;
4317 Register elements_reg = a3;
4318 Register length_reg = t1;
4319 Register scratch2 = t2;
danno@chromium.org40cb8782011-05-25 07:58:50 +00004320
4321 // This stub is meant to be tail-jumped to, the receiver must already
4322 // have been verified by the caller to not be a smi.
4323
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004324 // Check that the key is a smi or a heap number convertible to a smi.
4325 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004326
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004327 if (IsFastSmiElementsKind(elements_kind)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00004328 __ JumpIfNotSmi(value_reg, &transition_elements_kind);
4329 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004330
4331 // Check that the key is within bounds.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004332 __ lw(elements_reg,
4333 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00004334 if (is_js_array) {
4335 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4336 } else {
4337 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4338 }
4339 // Compare smis.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004340 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4341 __ Branch(&grow, hs, key_reg, Operand(scratch));
4342 } else {
4343 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4344 }
4345
4346 // Make sure elements is a fast element array, not 'cow'.
4347 __ CheckMap(elements_reg,
4348 scratch,
4349 Heap::kFixedArrayMapRootIndex,
4350 &miss_force_generic,
4351 DONT_DO_SMI_CHECK);
4352
4353 __ bind(&finish_store);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004354
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004355 if (IsFastSmiElementsKind(elements_kind)) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004356 __ Addu(scratch,
4357 elements_reg,
4358 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4359 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4360 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4361 __ Addu(scratch, scratch, scratch2);
4362 __ sw(value_reg, MemOperand(scratch));
4363 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004364 ASSERT(IsFastObjectElementsKind(elements_kind));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004365 __ Addu(scratch,
4366 elements_reg,
4367 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4368 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4369 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4370 __ Addu(scratch, scratch, scratch2);
4371 __ sw(value_reg, MemOperand(scratch));
4372 __ mov(receiver_reg, value_reg);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004373 __ RecordWrite(elements_reg, // Object.
4374 scratch, // Address.
4375 receiver_reg, // Value.
4376 kRAHasNotBeenSaved,
4377 kDontSaveFPRegs);
4378 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004379 // value_reg (a0) is preserved.
4380 // Done.
4381 __ Ret();
4382
4383 __ bind(&miss_force_generic);
4384 Handle<Code> ic =
4385 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4386 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004387
4388 __ bind(&transition_elements_kind);
4389 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4390 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
yangguo@chromium.org56454712012-02-16 15:33:53 +00004391
4392 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4393 // Grow the array by a single element if possible.
4394 __ bind(&grow);
4395
4396 // Make sure the array is only growing by a single element, anything else
4397 // must be handled by the runtime.
4398 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch));
4399
4400 // Check for the empty array, and preallocate a small backing store if
4401 // possible.
4402 __ lw(length_reg,
4403 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4404 __ lw(elements_reg,
4405 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4406 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
4407 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
4408
4409 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
4410 __ AllocateInNewSpace(size, elements_reg, scratch, scratch2, &slow,
4411 TAG_OBJECT);
4412
4413 __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex);
4414 __ sw(scratch, FieldMemOperand(elements_reg, JSObject::kMapOffset));
4415 __ li(scratch, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4416 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4417 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
4418 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
4419 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::SizeFor(i)));
4420 }
4421
4422 // Store the element at index zero.
4423 __ sw(value_reg, FieldMemOperand(elements_reg, FixedArray::SizeFor(0)));
4424
4425 // Install the new backing store in the JSArray.
4426 __ sw(elements_reg,
4427 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4428 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
4429 scratch, kRAHasNotBeenSaved, kDontSaveFPRegs,
4430 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4431
4432 // Increment the length of the array.
4433 __ li(length_reg, Operand(Smi::FromInt(1)));
4434 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4435 __ Ret();
4436
4437 __ bind(&check_capacity);
4438 // Check for cow elements, in general they are not handled by this stub
4439 __ CheckMap(elements_reg,
4440 scratch,
4441 Heap::kFixedCOWArrayMapRootIndex,
4442 &miss_force_generic,
4443 DONT_DO_SMI_CHECK);
4444
4445 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4446 __ Branch(&slow, hs, length_reg, Operand(scratch));
4447
4448 // Grow the array and finish the store.
4449 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
4450 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4451 __ jmp(&finish_store);
4452
4453 __ bind(&slow);
4454 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4455 __ Jump(ic_slow, RelocInfo::CODE_TARGET);
4456 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004457}
4458
4459
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004460void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
4461 MacroAssembler* masm,
yangguo@chromium.org56454712012-02-16 15:33:53 +00004462 bool is_js_array,
4463 KeyedAccessGrowMode grow_mode) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004464 // ----------- S t a t e -------------
4465 // -- a0 : value
4466 // -- a1 : key
4467 // -- a2 : receiver
4468 // -- ra : return address
4469 // -- a3 : scratch
4470 // -- t0 : scratch (elements_reg)
4471 // -- t1 : scratch (mantissa_reg)
4472 // -- t2 : scratch (exponent_reg)
4473 // -- t3 : scratch4
4474 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00004475 Label miss_force_generic, transition_elements_kind, grow, slow;
4476 Label finish_store, check_capacity;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004477
4478 Register value_reg = a0;
4479 Register key_reg = a1;
4480 Register receiver_reg = a2;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004481 Register elements_reg = a3;
4482 Register scratch1 = t0;
4483 Register scratch2 = t1;
4484 Register scratch3 = t2;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004485 Register scratch4 = t3;
yangguo@chromium.org56454712012-02-16 15:33:53 +00004486 Register length_reg = t3;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004487
4488 // This stub is meant to be tail-jumped to, the receiver must already
4489 // have been verified by the caller to not be a smi.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004490
4491 // Check that the key is a smi or a heap number convertible to a smi.
4492 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004493
4494 __ lw(elements_reg,
4495 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4496
4497 // Check that the key is within bounds.
4498 if (is_js_array) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004499 __ lw(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004500 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004501 __ lw(scratch1,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004502 FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4503 }
4504 // Compare smis, unsigned compare catches both negative and out-of-bound
4505 // indexes.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004506 if (grow_mode == ALLOW_JSARRAY_GROWTH) {
4507 __ Branch(&grow, hs, key_reg, Operand(scratch1));
4508 } else {
4509 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch1));
4510 }
4511
4512 __ bind(&finish_store);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004513
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004514 __ StoreNumberToDoubleElements(value_reg,
4515 key_reg,
4516 receiver_reg,
4517 elements_reg,
4518 scratch1,
4519 scratch2,
4520 scratch3,
4521 scratch4,
4522 &transition_elements_kind);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004523
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004524 __ Ret(USE_DELAY_SLOT);
4525 __ mov(v0, value_reg); // In delay slot.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004526
4527 // Handle store cache miss, replacing the ic with the generic stub.
4528 __ bind(&miss_force_generic);
4529 Handle<Code> ic =
4530 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4531 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004532
4533 __ bind(&transition_elements_kind);
4534 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4535 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
yangguo@chromium.org56454712012-02-16 15:33:53 +00004536
4537 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4538 // Grow the array by a single element if possible.
4539 __ bind(&grow);
4540
4541 // Make sure the array is only growing by a single element, anything else
4542 // must be handled by the runtime.
4543 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch1));
4544
4545 // Transition on values that can't be stored in a FixedDoubleArray.
4546 Label value_is_smi;
4547 __ JumpIfSmi(value_reg, &value_is_smi);
4548 __ lw(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
4549 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
4550 __ Branch(&transition_elements_kind, ne, scratch1, Operand(at));
4551 __ bind(&value_is_smi);
4552
4553 // Check for the empty array, and preallocate a small backing store if
4554 // possible.
4555 __ lw(length_reg,
4556 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4557 __ lw(elements_reg,
4558 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4559 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
4560 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
4561
4562 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
4563 __ AllocateInNewSpace(size, elements_reg, scratch1, scratch2, &slow,
4564 TAG_OBJECT);
4565
4566 // Initialize the new FixedDoubleArray. Leave elements unitialized for
4567 // efficiency, they are guaranteed to be initialized before use.
4568 __ LoadRoot(scratch1, Heap::kFixedDoubleArrayMapRootIndex);
4569 __ sw(scratch1, FieldMemOperand(elements_reg, JSObject::kMapOffset));
4570 __ li(scratch1, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4571 __ sw(scratch1,
4572 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
4573
4574 // Install the new backing store in the JSArray.
4575 __ sw(elements_reg,
4576 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4577 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
4578 scratch1, kRAHasNotBeenSaved, kDontSaveFPRegs,
4579 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4580
4581 // Increment the length of the array.
4582 __ li(length_reg, Operand(Smi::FromInt(1)));
4583 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
danno@chromium.org00379b82012-05-04 09:16:29 +00004584 __ lw(elements_reg,
4585 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
yangguo@chromium.org56454712012-02-16 15:33:53 +00004586 __ jmp(&finish_store);
4587
4588 __ bind(&check_capacity);
4589 // Make sure that the backing store can hold additional elements.
4590 __ lw(scratch1,
4591 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
4592 __ Branch(&slow, hs, length_reg, Operand(scratch1));
4593
4594 // Grow the array and finish the store.
4595 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
4596 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4597 __ jmp(&finish_store);
4598
4599 __ bind(&slow);
4600 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4601 __ Jump(ic_slow, RelocInfo::CODE_TARGET);
4602 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004603}
4604
4605
ager@chromium.org5c838252010-02-19 08:53:10 +00004606#undef __
4607
4608} } // namespace v8::internal
4609
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004610#endif // V8_TARGET_ARCH_MIPS