blob: f8cf9704b1049d4efe812cc8f4036c016d3e366b [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()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000461 // Update the map of the object; no write barrier updating is
462 // needed because the map is never in new space.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000463 __ li(t0, Operand(transition));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000464 __ sw(t0, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
465 }
466
467 // Adjust for the number of properties stored in the object. Even in the
468 // face of a transition we can use the old map here because the size of the
469 // object and the number of in-object properties is not going to change.
470 index -= object->map()->inobject_properties();
471
472 if (index < 0) {
473 // Set the property straight into the object.
474 int offset = object->map()->instance_size() + (index * kPointerSize);
475 __ sw(a0, FieldMemOperand(receiver_reg, offset));
476
477 // Skip updating write barrier if storing a smi.
478 __ JumpIfSmi(a0, &exit, scratch);
479
480 // Update the write barrier for the array address.
481 // Pass the now unused name_reg as a scratch register.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000482 __ mov(name_reg, a0);
483 __ RecordWriteField(receiver_reg,
484 offset,
485 name_reg,
486 scratch,
487 kRAHasNotBeenSaved,
488 kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000489 } else {
490 // Write to the properties array.
491 int offset = index * kPointerSize + FixedArray::kHeaderSize;
492 // Get the properties array.
493 __ lw(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
494 __ sw(a0, FieldMemOperand(scratch, offset));
495
496 // Skip updating write barrier if storing a smi.
497 __ JumpIfSmi(a0, &exit);
498
499 // Update the write barrier for the array address.
500 // Ok to clobber receiver_reg and name_reg, since we return.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000501 __ mov(name_reg, a0);
502 __ RecordWriteField(scratch,
503 offset,
504 name_reg,
505 receiver_reg,
506 kRAHasNotBeenSaved,
507 kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000508 }
509
510 // Return the value (register v0).
511 __ bind(&exit);
512 __ mov(v0, a0);
513 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000514}
515
516
517void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000518 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000519 Handle<Code> code = (kind == Code::LOAD_IC)
520 ? masm->isolate()->builtins()->LoadIC_Miss()
521 : masm->isolate()->builtins()->KeyedLoadIC_Miss();
522 __ Jump(code, RelocInfo::CODE_TARGET);
ager@chromium.org5c838252010-02-19 08:53:10 +0000523}
524
525
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000526static void GenerateCallFunction(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000527 Handle<Object> object,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000528 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000529 Label* miss,
530 Code::ExtraICState extra_ic_state) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000531 // ----------- S t a t e -------------
532 // -- a0: receiver
533 // -- a1: function to call
534 // -----------------------------------
535 // Check that the function really is a function.
536 __ JumpIfSmi(a1, miss);
537 __ GetObjectType(a1, a3, a3);
538 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
539
540 // Patch the receiver on the stack with the global proxy if
541 // necessary.
542 if (object->IsGlobalObject()) {
543 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
544 __ sw(a3, MemOperand(sp, arguments.immediate() * kPointerSize));
545 }
546
547 // Invoke the function.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000548 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
549 ? CALL_AS_FUNCTION
550 : CALL_AS_METHOD;
551 __ InvokeFunction(a1, arguments, JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000552}
553
554
555static void PushInterceptorArguments(MacroAssembler* masm,
556 Register receiver,
557 Register holder,
558 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000559 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000560 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000561 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
562 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000563 Register scratch = name;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000564 __ li(scratch, Operand(interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000565 __ Push(scratch, receiver, holder);
566 __ lw(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
567 __ push(scratch);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000568 __ li(scratch, Operand(ExternalReference::isolate_address()));
569 __ push(scratch);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000570}
571
572
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000573static void CompileCallLoadPropertyWithInterceptor(
574 MacroAssembler* masm,
575 Register receiver,
576 Register holder,
577 Register name,
578 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000579 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
580
581 ExternalReference ref =
582 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
583 masm->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000584 __ PrepareCEntryArgs(6);
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000585 __ PrepareCEntryFunction(ref);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000586
587 CEntryStub stub(1);
588 __ CallStub(&stub);
589}
590
591
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000592static const int kFastApiCallArguments = 4;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000593
594
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000595// Reserves space for the extra arguments to API function in the
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000596// caller's frame.
597//
598// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
599static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
600 Register scratch) {
601 ASSERT(Smi::FromInt(0) == 0);
602 for (int i = 0; i < kFastApiCallArguments; i++) {
603 __ push(zero_reg);
604 }
605}
606
607
608// Undoes the effects of ReserveSpaceForFastApiCall.
609static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
610 __ Drop(kFastApiCallArguments);
611}
612
613
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000614static void GenerateFastApiDirectCall(MacroAssembler* masm,
615 const CallOptimization& optimization,
616 int argc) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000617 // ----------- S t a t e -------------
618 // -- sp[0] : holder (set by CheckPrototypes)
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000619 // -- sp[4] : callee JS function
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000620 // -- sp[8] : call data
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000621 // -- sp[12] : isolate
622 // -- sp[16] : last JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000623 // -- ...
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000624 // -- sp[(argc + 3) * 4] : first JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000625 // -- sp[(argc + 4) * 4] : receiver
626 // -----------------------------------
627 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000628 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000629 __ LoadHeapObject(t1, function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000630 __ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset));
631
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000632 // Pass the additional arguments.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000633 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
634 Handle<Object> call_data(api_call_info->data());
635 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
636 __ li(a0, api_call_info);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000637 __ lw(t2, FieldMemOperand(a0, CallHandlerInfo::kDataOffset));
638 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000639 __ li(t2, call_data);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000640 }
641
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000642 __ li(t3, Operand(ExternalReference::isolate_address()));
643 // Store JS function, call data and isolate.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000644 __ sw(t1, MemOperand(sp, 1 * kPointerSize));
645 __ sw(t2, MemOperand(sp, 2 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000646 __ sw(t3, MemOperand(sp, 3 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000647
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000648 // Prepare arguments.
649 __ Addu(a2, sp, Operand(3 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000650
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000651 // Allocate the v8::Arguments structure in the arguments' space since
652 // it's not controlled by GC.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000653 const int kApiStackSpace = 4;
654
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000655 FrameScope frame_scope(masm, StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000656 __ EnterExitFrame(false, kApiStackSpace);
657
658 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
659 // struct from the function (which is currently the case). This means we pass
660 // the first argument in a1 instead of a0. TryCallApiFunctionAndReturn
661 // will handle setting up a0.
662
663 // a1 = v8::Arguments&
664 // Arguments is built at sp + 1 (sp is a reserved spot for ra).
665 __ Addu(a1, sp, kPointerSize);
666
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000667 // v8::Arguments::implicit_args_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000668 __ sw(a2, MemOperand(a1, 0 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000669 // v8::Arguments::values_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000670 __ Addu(t0, a2, Operand(argc * kPointerSize));
671 __ sw(t0, MemOperand(a1, 1 * kPointerSize));
672 // v8::Arguments::length_ = argc
673 __ li(t0, Operand(argc));
674 __ sw(t0, MemOperand(a1, 2 * kPointerSize));
675 // v8::Arguments::is_construct_call = 0
676 __ sw(zero_reg, MemOperand(a1, 3 * kPointerSize));
677
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000678 const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000679 Address function_address = v8::ToCData<Address>(api_call_info->callback());
680 ApiFunction fun(function_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000681 ExternalReference ref =
682 ExternalReference(&fun,
683 ExternalReference::DIRECT_API_CALL,
684 masm->isolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000685 AllowExternalCallThatCantCauseGC scope(masm);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000686 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000687}
688
lrn@chromium.org7516f052011-03-30 08:52:27 +0000689class CallInterceptorCompiler BASE_EMBEDDED {
690 public:
691 CallInterceptorCompiler(StubCompiler* stub_compiler,
692 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000693 Register name,
694 Code::ExtraICState extra_ic_state)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000695 : stub_compiler_(stub_compiler),
696 arguments_(arguments),
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000697 name_(name),
698 extra_ic_state_(extra_ic_state) {}
lrn@chromium.org7516f052011-03-30 08:52:27 +0000699
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000700 void Compile(MacroAssembler* masm,
701 Handle<JSObject> object,
702 Handle<JSObject> holder,
703 Handle<String> name,
704 LookupResult* lookup,
705 Register receiver,
706 Register scratch1,
707 Register scratch2,
708 Register scratch3,
709 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000710 ASSERT(holder->HasNamedInterceptor());
711 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
712
713 // Check that the receiver isn't a smi.
714 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000715 CallOptimization optimization(lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000716 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000717 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
718 holder, lookup, name, optimization, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000719 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000720 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
721 name, holder, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000722 }
723 }
724
725 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000726 void CompileCacheable(MacroAssembler* masm,
727 Handle<JSObject> object,
728 Register receiver,
729 Register scratch1,
730 Register scratch2,
731 Register scratch3,
732 Handle<JSObject> interceptor_holder,
733 LookupResult* lookup,
734 Handle<String> name,
735 const CallOptimization& optimization,
736 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000737 ASSERT(optimization.is_constant_call());
738 ASSERT(!lookup->holder()->IsGlobalObject());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000739 Counters* counters = masm->isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000740 int depth1 = kInvalidProtoDepth;
741 int depth2 = kInvalidProtoDepth;
742 bool can_do_fast_api_call = false;
743 if (optimization.is_simple_api_call() &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000744 !lookup->holder()->IsGlobalObject()) {
745 depth1 = optimization.GetPrototypeDepthOfExpectedType(
746 object, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000747 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000748 depth2 = optimization.GetPrototypeDepthOfExpectedType(
749 interceptor_holder, Handle<JSObject>(lookup->holder()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000750 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000751 can_do_fast_api_call =
752 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000753 }
754
755 __ IncrementCounter(counters->call_const_interceptor(), 1,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000756 scratch1, scratch2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000757
758 if (can_do_fast_api_call) {
759 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
760 scratch1, scratch2);
761 ReserveSpaceForFastApiCall(masm, scratch1);
762 }
763
764 // Check that the maps from receiver to interceptor's holder
765 // haven't changed and thus we can invoke interceptor.
766 Label miss_cleanup;
767 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
768 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000769 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
770 scratch1, scratch2, scratch3,
771 name, depth1, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000772
773 // Invoke an interceptor and if it provides a value,
774 // branch to |regular_invoke|.
775 Label regular_invoke;
776 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
777 &regular_invoke);
778
779 // Interceptor returned nothing for this property. Try to use cached
780 // constant function.
781
782 // Check that the maps from interceptor's holder to constant function's
783 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000784 if (*interceptor_holder != lookup->holder()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000785 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000786 Handle<JSObject>(lookup->holder()),
787 scratch1, scratch2, scratch3,
788 name, depth2, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000789 } else {
790 // CheckPrototypes has a side effect of fetching a 'holder'
791 // for API (object which is instanceof for the signature). It's
792 // safe to omit it here, as if present, it should be fetched
793 // by the previous CheckPrototypes.
794 ASSERT(depth2 == kInvalidProtoDepth);
795 }
796
797 // Invoke function.
798 if (can_do_fast_api_call) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000799 GenerateFastApiDirectCall(masm, optimization, arguments_.immediate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000800 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000801 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
802 ? CALL_AS_FUNCTION
803 : CALL_AS_METHOD;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000804 __ InvokeFunction(optimization.constant_function(), arguments_,
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000805 JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000806 }
807
808 // Deferred code for fast API call case---clean preallocated space.
809 if (can_do_fast_api_call) {
810 __ bind(&miss_cleanup);
811 FreeSpaceForFastApiCall(masm);
812 __ Branch(miss_label);
813 }
814
815 // Invoke a regular function.
816 __ bind(&regular_invoke);
817 if (can_do_fast_api_call) {
818 FreeSpaceForFastApiCall(masm);
819 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000820 }
821
822 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000823 Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000824 Register receiver,
825 Register scratch1,
826 Register scratch2,
827 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000828 Handle<String> name,
829 Handle<JSObject> interceptor_holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000830 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000831 Register holder =
832 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000833 scratch1, scratch2, scratch3,
834 name, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000835
836 // Call a runtime function to load the interceptor property.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000837 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000838 // Save the name_ register across the call.
839 __ push(name_);
840
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000841 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000842
843 __ CallExternalReference(
844 ExternalReference(
845 IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
846 masm->isolate()),
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000847 6);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000848 // Restore the name_ register.
849 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000850 // Leave the internal frame.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000851 }
852
853 void LoadWithInterceptor(MacroAssembler* masm,
854 Register receiver,
855 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000856 Handle<JSObject> holder_obj,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000857 Register scratch,
858 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000859 {
860 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000861
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000862 __ Push(holder, name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000863 CompileCallLoadPropertyWithInterceptor(masm,
864 receiver,
865 holder,
866 name_,
867 holder_obj);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000868 __ pop(name_); // Restore the name.
869 __ pop(receiver); // Restore the holder.
870 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000871 // If interceptor returns no-result sentinel, call the constant function.
872 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
873 __ Branch(interceptor_succeeded, ne, v0, Operand(scratch));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000874 }
875
876 StubCompiler* stub_compiler_;
877 const ParameterCount& arguments_;
878 Register name_;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000879 Code::ExtraICState extra_ic_state_;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000880};
881
882
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000883
884// Generate code to check that a global property cell is empty. Create
885// the property cell at compilation time if no cell exists for the
886// property.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000887static void GenerateCheckPropertyCell(MacroAssembler* masm,
888 Handle<GlobalObject> global,
889 Handle<String> name,
890 Register scratch,
891 Label* miss) {
892 Handle<JSGlobalPropertyCell> cell =
893 GlobalObject::EnsurePropertyCell(global, name);
894 ASSERT(cell->value()->IsTheHole());
895 __ li(scratch, Operand(cell));
896 __ lw(scratch,
897 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
898 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
899 __ Branch(miss, ne, scratch, Operand(at));
900}
901
902
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000903// Calls GenerateCheckPropertyCell for each global object in the prototype chain
904// from object to (but not including) holder.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000905static void GenerateCheckPropertyCells(MacroAssembler* masm,
906 Handle<JSObject> object,
907 Handle<JSObject> holder,
908 Handle<String> name,
909 Register scratch,
910 Label* miss) {
911 Handle<JSObject> current = object;
912 while (!current.is_identical_to(holder)) {
913 if (current->IsGlobalObject()) {
914 GenerateCheckPropertyCell(masm,
915 Handle<GlobalObject>::cast(current),
916 name,
917 scratch,
918 miss);
919 }
920 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
921 }
922}
923
924
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000925// Convert and store int passed in register ival to IEEE 754 single precision
926// floating point value at memory location (dst + 4 * wordoffset)
927// If FPU is available use it for conversion.
928static void StoreIntAsFloat(MacroAssembler* masm,
929 Register dst,
930 Register wordoffset,
931 Register ival,
932 Register fval,
933 Register scratch1,
934 Register scratch2) {
935 if (CpuFeatures::IsSupported(FPU)) {
936 CpuFeatures::Scope scope(FPU);
937 __ mtc1(ival, f0);
938 __ cvt_s_w(f0, f0);
939 __ sll(scratch1, wordoffset, 2);
940 __ addu(scratch1, dst, scratch1);
941 __ swc1(f0, MemOperand(scratch1, 0));
942 } else {
943 // FPU is not available, do manual conversions.
944
945 Label not_special, done;
946 // Move sign bit from source to destination. This works because the sign
947 // bit in the exponent word of the double has the same position and polarity
948 // as the 2's complement sign bit in a Smi.
949 ASSERT(kBinary32SignMask == 0x80000000u);
950
951 __ And(fval, ival, Operand(kBinary32SignMask));
952 // Negate value if it is negative.
953 __ subu(scratch1, zero_reg, ival);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +0000954 __ Movn(ival, scratch1, fval);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000955
956 // We have -1, 0 or 1, which we treat specially. Register ival contains
957 // absolute value: it is either equal to 1 (special case of -1 and 1),
958 // greater than 1 (not a special case) or less than 1 (special case of 0).
959 __ Branch(&not_special, gt, ival, Operand(1));
960
961 // For 1 or -1 we need to or in the 0 exponent (biased).
962 static const uint32_t exponent_word_for_1 =
963 kBinary32ExponentBias << kBinary32ExponentShift;
964
965 __ Xor(scratch1, ival, Operand(1));
966 __ li(scratch2, exponent_word_for_1);
967 __ or_(scratch2, fval, scratch2);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +0000968 __ Movz(fval, scratch2, scratch1); // Only if ival is equal to 1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000969 __ Branch(&done);
970
971 __ bind(&not_special);
972 // Count leading zeros.
973 // Gets the wrong answer for 0, but we already checked for that case above.
974 Register zeros = scratch2;
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +0000975 __ Clz(zeros, ival);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000976
977 // Compute exponent and or it into the exponent register.
978 __ li(scratch1, (kBitsPerInt - 1) + kBinary32ExponentBias);
979 __ subu(scratch1, scratch1, zeros);
980
981 __ sll(scratch1, scratch1, kBinary32ExponentShift);
982 __ or_(fval, fval, scratch1);
983
984 // Shift up the source chopping the top bit off.
985 __ Addu(zeros, zeros, Operand(1));
986 // This wouldn't work for 1 and -1 as the shift would be 32 which means 0.
987 __ sllv(ival, ival, zeros);
988 // And the top (top 20 bits).
989 __ srl(scratch1, ival, kBitsPerInt - kBinary32MantissaBits);
990 __ or_(fval, fval, scratch1);
991
992 __ bind(&done);
993
994 __ sll(scratch1, wordoffset, 2);
995 __ addu(scratch1, dst, scratch1);
996 __ sw(fval, MemOperand(scratch1, 0));
997 }
998}
999
1000
1001// Convert unsigned integer with specified number of leading zeroes in binary
1002// representation to IEEE 754 double.
1003// Integer to convert is passed in register hiword.
1004// Resulting double is returned in registers hiword:loword.
1005// This functions does not work correctly for 0.
1006static void GenerateUInt2Double(MacroAssembler* masm,
1007 Register hiword,
1008 Register loword,
1009 Register scratch,
1010 int leading_zeroes) {
1011 const int meaningful_bits = kBitsPerInt - leading_zeroes - 1;
1012 const int biased_exponent = HeapNumber::kExponentBias + meaningful_bits;
1013
1014 const int mantissa_shift_for_hi_word =
1015 meaningful_bits - HeapNumber::kMantissaBitsInTopWord;
1016
1017 const int mantissa_shift_for_lo_word =
1018 kBitsPerInt - mantissa_shift_for_hi_word;
1019
1020 __ li(scratch, biased_exponent << HeapNumber::kExponentShift);
1021 if (mantissa_shift_for_hi_word > 0) {
1022 __ sll(loword, hiword, mantissa_shift_for_lo_word);
1023 __ srl(hiword, hiword, mantissa_shift_for_hi_word);
1024 __ or_(hiword, scratch, hiword);
1025 } else {
1026 __ mov(loword, zero_reg);
1027 __ sll(hiword, hiword, mantissa_shift_for_hi_word);
1028 __ or_(hiword, scratch, hiword);
1029 }
1030
1031 // If least significant bit of biased exponent was not 1 it was corrupted
1032 // by most significant bit of mantissa so we should fix that.
1033 if (!(biased_exponent & 1)) {
1034 __ li(scratch, 1 << HeapNumber::kExponentShift);
1035 __ nor(scratch, scratch, scratch);
1036 __ and_(hiword, hiword, scratch);
1037 }
1038}
1039
1040
ager@chromium.org5c838252010-02-19 08:53:10 +00001041#undef __
1042#define __ ACCESS_MASM(masm())
1043
1044
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001045Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
1046 Register object_reg,
1047 Handle<JSObject> holder,
1048 Register holder_reg,
1049 Register scratch1,
1050 Register scratch2,
1051 Handle<String> name,
1052 int save_at_depth,
1053 Label* miss) {
1054 // Make sure there's no overlap between holder and object registers.
1055 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1056 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1057 && !scratch2.is(scratch1));
1058
1059 // Keep track of the current object in register reg.
1060 Register reg = object_reg;
1061 int depth = 0;
1062
1063 if (save_at_depth == depth) {
1064 __ sw(reg, MemOperand(sp));
1065 }
1066
1067 // Check the maps in the prototype chain.
1068 // Traverse the prototype chain from the object and do map checks.
1069 Handle<JSObject> current = object;
1070 while (!current.is_identical_to(holder)) {
1071 ++depth;
1072
1073 // Only global objects and objects that do not require access
1074 // checks are allowed in stubs.
1075 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1076
1077 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
1078 if (!current->HasFastProperties() &&
1079 !current->IsJSGlobalObject() &&
1080 !current->IsJSGlobalProxy()) {
1081 if (!name->IsSymbol()) {
1082 name = factory()->LookupSymbol(name);
1083 }
1084 ASSERT(current->property_dictionary()->FindEntry(*name) ==
1085 StringDictionary::kNotFound);
1086
1087 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1088 scratch1, scratch2);
1089
1090 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1091 reg = holder_reg; // From now on the object will be in holder_reg.
1092 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1093 } else {
1094 Handle<Map> current_map(current->map());
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001095 __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK,
1096 ALLOW_ELEMENT_TRANSITION_MAPS);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001097 // Check access rights to the global object. This has to happen after
1098 // the map check so that we know that the object is actually a global
1099 // object.
1100 if (current->IsJSGlobalProxy()) {
1101 __ CheckAccessGlobalProxy(reg, scratch2, miss);
1102 }
1103 reg = holder_reg; // From now on the object will be in holder_reg.
1104
1105 if (heap()->InNewSpace(*prototype)) {
1106 // The prototype is in new space; we cannot store a reference to it
1107 // in the code. Load it from the map.
1108 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1109 } else {
1110 // The prototype is in old space; load it directly.
1111 __ li(reg, Operand(prototype));
1112 }
1113 }
1114
1115 if (save_at_depth == depth) {
1116 __ sw(reg, MemOperand(sp));
1117 }
1118
1119 // Go to the next object in the prototype chain.
1120 current = prototype;
1121 }
1122
1123 // Log the check depth.
1124 LOG(masm()->isolate(), IntEvent("check-maps-depth", depth + 1));
1125
1126 // Check the holder map.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001127 __ CheckMap(reg, scratch1, Handle<Map>(current->map()), miss,
1128 DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001129
1130 // Perform security check for access to the global object.
1131 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1132 if (holder->IsJSGlobalProxy()) {
1133 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1134 }
1135
1136 // If we've skipped any global objects, it's not enough to verify that
1137 // their maps haven't changed. We also need to check that the property
1138 // cell for the property is still empty.
1139 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1140
1141 // Return the register containing the holder.
1142 return reg;
1143}
1144
1145
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001146void StubCompiler::GenerateLoadField(Handle<JSObject> object,
1147 Handle<JSObject> holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001148 Register receiver,
1149 Register scratch1,
1150 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001151 Register scratch3,
ager@chromium.org5c838252010-02-19 08:53:10 +00001152 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001153 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001154 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001155 // Check that the receiver isn't a smi.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001156 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001157
1158 // Check that the maps haven't changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001159 Register reg = CheckPrototypes(
1160 object, receiver, holder, scratch1, scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001161 GenerateFastPropertyLoad(masm(), v0, reg, holder, index);
1162 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001163}
1164
1165
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001166void StubCompiler::GenerateLoadConstant(Handle<JSObject> object,
1167 Handle<JSObject> holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001168 Register receiver,
1169 Register scratch1,
1170 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001171 Register scratch3,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001172 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001173 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001174 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001175 // Check that the receiver isn't a smi.
1176 __ JumpIfSmi(receiver, miss, scratch1);
1177
1178 // Check that the maps haven't changed.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001179 CheckPrototypes(object, receiver, holder,
1180 scratch1, scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001181
1182 // Return the constant value.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001183 __ LoadHeapObject(v0, value);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001184 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001185}
1186
1187
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001188void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
1189 Handle<JSObject> holder,
1190 Register receiver,
1191 Register name_reg,
1192 Register scratch1,
1193 Register scratch2,
1194 Register scratch3,
1195 Handle<AccessorInfo> callback,
1196 Handle<String> name,
1197 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001198 // Check that the receiver isn't a smi.
1199 __ JumpIfSmi(receiver, miss, scratch1);
1200
1201 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001202 Register reg = CheckPrototypes(object, receiver, holder, scratch1,
1203 scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001204
1205 // Build AccessorInfo::args_ list on the stack and push property name below
1206 // the exit frame to make GC aware of them and store pointers to them.
1207 __ push(receiver);
1208 __ mov(scratch2, sp); // scratch2 = AccessorInfo::args_
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001209 if (heap()->InNewSpace(callback->data())) {
1210 __ li(scratch3, callback);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001211 __ lw(scratch3, FieldMemOperand(scratch3, AccessorInfo::kDataOffset));
1212 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001213 __ li(scratch3, Handle<Object>(callback->data()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001214 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001215 __ Subu(sp, sp, 4 * kPointerSize);
1216 __ sw(reg, MemOperand(sp, 3 * kPointerSize));
1217 __ sw(scratch3, MemOperand(sp, 2 * kPointerSize));
1218 __ li(scratch3, Operand(ExternalReference::isolate_address()));
1219 __ sw(scratch3, MemOperand(sp, 1 * kPointerSize));
1220 __ sw(name_reg, MemOperand(sp, 0 * kPointerSize));
1221
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001222 __ mov(a2, scratch2); // Saved in case scratch2 == a1.
1223 __ mov(a1, sp); // a1 (first argument - see note below) = Handle<String>
1224
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001225 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
1226 // struct from the function (which is currently the case). This means we pass
1227 // the arguments in a1-a2 instead of a0-a1. TryCallApiFunctionAndReturn
1228 // will handle setting up a0.
1229
1230 const int kApiStackSpace = 1;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001231 FrameScope frame_scope(masm(), StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001232 __ EnterExitFrame(false, kApiStackSpace);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001233
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001234 // Create AccessorInfo instance on the stack above the exit frame with
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001235 // scratch2 (internal::Object** args_) as the data.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001236 __ sw(a2, MemOperand(sp, kPointerSize));
1237 // a2 (second argument - see note above) = AccessorInfo&
1238 __ Addu(a2, sp, kPointerSize);
1239
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001240 const int kStackUnwindSpace = 5;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001241 Address getter_address = v8::ToCData<Address>(callback->getter());
1242 ApiFunction fun(getter_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001243 ExternalReference ref =
1244 ExternalReference(&fun,
1245 ExternalReference::DIRECT_GETTER_CALL,
1246 masm()->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001247 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
ager@chromium.org5c838252010-02-19 08:53:10 +00001248}
1249
1250
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001251void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
1252 Handle<JSObject> interceptor_holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001253 LookupResult* lookup,
1254 Register receiver,
1255 Register name_reg,
1256 Register scratch1,
1257 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001258 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001259 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001260 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001261 ASSERT(interceptor_holder->HasNamedInterceptor());
1262 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1263
1264 // Check that the receiver isn't a smi.
1265 __ JumpIfSmi(receiver, miss);
1266
1267 // So far the most popular follow ups for interceptor loads are FIELD
1268 // and CALLBACKS, so inline only them, other cases may be added
1269 // later.
1270 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001271 if (lookup->IsFound() && lookup->IsCacheable()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001272 if (lookup->type() == FIELD) {
1273 compile_followup_inline = true;
1274 } else if (lookup->type() == CALLBACKS &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001275 lookup->GetCallbackObject()->IsAccessorInfo()) {
1276 compile_followup_inline =
1277 AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001278 }
1279 }
1280
1281 if (compile_followup_inline) {
1282 // Compile the interceptor call, followed by inline code to load the
1283 // property from further up the prototype chain if the call fails.
1284 // Check that the maps haven't changed.
1285 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1286 scratch1, scratch2, scratch3,
1287 name, miss);
1288 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
1289
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001290 // Preserve the receiver register explicitly whenever it is different from
1291 // the holder and it is needed should the interceptor return without any
1292 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1293 // the FIELD case might cause a miss during the prototype check.
1294 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
1295 bool must_preserve_receiver_reg = !receiver.is(holder_reg) &&
1296 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1297
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001298 // Save necessary data before invoking an interceptor.
1299 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001300 {
1301 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001302 if (must_preserve_receiver_reg) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001303 __ Push(receiver, holder_reg, name_reg);
1304 } else {
1305 __ Push(holder_reg, name_reg);
1306 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001307 // Invoke an interceptor. Note: map checks from receiver to
1308 // interceptor's holder has been compiled before (see a caller
1309 // of this method).
1310 CompileCallLoadPropertyWithInterceptor(masm(),
1311 receiver,
1312 holder_reg,
1313 name_reg,
1314 interceptor_holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001315 // Check if interceptor provided a value for property. If it's
1316 // the case, return immediately.
1317 Label interceptor_failed;
1318 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
1319 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1));
1320 frame_scope.GenerateLeaveFrame();
1321 __ Ret();
1322
1323 __ bind(&interceptor_failed);
1324 __ pop(name_reg);
1325 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001326 if (must_preserve_receiver_reg) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001327 __ pop(receiver);
1328 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001329 // Leave the internal frame.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001330 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001331 // Check that the maps from interceptor's holder to lookup's holder
1332 // haven't changed. And load lookup's holder into |holder| register.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001333 if (must_perfrom_prototype_check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001334 holder_reg = CheckPrototypes(interceptor_holder,
1335 holder_reg,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001336 Handle<JSObject>(lookup->holder()),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001337 scratch1,
1338 scratch2,
1339 scratch3,
1340 name,
1341 miss);
1342 }
1343
1344 if (lookup->type() == FIELD) {
1345 // We found FIELD property in prototype chain of interceptor's holder.
1346 // Retrieve a field from field's holder.
1347 GenerateFastPropertyLoad(masm(), v0, holder_reg,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001348 Handle<JSObject>(lookup->holder()),
1349 lookup->GetFieldIndex());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001350 __ Ret();
1351 } else {
1352 // We found CALLBACKS property in prototype chain of interceptor's
1353 // holder.
1354 ASSERT(lookup->type() == CALLBACKS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001355 Handle<AccessorInfo> callback(
1356 AccessorInfo::cast(lookup->GetCallbackObject()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001357 ASSERT(callback->getter() != NULL);
1358
1359 // Tail call to runtime.
1360 // Important invariant in CALLBACKS case: the code above must be
1361 // structured to never clobber |receiver| register.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001362 __ li(scratch2, callback);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001363
1364 __ Push(receiver, holder_reg);
1365 __ lw(scratch3,
1366 FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
1367 __ li(scratch1, Operand(ExternalReference::isolate_address()));
1368 __ Push(scratch3, scratch1, scratch2, name_reg);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001369
1370 ExternalReference ref =
1371 ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
1372 masm()->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001373 __ TailCallExternalReference(ref, 6, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001374 }
1375 } else { // !compile_followup_inline
1376 // Call the runtime system to load the interceptor.
1377 // Check that the maps haven't changed.
1378 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1379 scratch1, scratch2, scratch3,
1380 name, miss);
1381 PushInterceptorArguments(masm(), receiver, holder_reg,
1382 name_reg, interceptor_holder);
1383
1384 ExternalReference ref = ExternalReference(
1385 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), masm()->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001386 __ TailCallExternalReference(ref, 6, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001387 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001388}
1389
1390
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001391void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001392 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001393 __ Branch(miss, ne, a2, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001394 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001395}
1396
1397
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001398void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1399 Handle<JSObject> holder,
1400 Handle<String> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001401 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001402 ASSERT(holder->IsGlobalObject());
1403
1404 // Get the number of arguments.
1405 const int argc = arguments().immediate();
1406
1407 // Get the receiver from the stack.
1408 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1409
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001410 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001411 __ JumpIfSmi(a0, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001412 CheckPrototypes(object, a0, holder, a3, a1, t0, name, miss);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001413}
1414
1415
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001416void CallStubCompiler::GenerateLoadFunctionFromCell(
1417 Handle<JSGlobalPropertyCell> cell,
1418 Handle<JSFunction> function,
1419 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001420 // Get the value from the cell.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001421 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001422 __ lw(a1, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
1423
1424 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001425 if (heap()->InNewSpace(*function)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001426 // We can't embed a pointer to a function in new space so we have
1427 // to verify that the shared function info is unchanged. This has
1428 // the nice side effect that multiple closures based on the same
1429 // function can all use this call IC. Before we load through the
1430 // function, we have to verify that it still is a function.
1431 __ JumpIfSmi(a1, miss);
1432 __ GetObjectType(a1, a3, a3);
1433 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
1434
1435 // Check the shared function info. Make sure it hasn't changed.
1436 __ li(a3, Handle<SharedFunctionInfo>(function->shared()));
1437 __ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
1438 __ Branch(miss, ne, t0, Operand(a3));
1439 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001440 __ Branch(miss, ne, a1, Operand(function));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001441 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001442}
1443
1444
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001445void CallStubCompiler::GenerateMissBranch() {
1446 Handle<Code> code =
danno@chromium.org40cb8782011-05-25 07:58:50 +00001447 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1448 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001449 extra_state_);
1450 __ Jump(code, RelocInfo::CODE_TARGET);
1451}
1452
1453
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001454Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1455 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001456 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001457 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001458 // ----------- S t a t e -------------
1459 // -- a2 : name
1460 // -- ra : return address
1461 // -----------------------------------
1462 Label miss;
1463
1464 GenerateNameCheck(name, &miss);
1465
1466 const int argc = arguments().immediate();
1467
1468 // Get the receiver of the function from the stack into a0.
1469 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1470 // Check that the receiver isn't a smi.
1471 __ JumpIfSmi(a0, &miss, t0);
1472
1473 // Do the right check and compute the holder register.
1474 Register reg = CheckPrototypes(object, a0, holder, a1, a3, t0, name, &miss);
1475 GenerateFastPropertyLoad(masm(), a1, reg, holder, index);
1476
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001477 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001478
1479 // Handle call cache miss.
1480 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001481 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001482
1483 // Return the generated code.
1484 return GetCode(FIELD, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001485}
1486
1487
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001488Handle<Code> CallStubCompiler::CompileArrayPushCall(
1489 Handle<Object> object,
1490 Handle<JSObject> holder,
1491 Handle<JSGlobalPropertyCell> cell,
1492 Handle<JSFunction> function,
1493 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001494 // ----------- S t a t e -------------
1495 // -- a2 : name
1496 // -- ra : return address
1497 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1498 // -- ...
1499 // -- sp[argc * 4] : receiver
1500 // -----------------------------------
1501
1502 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001503 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001504
1505 Label miss;
1506
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001507 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001508
1509 Register receiver = a1;
1510
1511 // Get the receiver from the stack.
1512 const int argc = arguments().immediate();
1513 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1514
1515 // Check that the receiver isn't a smi.
1516 __ JumpIfSmi(receiver, &miss);
1517
1518 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001519 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, a3, v0, t0,
1520 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001521
1522 if (argc == 0) {
1523 // Nothing to do, just return the length.
1524 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1525 __ Drop(argc + 1);
1526 __ Ret();
1527 } else {
1528 Label call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001529 if (argc == 1) { // Otherwise fall through to call the builtin.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001530 Label attempt_to_grow_elements;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001531
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001532 Register elements = t2;
1533 Register end_elements = t1;
1534 // Get the elements array of the object.
1535 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1536
1537 // Check that the elements are in fast mode and writable.
1538 __ CheckMap(elements,
1539 v0,
1540 Heap::kFixedArrayMapRootIndex,
1541 &call_builtin,
1542 DONT_DO_SMI_CHECK);
1543
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001544 // Get the array's length into v0 and calculate new length.
1545 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1546 STATIC_ASSERT(kSmiTagSize == 1);
1547 STATIC_ASSERT(kSmiTag == 0);
1548 __ Addu(v0, v0, Operand(Smi::FromInt(argc)));
1549
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001550 // Get the elements' length.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001551 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1552
1553 // Check if we could survive without allocation.
1554 __ Branch(&attempt_to_grow_elements, gt, v0, Operand(t0));
1555
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001556 // Check if value is a smi.
1557 Label with_write_barrier;
1558 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1559 __ JumpIfNotSmi(t0, &with_write_barrier);
1560
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001561 // Save new length.
1562 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1563
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001564 // Store the value.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001565 // We may need a register containing the address end_elements below,
1566 // so write back the value in end_elements.
1567 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1568 __ Addu(end_elements, elements, end_elements);
1569 const int kEndElementsOffset =
1570 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001571 __ Addu(end_elements, end_elements, kEndElementsOffset);
1572 __ sw(t0, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001573
1574 // Check for a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001575 __ Drop(argc + 1);
1576 __ Ret();
1577
1578 __ bind(&with_write_barrier);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001579
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001580 __ lw(a3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1581
1582 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
1583 Label fast_object, not_fast_object;
1584 __ CheckFastObjectElements(a3, t3, &not_fast_object);
1585 __ jmp(&fast_object);
1586 // In case of fast smi-only, convert to fast object, otherwise bail out.
1587 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001588 __ CheckFastSmiElements(a3, t3, &call_builtin);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001589 // edx: receiver
1590 // r3: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001591 Label try_holey_map;
1592 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001593 FAST_ELEMENTS,
1594 a3,
1595 t3,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001596 &try_holey_map);
1597 __ mov(a2, receiver);
1598 ElementsTransitionGenerator::
1599 GenerateMapChangeElementsTransition(masm());
1600 __ jmp(&fast_object);
1601
1602 __ bind(&try_holey_map);
1603 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1604 FAST_HOLEY_ELEMENTS,
1605 a3,
1606 t3,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001607 &call_builtin);
1608 __ mov(a2, receiver);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001609 ElementsTransitionGenerator::
1610 GenerateMapChangeElementsTransition(masm());
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001611 __ bind(&fast_object);
1612 } else {
1613 __ CheckFastObjectElements(a3, a3, &call_builtin);
1614 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001615
1616 // Save new length.
1617 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1618
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001619 // Store the value.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001620 // We may need a register containing the address end_elements below,
1621 // so write back the value in end_elements.
1622 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1623 __ Addu(end_elements, elements, end_elements);
1624 __ Addu(end_elements, end_elements, kEndElementsOffset);
1625 __ sw(t0, MemOperand(end_elements));
1626
1627 __ RecordWrite(elements,
1628 end_elements,
1629 t0,
1630 kRAHasNotBeenSaved,
1631 kDontSaveFPRegs,
1632 EMIT_REMEMBERED_SET,
1633 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001634 __ Drop(argc + 1);
1635 __ Ret();
1636
1637 __ bind(&attempt_to_grow_elements);
1638 // v0: array's length + 1.
1639 // t0: elements' length.
1640
1641 if (!FLAG_inline_new) {
1642 __ Branch(&call_builtin);
1643 }
1644
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001645 __ lw(a2, MemOperand(sp, (argc - 1) * kPointerSize));
1646 // Growing elements that are SMI-only requires special handling in case
1647 // the new element is non-Smi. For now, delegate to the builtin.
1648 Label no_fast_elements_check;
1649 __ JumpIfSmi(a2, &no_fast_elements_check);
1650 __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1651 __ CheckFastObjectElements(t3, t3, &call_builtin);
1652 __ bind(&no_fast_elements_check);
1653
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001654 ExternalReference new_space_allocation_top =
1655 ExternalReference::new_space_allocation_top_address(
1656 masm()->isolate());
1657 ExternalReference new_space_allocation_limit =
1658 ExternalReference::new_space_allocation_limit_address(
1659 masm()->isolate());
1660
1661 const int kAllocationDelta = 4;
1662 // Load top and check if it is the end of elements.
1663 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1664 __ Addu(end_elements, elements, end_elements);
1665 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset));
1666 __ li(t3, Operand(new_space_allocation_top));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001667 __ lw(a3, MemOperand(t3));
1668 __ Branch(&call_builtin, ne, end_elements, Operand(a3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001669
1670 __ li(t5, Operand(new_space_allocation_limit));
1671 __ lw(t5, MemOperand(t5));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001672 __ Addu(a3, a3, Operand(kAllocationDelta * kPointerSize));
1673 __ Branch(&call_builtin, hi, a3, Operand(t5));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001674
1675 // We fit and could grow elements.
1676 // Update new_space_allocation_top.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001677 __ sw(a3, MemOperand(t3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001678 // Push the argument.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001679 __ sw(a2, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001680 // Fill the rest with holes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001681 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001682 for (int i = 1; i < kAllocationDelta; i++) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001683 __ sw(a3, MemOperand(end_elements, i * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001684 }
1685
1686 // Update elements' and array's sizes.
1687 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1688 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta)));
1689 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1690
1691 // Elements are in new space, so write barrier is not required.
1692 __ Drop(argc + 1);
1693 __ Ret();
1694 }
1695 __ bind(&call_builtin);
1696 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
1697 masm()->isolate()),
1698 argc + 1,
1699 1);
1700 }
1701
1702 // Handle call cache miss.
1703 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001704 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001705
1706 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001707 return GetCode(function);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001708}
1709
1710
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001711Handle<Code> CallStubCompiler::CompileArrayPopCall(
1712 Handle<Object> object,
1713 Handle<JSObject> holder,
1714 Handle<JSGlobalPropertyCell> cell,
1715 Handle<JSFunction> function,
1716 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001717 // ----------- S t a t e -------------
1718 // -- a2 : name
1719 // -- ra : return address
1720 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1721 // -- ...
1722 // -- sp[argc * 4] : receiver
1723 // -----------------------------------
1724
1725 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001726 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001727
1728 Label miss, return_undefined, call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001729 Register receiver = a1;
1730 Register elements = a3;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001731 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001732
1733 // Get the receiver from the stack.
1734 const int argc = arguments().immediate();
1735 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001736 // Check that the receiver isn't a smi.
1737 __ JumpIfSmi(receiver, &miss);
1738
1739 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001740 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, elements,
1741 t0, v0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001742
1743 // Get the elements array of the object.
1744 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1745
1746 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001747 __ CheckMap(elements,
1748 v0,
1749 Heap::kFixedArrayMapRootIndex,
1750 &call_builtin,
1751 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001752
1753 // Get the array's length into t0 and calculate new length.
1754 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1755 __ Subu(t0, t0, Operand(Smi::FromInt(1)));
1756 __ Branch(&return_undefined, lt, t0, Operand(zero_reg));
1757
1758 // Get the last element.
1759 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1760 STATIC_ASSERT(kSmiTagSize == 1);
1761 STATIC_ASSERT(kSmiTag == 0);
1762 // We can't address the last element in one operation. Compute the more
1763 // expensive shift first, and use an offset later on.
1764 __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize);
1765 __ Addu(elements, elements, t1);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001766 __ lw(v0, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001767 __ Branch(&call_builtin, eq, v0, Operand(t2));
1768
1769 // Set the array's length.
1770 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1771
1772 // Fill with the hole.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001773 __ sw(t2, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001774 __ Drop(argc + 1);
1775 __ Ret();
1776
1777 __ bind(&return_undefined);
1778 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
1779 __ Drop(argc + 1);
1780 __ Ret();
1781
1782 __ bind(&call_builtin);
1783 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop,
1784 masm()->isolate()),
1785 argc + 1,
1786 1);
1787
1788 // Handle call cache miss.
1789 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001790 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001791
1792 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001793 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001794}
1795
1796
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001797Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1798 Handle<Object> object,
1799 Handle<JSObject> holder,
1800 Handle<JSGlobalPropertyCell> cell,
1801 Handle<JSFunction> function,
1802 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001803 // ----------- S t a t e -------------
1804 // -- a2 : function name
1805 // -- ra : return address
1806 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1807 // -- ...
1808 // -- sp[argc * 4] : receiver
1809 // -----------------------------------
1810
1811 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001812 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001813
1814 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001815 Label miss;
1816 Label name_miss;
1817 Label index_out_of_range;
1818
1819 Label* index_out_of_range_label = &index_out_of_range;
1820
danno@chromium.org40cb8782011-05-25 07:58:50 +00001821 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001822 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001823 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001824 index_out_of_range_label = &miss;
1825 }
1826
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001827 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001828
1829 // Check that the maps starting from the prototype haven't changed.
1830 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1831 Context::STRING_FUNCTION_INDEX,
1832 v0,
1833 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001834 ASSERT(!object.is_identical_to(holder));
1835 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1836 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001837
1838 Register receiver = a1;
1839 Register index = t1;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001840 Register result = v0;
1841 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1842 if (argc > 0) {
1843 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1844 } else {
1845 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1846 }
1847
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001848 StringCharCodeAtGenerator generator(receiver,
1849 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001850 result,
1851 &miss, // When not a string.
1852 &miss, // When not a number.
1853 index_out_of_range_label,
1854 STRING_INDEX_IS_NUMBER);
1855 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001856 __ Drop(argc + 1);
1857 __ Ret();
1858
1859 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001860 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001861
1862 if (index_out_of_range.is_linked()) {
1863 __ bind(&index_out_of_range);
1864 __ LoadRoot(v0, Heap::kNanValueRootIndex);
1865 __ Drop(argc + 1);
1866 __ Ret();
1867 }
1868
1869 __ bind(&miss);
1870 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001871 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001872 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001873 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001874
1875 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001876 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001877}
1878
1879
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001880Handle<Code> CallStubCompiler::CompileStringCharAtCall(
1881 Handle<Object> object,
1882 Handle<JSObject> holder,
1883 Handle<JSGlobalPropertyCell> cell,
1884 Handle<JSFunction> function,
1885 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001886 // ----------- S t a t e -------------
1887 // -- a2 : function name
1888 // -- ra : return address
1889 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1890 // -- ...
1891 // -- sp[argc * 4] : receiver
1892 // -----------------------------------
1893
1894 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001895 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001896
1897 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001898 Label miss;
1899 Label name_miss;
1900 Label index_out_of_range;
1901 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00001902 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001903 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001904 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001905 index_out_of_range_label = &miss;
1906 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001907 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001908
1909 // Check that the maps starting from the prototype haven't changed.
1910 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1911 Context::STRING_FUNCTION_INDEX,
1912 v0,
1913 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001914 ASSERT(!object.is_identical_to(holder));
1915 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1916 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001917
1918 Register receiver = v0;
1919 Register index = t1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001920 Register scratch = a3;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001921 Register result = v0;
1922 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1923 if (argc > 0) {
1924 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1925 } else {
1926 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1927 }
1928
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001929 StringCharAtGenerator generator(receiver,
1930 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00001931 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001932 result,
1933 &miss, // When not a string.
1934 &miss, // When not a number.
1935 index_out_of_range_label,
1936 STRING_INDEX_IS_NUMBER);
1937 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001938 __ Drop(argc + 1);
1939 __ Ret();
1940
1941 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001942 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001943
1944 if (index_out_of_range.is_linked()) {
1945 __ bind(&index_out_of_range);
1946 __ LoadRoot(v0, Heap::kEmptyStringRootIndex);
1947 __ Drop(argc + 1);
1948 __ Ret();
1949 }
1950
1951 __ bind(&miss);
1952 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001953 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001954 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001955 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001956
1957 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001958 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001959}
1960
1961
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001962Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
1963 Handle<Object> object,
1964 Handle<JSObject> holder,
1965 Handle<JSGlobalPropertyCell> cell,
1966 Handle<JSFunction> function,
1967 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001968 // ----------- S t a t e -------------
1969 // -- a2 : function name
1970 // -- ra : return address
1971 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1972 // -- ...
1973 // -- sp[argc * 4] : receiver
1974 // -----------------------------------
1975
1976 const int argc = arguments().immediate();
1977
1978 // If the object is not a JSObject or we got an unexpected number of
1979 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001980 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001981
1982 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001983 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001984
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001985 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001986 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
1987
1988 STATIC_ASSERT(kSmiTag == 0);
1989 __ JumpIfSmi(a1, &miss);
1990
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001991 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
1992 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001993 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001994 ASSERT(cell->value() == *function);
1995 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
1996 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001997 GenerateLoadFunctionFromCell(cell, function, &miss);
1998 }
1999
2000 // Load the char code argument.
2001 Register code = a1;
2002 __ lw(code, MemOperand(sp, 0 * kPointerSize));
2003
2004 // Check the code is a smi.
2005 Label slow;
2006 STATIC_ASSERT(kSmiTag == 0);
2007 __ JumpIfNotSmi(code, &slow);
2008
2009 // Convert the smi code to uint16.
2010 __ And(code, code, Operand(Smi::FromInt(0xffff)));
2011
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002012 StringCharFromCodeGenerator generator(code, v0);
2013 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002014 __ Drop(argc + 1);
2015 __ Ret();
2016
2017 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002018 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002019
2020 // Tail call the full function. We do not have to patch the receiver
2021 // because the function makes no use of it.
2022 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002023 __ InvokeFunction(
2024 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002025
2026 __ bind(&miss);
2027 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002028 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002029
2030 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002031 return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002032}
2033
2034
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002035Handle<Code> CallStubCompiler::CompileMathFloorCall(
2036 Handle<Object> object,
2037 Handle<JSObject> holder,
2038 Handle<JSGlobalPropertyCell> cell,
2039 Handle<JSFunction> function,
2040 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002041 // ----------- S t a t e -------------
2042 // -- a2 : function name
2043 // -- ra : return address
2044 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2045 // -- ...
2046 // -- sp[argc * 4] : receiver
2047 // -----------------------------------
2048
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002049 if (!CpuFeatures::IsSupported(FPU)) {
2050 return Handle<Code>::null();
2051 }
2052
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002053 CpuFeatures::Scope scope_fpu(FPU);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002054 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002055 // If the object is not a JSObject or we got an unexpected number of
2056 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002057 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002058
2059 Label miss, slow;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002060 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002061
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002062 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002063 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002064 STATIC_ASSERT(kSmiTag == 0);
2065 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002066 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2067 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002068 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002069 ASSERT(cell->value() == *function);
2070 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2071 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002072 GenerateLoadFunctionFromCell(cell, function, &miss);
2073 }
2074
2075 // Load the (only) argument into v0.
2076 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2077
2078 // If the argument is a smi, just return.
2079 STATIC_ASSERT(kSmiTag == 0);
2080 __ And(t0, v0, Operand(kSmiTagMask));
2081 __ Drop(argc + 1, eq, t0, Operand(zero_reg));
2082 __ Ret(eq, t0, Operand(zero_reg));
2083
danno@chromium.org40cb8782011-05-25 07:58:50 +00002084 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002085
2086 Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return;
2087
2088 // If fpu is enabled, we use the floor instruction.
2089
2090 // Load the HeapNumber value.
2091 __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2092
2093 // Backup FCSR.
2094 __ cfc1(a3, FCSR);
2095 // Clearing FCSR clears the exception mask with no side-effects.
2096 __ ctc1(zero_reg, FCSR);
2097 // Convert the argument to an integer.
2098 __ floor_w_d(f0, f0);
2099
2100 // Start checking for special cases.
2101 // Get the argument exponent and clear the sign bit.
2102 __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize));
2103 __ And(t2, t1, Operand(~HeapNumber::kSignMask));
2104 __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord);
2105
2106 // Retrieve FCSR and check for fpu errors.
2107 __ cfc1(t5, FCSR);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002108 __ And(t5, t5, Operand(kFCSRExceptionFlagMask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002109 __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));
2110
2111 // Check for NaN, Infinity, and -Infinity.
2112 // They are invariant through a Math.Floor call, so just
2113 // return the original argument.
2114 __ Subu(t3, t2, Operand(HeapNumber::kExponentMask
2115 >> HeapNumber::kMantissaBitsInTopWord));
2116 __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg));
2117 // We had an overflow or underflow in the conversion. Check if we
2118 // have a big exponent.
2119 // If greater or equal, the argument is already round and in v0.
2120 __ Branch(&restore_fcsr_and_return, ge, t3,
2121 Operand(HeapNumber::kMantissaBits));
2122 __ Branch(&wont_fit_smi);
2123
2124 __ bind(&no_fpu_error);
2125 // Move the result back to v0.
2126 __ mfc1(v0, f0);
2127 // Check if the result fits into a smi.
2128 __ Addu(a1, v0, Operand(0x40000000));
2129 __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg));
2130 // Tag the result.
2131 STATIC_ASSERT(kSmiTag == 0);
2132 __ sll(v0, v0, kSmiTagSize);
2133
2134 // Check for -0.
2135 __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg));
2136 // t1 already holds the HeapNumber exponent.
2137 __ And(t0, t1, Operand(HeapNumber::kSignMask));
2138 // If our HeapNumber is negative it was -0, so load its address and return.
2139 // Else v0 is loaded with 0, so we can also just return.
2140 __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg));
2141 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2142
2143 __ bind(&restore_fcsr_and_return);
2144 // Restore FCSR and return.
2145 __ ctc1(a3, FCSR);
2146
2147 __ Drop(argc + 1);
2148 __ Ret();
2149
2150 __ bind(&wont_fit_smi);
2151 // Restore FCSR and fall to slow case.
2152 __ ctc1(a3, FCSR);
2153
2154 __ bind(&slow);
2155 // Tail call the full function. We do not have to patch the receiver
2156 // because the function makes no use of it.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002157 __ InvokeFunction(
2158 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002159
2160 __ bind(&miss);
2161 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002162 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002163
2164 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002165 return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002166}
2167
2168
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002169Handle<Code> CallStubCompiler::CompileMathAbsCall(
2170 Handle<Object> object,
2171 Handle<JSObject> holder,
2172 Handle<JSGlobalPropertyCell> cell,
2173 Handle<JSFunction> function,
2174 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002175 // ----------- S t a t e -------------
2176 // -- a2 : function name
2177 // -- ra : return address
2178 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2179 // -- ...
2180 // -- sp[argc * 4] : receiver
2181 // -----------------------------------
2182
2183 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002184 // If the object is not a JSObject or we got an unexpected number of
2185 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002186 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002187
2188 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002189
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002190 GenerateNameCheck(name, &miss);
2191 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002192 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002193 STATIC_ASSERT(kSmiTag == 0);
2194 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002195 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2196 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002197 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002198 ASSERT(cell->value() == *function);
2199 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2200 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002201 GenerateLoadFunctionFromCell(cell, function, &miss);
2202 }
2203
2204 // Load the (only) argument into v0.
2205 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2206
2207 // Check if the argument is a smi.
2208 Label not_smi;
2209 STATIC_ASSERT(kSmiTag == 0);
2210 __ JumpIfNotSmi(v0, &not_smi);
2211
2212 // Do bitwise not or do nothing depending on the sign of the
2213 // argument.
2214 __ sra(t0, v0, kBitsPerInt - 1);
2215 __ Xor(a1, v0, t0);
2216
2217 // Add 1 or do nothing depending on the sign of the argument.
2218 __ Subu(v0, a1, t0);
2219
2220 // If the result is still negative, go to the slow case.
2221 // This only happens for the most negative smi.
2222 Label slow;
2223 __ Branch(&slow, lt, v0, Operand(zero_reg));
2224
2225 // Smi case done.
2226 __ Drop(argc + 1);
2227 __ Ret();
2228
2229 // Check if the argument is a heap number and load its exponent and
2230 // sign.
2231 __ bind(&not_smi);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002232 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002233 __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2234
2235 // Check the sign of the argument. If the argument is positive,
2236 // just return it.
2237 Label negative_sign;
2238 __ And(t0, a1, Operand(HeapNumber::kSignMask));
2239 __ Branch(&negative_sign, ne, t0, Operand(zero_reg));
2240 __ Drop(argc + 1);
2241 __ Ret();
2242
2243 // If the argument is negative, clear the sign, and return a new
2244 // number.
2245 __ bind(&negative_sign);
2246 __ Xor(a1, a1, Operand(HeapNumber::kSignMask));
2247 __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2248 __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
2249 __ AllocateHeapNumber(v0, t0, t1, t2, &slow);
2250 __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2251 __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2252 __ Drop(argc + 1);
2253 __ Ret();
2254
2255 // Tail call the full function. We do not have to patch the receiver
2256 // because the function makes no use of it.
2257 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002258 __ InvokeFunction(
2259 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002260
2261 __ bind(&miss);
2262 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002263 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002264
2265 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002266 return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002267}
2268
2269
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002270Handle<Code> CallStubCompiler::CompileFastApiCall(
lrn@chromium.org7516f052011-03-30 08:52:27 +00002271 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002272 Handle<Object> object,
2273 Handle<JSObject> holder,
2274 Handle<JSGlobalPropertyCell> cell,
2275 Handle<JSFunction> function,
2276 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002277
danno@chromium.org40cb8782011-05-25 07:58:50 +00002278 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002279
2280 ASSERT(optimization.is_simple_api_call());
2281 // Bail out if object is a global object as we don't want to
2282 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002283 if (object->IsGlobalObject()) return Handle<Code>::null();
2284 if (!cell.is_null()) return Handle<Code>::null();
2285 if (!object->IsJSObject()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002286 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002287 Handle<JSObject>::cast(object), holder);
2288 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002289
2290 Label miss, miss_before_stack_reserved;
2291
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002292 GenerateNameCheck(name, &miss_before_stack_reserved);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002293
2294 // Get the receiver from the stack.
2295 const int argc = arguments().immediate();
2296 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2297
2298 // Check that the receiver isn't a smi.
2299 __ JumpIfSmi(a1, &miss_before_stack_reserved);
2300
2301 __ IncrementCounter(counters->call_const(), 1, a0, a3);
2302 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2303
2304 ReserveSpaceForFastApiCall(masm(), a0);
2305
2306 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002307 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002308 depth, &miss);
2309
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002310 GenerateFastApiDirectCall(masm(), optimization, argc);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002311
2312 __ bind(&miss);
2313 FreeSpaceForFastApiCall(masm());
2314
2315 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002316 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002317
2318 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002319 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002320}
2321
2322
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002323Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object,
2324 Handle<JSObject> holder,
2325 Handle<JSFunction> function,
2326 Handle<String> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002327 CheckType check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002328 // ----------- S t a t e -------------
2329 // -- a2 : name
2330 // -- ra : return address
2331 // -----------------------------------
2332 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002333 Handle<Code> code = CompileCustomCall(object, holder,
2334 Handle<JSGlobalPropertyCell>::null(),
2335 function, name);
2336 // A null handle means bail out to the regular compiler code below.
2337 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002338 }
2339
2340 Label miss;
2341
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002342 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002343
2344 // Get the receiver from the stack.
2345 const int argc = arguments().immediate();
2346 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2347
2348 // Check that the receiver isn't a smi.
2349 if (check != NUMBER_CHECK) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002350 __ JumpIfSmi(a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002351 }
2352
2353 // Make sure that it's okay not to patch the on stack receiver
2354 // unless we're doing a receiver map check.
2355 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002356 switch (check) {
2357 case RECEIVER_MAP_CHECK:
2358 __ IncrementCounter(masm()->isolate()->counters()->call_const(),
2359 1, a0, a3);
2360
2361 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002362 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2363 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002364
2365 // Patch the receiver on the stack with the global proxy if
2366 // necessary.
2367 if (object->IsGlobalObject()) {
2368 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2369 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2370 }
2371 break;
2372
2373 case STRING_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002374 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002375 // Check that the object is a two-byte string or a symbol.
2376 __ GetObjectType(a1, a3, a3);
2377 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2378 // Check that the maps starting from the prototype haven't changed.
2379 GenerateDirectLoadGlobalFunctionPrototype(
2380 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002381 CheckPrototypes(
2382 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2383 a0, holder, a3, a1, t0, name, &miss);
2384 } else {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002385 // Calling non-strict non-builtins with a value as the receiver
2386 // requires boxing.
2387 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002388 }
2389 break;
2390
2391 case NUMBER_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002392 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002393 Label fast;
2394 // Check that the object is a smi or a heap number.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002395 __ JumpIfSmi(a1, &fast);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002396 __ GetObjectType(a1, a0, a0);
2397 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
2398 __ bind(&fast);
2399 // Check that the maps starting from the prototype haven't changed.
2400 GenerateDirectLoadGlobalFunctionPrototype(
2401 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002402 CheckPrototypes(
2403 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2404 a0, holder, a3, a1, t0, name, &miss);
2405 } else {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002406 // Calling non-strict non-builtins with a value as the receiver
2407 // requires boxing.
2408 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002409 }
2410 break;
2411
2412 case BOOLEAN_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002413 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002414 Label fast;
2415 // Check that the object is a boolean.
2416 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
2417 __ Branch(&fast, eq, a1, Operand(t0));
2418 __ LoadRoot(t0, Heap::kFalseValueRootIndex);
2419 __ Branch(&miss, ne, a1, Operand(t0));
2420 __ bind(&fast);
2421 // Check that the maps starting from the prototype haven't changed.
2422 GenerateDirectLoadGlobalFunctionPrototype(
2423 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002424 CheckPrototypes(
2425 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2426 a0, holder, a3, a1, t0, name, &miss);
2427 } else {
2428 // Calling non-strict non-builtins with a value as the receiver
2429 // requires boxing.
2430 __ jmp(&miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002431 }
2432 break;
2433 }
2434
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002435 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002436 ? CALL_AS_FUNCTION
2437 : CALL_AS_METHOD;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002438 __ InvokeFunction(
2439 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002440
2441 // Handle call cache miss.
2442 __ bind(&miss);
2443
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002444 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002445
2446 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002447 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002448}
2449
2450
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002451Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2452 Handle<JSObject> holder,
2453 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002454 // ----------- S t a t e -------------
2455 // -- a2 : name
2456 // -- ra : return address
2457 // -----------------------------------
2458
2459 Label miss;
2460
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002461 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002462
2463 // Get the number of arguments.
2464 const int argc = arguments().immediate();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002465 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002466 LookupPostInterceptor(holder, name, &lookup);
2467
2468 // Get the receiver from the stack.
2469 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2470
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002471 CallInterceptorCompiler compiler(this, arguments(), a2, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002472 compiler.Compile(masm(), object, holder, name, &lookup, a1, a3, t0, a0,
2473 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002474
2475 // Move returned value, the function to call, to a1.
2476 __ mov(a1, v0);
2477 // Restore receiver.
2478 __ lw(a0, MemOperand(sp, argc * kPointerSize));
2479
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002480 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002481
2482 // Handle call cache miss.
2483 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002484 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002485
2486 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002487 return GetCode(INTERCEPTOR, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002488}
2489
2490
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002491Handle<Code> CallStubCompiler::CompileCallGlobal(
2492 Handle<JSObject> object,
2493 Handle<GlobalObject> holder,
2494 Handle<JSGlobalPropertyCell> cell,
2495 Handle<JSFunction> function,
2496 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002497 // ----------- S t a t e -------------
2498 // -- a2 : name
2499 // -- ra : return address
2500 // -----------------------------------
2501
2502 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002503 Handle<Code> code = CompileCustomCall(object, holder, cell, function, name);
2504 // A null handle means bail out to the regular compiler code below.
2505 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002506 }
2507
2508 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002509 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002510
2511 // Get the number of arguments.
2512 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002513 GenerateGlobalReceiverCheck(object, holder, name, &miss);
2514 GenerateLoadFunctionFromCell(cell, function, &miss);
2515
2516 // Patch the receiver on the stack with the global proxy if
2517 // necessary.
2518 if (object->IsGlobalObject()) {
2519 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
2520 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2521 }
2522
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002523 // Set up the context (function already in r1).
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002524 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
2525
2526 // Jump to the cached code (tail call).
2527 Counters* counters = masm()->isolate()->counters();
2528 __ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002529 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002530 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002531 ? CALL_AS_FUNCTION
2532 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002533 // We call indirectly through the code field in the function to
2534 // allow recompilation to take effect without changing any of the
2535 // call sites.
2536 __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
2537 __ InvokeCode(a3, expected, arguments(), JUMP_FUNCTION,
2538 NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002539
2540 // Handle call cache miss.
2541 __ bind(&miss);
2542 __ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002543 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002544
2545 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002546 return GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002547}
2548
2549
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002550Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +00002551 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002552 Handle<Map> transition,
2553 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002554 // ----------- S t a t e -------------
2555 // -- a0 : value
2556 // -- a1 : receiver
2557 // -- a2 : name
2558 // -- ra : return address
2559 // -----------------------------------
2560 Label miss;
2561
2562 // Name register might be clobbered.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002563 GenerateStoreField(masm(), object, index, transition, a1, a2, a3, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002564 __ bind(&miss);
2565 __ li(a2, Operand(Handle<String>(name))); // Restore name.
2566 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2567 __ Jump(ic, RelocInfo::CODE_TARGET);
2568
2569 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002570 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002571}
2572
2573
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002574Handle<Code> StoreStubCompiler::CompileStoreCallback(
2575 Handle<JSObject> object,
2576 Handle<AccessorInfo> callback,
2577 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002578 // ----------- S t a t e -------------
2579 // -- a0 : value
2580 // -- a1 : receiver
2581 // -- a2 : name
2582 // -- ra : return address
2583 // -----------------------------------
2584 Label miss;
2585
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002586 // Check that the map of the object hasn't changed.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002587 __ CheckMap(a1, a3, Handle<Map>(object->map()), &miss,
2588 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002589
2590 // Perform global security token check if needed.
2591 if (object->IsJSGlobalProxy()) {
2592 __ CheckAccessGlobalProxy(a1, a3, &miss);
2593 }
2594
2595 // Stub never generated for non-global objects that require access
2596 // checks.
2597 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
2598
2599 __ push(a1); // Receiver.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002600 __ li(a3, Operand(callback)); // Callback info.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002601 __ Push(a3, a2, a0);
2602
2603 // Do tail-call to the runtime system.
2604 ExternalReference store_callback_property =
2605 ExternalReference(IC_Utility(IC::kStoreCallbackProperty),
2606 masm()->isolate());
2607 __ TailCallExternalReference(store_callback_property, 4, 1);
2608
2609 // Handle store cache miss.
2610 __ bind(&miss);
2611 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2612 __ Jump(ic, RelocInfo::CODE_TARGET);
2613
2614 // Return the generated code.
2615 return GetCode(CALLBACKS, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002616}
2617
2618
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002619Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
2620 Handle<JSObject> receiver,
2621 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002622 // ----------- S t a t e -------------
2623 // -- a0 : value
2624 // -- a1 : receiver
2625 // -- a2 : name
2626 // -- ra : return address
2627 // -----------------------------------
2628 Label miss;
2629
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002630 // Check that the map of the object hasn't changed.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002631 __ CheckMap(a1, a3, Handle<Map>(receiver->map()), &miss,
2632 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002633
2634 // Perform global security token check if needed.
2635 if (receiver->IsJSGlobalProxy()) {
2636 __ CheckAccessGlobalProxy(a1, a3, &miss);
2637 }
2638
2639 // Stub is never generated for non-global objects that require access
2640 // checks.
2641 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2642
2643 __ Push(a1, a2, a0); // Receiver, name, value.
2644
2645 __ li(a0, Operand(Smi::FromInt(strict_mode_)));
2646 __ push(a0); // Strict mode.
2647
2648 // Do tail-call to the runtime system.
2649 ExternalReference store_ic_property =
2650 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty),
2651 masm()->isolate());
2652 __ TailCallExternalReference(store_ic_property, 4, 1);
2653
2654 // Handle store cache miss.
2655 __ bind(&miss);
2656 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2657 __ Jump(ic, RelocInfo::CODE_TARGET);
2658
2659 // Return the generated code.
2660 return GetCode(INTERCEPTOR, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002661}
2662
2663
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002664Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2665 Handle<GlobalObject> object,
2666 Handle<JSGlobalPropertyCell> cell,
2667 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002668 // ----------- S t a t e -------------
2669 // -- a0 : value
2670 // -- a1 : receiver
2671 // -- a2 : name
2672 // -- ra : return address
2673 // -----------------------------------
2674 Label miss;
2675
2676 // Check that the map of the global has not changed.
2677 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2678 __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map())));
2679
2680 // Check that the value in the cell is not the hole. If it is, this
2681 // cell could have been deleted and reintroducing the global needs
2682 // to update the property details in the property dictionary of the
2683 // global object. We bail out to the runtime system to do that.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002684 __ li(t0, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002685 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
2686 __ lw(t2, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2687 __ Branch(&miss, eq, t1, Operand(t2));
2688
2689 // Store the value in the cell.
2690 __ sw(a0, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2691 __ mov(v0, a0); // Stored value must be returned in v0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002692 // Cells are always rescanned, so no write barrier here.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002693
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002694 Counters* counters = masm()->isolate()->counters();
2695 __ IncrementCounter(counters->named_store_global_inline(), 1, a1, a3);
2696 __ Ret();
2697
2698 // Handle store cache miss.
2699 __ bind(&miss);
2700 __ IncrementCounter(counters->named_store_global_inline_miss(), 1, a1, a3);
2701 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2702 __ Jump(ic, RelocInfo::CODE_TARGET);
2703
2704 // Return the generated code.
2705 return GetCode(NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002706}
2707
2708
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002709Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
2710 Handle<JSObject> object,
2711 Handle<JSObject> last) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002712 // ----------- S t a t e -------------
2713 // -- a0 : receiver
2714 // -- ra : return address
2715 // -----------------------------------
2716 Label miss;
2717
2718 // Check that the receiver is not a smi.
2719 __ JumpIfSmi(a0, &miss);
2720
2721 // Check the maps of the full prototype chain.
2722 CheckPrototypes(object, a0, last, a3, a1, t0, name, &miss);
2723
2724 // If the last object in the prototype chain is a global object,
2725 // check that the global property cell is empty.
2726 if (last->IsGlobalObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002727 GenerateCheckPropertyCell(
2728 masm(), Handle<GlobalObject>::cast(last), name, a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002729 }
2730
2731 // Return undefined if maps of the full prototype chain is still the same.
2732 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2733 __ Ret();
2734
2735 __ bind(&miss);
2736 GenerateLoadMiss(masm(), Code::LOAD_IC);
2737
2738 // Return the generated code.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002739 return GetCode(NONEXISTENT, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00002740}
2741
2742
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002743Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object,
2744 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002745 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002746 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002747 // ----------- S t a t e -------------
2748 // -- a0 : receiver
2749 // -- a2 : name
2750 // -- ra : return address
2751 // -----------------------------------
2752 Label miss;
2753
2754 __ mov(v0, a0);
2755
2756 GenerateLoadField(object, holder, v0, a3, a1, t0, index, name, &miss);
2757 __ bind(&miss);
2758 GenerateLoadMiss(masm(), Code::LOAD_IC);
2759
2760 // Return the generated code.
2761 return GetCode(FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002762}
2763
2764
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002765Handle<Code> LoadStubCompiler::CompileLoadCallback(
2766 Handle<String> name,
2767 Handle<JSObject> object,
2768 Handle<JSObject> holder,
2769 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002770 // ----------- S t a t e -------------
2771 // -- a0 : receiver
2772 // -- a2 : name
2773 // -- ra : return address
2774 // -----------------------------------
2775 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002776 GenerateLoadCallback(object, holder, a0, a2, a3, a1, t0, callback, name,
2777 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002778 __ bind(&miss);
2779 GenerateLoadMiss(masm(), Code::LOAD_IC);
2780
2781 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002782 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002783}
2784
2785
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002786Handle<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object,
2787 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002788 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002789 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002790 // ----------- S t a t e -------------
2791 // -- a0 : receiver
2792 // -- a2 : name
2793 // -- ra : return address
2794 // -----------------------------------
2795 Label miss;
2796
2797 GenerateLoadConstant(object, holder, a0, a3, a1, t0, value, name, &miss);
2798 __ bind(&miss);
2799 GenerateLoadMiss(masm(), Code::LOAD_IC);
2800
2801 // Return the generated code.
2802 return GetCode(CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002803}
2804
2805
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002806Handle<Code> LoadStubCompiler::CompileLoadInterceptor(Handle<JSObject> object,
2807 Handle<JSObject> holder,
2808 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002809 // ----------- S t a t e -------------
2810 // -- a0 : receiver
2811 // -- a2 : name
2812 // -- ra : return address
2813 // -- [sp] : receiver
2814 // -----------------------------------
2815 Label miss;
2816
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002817 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002818 LookupPostInterceptor(holder, name, &lookup);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002819 GenerateLoadInterceptor(object, holder, &lookup, a0, a2, a3, a1, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002820 &miss);
2821 __ bind(&miss);
2822 GenerateLoadMiss(masm(), Code::LOAD_IC);
2823
2824 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002825 return GetCode(INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002826}
2827
2828
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002829Handle<Code> LoadStubCompiler::CompileLoadGlobal(
2830 Handle<JSObject> object,
2831 Handle<GlobalObject> holder,
2832 Handle<JSGlobalPropertyCell> cell,
2833 Handle<String> name,
2834 bool is_dont_delete) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002835 // ----------- S t a t e -------------
2836 // -- a0 : receiver
2837 // -- a2 : name
2838 // -- ra : return address
2839 // -----------------------------------
2840 Label miss;
2841
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002842 // Check that the map of the global has not changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00002843 __ JumpIfSmi(a0, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002844 CheckPrototypes(object, a0, holder, a3, t0, a1, name, &miss);
2845
2846 // Get the value from the cell.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002847 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002848 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
2849
2850 // Check for deleted property if property can actually be deleted.
2851 if (!is_dont_delete) {
2852 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
2853 __ Branch(&miss, eq, t0, Operand(at));
2854 }
2855
2856 __ mov(v0, t0);
2857 Counters* counters = masm()->isolate()->counters();
2858 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
2859 __ Ret();
2860
2861 __ bind(&miss);
2862 __ IncrementCounter(counters->named_load_global_stub_miss(), 1, a1, a3);
2863 GenerateLoadMiss(masm(), Code::LOAD_IC);
2864
2865 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002866 return GetCode(NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002867}
2868
2869
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002870Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
2871 Handle<JSObject> receiver,
2872 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002873 int index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002874 // ----------- S t a t e -------------
2875 // -- ra : return address
2876 // -- a0 : key
2877 // -- a1 : receiver
2878 // -----------------------------------
2879 Label miss;
2880
2881 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002882 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002883
2884 GenerateLoadField(receiver, holder, a1, a2, a3, t0, index, name, &miss);
2885 __ bind(&miss);
2886 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2887
2888 return GetCode(FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002889}
2890
2891
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002892Handle<Code> KeyedLoadStubCompiler::CompileLoadCallback(
2893 Handle<String> name,
2894 Handle<JSObject> receiver,
2895 Handle<JSObject> holder,
2896 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002897 // ----------- S t a t e -------------
2898 // -- ra : return address
2899 // -- a0 : key
2900 // -- a1 : receiver
2901 // -----------------------------------
2902 Label miss;
2903
2904 // Check the key is the cached one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002905 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002906
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002907 GenerateLoadCallback(receiver, holder, a1, a0, a2, a3, t0, callback, name,
2908 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002909 __ bind(&miss);
2910 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2911
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002912 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002913}
2914
2915
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002916Handle<Code> KeyedLoadStubCompiler::CompileLoadConstant(
2917 Handle<String> name,
2918 Handle<JSObject> receiver,
2919 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002920 Handle<JSFunction> value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002921 // ----------- S t a t e -------------
2922 // -- ra : return address
2923 // -- a0 : key
2924 // -- a1 : receiver
2925 // -----------------------------------
2926 Label miss;
2927
2928 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002929 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002930
2931 GenerateLoadConstant(receiver, holder, a1, a2, a3, t0, value, name, &miss);
2932 __ bind(&miss);
2933 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2934
2935 // Return the generated code.
2936 return GetCode(CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002937}
2938
2939
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002940Handle<Code> KeyedLoadStubCompiler::CompileLoadInterceptor(
2941 Handle<JSObject> receiver,
2942 Handle<JSObject> holder,
2943 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002944 // ----------- S t a t e -------------
2945 // -- ra : return address
2946 // -- a0 : key
2947 // -- a1 : receiver
2948 // -----------------------------------
2949 Label miss;
2950
2951 // Check the key is the cached one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002952 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002953
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002954 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002955 LookupPostInterceptor(holder, name, &lookup);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002956 GenerateLoadInterceptor(receiver, holder, &lookup, a1, a0, a2, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002957 &miss);
2958 __ bind(&miss);
2959 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2960
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002961 return GetCode(INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002962}
2963
2964
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002965Handle<Code> KeyedLoadStubCompiler::CompileLoadArrayLength(
2966 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002967 // ----------- S t a t e -------------
2968 // -- ra : return address
2969 // -- a0 : key
2970 // -- a1 : receiver
2971 // -----------------------------------
2972 Label miss;
2973
2974 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002975 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002976
2977 GenerateLoadArrayLength(masm(), a1, a2, &miss);
2978 __ bind(&miss);
2979 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2980
2981 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002982}
2983
2984
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002985Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength(
2986 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002987 // ----------- S t a t e -------------
2988 // -- ra : return address
2989 // -- a0 : key
2990 // -- a1 : receiver
2991 // -----------------------------------
2992 Label miss;
2993
2994 Counters* counters = masm()->isolate()->counters();
2995 __ IncrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
2996
2997 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002998 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002999
3000 GenerateLoadStringLength(masm(), a1, a2, a3, &miss, true);
3001 __ bind(&miss);
3002 __ DecrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
3003
3004 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3005
3006 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003007}
3008
3009
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003010Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype(
3011 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003012 // ----------- S t a t e -------------
3013 // -- ra : return address
3014 // -- a0 : key
3015 // -- a1 : receiver
3016 // -----------------------------------
3017 Label miss;
3018
3019 Counters* counters = masm()->isolate()->counters();
3020 __ IncrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
3021
3022 // Check the name hasn't changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003023 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003024
3025 GenerateLoadFunctionPrototype(masm(), a1, a2, a3, &miss);
3026 __ bind(&miss);
3027 __ DecrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
3028 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3029
3030 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003031}
3032
3033
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003034Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
3035 Handle<Map> receiver_map) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003036 // ----------- S t a t e -------------
3037 // -- ra : return address
3038 // -- a0 : key
3039 // -- a1 : receiver
3040 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003041 ElementsKind elements_kind = receiver_map->elements_kind();
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003042 Handle<Code> stub = KeyedLoadElementStub(elements_kind).GetCode();
3043
3044 __ DispatchMap(a1, a2, receiver_map, stub, DO_SMI_CHECK);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003045
3046 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
3047 __ Jump(ic, RelocInfo::CODE_TARGET);
3048
3049 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003050 return GetCode(NORMAL, factory()->empty_string());
danno@chromium.org40cb8782011-05-25 07:58:50 +00003051}
3052
3053
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003054Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
3055 MapHandleList* receiver_maps,
3056 CodeHandleList* handler_ics) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003057 // ----------- S t a t e -------------
3058 // -- ra : return address
3059 // -- a0 : key
3060 // -- a1 : receiver
3061 // -----------------------------------
3062 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003063 __ JumpIfSmi(a1, &miss);
3064
danno@chromium.org40cb8782011-05-25 07:58:50 +00003065 int receiver_count = receiver_maps->length();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003066 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003067 for (int current = 0; current < receiver_count; ++current) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003068 __ Jump(handler_ics->at(current), RelocInfo::CODE_TARGET,
3069 eq, a2, Operand(receiver_maps->at(current)));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003070 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003071
3072 __ bind(&miss);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003073 Handle<Code> miss_ic = isolate()->builtins()->KeyedLoadIC_Miss();
3074 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003075
3076 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003077 return GetCode(NORMAL, factory()->empty_string(), MEGAMORPHIC);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003078}
3079
3080
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003081Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +00003082 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003083 Handle<Map> transition,
3084 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003085 // ----------- S t a t e -------------
3086 // -- a0 : value
3087 // -- a1 : key
3088 // -- a2 : receiver
3089 // -- ra : return address
3090 // -----------------------------------
3091
3092 Label miss;
3093
3094 Counters* counters = masm()->isolate()->counters();
3095 __ IncrementCounter(counters->keyed_store_field(), 1, a3, t0);
3096
3097 // Check that the name has not changed.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003098 __ Branch(&miss, ne, a1, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003099
3100 // a3 is used as scratch register. a1 and a2 keep their values if a jump to
3101 // the miss label is generated.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003102 GenerateStoreField(masm(), object, index, transition, a2, a1, a3, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003103 __ bind(&miss);
3104
3105 __ DecrementCounter(counters->keyed_store_field(), 1, a3, t0);
3106 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss();
3107 __ Jump(ic, RelocInfo::CODE_TARGET);
3108
3109 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003110 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003111}
3112
3113
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003114Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
3115 Handle<Map> receiver_map) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003116 // ----------- S t a t e -------------
3117 // -- a0 : value
3118 // -- a1 : key
3119 // -- a2 : receiver
3120 // -- ra : return address
3121 // -- a3 : scratch
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003122 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003123 ElementsKind elements_kind = receiver_map->elements_kind();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003124 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003125 Handle<Code> stub =
yangguo@chromium.org56454712012-02-16 15:33:53 +00003126 KeyedStoreElementStub(is_js_array, elements_kind, grow_mode_).GetCode();
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003127
3128 __ DispatchMap(a2, a3, receiver_map, stub, DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003129
danno@chromium.org40cb8782011-05-25 07:58:50 +00003130 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003131 __ Jump(ic, RelocInfo::CODE_TARGET);
3132
3133 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003134 return GetCode(NORMAL, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00003135}
3136
3137
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003138Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
3139 MapHandleList* receiver_maps,
3140 CodeHandleList* handler_stubs,
3141 MapHandleList* transitioned_maps) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003142 // ----------- S t a t e -------------
3143 // -- a0 : value
3144 // -- a1 : key
3145 // -- a2 : receiver
3146 // -- ra : return address
3147 // -- a3 : scratch
3148 // -----------------------------------
3149 Label miss;
3150 __ JumpIfSmi(a2, &miss);
3151
3152 int receiver_count = receiver_maps->length();
3153 __ lw(a3, FieldMemOperand(a2, HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003154 for (int i = 0; i < receiver_count; ++i) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003155 if (transitioned_maps->at(i).is_null()) {
3156 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq,
3157 a3, Operand(receiver_maps->at(i)));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003158 } else {
3159 Label next_map;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003160 __ Branch(&next_map, ne, a3, Operand(receiver_maps->at(i)));
3161 __ li(a3, Operand(transitioned_maps->at(i)));
3162 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003163 __ bind(&next_map);
3164 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003165 }
3166
3167 __ bind(&miss);
3168 Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
3169 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3170
3171 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003172 return GetCode(NORMAL, factory()->empty_string(), MEGAMORPHIC);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003173}
3174
3175
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003176Handle<Code> ConstructStubCompiler::CompileConstructStub(
3177 Handle<JSFunction> function) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003178 // a0 : argc
3179 // a1 : constructor
3180 // ra : return address
3181 // [sp] : last argument
3182 Label generic_stub_call;
3183
3184 // Use t7 for holding undefined which is used in several places below.
3185 __ LoadRoot(t7, Heap::kUndefinedValueRootIndex);
3186
3187#ifdef ENABLE_DEBUGGER_SUPPORT
3188 // Check to see whether there are any break points in the function code. If
3189 // there are jump to the generic constructor stub which calls the actual
3190 // code for the function thereby hitting the break points.
3191 __ lw(t5, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3192 __ lw(a2, FieldMemOperand(t5, SharedFunctionInfo::kDebugInfoOffset));
3193 __ Branch(&generic_stub_call, ne, a2, Operand(t7));
3194#endif
3195
3196 // Load the initial map and verify that it is in fact a map.
3197 // a1: constructor function
3198 // t7: undefined
3199 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003200 __ JumpIfSmi(a2, &generic_stub_call);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003201 __ GetObjectType(a2, a3, t0);
3202 __ Branch(&generic_stub_call, ne, t0, Operand(MAP_TYPE));
3203
3204#ifdef DEBUG
3205 // Cannot construct functions this way.
3206 // a0: argc
3207 // a1: constructor function
3208 // a2: initial map
3209 // t7: undefined
3210 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
3211 __ Check(ne, "Function constructed by construct stub.",
3212 a3, Operand(JS_FUNCTION_TYPE));
3213#endif
3214
3215 // Now allocate the JSObject in new space.
3216 // a0: argc
3217 // a1: constructor function
3218 // a2: initial map
3219 // t7: undefined
3220 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003221 __ AllocateInNewSpace(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003222
3223 // Allocated the JSObject, now initialize the fields. Map is set to initial
3224 // map and properties and elements are set to empty fixed array.
3225 // a0: argc
3226 // a1: constructor function
3227 // a2: initial map
3228 // a3: object size (in words)
3229 // t4: JSObject (not tagged)
3230 // t7: undefined
3231 __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex);
3232 __ mov(t5, t4);
3233 __ sw(a2, MemOperand(t5, JSObject::kMapOffset));
3234 __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset));
3235 __ sw(t6, MemOperand(t5, JSObject::kElementsOffset));
3236 __ Addu(t5, t5, Operand(3 * kPointerSize));
3237 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
3238 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
3239 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
3240
3241
3242 // Calculate the location of the first argument. The stack contains only the
3243 // argc arguments.
3244 __ sll(a1, a0, kPointerSizeLog2);
3245 __ Addu(a1, a1, sp);
3246
3247 // Fill all the in-object properties with undefined.
3248 // a0: argc
3249 // a1: first argument
3250 // a3: object size (in words)
3251 // t4: JSObject (not tagged)
3252 // t5: First in-object property of JSObject (not tagged)
3253 // t7: undefined
3254 // Fill the initialized properties with a constant value or a passed argument
3255 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003256 Handle<SharedFunctionInfo> shared(function->shared());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003257 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3258 if (shared->IsThisPropertyAssignmentArgument(i)) {
3259 Label not_passed, next;
3260 // Check if the argument assigned to the property is actually passed.
3261 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3262 __ Branch(&not_passed, less_equal, a0, Operand(arg_number));
3263 // Argument passed - find it on the stack.
3264 __ lw(a2, MemOperand(a1, (arg_number + 1) * -kPointerSize));
3265 __ sw(a2, MemOperand(t5));
3266 __ Addu(t5, t5, kPointerSize);
3267 __ jmp(&next);
3268 __ bind(&not_passed);
3269 // Set the property to undefined.
3270 __ sw(t7, MemOperand(t5));
3271 __ Addu(t5, t5, Operand(kPointerSize));
3272 __ bind(&next);
3273 } else {
3274 // Set the property to the constant value.
3275 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
3276 __ li(a2, Operand(constant));
3277 __ sw(a2, MemOperand(t5));
3278 __ Addu(t5, t5, kPointerSize);
3279 }
3280 }
3281
3282 // Fill the unused in-object property fields with undefined.
3283 ASSERT(function->has_initial_map());
3284 for (int i = shared->this_property_assignments_count();
3285 i < function->initial_map()->inobject_properties();
3286 i++) {
3287 __ sw(t7, MemOperand(t5));
3288 __ Addu(t5, t5, kPointerSize);
3289 }
3290
3291 // a0: argc
3292 // t4: JSObject (not tagged)
3293 // Move argc to a1 and the JSObject to return to v0 and tag it.
3294 __ mov(a1, a0);
3295 __ mov(v0, t4);
3296 __ Or(v0, v0, Operand(kHeapObjectTag));
3297
3298 // v0: JSObject
3299 // a1: argc
3300 // Remove caller arguments and receiver from the stack and return.
3301 __ sll(t0, a1, kPointerSizeLog2);
3302 __ Addu(sp, sp, t0);
3303 __ Addu(sp, sp, Operand(kPointerSize));
3304 Counters* counters = masm()->isolate()->counters();
3305 __ IncrementCounter(counters->constructed_objects(), 1, a1, a2);
3306 __ IncrementCounter(counters->constructed_objects_stub(), 1, a1, a2);
3307 __ Ret();
3308
3309 // Jump to the generic stub in case the specialized code cannot handle the
3310 // construction.
3311 __ bind(&generic_stub_call);
3312 Handle<Code> generic_construct_stub =
3313 masm()->isolate()->builtins()->JSConstructStubGeneric();
3314 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
3315
3316 // Return the generated code.
3317 return GetCode();
3318}
3319
3320
danno@chromium.org40cb8782011-05-25 07:58:50 +00003321#undef __
3322#define __ ACCESS_MASM(masm)
3323
3324
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003325void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3326 MacroAssembler* masm) {
3327 // ---------- S t a t e --------------
3328 // -- ra : return address
3329 // -- a0 : key
3330 // -- a1 : receiver
3331 // -----------------------------------
3332 Label slow, miss_force_generic;
3333
3334 Register key = a0;
3335 Register receiver = a1;
3336
3337 __ JumpIfNotSmi(key, &miss_force_generic);
3338 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
3339 __ sra(a2, a0, kSmiTagSize);
3340 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
3341 __ Ret();
3342
3343 // Slow case, key and receiver still in a0 and a1.
3344 __ bind(&slow);
3345 __ IncrementCounter(
3346 masm->isolate()->counters()->keyed_load_external_array_slow(),
3347 1, a2, a3);
3348 // Entry registers are intact.
3349 // ---------- S t a t e --------------
3350 // -- ra : return address
3351 // -- a0 : key
3352 // -- a1 : receiver
3353 // -----------------------------------
3354 Handle<Code> slow_ic =
3355 masm->isolate()->builtins()->KeyedLoadIC_Slow();
3356 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
3357
3358 // Miss case, call the runtime.
3359 __ bind(&miss_force_generic);
3360
3361 // ---------- S t a t e --------------
3362 // -- ra : return address
3363 // -- a0 : key
3364 // -- a1 : receiver
3365 // -----------------------------------
3366
3367 Handle<Code> miss_ic =
3368 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3369 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3370}
3371
3372
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003373static bool IsElementTypeSigned(ElementsKind elements_kind) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003374 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003375 case EXTERNAL_BYTE_ELEMENTS:
3376 case EXTERNAL_SHORT_ELEMENTS:
3377 case EXTERNAL_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003378 return true;
3379
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003380 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3381 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3382 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3383 case EXTERNAL_PIXEL_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003384 return false;
3385
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003386 case EXTERNAL_FLOAT_ELEMENTS:
3387 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003388 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003389 case FAST_ELEMENTS:
3390 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003391 case FAST_HOLEY_SMI_ELEMENTS:
3392 case FAST_HOLEY_ELEMENTS:
3393 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003394 case DICTIONARY_ELEMENTS:
3395 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003396 UNREACHABLE();
3397 return false;
3398 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003399 return false;
lrn@chromium.org7516f052011-03-30 08:52:27 +00003400}
3401
3402
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003403static void GenerateSmiKeyCheck(MacroAssembler* masm,
3404 Register key,
3405 Register scratch0,
3406 Register scratch1,
3407 FPURegister double_scratch0,
3408 Label* fail) {
3409 if (CpuFeatures::IsSupported(FPU)) {
3410 CpuFeatures::Scope scope(FPU);
3411 Label key_ok;
3412 // Check for smi or a smi inside a heap number. We convert the heap
3413 // number and check if the conversion is exact and fits into the smi
3414 // range.
3415 __ JumpIfSmi(key, &key_ok);
3416 __ CheckMap(key,
3417 scratch0,
3418 Heap::kHeapNumberMapRootIndex,
3419 fail,
3420 DONT_DO_SMI_CHECK);
3421 __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
3422 __ EmitFPUTruncate(kRoundToZero,
3423 double_scratch0,
3424 double_scratch0,
3425 scratch0,
3426 scratch1,
3427 kCheckForInexactConversion);
3428
3429 __ Branch(fail, ne, scratch1, Operand(zero_reg));
3430
3431 __ mfc1(scratch0, double_scratch0);
3432 __ SmiTagCheckOverflow(key, scratch0, scratch1);
3433 __ BranchOnOverflow(fail, scratch1);
3434 __ bind(&key_ok);
3435 } else {
3436 // Check that the key is a smi.
3437 __ JumpIfNotSmi(key, fail);
3438 }
3439}
3440
3441
danno@chromium.org40cb8782011-05-25 07:58:50 +00003442void KeyedLoadStubCompiler::GenerateLoadExternalArray(
3443 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003444 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003445 // ---------- S t a t e --------------
3446 // -- ra : return address
3447 // -- a0 : key
3448 // -- a1 : receiver
3449 // -----------------------------------
danno@chromium.org40cb8782011-05-25 07:58:50 +00003450 Label miss_force_generic, slow, failed_allocation;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003451
3452 Register key = a0;
3453 Register receiver = a1;
3454
danno@chromium.org40cb8782011-05-25 07:58:50 +00003455 // This stub is meant to be tail-jumped to, the receiver must already
3456 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003457
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003458 // Check that the key is a smi or a heap number convertible to a smi.
3459 GenerateSmiKeyCheck(masm, key, t0, t1, f2, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003460
3461 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3462 // a3: elements array
3463
3464 // Check that the index is in range.
3465 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3466 __ sra(t2, key, kSmiTagSize);
3467 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003468 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003469
3470 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3471 // a3: base pointer of external storage
3472
3473 // We are not untagging smi key and instead work with it
3474 // as if it was premultiplied by 2.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003475 STATIC_ASSERT((kSmiTag == 0) && (kSmiTagSize == 1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003476
3477 Register value = a2;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003478 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003479 case EXTERNAL_BYTE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003480 __ srl(t2, key, 1);
3481 __ addu(t3, a3, t2);
3482 __ lb(value, MemOperand(t3, 0));
3483 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003484 case EXTERNAL_PIXEL_ELEMENTS:
3485 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003486 __ srl(t2, key, 1);
3487 __ addu(t3, a3, t2);
3488 __ lbu(value, MemOperand(t3, 0));
3489 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003490 case EXTERNAL_SHORT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003491 __ addu(t3, a3, key);
3492 __ lh(value, MemOperand(t3, 0));
3493 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003494 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003495 __ addu(t3, a3, key);
3496 __ lhu(value, MemOperand(t3, 0));
3497 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003498 case EXTERNAL_INT_ELEMENTS:
3499 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003500 __ sll(t2, key, 1);
3501 __ addu(t3, a3, t2);
3502 __ lw(value, MemOperand(t3, 0));
3503 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003504 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003505 __ sll(t3, t2, 2);
3506 __ addu(t3, a3, t3);
3507 if (CpuFeatures::IsSupported(FPU)) {
3508 CpuFeatures::Scope scope(FPU);
3509 __ lwc1(f0, MemOperand(t3, 0));
3510 } else {
3511 __ lw(value, MemOperand(t3, 0));
3512 }
3513 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003514 case EXTERNAL_DOUBLE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003515 __ sll(t2, key, 2);
3516 __ addu(t3, a3, t2);
3517 if (CpuFeatures::IsSupported(FPU)) {
3518 CpuFeatures::Scope scope(FPU);
3519 __ ldc1(f0, MemOperand(t3, 0));
3520 } else {
3521 // t3: pointer to the beginning of the double we want to load.
3522 __ lw(a2, MemOperand(t3, 0));
3523 __ lw(a3, MemOperand(t3, Register::kSizeInBytes));
3524 }
3525 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003526 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003527 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003528 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003529 case FAST_HOLEY_ELEMENTS:
3530 case FAST_HOLEY_SMI_ELEMENTS:
3531 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003532 case DICTIONARY_ELEMENTS:
3533 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003534 UNREACHABLE();
3535 break;
3536 }
3537
3538 // For integer array types:
3539 // a2: value
3540 // For float array type:
3541 // f0: value (if FPU is supported)
3542 // a2: value (if FPU is not supported)
3543 // For double array type:
3544 // f0: value (if FPU is supported)
3545 // a2/a3: value (if FPU is not supported)
3546
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003547 if (elements_kind == EXTERNAL_INT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003548 // For the Int and UnsignedInt array types, we need to see whether
3549 // the value can be represented in a Smi. If not, we need to convert
3550 // it to a HeapNumber.
3551 Label box_int;
3552 __ Subu(t3, value, Operand(0xC0000000)); // Non-smi value gives neg result.
3553 __ Branch(&box_int, lt, t3, Operand(zero_reg));
3554 // Tag integer as smi and return it.
3555 __ sll(v0, value, kSmiTagSize);
3556 __ Ret();
3557
3558 __ bind(&box_int);
3559 // Allocate a HeapNumber for the result and perform int-to-double
3560 // conversion.
3561 // The arm version uses a temporary here to save r0, but we don't need to
3562 // (a0 is not modified).
3563 __ LoadRoot(t1, Heap::kHeapNumberMapRootIndex);
3564 __ AllocateHeapNumber(v0, a3, t0, t1, &slow);
3565
3566 if (CpuFeatures::IsSupported(FPU)) {
3567 CpuFeatures::Scope scope(FPU);
3568 __ mtc1(value, f0);
3569 __ cvt_d_w(f0, f0);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00003570 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003571 __ Ret();
3572 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003573 Register dst1 = t2;
3574 Register dst2 = t3;
3575 FloatingPointHelper::Destination dest =
3576 FloatingPointHelper::kCoreRegisters;
3577 FloatingPointHelper::ConvertIntToDouble(masm,
3578 value,
3579 dest,
3580 f0,
3581 dst1,
3582 dst2,
3583 t1,
3584 f2);
3585 __ sw(dst1, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3586 __ sw(dst2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3587 __ Ret();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003588 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003589 } else if (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003590 // The test is different for unsigned int values. Since we need
3591 // the value to be in the range of a positive smi, we can't
3592 // handle either of the top two bits being set in the value.
3593 if (CpuFeatures::IsSupported(FPU)) {
3594 CpuFeatures::Scope scope(FPU);
3595 Label pl_box_int;
3596 __ And(t2, value, Operand(0xC0000000));
3597 __ Branch(&pl_box_int, ne, t2, Operand(zero_reg));
3598
3599 // It can fit in an Smi.
3600 // Tag integer as smi and return it.
3601 __ sll(v0, value, kSmiTagSize);
3602 __ Ret();
3603
3604 __ bind(&pl_box_int);
3605 // Allocate a HeapNumber for the result and perform int-to-double
3606 // conversion. Don't use a0 and a1 as AllocateHeapNumber clobbers all
3607 // registers - also when jumping due to exhausted young space.
3608 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3609 __ AllocateHeapNumber(v0, t2, t3, t6, &slow);
3610
3611 // This is replaced by a macro:
3612 // __ mtc1(value, f0); // LS 32-bits.
3613 // __ mtc1(zero_reg, f1); // MS 32-bits are all zero.
3614 // __ cvt_d_l(f0, f0); // Use 64 bit conv to get correct unsigned 32-bit.
3615
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003616 __ Cvt_d_uw(f0, value, f22);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003617
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00003618 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003619
3620 __ Ret();
3621 } else {
3622 // Check whether unsigned integer fits into smi.
3623 Label box_int_0, box_int_1, done;
3624 __ And(t2, value, Operand(0x80000000));
3625 __ Branch(&box_int_0, ne, t2, Operand(zero_reg));
3626 __ And(t2, value, Operand(0x40000000));
3627 __ Branch(&box_int_1, ne, t2, Operand(zero_reg));
3628
3629 // Tag integer as smi and return it.
3630 __ sll(v0, value, kSmiTagSize);
3631 __ Ret();
3632
3633 Register hiword = value; // a2.
3634 Register loword = a3;
3635
3636 __ bind(&box_int_0);
3637 // Integer does not have leading zeros.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003638 GenerateUInt2Double(masm, hiword, loword, t0, 0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003639 __ Branch(&done);
3640
3641 __ bind(&box_int_1);
3642 // Integer has one leading zero.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003643 GenerateUInt2Double(masm, hiword, loword, t0, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003644
3645
3646 __ bind(&done);
3647 // Integer was converted to double in registers hiword:loword.
3648 // Wrap it into a HeapNumber. Don't use a0 and a1 as AllocateHeapNumber
3649 // clobbers all registers - also when jumping due to exhausted young
3650 // space.
3651 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3652 __ AllocateHeapNumber(t2, t3, t5, t6, &slow);
3653
3654 __ sw(hiword, FieldMemOperand(t2, HeapNumber::kExponentOffset));
3655 __ sw(loword, FieldMemOperand(t2, HeapNumber::kMantissaOffset));
3656
3657 __ mov(v0, t2);
3658 __ Ret();
3659 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003660 } else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003661 // For the floating-point array type, we need to always allocate a
3662 // HeapNumber.
3663 if (CpuFeatures::IsSupported(FPU)) {
3664 CpuFeatures::Scope scope(FPU);
3665 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3666 // AllocateHeapNumber clobbers all registers - also when jumping due to
3667 // exhausted young space.
3668 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3669 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3670 // The float (single) value is already in fpu reg f0 (if we use float).
3671 __ cvt_d_s(f0, f0);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00003672 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003673 __ Ret();
3674 } else {
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 // FPU is not available, do manual single to double conversion.
3681
3682 // a2: floating point value (binary32).
3683 // v0: heap number for result
3684
3685 // Extract mantissa to t4.
3686 __ And(t4, value, Operand(kBinary32MantissaMask));
3687
3688 // Extract exponent to t5.
3689 __ srl(t5, value, kBinary32MantissaBits);
3690 __ And(t5, t5, Operand(kBinary32ExponentMask >> kBinary32MantissaBits));
3691
3692 Label exponent_rebiased;
3693 __ Branch(&exponent_rebiased, eq, t5, Operand(zero_reg));
3694
3695 __ li(t0, 0x7ff);
3696 __ Xor(t1, t5, Operand(0xFF));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003697 __ Movz(t5, t0, t1); // Set t5 to 0x7ff only if t5 is equal to 0xff.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003698 __ Branch(&exponent_rebiased, eq, t0, Operand(0xff));
3699
3700 // Rebias exponent.
3701 __ Addu(t5,
3702 t5,
3703 Operand(-kBinary32ExponentBias + HeapNumber::kExponentBias));
3704
3705 __ bind(&exponent_rebiased);
3706 __ And(a2, value, Operand(kBinary32SignMask));
3707 value = no_reg;
3708 __ sll(t0, t5, HeapNumber::kMantissaBitsInTopWord);
3709 __ or_(a2, a2, t0);
3710
3711 // Shift mantissa.
3712 static const int kMantissaShiftForHiWord =
3713 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3714
3715 static const int kMantissaShiftForLoWord =
3716 kBitsPerInt - kMantissaShiftForHiWord;
3717
3718 __ srl(t0, t4, kMantissaShiftForHiWord);
3719 __ or_(a2, a2, t0);
3720 __ sll(a0, t4, kMantissaShiftForLoWord);
3721
3722 __ sw(a2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3723 __ sw(a0, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3724 __ Ret();
3725 }
3726
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003727 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003728 if (CpuFeatures::IsSupported(FPU)) {
3729 CpuFeatures::Scope scope(FPU);
3730 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3731 // AllocateHeapNumber clobbers all registers - also when jumping due to
3732 // exhausted young space.
3733 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3734 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3735 // The double value is already in f0
3736 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
3737 __ Ret();
3738 } else {
3739 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3740 // AllocateHeapNumber clobbers all registers - also when jumping due to
3741 // exhausted young space.
3742 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3743 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3744
3745 __ sw(a2, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3746 __ sw(a3, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3747 __ Ret();
3748 }
3749
3750 } else {
3751 // Tag integer as smi and return it.
3752 __ sll(v0, value, kSmiTagSize);
3753 __ Ret();
3754 }
3755
3756 // Slow case, key and receiver still in a0 and a1.
3757 __ bind(&slow);
3758 __ IncrementCounter(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003759 masm->isolate()->counters()->keyed_load_external_array_slow(),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003760 1, a2, a3);
3761
3762 // ---------- S t a t e --------------
3763 // -- ra : return address
3764 // -- a0 : key
3765 // -- a1 : receiver
3766 // -----------------------------------
3767
3768 __ Push(a1, a0);
3769
3770 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
3771
danno@chromium.org40cb8782011-05-25 07:58:50 +00003772 __ bind(&miss_force_generic);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003773 Handle<Code> stub =
3774 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3775 __ Jump(stub, RelocInfo::CODE_TARGET);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003776}
3777
3778
danno@chromium.org40cb8782011-05-25 07:58:50 +00003779void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3780 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003781 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003782 // ---------- S t a t e --------------
3783 // -- a0 : value
3784 // -- a1 : key
3785 // -- a2 : receiver
3786 // -- ra : return address
3787 // -----------------------------------
3788
danno@chromium.org40cb8782011-05-25 07:58:50 +00003789 Label slow, check_heap_number, miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003790
3791 // Register usage.
3792 Register value = a0;
3793 Register key = a1;
3794 Register receiver = a2;
3795 // a3 mostly holds the elements array or the destination external array.
3796
danno@chromium.org40cb8782011-05-25 07:58:50 +00003797 // This stub is meant to be tail-jumped to, the receiver must already
3798 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003799
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003800 // Check that the key is a smi or a heap number convertible to a smi.
3801 GenerateSmiKeyCheck(masm, key, t0, t1, f2, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003802
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003803 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3804
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003805 // Check that the index is in range.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003806 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3807 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003808 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003809
3810 // Handle both smis and HeapNumbers in the fast path. Go to the
3811 // runtime for all other kinds of values.
3812 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003813
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003814 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003815 // Double to pixel conversion is only implemented in the runtime for now.
3816 __ JumpIfNotSmi(value, &slow);
3817 } else {
3818 __ JumpIfNotSmi(value, &check_heap_number);
3819 }
3820 __ SmiUntag(t1, value);
3821 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3822
3823 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003824 // t1: value (integer).
3825
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003826 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003827 case EXTERNAL_PIXEL_ELEMENTS: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003828 // Clamp the value to [0..255].
3829 // v0 is used as a scratch register here.
3830 Label done;
3831 __ li(v0, Operand(255));
3832 // Normal branch: nop in delay slot.
3833 __ Branch(&done, gt, t1, Operand(v0));
3834 // Use delay slot in this branch.
3835 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg));
3836 __ mov(v0, zero_reg); // In delay slot.
3837 __ mov(v0, t1); // Value is in range 0..255.
3838 __ bind(&done);
3839 __ mov(t1, v0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003840
3841 __ srl(t8, key, 1);
3842 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003843 __ sb(t1, MemOperand(t8, 0));
3844 }
3845 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003846 case EXTERNAL_BYTE_ELEMENTS:
3847 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003848 __ srl(t8, key, 1);
3849 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003850 __ sb(t1, MemOperand(t8, 0));
3851 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003852 case EXTERNAL_SHORT_ELEMENTS:
3853 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003854 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003855 __ sh(t1, MemOperand(t8, 0));
3856 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003857 case EXTERNAL_INT_ELEMENTS:
3858 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003859 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003860 __ addu(t8, a3, t8);
3861 __ sw(t1, MemOperand(t8, 0));
3862 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003863 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003864 // Perform int-to-float conversion and store to memory.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003865 __ SmiUntag(t0, key);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003866 StoreIntAsFloat(masm, a3, t0, t1, t2, t3, t4);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003867 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003868 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003869 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003870 __ addu(a3, a3, t8);
3871 // a3: effective address of the double element
3872 FloatingPointHelper::Destination destination;
3873 if (CpuFeatures::IsSupported(FPU)) {
3874 destination = FloatingPointHelper::kFPURegisters;
3875 } else {
3876 destination = FloatingPointHelper::kCoreRegisters;
3877 }
3878 FloatingPointHelper::ConvertIntToDouble(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003879 masm, t1, destination,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003880 f0, t2, t3, // These are: double_dst, dst1, dst2.
3881 t0, f2); // These are: scratch2, single_scratch.
3882 if (destination == FloatingPointHelper::kFPURegisters) {
3883 CpuFeatures::Scope scope(FPU);
3884 __ sdc1(f0, MemOperand(a3, 0));
3885 } else {
3886 __ sw(t2, MemOperand(a3, 0));
3887 __ sw(t3, MemOperand(a3, Register::kSizeInBytes));
3888 }
3889 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003890 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003891 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003892 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003893 case FAST_HOLEY_ELEMENTS:
3894 case FAST_HOLEY_SMI_ELEMENTS:
3895 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003896 case DICTIONARY_ELEMENTS:
3897 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003898 UNREACHABLE();
3899 break;
3900 }
3901
3902 // Entry registers are intact, a0 holds the value which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003903 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003904 __ Ret();
3905
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003906 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003907 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003908 __ bind(&check_heap_number);
3909 __ GetObjectType(value, t1, t2);
3910 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE));
3911
3912 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3913
3914 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003915
3916 // The WebGL specification leaves the behavior of storing NaN and
3917 // +/-Infinity into integer arrays basically undefined. For more
3918 // reproducible behavior, convert these to zero.
3919
3920 if (CpuFeatures::IsSupported(FPU)) {
3921 CpuFeatures::Scope scope(FPU);
3922
3923 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
3924
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003925 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003926 __ cvt_s_d(f0, f0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003927 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003928 __ addu(t8, a3, t8);
3929 __ swc1(f0, MemOperand(t8, 0));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003930 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003931 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003932 __ addu(t8, a3, t8);
3933 __ sdc1(f0, MemOperand(t8, 0));
3934 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003935 __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003936
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003937 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003938 case EXTERNAL_BYTE_ELEMENTS:
3939 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003940 __ srl(t8, key, 1);
3941 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003942 __ sb(t3, MemOperand(t8, 0));
3943 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003944 case EXTERNAL_SHORT_ELEMENTS:
3945 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003946 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003947 __ sh(t3, MemOperand(t8, 0));
3948 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003949 case EXTERNAL_INT_ELEMENTS:
3950 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003951 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003952 __ addu(t8, a3, t8);
3953 __ sw(t3, MemOperand(t8, 0));
3954 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003955 case EXTERNAL_PIXEL_ELEMENTS:
3956 case EXTERNAL_FLOAT_ELEMENTS:
3957 case EXTERNAL_DOUBLE_ELEMENTS:
3958 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003959 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003960 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003961 case FAST_HOLEY_ELEMENTS:
3962 case FAST_HOLEY_SMI_ELEMENTS:
3963 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003964 case DICTIONARY_ELEMENTS:
3965 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003966 UNREACHABLE();
3967 break;
3968 }
3969 }
3970
3971 // Entry registers are intact, a0 holds the value
3972 // which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003973 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003974 __ Ret();
3975 } else {
3976 // FPU is not available, do manual conversions.
3977
3978 __ lw(t3, FieldMemOperand(value, HeapNumber::kExponentOffset));
3979 __ lw(t4, FieldMemOperand(value, HeapNumber::kMantissaOffset));
3980
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003981 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003982 Label done, nan_or_infinity_or_zero;
3983 static const int kMantissaInHiWordShift =
3984 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3985
3986 static const int kMantissaInLoWordShift =
3987 kBitsPerInt - kMantissaInHiWordShift;
3988
3989 // Test for all special exponent values: zeros, subnormal numbers, NaNs
3990 // and infinities. All these should be converted to 0.
3991 __ li(t5, HeapNumber::kExponentMask);
3992 __ and_(t6, t3, t5);
3993 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(zero_reg));
3994
3995 __ xor_(t1, t6, t5);
3996 __ li(t2, kBinary32ExponentMask);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003997 __ Movz(t6, t2, t1); // Only if t6 is equal to t5.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003998 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(t5));
3999
4000 // Rebias exponent.
4001 __ srl(t6, t6, HeapNumber::kExponentShift);
4002 __ Addu(t6,
4003 t6,
4004 Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
4005
4006 __ li(t1, Operand(kBinary32MaxExponent));
4007 __ Slt(t1, t1, t6);
4008 __ And(t2, t3, Operand(HeapNumber::kSignMask));
4009 __ Or(t2, t2, Operand(kBinary32ExponentMask));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004010 __ Movn(t3, t2, t1); // Only if t6 is gt kBinary32MaxExponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004011 __ Branch(&done, gt, t6, Operand(kBinary32MaxExponent));
4012
4013 __ Slt(t1, t6, Operand(kBinary32MinExponent));
4014 __ And(t2, t3, Operand(HeapNumber::kSignMask));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004015 __ Movn(t3, t2, t1); // Only if t6 is lt kBinary32MinExponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004016 __ Branch(&done, lt, t6, Operand(kBinary32MinExponent));
4017
4018 __ And(t7, t3, Operand(HeapNumber::kSignMask));
4019 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4020 __ sll(t3, t3, kMantissaInHiWordShift);
4021 __ or_(t7, t7, t3);
4022 __ srl(t4, t4, kMantissaInLoWordShift);
4023 __ or_(t7, t7, t4);
4024 __ sll(t6, t6, kBinary32ExponentShift);
4025 __ or_(t3, t7, t6);
4026
4027 __ bind(&done);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004028 __ sll(t9, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004029 __ addu(t9, a2, t9);
4030 __ sw(t3, MemOperand(t9, 0));
4031
4032 // Entry registers are intact, a0 holds the value which is the return
4033 // value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004034 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004035 __ Ret();
4036
4037 __ bind(&nan_or_infinity_or_zero);
4038 __ And(t7, t3, Operand(HeapNumber::kSignMask));
4039 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4040 __ or_(t6, t6, t7);
4041 __ sll(t3, t3, kMantissaInHiWordShift);
4042 __ or_(t6, t6, t3);
4043 __ srl(t4, t4, kMantissaInLoWordShift);
4044 __ or_(t3, t6, t4);
4045 __ Branch(&done);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004046 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004047 __ sll(t8, t0, 3);
4048 __ addu(t8, a3, t8);
4049 // t8: effective address of destination element.
4050 __ sw(t4, MemOperand(t8, 0));
4051 __ sw(t3, MemOperand(t8, Register::kSizeInBytes));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004052 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004053 __ Ret();
4054 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004055 bool is_signed_type = IsElementTypeSigned(elements_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004056 int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
4057 int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
4058
4059 Label done, sign;
4060
4061 // Test for all special exponent values: zeros, subnormal numbers, NaNs
4062 // and infinities. All these should be converted to 0.
4063 __ li(t5, HeapNumber::kExponentMask);
4064 __ and_(t6, t3, t5);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004065 __ Movz(t3, zero_reg, t6); // Only if t6 is equal to zero.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004066 __ Branch(&done, eq, t6, Operand(zero_reg));
4067
4068 __ xor_(t2, t6, t5);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004069 __ Movz(t3, zero_reg, t2); // Only if t6 is equal to t5.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004070 __ Branch(&done, eq, t6, Operand(t5));
4071
4072 // Unbias exponent.
4073 __ srl(t6, t6, HeapNumber::kExponentShift);
4074 __ Subu(t6, t6, Operand(HeapNumber::kExponentBias));
4075 // If exponent is negative then result is 0.
4076 __ slt(t2, t6, zero_reg);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004077 __ Movn(t3, zero_reg, t2); // Only if exponent is negative.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004078 __ Branch(&done, lt, t6, Operand(zero_reg));
4079
4080 // If exponent is too big then result is minimal value.
4081 __ slti(t1, t6, meaningfull_bits - 1);
4082 __ li(t2, min_value);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004083 __ Movz(t3, t2, t1); // Only if t6 is ge meaningfull_bits - 1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004084 __ Branch(&done, ge, t6, Operand(meaningfull_bits - 1));
4085
4086 __ And(t5, t3, Operand(HeapNumber::kSignMask));
4087 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4088 __ Or(t3, t3, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
4089
4090 __ li(t9, HeapNumber::kMantissaBitsInTopWord);
4091 __ subu(t6, t9, t6);
4092 __ slt(t1, t6, zero_reg);
4093 __ srlv(t2, t3, t6);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004094 __ Movz(t3, t2, t1); // Only if t6 is positive.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004095 __ Branch(&sign, ge, t6, Operand(zero_reg));
4096
4097 __ subu(t6, zero_reg, t6);
4098 __ sllv(t3, t3, t6);
4099 __ li(t9, meaningfull_bits);
4100 __ subu(t6, t9, t6);
4101 __ srlv(t4, t4, t6);
4102 __ or_(t3, t3, t4);
4103
4104 __ bind(&sign);
4105 __ subu(t2, t3, zero_reg);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004106 __ Movz(t3, t2, t5); // Only if t5 is zero.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004107
4108 __ bind(&done);
4109
4110 // Result is in t3.
4111 // This switch block should be exactly the same as above (FPU mode).
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004112 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004113 case EXTERNAL_BYTE_ELEMENTS:
4114 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004115 __ srl(t8, key, 1);
4116 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004117 __ sb(t3, MemOperand(t8, 0));
4118 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004119 case EXTERNAL_SHORT_ELEMENTS:
4120 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004121 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004122 __ sh(t3, MemOperand(t8, 0));
4123 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004124 case EXTERNAL_INT_ELEMENTS:
4125 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004126 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004127 __ addu(t8, a3, t8);
4128 __ sw(t3, MemOperand(t8, 0));
4129 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004130 case EXTERNAL_PIXEL_ELEMENTS:
4131 case EXTERNAL_FLOAT_ELEMENTS:
4132 case EXTERNAL_DOUBLE_ELEMENTS:
4133 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004134 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004135 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004136 case FAST_HOLEY_ELEMENTS:
4137 case FAST_HOLEY_SMI_ELEMENTS:
4138 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004139 case DICTIONARY_ELEMENTS:
4140 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004141 UNREACHABLE();
4142 break;
4143 }
4144 }
4145 }
4146 }
4147
danno@chromium.org40cb8782011-05-25 07:58:50 +00004148 // Slow case, key and receiver still in a0 and a1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004149 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004150 __ IncrementCounter(
4151 masm->isolate()->counters()->keyed_load_external_array_slow(),
4152 1, a2, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004153 // Entry registers are intact.
4154 // ---------- S t a t e --------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004155 // -- ra : return address
danno@chromium.org40cb8782011-05-25 07:58:50 +00004156 // -- a0 : key
4157 // -- a1 : receiver
4158 // -----------------------------------
4159 Handle<Code> slow_ic =
4160 masm->isolate()->builtins()->KeyedStoreIC_Slow();
4161 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4162
4163 // Miss case, call the runtime.
4164 __ bind(&miss_force_generic);
4165
4166 // ---------- S t a t e --------------
4167 // -- ra : return address
4168 // -- a0 : key
4169 // -- a1 : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004170 // -----------------------------------
4171
danno@chromium.org40cb8782011-05-25 07:58:50 +00004172 Handle<Code> miss_ic =
4173 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4174 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
4175}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004176
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004177
danno@chromium.org40cb8782011-05-25 07:58:50 +00004178void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
4179 // ----------- S t a t e -------------
4180 // -- ra : return address
4181 // -- a0 : key
4182 // -- a1 : receiver
4183 // -----------------------------------
4184 Label miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004185
danno@chromium.org40cb8782011-05-25 07:58:50 +00004186 // This stub is meant to be tail-jumped to, the receiver must already
4187 // have been verified by the caller to not be a smi.
4188
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004189 // Check that the key is a smi or a heap number convertible to a smi.
4190 GenerateSmiKeyCheck(masm, a0, t0, t1, f2, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004191
4192 // Get the elements array.
4193 __ lw(a2, FieldMemOperand(a1, JSObject::kElementsOffset));
4194 __ AssertFastElements(a2);
4195
4196 // Check that the key is within bounds.
4197 __ lw(a3, FieldMemOperand(a2, FixedArray::kLengthOffset));
ulan@chromium.org6ff65142012-03-21 09:52:17 +00004198 __ Branch(USE_DELAY_SLOT, &miss_force_generic, hs, a0, Operand(a3));
danno@chromium.org40cb8782011-05-25 07:58:50 +00004199
4200 // Load the result and make sure it's not the hole.
4201 __ Addu(a3, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004202 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004203 __ sll(t0, a0, kPointerSizeLog2 - kSmiTagSize);
4204 __ Addu(t0, t0, a3);
4205 __ lw(t0, MemOperand(t0));
4206 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
4207 __ Branch(&miss_force_generic, eq, t0, Operand(t1));
ulan@chromium.org6ff65142012-03-21 09:52:17 +00004208 __ Ret(USE_DELAY_SLOT);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004209 __ mov(v0, t0);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004210
4211 __ bind(&miss_force_generic);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004212 Handle<Code> stub =
4213 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4214 __ Jump(stub, RelocInfo::CODE_TARGET);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004215}
4216
4217
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004218void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
4219 MacroAssembler* masm) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004220 // ----------- S t a t e -------------
4221 // -- ra : return address
4222 // -- a0 : key
4223 // -- a1 : receiver
4224 // -----------------------------------
4225 Label miss_force_generic, slow_allocate_heapnumber;
4226
4227 Register key_reg = a0;
4228 Register receiver_reg = a1;
4229 Register elements_reg = a2;
4230 Register heap_number_reg = a2;
4231 Register indexed_double_offset = a3;
4232 Register scratch = t0;
4233 Register scratch2 = t1;
4234 Register scratch3 = t2;
4235 Register heap_number_map = t3;
4236
4237 // This stub is meant to be tail-jumped to, the receiver must already
4238 // have been verified by the caller to not be a smi.
4239
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004240 // Check that the key is a smi or a heap number convertible to a smi.
4241 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004242
4243 // Get the elements array.
4244 __ lw(elements_reg,
4245 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4246
4247 // Check that the key is within bounds.
4248 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4249 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4250
4251 // Load the upper word of the double in the fixed array and test for NaN.
4252 __ sll(scratch2, key_reg, kDoubleSizeLog2 - kSmiTagSize);
4253 __ Addu(indexed_double_offset, elements_reg, Operand(scratch2));
4254 uint32_t upper_32_offset = FixedArray::kHeaderSize + sizeof(kHoleNanLower32);
4255 __ lw(scratch, FieldMemOperand(indexed_double_offset, upper_32_offset));
4256 __ Branch(&miss_force_generic, eq, scratch, Operand(kHoleNanUpper32));
4257
4258 // Non-NaN. Allocate a new heap number and copy the double value into it.
4259 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
4260 __ AllocateHeapNumber(heap_number_reg, scratch2, scratch3,
4261 heap_number_map, &slow_allocate_heapnumber);
4262
4263 // Don't need to reload the upper 32 bits of the double, it's already in
4264 // scratch.
4265 __ sw(scratch, FieldMemOperand(heap_number_reg,
4266 HeapNumber::kExponentOffset));
4267 __ lw(scratch, FieldMemOperand(indexed_double_offset,
4268 FixedArray::kHeaderSize));
4269 __ sw(scratch, FieldMemOperand(heap_number_reg,
4270 HeapNumber::kMantissaOffset));
4271
4272 __ mov(v0, heap_number_reg);
4273 __ Ret();
4274
4275 __ bind(&slow_allocate_heapnumber);
4276 Handle<Code> slow_ic =
4277 masm->isolate()->builtins()->KeyedLoadIC_Slow();
4278 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4279
4280 __ bind(&miss_force_generic);
4281 Handle<Code> miss_ic =
4282 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4283 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004284}
4285
4286
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004287void KeyedStoreStubCompiler::GenerateStoreFastElement(
4288 MacroAssembler* masm,
4289 bool is_js_array,
yangguo@chromium.org56454712012-02-16 15:33:53 +00004290 ElementsKind elements_kind,
4291 KeyedAccessGrowMode grow_mode) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00004292 // ----------- S t a t e -------------
4293 // -- a0 : value
4294 // -- a1 : key
4295 // -- a2 : receiver
4296 // -- ra : return address
4297 // -- a3 : scratch
4298 // -- a4 : scratch (elements)
4299 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00004300 Label miss_force_generic, transition_elements_kind, grow, slow;
4301 Label finish_store, check_capacity;
danno@chromium.org40cb8782011-05-25 07:58:50 +00004302
4303 Register value_reg = a0;
4304 Register key_reg = a1;
4305 Register receiver_reg = a2;
yangguo@chromium.org56454712012-02-16 15:33:53 +00004306 Register scratch = t0;
4307 Register elements_reg = a3;
4308 Register length_reg = t1;
4309 Register scratch2 = t2;
danno@chromium.org40cb8782011-05-25 07:58:50 +00004310
4311 // This stub is meant to be tail-jumped to, the receiver must already
4312 // have been verified by the caller to not be a smi.
4313
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004314 // Check that the key is a smi or a heap number convertible to a smi.
4315 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004316
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004317 if (IsFastSmiElementsKind(elements_kind)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00004318 __ JumpIfNotSmi(value_reg, &transition_elements_kind);
4319 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004320
4321 // Check that the key is within bounds.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004322 __ lw(elements_reg,
4323 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00004324 if (is_js_array) {
4325 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4326 } else {
4327 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4328 }
4329 // Compare smis.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004330 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4331 __ Branch(&grow, hs, key_reg, Operand(scratch));
4332 } else {
4333 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4334 }
4335
4336 // Make sure elements is a fast element array, not 'cow'.
4337 __ CheckMap(elements_reg,
4338 scratch,
4339 Heap::kFixedArrayMapRootIndex,
4340 &miss_force_generic,
4341 DONT_DO_SMI_CHECK);
4342
4343 __ bind(&finish_store);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004344
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004345 if (IsFastSmiElementsKind(elements_kind)) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004346 __ Addu(scratch,
4347 elements_reg,
4348 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4349 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4350 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4351 __ Addu(scratch, scratch, scratch2);
4352 __ sw(value_reg, MemOperand(scratch));
4353 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004354 ASSERT(IsFastObjectElementsKind(elements_kind));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004355 __ Addu(scratch,
4356 elements_reg,
4357 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4358 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4359 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4360 __ Addu(scratch, scratch, scratch2);
4361 __ sw(value_reg, MemOperand(scratch));
4362 __ mov(receiver_reg, value_reg);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004363 __ RecordWrite(elements_reg, // Object.
4364 scratch, // Address.
4365 receiver_reg, // Value.
4366 kRAHasNotBeenSaved,
4367 kDontSaveFPRegs);
4368 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004369 // value_reg (a0) is preserved.
4370 // Done.
4371 __ Ret();
4372
4373 __ bind(&miss_force_generic);
4374 Handle<Code> ic =
4375 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4376 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004377
4378 __ bind(&transition_elements_kind);
4379 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4380 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
yangguo@chromium.org56454712012-02-16 15:33:53 +00004381
4382 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4383 // Grow the array by a single element if possible.
4384 __ bind(&grow);
4385
4386 // Make sure the array is only growing by a single element, anything else
4387 // must be handled by the runtime.
4388 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch));
4389
4390 // Check for the empty array, and preallocate a small backing store if
4391 // possible.
4392 __ lw(length_reg,
4393 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4394 __ lw(elements_reg,
4395 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4396 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
4397 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
4398
4399 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
4400 __ AllocateInNewSpace(size, elements_reg, scratch, scratch2, &slow,
4401 TAG_OBJECT);
4402
4403 __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex);
4404 __ sw(scratch, FieldMemOperand(elements_reg, JSObject::kMapOffset));
4405 __ li(scratch, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4406 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4407 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
4408 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
4409 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::SizeFor(i)));
4410 }
4411
4412 // Store the element at index zero.
4413 __ sw(value_reg, FieldMemOperand(elements_reg, FixedArray::SizeFor(0)));
4414
4415 // Install the new backing store in the JSArray.
4416 __ sw(elements_reg,
4417 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4418 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
4419 scratch, kRAHasNotBeenSaved, kDontSaveFPRegs,
4420 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4421
4422 // Increment the length of the array.
4423 __ li(length_reg, Operand(Smi::FromInt(1)));
4424 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4425 __ Ret();
4426
4427 __ bind(&check_capacity);
4428 // Check for cow elements, in general they are not handled by this stub
4429 __ CheckMap(elements_reg,
4430 scratch,
4431 Heap::kFixedCOWArrayMapRootIndex,
4432 &miss_force_generic,
4433 DONT_DO_SMI_CHECK);
4434
4435 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4436 __ Branch(&slow, hs, length_reg, Operand(scratch));
4437
4438 // Grow the array and finish the store.
4439 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
4440 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4441 __ jmp(&finish_store);
4442
4443 __ bind(&slow);
4444 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4445 __ Jump(ic_slow, RelocInfo::CODE_TARGET);
4446 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004447}
4448
4449
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004450void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
4451 MacroAssembler* masm,
yangguo@chromium.org56454712012-02-16 15:33:53 +00004452 bool is_js_array,
4453 KeyedAccessGrowMode grow_mode) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004454 // ----------- S t a t e -------------
4455 // -- a0 : value
4456 // -- a1 : key
4457 // -- a2 : receiver
4458 // -- ra : return address
4459 // -- a3 : scratch
4460 // -- t0 : scratch (elements_reg)
4461 // -- t1 : scratch (mantissa_reg)
4462 // -- t2 : scratch (exponent_reg)
4463 // -- t3 : scratch4
4464 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00004465 Label miss_force_generic, transition_elements_kind, grow, slow;
4466 Label finish_store, check_capacity;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004467
4468 Register value_reg = a0;
4469 Register key_reg = a1;
4470 Register receiver_reg = a2;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004471 Register elements_reg = a3;
4472 Register scratch1 = t0;
4473 Register scratch2 = t1;
4474 Register scratch3 = t2;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004475 Register scratch4 = t3;
yangguo@chromium.org56454712012-02-16 15:33:53 +00004476 Register length_reg = t3;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004477
4478 // This stub is meant to be tail-jumped to, the receiver must already
4479 // have been verified by the caller to not be a smi.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004480
4481 // Check that the key is a smi or a heap number convertible to a smi.
4482 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004483
4484 __ lw(elements_reg,
4485 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4486
4487 // Check that the key is within bounds.
4488 if (is_js_array) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004489 __ lw(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004490 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004491 __ lw(scratch1,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004492 FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4493 }
4494 // Compare smis, unsigned compare catches both negative and out-of-bound
4495 // indexes.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004496 if (grow_mode == ALLOW_JSARRAY_GROWTH) {
4497 __ Branch(&grow, hs, key_reg, Operand(scratch1));
4498 } else {
4499 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch1));
4500 }
4501
4502 __ bind(&finish_store);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004503
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004504 __ StoreNumberToDoubleElements(value_reg,
4505 key_reg,
4506 receiver_reg,
4507 elements_reg,
4508 scratch1,
4509 scratch2,
4510 scratch3,
4511 scratch4,
4512 &transition_elements_kind);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004513
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004514 __ Ret(USE_DELAY_SLOT);
4515 __ mov(v0, value_reg); // In delay slot.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004516
4517 // Handle store cache miss, replacing the ic with the generic stub.
4518 __ bind(&miss_force_generic);
4519 Handle<Code> ic =
4520 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4521 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004522
4523 __ bind(&transition_elements_kind);
4524 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4525 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
yangguo@chromium.org56454712012-02-16 15:33:53 +00004526
4527 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4528 // Grow the array by a single element if possible.
4529 __ bind(&grow);
4530
4531 // Make sure the array is only growing by a single element, anything else
4532 // must be handled by the runtime.
4533 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch1));
4534
4535 // Transition on values that can't be stored in a FixedDoubleArray.
4536 Label value_is_smi;
4537 __ JumpIfSmi(value_reg, &value_is_smi);
4538 __ lw(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
4539 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
4540 __ Branch(&transition_elements_kind, ne, scratch1, Operand(at));
4541 __ bind(&value_is_smi);
4542
4543 // Check for the empty array, and preallocate a small backing store if
4544 // possible.
4545 __ lw(length_reg,
4546 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4547 __ lw(elements_reg,
4548 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4549 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
4550 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
4551
4552 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
4553 __ AllocateInNewSpace(size, elements_reg, scratch1, scratch2, &slow,
4554 TAG_OBJECT);
4555
4556 // Initialize the new FixedDoubleArray. Leave elements unitialized for
4557 // efficiency, they are guaranteed to be initialized before use.
4558 __ LoadRoot(scratch1, Heap::kFixedDoubleArrayMapRootIndex);
4559 __ sw(scratch1, FieldMemOperand(elements_reg, JSObject::kMapOffset));
4560 __ li(scratch1, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4561 __ sw(scratch1,
4562 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
4563
4564 // Install the new backing store in the JSArray.
4565 __ sw(elements_reg,
4566 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4567 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
4568 scratch1, kRAHasNotBeenSaved, kDontSaveFPRegs,
4569 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4570
4571 // Increment the length of the array.
4572 __ li(length_reg, Operand(Smi::FromInt(1)));
4573 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
danno@chromium.org00379b82012-05-04 09:16:29 +00004574 __ lw(elements_reg,
4575 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
yangguo@chromium.org56454712012-02-16 15:33:53 +00004576 __ jmp(&finish_store);
4577
4578 __ bind(&check_capacity);
4579 // Make sure that the backing store can hold additional elements.
4580 __ lw(scratch1,
4581 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
4582 __ Branch(&slow, hs, length_reg, Operand(scratch1));
4583
4584 // Grow the array and finish the store.
4585 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
4586 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4587 __ jmp(&finish_store);
4588
4589 __ bind(&slow);
4590 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4591 __ Jump(ic_slow, RelocInfo::CODE_TARGET);
4592 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004593}
4594
4595
ager@chromium.org5c838252010-02-19 08:53:10 +00004596#undef __
4597
4598} } // namespace v8::internal
4599
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004600#endif // V8_TARGET_ARCH_MIPS