blob: 18a5f5f7e11d4f9efd696484ef9f54c96ad42a86 [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);
1588 __ CheckFastSmiOnlyElements(a3, t3, &call_builtin);
1589 // edx: receiver
1590 // r3: map
1591 __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
1592 FAST_ELEMENTS,
1593 a3,
1594 t3,
1595 &call_builtin);
1596 __ mov(a2, receiver);
1597 ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm());
1598 __ bind(&fast_object);
1599 } else {
1600 __ CheckFastObjectElements(a3, a3, &call_builtin);
1601 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001602
1603 // Save new length.
1604 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1605
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001606 // Store the value.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001607 // We may need a register containing the address end_elements below,
1608 // so write back the value in end_elements.
1609 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1610 __ Addu(end_elements, elements, end_elements);
1611 __ Addu(end_elements, end_elements, kEndElementsOffset);
1612 __ sw(t0, MemOperand(end_elements));
1613
1614 __ RecordWrite(elements,
1615 end_elements,
1616 t0,
1617 kRAHasNotBeenSaved,
1618 kDontSaveFPRegs,
1619 EMIT_REMEMBERED_SET,
1620 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001621 __ Drop(argc + 1);
1622 __ Ret();
1623
1624 __ bind(&attempt_to_grow_elements);
1625 // v0: array's length + 1.
1626 // t0: elements' length.
1627
1628 if (!FLAG_inline_new) {
1629 __ Branch(&call_builtin);
1630 }
1631
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001632 __ lw(a2, MemOperand(sp, (argc - 1) * kPointerSize));
1633 // Growing elements that are SMI-only requires special handling in case
1634 // the new element is non-Smi. For now, delegate to the builtin.
1635 Label no_fast_elements_check;
1636 __ JumpIfSmi(a2, &no_fast_elements_check);
1637 __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1638 __ CheckFastObjectElements(t3, t3, &call_builtin);
1639 __ bind(&no_fast_elements_check);
1640
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001641 ExternalReference new_space_allocation_top =
1642 ExternalReference::new_space_allocation_top_address(
1643 masm()->isolate());
1644 ExternalReference new_space_allocation_limit =
1645 ExternalReference::new_space_allocation_limit_address(
1646 masm()->isolate());
1647
1648 const int kAllocationDelta = 4;
1649 // Load top and check if it is the end of elements.
1650 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1651 __ Addu(end_elements, elements, end_elements);
1652 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset));
1653 __ li(t3, Operand(new_space_allocation_top));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001654 __ lw(a3, MemOperand(t3));
1655 __ Branch(&call_builtin, ne, end_elements, Operand(a3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001656
1657 __ li(t5, Operand(new_space_allocation_limit));
1658 __ lw(t5, MemOperand(t5));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001659 __ Addu(a3, a3, Operand(kAllocationDelta * kPointerSize));
1660 __ Branch(&call_builtin, hi, a3, Operand(t5));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001661
1662 // We fit and could grow elements.
1663 // Update new_space_allocation_top.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001664 __ sw(a3, MemOperand(t3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001665 // Push the argument.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001666 __ sw(a2, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001667 // Fill the rest with holes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001668 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001669 for (int i = 1; i < kAllocationDelta; i++) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001670 __ sw(a3, MemOperand(end_elements, i * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001671 }
1672
1673 // Update elements' and array's sizes.
1674 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1675 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta)));
1676 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1677
1678 // Elements are in new space, so write barrier is not required.
1679 __ Drop(argc + 1);
1680 __ Ret();
1681 }
1682 __ bind(&call_builtin);
1683 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
1684 masm()->isolate()),
1685 argc + 1,
1686 1);
1687 }
1688
1689 // Handle call cache miss.
1690 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001691 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001692
1693 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001694 return GetCode(function);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001695}
1696
1697
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001698Handle<Code> CallStubCompiler::CompileArrayPopCall(
1699 Handle<Object> object,
1700 Handle<JSObject> holder,
1701 Handle<JSGlobalPropertyCell> cell,
1702 Handle<JSFunction> function,
1703 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001704 // ----------- S t a t e -------------
1705 // -- a2 : name
1706 // -- ra : return address
1707 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1708 // -- ...
1709 // -- sp[argc * 4] : receiver
1710 // -----------------------------------
1711
1712 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001713 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001714
1715 Label miss, return_undefined, call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001716 Register receiver = a1;
1717 Register elements = a3;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001718 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001719
1720 // Get the receiver from the stack.
1721 const int argc = arguments().immediate();
1722 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001723 // Check that the receiver isn't a smi.
1724 __ JumpIfSmi(receiver, &miss);
1725
1726 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001727 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, elements,
1728 t0, v0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001729
1730 // Get the elements array of the object.
1731 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1732
1733 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001734 __ CheckMap(elements,
1735 v0,
1736 Heap::kFixedArrayMapRootIndex,
1737 &call_builtin,
1738 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001739
1740 // Get the array's length into t0 and calculate new length.
1741 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1742 __ Subu(t0, t0, Operand(Smi::FromInt(1)));
1743 __ Branch(&return_undefined, lt, t0, Operand(zero_reg));
1744
1745 // Get the last element.
1746 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1747 STATIC_ASSERT(kSmiTagSize == 1);
1748 STATIC_ASSERT(kSmiTag == 0);
1749 // We can't address the last element in one operation. Compute the more
1750 // expensive shift first, and use an offset later on.
1751 __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize);
1752 __ Addu(elements, elements, t1);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001753 __ lw(v0, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001754 __ Branch(&call_builtin, eq, v0, Operand(t2));
1755
1756 // Set the array's length.
1757 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1758
1759 // Fill with the hole.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001760 __ sw(t2, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001761 __ Drop(argc + 1);
1762 __ Ret();
1763
1764 __ bind(&return_undefined);
1765 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
1766 __ Drop(argc + 1);
1767 __ Ret();
1768
1769 __ bind(&call_builtin);
1770 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop,
1771 masm()->isolate()),
1772 argc + 1,
1773 1);
1774
1775 // Handle call cache miss.
1776 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001777 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001778
1779 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001780 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001781}
1782
1783
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001784Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1785 Handle<Object> object,
1786 Handle<JSObject> holder,
1787 Handle<JSGlobalPropertyCell> cell,
1788 Handle<JSFunction> function,
1789 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001790 // ----------- S t a t e -------------
1791 // -- a2 : function name
1792 // -- ra : return address
1793 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1794 // -- ...
1795 // -- sp[argc * 4] : receiver
1796 // -----------------------------------
1797
1798 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001799 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001800
1801 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001802 Label miss;
1803 Label name_miss;
1804 Label index_out_of_range;
1805
1806 Label* index_out_of_range_label = &index_out_of_range;
1807
danno@chromium.org40cb8782011-05-25 07:58:50 +00001808 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001809 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001810 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001811 index_out_of_range_label = &miss;
1812 }
1813
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001814 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001815
1816 // Check that the maps starting from the prototype haven't changed.
1817 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1818 Context::STRING_FUNCTION_INDEX,
1819 v0,
1820 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001821 ASSERT(!object.is_identical_to(holder));
1822 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1823 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001824
1825 Register receiver = a1;
1826 Register index = t1;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001827 Register result = v0;
1828 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1829 if (argc > 0) {
1830 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1831 } else {
1832 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1833 }
1834
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001835 StringCharCodeAtGenerator generator(receiver,
1836 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001837 result,
1838 &miss, // When not a string.
1839 &miss, // When not a number.
1840 index_out_of_range_label,
1841 STRING_INDEX_IS_NUMBER);
1842 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001843 __ Drop(argc + 1);
1844 __ Ret();
1845
1846 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001847 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001848
1849 if (index_out_of_range.is_linked()) {
1850 __ bind(&index_out_of_range);
1851 __ LoadRoot(v0, Heap::kNanValueRootIndex);
1852 __ Drop(argc + 1);
1853 __ Ret();
1854 }
1855
1856 __ bind(&miss);
1857 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001858 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001859 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001860 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001861
1862 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001863 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001864}
1865
1866
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001867Handle<Code> CallStubCompiler::CompileStringCharAtCall(
1868 Handle<Object> object,
1869 Handle<JSObject> holder,
1870 Handle<JSGlobalPropertyCell> cell,
1871 Handle<JSFunction> function,
1872 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001873 // ----------- S t a t e -------------
1874 // -- a2 : function name
1875 // -- ra : return address
1876 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1877 // -- ...
1878 // -- sp[argc * 4] : receiver
1879 // -----------------------------------
1880
1881 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001882 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001883
1884 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001885 Label miss;
1886 Label name_miss;
1887 Label index_out_of_range;
1888 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00001889 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001890 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001891 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001892 index_out_of_range_label = &miss;
1893 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001894 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001895
1896 // Check that the maps starting from the prototype haven't changed.
1897 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1898 Context::STRING_FUNCTION_INDEX,
1899 v0,
1900 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001901 ASSERT(!object.is_identical_to(holder));
1902 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1903 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001904
1905 Register receiver = v0;
1906 Register index = t1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001907 Register scratch = a3;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001908 Register result = v0;
1909 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1910 if (argc > 0) {
1911 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1912 } else {
1913 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1914 }
1915
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001916 StringCharAtGenerator generator(receiver,
1917 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00001918 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001919 result,
1920 &miss, // When not a string.
1921 &miss, // When not a number.
1922 index_out_of_range_label,
1923 STRING_INDEX_IS_NUMBER);
1924 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001925 __ Drop(argc + 1);
1926 __ Ret();
1927
1928 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001929 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001930
1931 if (index_out_of_range.is_linked()) {
1932 __ bind(&index_out_of_range);
1933 __ LoadRoot(v0, Heap::kEmptyStringRootIndex);
1934 __ Drop(argc + 1);
1935 __ Ret();
1936 }
1937
1938 __ bind(&miss);
1939 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001940 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001941 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001942 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001943
1944 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001945 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001946}
1947
1948
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001949Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
1950 Handle<Object> object,
1951 Handle<JSObject> holder,
1952 Handle<JSGlobalPropertyCell> cell,
1953 Handle<JSFunction> function,
1954 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001955 // ----------- S t a t e -------------
1956 // -- a2 : function name
1957 // -- ra : return address
1958 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1959 // -- ...
1960 // -- sp[argc * 4] : receiver
1961 // -----------------------------------
1962
1963 const int argc = arguments().immediate();
1964
1965 // If the object is not a JSObject or we got an unexpected number of
1966 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001967 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001968
1969 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001970 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001971
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001972 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001973 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
1974
1975 STATIC_ASSERT(kSmiTag == 0);
1976 __ JumpIfSmi(a1, &miss);
1977
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001978 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
1979 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001980 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001981 ASSERT(cell->value() == *function);
1982 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
1983 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001984 GenerateLoadFunctionFromCell(cell, function, &miss);
1985 }
1986
1987 // Load the char code argument.
1988 Register code = a1;
1989 __ lw(code, MemOperand(sp, 0 * kPointerSize));
1990
1991 // Check the code is a smi.
1992 Label slow;
1993 STATIC_ASSERT(kSmiTag == 0);
1994 __ JumpIfNotSmi(code, &slow);
1995
1996 // Convert the smi code to uint16.
1997 __ And(code, code, Operand(Smi::FromInt(0xffff)));
1998
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001999 StringCharFromCodeGenerator generator(code, v0);
2000 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002001 __ Drop(argc + 1);
2002 __ Ret();
2003
2004 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002005 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002006
2007 // Tail call the full function. We do not have to patch the receiver
2008 // because the function makes no use of it.
2009 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002010 __ InvokeFunction(
2011 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002012
2013 __ bind(&miss);
2014 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002015 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002016
2017 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002018 return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002019}
2020
2021
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002022Handle<Code> CallStubCompiler::CompileMathFloorCall(
2023 Handle<Object> object,
2024 Handle<JSObject> holder,
2025 Handle<JSGlobalPropertyCell> cell,
2026 Handle<JSFunction> function,
2027 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002028 // ----------- S t a t e -------------
2029 // -- a2 : function name
2030 // -- ra : return address
2031 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2032 // -- ...
2033 // -- sp[argc * 4] : receiver
2034 // -----------------------------------
2035
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002036 if (!CpuFeatures::IsSupported(FPU)) {
2037 return Handle<Code>::null();
2038 }
2039
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002040 CpuFeatures::Scope scope_fpu(FPU);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002041 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002042 // If the object is not a JSObject or we got an unexpected number of
2043 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002044 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002045
2046 Label miss, slow;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002047 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002048
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002049 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002050 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002051 STATIC_ASSERT(kSmiTag == 0);
2052 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002053 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2054 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002055 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002056 ASSERT(cell->value() == *function);
2057 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2058 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002059 GenerateLoadFunctionFromCell(cell, function, &miss);
2060 }
2061
2062 // Load the (only) argument into v0.
2063 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2064
2065 // If the argument is a smi, just return.
2066 STATIC_ASSERT(kSmiTag == 0);
2067 __ And(t0, v0, Operand(kSmiTagMask));
2068 __ Drop(argc + 1, eq, t0, Operand(zero_reg));
2069 __ Ret(eq, t0, Operand(zero_reg));
2070
danno@chromium.org40cb8782011-05-25 07:58:50 +00002071 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002072
2073 Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return;
2074
2075 // If fpu is enabled, we use the floor instruction.
2076
2077 // Load the HeapNumber value.
2078 __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2079
2080 // Backup FCSR.
2081 __ cfc1(a3, FCSR);
2082 // Clearing FCSR clears the exception mask with no side-effects.
2083 __ ctc1(zero_reg, FCSR);
2084 // Convert the argument to an integer.
2085 __ floor_w_d(f0, f0);
2086
2087 // Start checking for special cases.
2088 // Get the argument exponent and clear the sign bit.
2089 __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize));
2090 __ And(t2, t1, Operand(~HeapNumber::kSignMask));
2091 __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord);
2092
2093 // Retrieve FCSR and check for fpu errors.
2094 __ cfc1(t5, FCSR);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002095 __ And(t5, t5, Operand(kFCSRExceptionFlagMask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002096 __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));
2097
2098 // Check for NaN, Infinity, and -Infinity.
2099 // They are invariant through a Math.Floor call, so just
2100 // return the original argument.
2101 __ Subu(t3, t2, Operand(HeapNumber::kExponentMask
2102 >> HeapNumber::kMantissaBitsInTopWord));
2103 __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg));
2104 // We had an overflow or underflow in the conversion. Check if we
2105 // have a big exponent.
2106 // If greater or equal, the argument is already round and in v0.
2107 __ Branch(&restore_fcsr_and_return, ge, t3,
2108 Operand(HeapNumber::kMantissaBits));
2109 __ Branch(&wont_fit_smi);
2110
2111 __ bind(&no_fpu_error);
2112 // Move the result back to v0.
2113 __ mfc1(v0, f0);
2114 // Check if the result fits into a smi.
2115 __ Addu(a1, v0, Operand(0x40000000));
2116 __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg));
2117 // Tag the result.
2118 STATIC_ASSERT(kSmiTag == 0);
2119 __ sll(v0, v0, kSmiTagSize);
2120
2121 // Check for -0.
2122 __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg));
2123 // t1 already holds the HeapNumber exponent.
2124 __ And(t0, t1, Operand(HeapNumber::kSignMask));
2125 // If our HeapNumber is negative it was -0, so load its address and return.
2126 // Else v0 is loaded with 0, so we can also just return.
2127 __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg));
2128 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2129
2130 __ bind(&restore_fcsr_and_return);
2131 // Restore FCSR and return.
2132 __ ctc1(a3, FCSR);
2133
2134 __ Drop(argc + 1);
2135 __ Ret();
2136
2137 __ bind(&wont_fit_smi);
2138 // Restore FCSR and fall to slow case.
2139 __ ctc1(a3, FCSR);
2140
2141 __ bind(&slow);
2142 // Tail call the full function. We do not have to patch the receiver
2143 // because the function makes no use of it.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002144 __ InvokeFunction(
2145 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002146
2147 __ bind(&miss);
2148 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002149 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002150
2151 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002152 return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002153}
2154
2155
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002156Handle<Code> CallStubCompiler::CompileMathAbsCall(
2157 Handle<Object> object,
2158 Handle<JSObject> holder,
2159 Handle<JSGlobalPropertyCell> cell,
2160 Handle<JSFunction> function,
2161 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002162 // ----------- S t a t e -------------
2163 // -- a2 : function name
2164 // -- ra : return address
2165 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2166 // -- ...
2167 // -- sp[argc * 4] : receiver
2168 // -----------------------------------
2169
2170 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002171 // If the object is not a JSObject or we got an unexpected number of
2172 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002173 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002174
2175 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002176
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002177 GenerateNameCheck(name, &miss);
2178 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002179 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002180 STATIC_ASSERT(kSmiTag == 0);
2181 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002182 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2183 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002184 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002185 ASSERT(cell->value() == *function);
2186 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2187 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002188 GenerateLoadFunctionFromCell(cell, function, &miss);
2189 }
2190
2191 // Load the (only) argument into v0.
2192 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2193
2194 // Check if the argument is a smi.
2195 Label not_smi;
2196 STATIC_ASSERT(kSmiTag == 0);
2197 __ JumpIfNotSmi(v0, &not_smi);
2198
2199 // Do bitwise not or do nothing depending on the sign of the
2200 // argument.
2201 __ sra(t0, v0, kBitsPerInt - 1);
2202 __ Xor(a1, v0, t0);
2203
2204 // Add 1 or do nothing depending on the sign of the argument.
2205 __ Subu(v0, a1, t0);
2206
2207 // If the result is still negative, go to the slow case.
2208 // This only happens for the most negative smi.
2209 Label slow;
2210 __ Branch(&slow, lt, v0, Operand(zero_reg));
2211
2212 // Smi case done.
2213 __ Drop(argc + 1);
2214 __ Ret();
2215
2216 // Check if the argument is a heap number and load its exponent and
2217 // sign.
2218 __ bind(&not_smi);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002219 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002220 __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2221
2222 // Check the sign of the argument. If the argument is positive,
2223 // just return it.
2224 Label negative_sign;
2225 __ And(t0, a1, Operand(HeapNumber::kSignMask));
2226 __ Branch(&negative_sign, ne, t0, Operand(zero_reg));
2227 __ Drop(argc + 1);
2228 __ Ret();
2229
2230 // If the argument is negative, clear the sign, and return a new
2231 // number.
2232 __ bind(&negative_sign);
2233 __ Xor(a1, a1, Operand(HeapNumber::kSignMask));
2234 __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2235 __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
2236 __ AllocateHeapNumber(v0, t0, t1, t2, &slow);
2237 __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2238 __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2239 __ Drop(argc + 1);
2240 __ Ret();
2241
2242 // Tail call the full function. We do not have to patch the receiver
2243 // because the function makes no use of it.
2244 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002245 __ InvokeFunction(
2246 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002247
2248 __ bind(&miss);
2249 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002250 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002251
2252 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002253 return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002254}
2255
2256
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002257Handle<Code> CallStubCompiler::CompileFastApiCall(
lrn@chromium.org7516f052011-03-30 08:52:27 +00002258 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002259 Handle<Object> object,
2260 Handle<JSObject> holder,
2261 Handle<JSGlobalPropertyCell> cell,
2262 Handle<JSFunction> function,
2263 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002264
danno@chromium.org40cb8782011-05-25 07:58:50 +00002265 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002266
2267 ASSERT(optimization.is_simple_api_call());
2268 // Bail out if object is a global object as we don't want to
2269 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002270 if (object->IsGlobalObject()) return Handle<Code>::null();
2271 if (!cell.is_null()) return Handle<Code>::null();
2272 if (!object->IsJSObject()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002273 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002274 Handle<JSObject>::cast(object), holder);
2275 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002276
2277 Label miss, miss_before_stack_reserved;
2278
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002279 GenerateNameCheck(name, &miss_before_stack_reserved);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002280
2281 // Get the receiver from the stack.
2282 const int argc = arguments().immediate();
2283 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2284
2285 // Check that the receiver isn't a smi.
2286 __ JumpIfSmi(a1, &miss_before_stack_reserved);
2287
2288 __ IncrementCounter(counters->call_const(), 1, a0, a3);
2289 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2290
2291 ReserveSpaceForFastApiCall(masm(), a0);
2292
2293 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002294 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002295 depth, &miss);
2296
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002297 GenerateFastApiDirectCall(masm(), optimization, argc);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002298
2299 __ bind(&miss);
2300 FreeSpaceForFastApiCall(masm());
2301
2302 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002303 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002304
2305 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002306 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002307}
2308
2309
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002310Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object,
2311 Handle<JSObject> holder,
2312 Handle<JSFunction> function,
2313 Handle<String> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002314 CheckType check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002315 // ----------- S t a t e -------------
2316 // -- a2 : name
2317 // -- ra : return address
2318 // -----------------------------------
2319 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002320 Handle<Code> code = CompileCustomCall(object, holder,
2321 Handle<JSGlobalPropertyCell>::null(),
2322 function, name);
2323 // A null handle means bail out to the regular compiler code below.
2324 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002325 }
2326
2327 Label miss;
2328
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002329 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002330
2331 // Get the receiver from the stack.
2332 const int argc = arguments().immediate();
2333 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2334
2335 // Check that the receiver isn't a smi.
2336 if (check != NUMBER_CHECK) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002337 __ JumpIfSmi(a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002338 }
2339
2340 // Make sure that it's okay not to patch the on stack receiver
2341 // unless we're doing a receiver map check.
2342 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002343 switch (check) {
2344 case RECEIVER_MAP_CHECK:
2345 __ IncrementCounter(masm()->isolate()->counters()->call_const(),
2346 1, a0, a3);
2347
2348 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002349 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2350 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002351
2352 // Patch the receiver on the stack with the global proxy if
2353 // necessary.
2354 if (object->IsGlobalObject()) {
2355 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2356 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2357 }
2358 break;
2359
2360 case STRING_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002361 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002362 // Check that the object is a two-byte string or a symbol.
2363 __ GetObjectType(a1, a3, a3);
2364 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2365 // Check that the maps starting from the prototype haven't changed.
2366 GenerateDirectLoadGlobalFunctionPrototype(
2367 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002368 CheckPrototypes(
2369 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2370 a0, holder, a3, a1, t0, name, &miss);
2371 } else {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002372 // Calling non-strict non-builtins with a value as the receiver
2373 // requires boxing.
2374 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002375 }
2376 break;
2377
2378 case NUMBER_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002379 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002380 Label fast;
2381 // Check that the object is a smi or a heap number.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002382 __ JumpIfSmi(a1, &fast);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002383 __ GetObjectType(a1, a0, a0);
2384 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
2385 __ bind(&fast);
2386 // Check that the maps starting from the prototype haven't changed.
2387 GenerateDirectLoadGlobalFunctionPrototype(
2388 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002389 CheckPrototypes(
2390 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2391 a0, holder, a3, a1, t0, name, &miss);
2392 } else {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002393 // Calling non-strict non-builtins with a value as the receiver
2394 // requires boxing.
2395 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002396 }
2397 break;
2398
2399 case BOOLEAN_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002400 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002401 Label fast;
2402 // Check that the object is a boolean.
2403 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
2404 __ Branch(&fast, eq, a1, Operand(t0));
2405 __ LoadRoot(t0, Heap::kFalseValueRootIndex);
2406 __ Branch(&miss, ne, a1, Operand(t0));
2407 __ bind(&fast);
2408 // Check that the maps starting from the prototype haven't changed.
2409 GenerateDirectLoadGlobalFunctionPrototype(
2410 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002411 CheckPrototypes(
2412 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2413 a0, holder, a3, a1, t0, name, &miss);
2414 } else {
2415 // Calling non-strict non-builtins with a value as the receiver
2416 // requires boxing.
2417 __ jmp(&miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002418 }
2419 break;
2420 }
2421
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002422 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002423 ? CALL_AS_FUNCTION
2424 : CALL_AS_METHOD;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002425 __ InvokeFunction(
2426 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002427
2428 // Handle call cache miss.
2429 __ bind(&miss);
2430
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002431 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002432
2433 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002434 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002435}
2436
2437
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002438Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2439 Handle<JSObject> holder,
2440 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002441 // ----------- S t a t e -------------
2442 // -- a2 : name
2443 // -- ra : return address
2444 // -----------------------------------
2445
2446 Label miss;
2447
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002448 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002449
2450 // Get the number of arguments.
2451 const int argc = arguments().immediate();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002452 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002453 LookupPostInterceptor(holder, name, &lookup);
2454
2455 // Get the receiver from the stack.
2456 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2457
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002458 CallInterceptorCompiler compiler(this, arguments(), a2, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002459 compiler.Compile(masm(), object, holder, name, &lookup, a1, a3, t0, a0,
2460 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002461
2462 // Move returned value, the function to call, to a1.
2463 __ mov(a1, v0);
2464 // Restore receiver.
2465 __ lw(a0, MemOperand(sp, argc * kPointerSize));
2466
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002467 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002468
2469 // Handle call cache miss.
2470 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002471 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002472
2473 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002474 return GetCode(INTERCEPTOR, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002475}
2476
2477
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002478Handle<Code> CallStubCompiler::CompileCallGlobal(
2479 Handle<JSObject> object,
2480 Handle<GlobalObject> holder,
2481 Handle<JSGlobalPropertyCell> cell,
2482 Handle<JSFunction> function,
2483 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002484 // ----------- S t a t e -------------
2485 // -- a2 : name
2486 // -- ra : return address
2487 // -----------------------------------
2488
2489 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002490 Handle<Code> code = CompileCustomCall(object, holder, cell, function, name);
2491 // A null handle means bail out to the regular compiler code below.
2492 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002493 }
2494
2495 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002496 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002497
2498 // Get the number of arguments.
2499 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002500 GenerateGlobalReceiverCheck(object, holder, name, &miss);
2501 GenerateLoadFunctionFromCell(cell, function, &miss);
2502
2503 // Patch the receiver on the stack with the global proxy if
2504 // necessary.
2505 if (object->IsGlobalObject()) {
2506 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
2507 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2508 }
2509
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002510 // Set up the context (function already in r1).
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002511 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
2512
2513 // Jump to the cached code (tail call).
2514 Counters* counters = masm()->isolate()->counters();
2515 __ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002516 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002517 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002518 ? CALL_AS_FUNCTION
2519 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002520 // We call indirectly through the code field in the function to
2521 // allow recompilation to take effect without changing any of the
2522 // call sites.
2523 __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
2524 __ InvokeCode(a3, expected, arguments(), JUMP_FUNCTION,
2525 NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002526
2527 // Handle call cache miss.
2528 __ bind(&miss);
2529 __ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002530 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002531
2532 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002533 return GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002534}
2535
2536
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002537Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +00002538 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002539 Handle<Map> transition,
2540 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002541 // ----------- S t a t e -------------
2542 // -- a0 : value
2543 // -- a1 : receiver
2544 // -- a2 : name
2545 // -- ra : return address
2546 // -----------------------------------
2547 Label miss;
2548
2549 // Name register might be clobbered.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002550 GenerateStoreField(masm(), object, index, transition, a1, a2, a3, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002551 __ bind(&miss);
2552 __ li(a2, Operand(Handle<String>(name))); // Restore name.
2553 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2554 __ Jump(ic, RelocInfo::CODE_TARGET);
2555
2556 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002557 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002558}
2559
2560
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002561Handle<Code> StoreStubCompiler::CompileStoreCallback(
2562 Handle<JSObject> object,
2563 Handle<AccessorInfo> callback,
2564 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002565 // ----------- S t a t e -------------
2566 // -- a0 : value
2567 // -- a1 : receiver
2568 // -- a2 : name
2569 // -- ra : return address
2570 // -----------------------------------
2571 Label miss;
2572
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002573 // Check that the map of the object hasn't changed.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002574 __ CheckMap(a1, a3, Handle<Map>(object->map()), &miss,
2575 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002576
2577 // Perform global security token check if needed.
2578 if (object->IsJSGlobalProxy()) {
2579 __ CheckAccessGlobalProxy(a1, a3, &miss);
2580 }
2581
2582 // Stub never generated for non-global objects that require access
2583 // checks.
2584 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
2585
2586 __ push(a1); // Receiver.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002587 __ li(a3, Operand(callback)); // Callback info.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002588 __ Push(a3, a2, a0);
2589
2590 // Do tail-call to the runtime system.
2591 ExternalReference store_callback_property =
2592 ExternalReference(IC_Utility(IC::kStoreCallbackProperty),
2593 masm()->isolate());
2594 __ TailCallExternalReference(store_callback_property, 4, 1);
2595
2596 // Handle store cache miss.
2597 __ bind(&miss);
2598 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2599 __ Jump(ic, RelocInfo::CODE_TARGET);
2600
2601 // Return the generated code.
2602 return GetCode(CALLBACKS, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002603}
2604
2605
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002606Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
2607 Handle<JSObject> receiver,
2608 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002609 // ----------- S t a t e -------------
2610 // -- a0 : value
2611 // -- a1 : receiver
2612 // -- a2 : name
2613 // -- ra : return address
2614 // -----------------------------------
2615 Label miss;
2616
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002617 // Check that the map of the object hasn't changed.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002618 __ CheckMap(a1, a3, Handle<Map>(receiver->map()), &miss,
2619 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002620
2621 // Perform global security token check if needed.
2622 if (receiver->IsJSGlobalProxy()) {
2623 __ CheckAccessGlobalProxy(a1, a3, &miss);
2624 }
2625
2626 // Stub is never generated for non-global objects that require access
2627 // checks.
2628 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2629
2630 __ Push(a1, a2, a0); // Receiver, name, value.
2631
2632 __ li(a0, Operand(Smi::FromInt(strict_mode_)));
2633 __ push(a0); // Strict mode.
2634
2635 // Do tail-call to the runtime system.
2636 ExternalReference store_ic_property =
2637 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty),
2638 masm()->isolate());
2639 __ TailCallExternalReference(store_ic_property, 4, 1);
2640
2641 // Handle store cache miss.
2642 __ bind(&miss);
2643 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2644 __ Jump(ic, RelocInfo::CODE_TARGET);
2645
2646 // Return the generated code.
2647 return GetCode(INTERCEPTOR, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002648}
2649
2650
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002651Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2652 Handle<GlobalObject> object,
2653 Handle<JSGlobalPropertyCell> cell,
2654 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002655 // ----------- S t a t e -------------
2656 // -- a0 : value
2657 // -- a1 : receiver
2658 // -- a2 : name
2659 // -- ra : return address
2660 // -----------------------------------
2661 Label miss;
2662
2663 // Check that the map of the global has not changed.
2664 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2665 __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map())));
2666
2667 // Check that the value in the cell is not the hole. If it is, this
2668 // cell could have been deleted and reintroducing the global needs
2669 // to update the property details in the property dictionary of the
2670 // global object. We bail out to the runtime system to do that.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002671 __ li(t0, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002672 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
2673 __ lw(t2, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2674 __ Branch(&miss, eq, t1, Operand(t2));
2675
2676 // Store the value in the cell.
2677 __ sw(a0, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2678 __ mov(v0, a0); // Stored value must be returned in v0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002679 // Cells are always rescanned, so no write barrier here.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002680
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002681 Counters* counters = masm()->isolate()->counters();
2682 __ IncrementCounter(counters->named_store_global_inline(), 1, a1, a3);
2683 __ Ret();
2684
2685 // Handle store cache miss.
2686 __ bind(&miss);
2687 __ IncrementCounter(counters->named_store_global_inline_miss(), 1, a1, a3);
2688 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2689 __ Jump(ic, RelocInfo::CODE_TARGET);
2690
2691 // Return the generated code.
2692 return GetCode(NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002693}
2694
2695
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002696Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
2697 Handle<JSObject> object,
2698 Handle<JSObject> last) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002699 // ----------- S t a t e -------------
2700 // -- a0 : receiver
2701 // -- ra : return address
2702 // -----------------------------------
2703 Label miss;
2704
2705 // Check that the receiver is not a smi.
2706 __ JumpIfSmi(a0, &miss);
2707
2708 // Check the maps of the full prototype chain.
2709 CheckPrototypes(object, a0, last, a3, a1, t0, name, &miss);
2710
2711 // If the last object in the prototype chain is a global object,
2712 // check that the global property cell is empty.
2713 if (last->IsGlobalObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002714 GenerateCheckPropertyCell(
2715 masm(), Handle<GlobalObject>::cast(last), name, a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002716 }
2717
2718 // Return undefined if maps of the full prototype chain is still the same.
2719 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2720 __ Ret();
2721
2722 __ bind(&miss);
2723 GenerateLoadMiss(masm(), Code::LOAD_IC);
2724
2725 // Return the generated code.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002726 return GetCode(NONEXISTENT, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00002727}
2728
2729
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002730Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object,
2731 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002732 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002733 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002734 // ----------- S t a t e -------------
2735 // -- a0 : receiver
2736 // -- a2 : name
2737 // -- ra : return address
2738 // -----------------------------------
2739 Label miss;
2740
2741 __ mov(v0, a0);
2742
2743 GenerateLoadField(object, holder, v0, a3, a1, t0, index, name, &miss);
2744 __ bind(&miss);
2745 GenerateLoadMiss(masm(), Code::LOAD_IC);
2746
2747 // Return the generated code.
2748 return GetCode(FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002749}
2750
2751
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002752Handle<Code> LoadStubCompiler::CompileLoadCallback(
2753 Handle<String> name,
2754 Handle<JSObject> object,
2755 Handle<JSObject> holder,
2756 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002757 // ----------- S t a t e -------------
2758 // -- a0 : receiver
2759 // -- a2 : name
2760 // -- ra : return address
2761 // -----------------------------------
2762 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002763 GenerateLoadCallback(object, holder, a0, a2, a3, a1, t0, callback, name,
2764 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002765 __ bind(&miss);
2766 GenerateLoadMiss(masm(), Code::LOAD_IC);
2767
2768 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002769 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002770}
2771
2772
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002773Handle<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object,
2774 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002775 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002776 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002777 // ----------- S t a t e -------------
2778 // -- a0 : receiver
2779 // -- a2 : name
2780 // -- ra : return address
2781 // -----------------------------------
2782 Label miss;
2783
2784 GenerateLoadConstant(object, holder, a0, a3, a1, t0, value, name, &miss);
2785 __ bind(&miss);
2786 GenerateLoadMiss(masm(), Code::LOAD_IC);
2787
2788 // Return the generated code.
2789 return GetCode(CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002790}
2791
2792
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002793Handle<Code> LoadStubCompiler::CompileLoadInterceptor(Handle<JSObject> object,
2794 Handle<JSObject> holder,
2795 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002796 // ----------- S t a t e -------------
2797 // -- a0 : receiver
2798 // -- a2 : name
2799 // -- ra : return address
2800 // -- [sp] : receiver
2801 // -----------------------------------
2802 Label miss;
2803
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002804 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002805 LookupPostInterceptor(holder, name, &lookup);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002806 GenerateLoadInterceptor(object, holder, &lookup, a0, a2, a3, a1, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002807 &miss);
2808 __ bind(&miss);
2809 GenerateLoadMiss(masm(), Code::LOAD_IC);
2810
2811 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002812 return GetCode(INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002813}
2814
2815
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002816Handle<Code> LoadStubCompiler::CompileLoadGlobal(
2817 Handle<JSObject> object,
2818 Handle<GlobalObject> holder,
2819 Handle<JSGlobalPropertyCell> cell,
2820 Handle<String> name,
2821 bool is_dont_delete) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002822 // ----------- S t a t e -------------
2823 // -- a0 : receiver
2824 // -- a2 : name
2825 // -- ra : return address
2826 // -----------------------------------
2827 Label miss;
2828
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002829 // Check that the map of the global has not changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00002830 __ JumpIfSmi(a0, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002831 CheckPrototypes(object, a0, holder, a3, t0, a1, name, &miss);
2832
2833 // Get the value from the cell.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002834 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002835 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
2836
2837 // Check for deleted property if property can actually be deleted.
2838 if (!is_dont_delete) {
2839 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
2840 __ Branch(&miss, eq, t0, Operand(at));
2841 }
2842
2843 __ mov(v0, t0);
2844 Counters* counters = masm()->isolate()->counters();
2845 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
2846 __ Ret();
2847
2848 __ bind(&miss);
2849 __ IncrementCounter(counters->named_load_global_stub_miss(), 1, a1, a3);
2850 GenerateLoadMiss(masm(), Code::LOAD_IC);
2851
2852 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002853 return GetCode(NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002854}
2855
2856
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002857Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
2858 Handle<JSObject> receiver,
2859 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002860 int index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002861 // ----------- S t a t e -------------
2862 // -- ra : return address
2863 // -- a0 : key
2864 // -- a1 : receiver
2865 // -----------------------------------
2866 Label miss;
2867
2868 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002869 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002870
2871 GenerateLoadField(receiver, holder, a1, a2, a3, t0, index, name, &miss);
2872 __ bind(&miss);
2873 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2874
2875 return GetCode(FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002876}
2877
2878
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002879Handle<Code> KeyedLoadStubCompiler::CompileLoadCallback(
2880 Handle<String> name,
2881 Handle<JSObject> receiver,
2882 Handle<JSObject> holder,
2883 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002884 // ----------- S t a t e -------------
2885 // -- ra : return address
2886 // -- a0 : key
2887 // -- a1 : receiver
2888 // -----------------------------------
2889 Label miss;
2890
2891 // Check the key is the cached one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002892 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002893
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002894 GenerateLoadCallback(receiver, holder, a1, a0, a2, a3, t0, callback, name,
2895 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002896 __ bind(&miss);
2897 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2898
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002899 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002900}
2901
2902
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002903Handle<Code> KeyedLoadStubCompiler::CompileLoadConstant(
2904 Handle<String> name,
2905 Handle<JSObject> receiver,
2906 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002907 Handle<JSFunction> value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002908 // ----------- S t a t e -------------
2909 // -- ra : return address
2910 // -- a0 : key
2911 // -- a1 : receiver
2912 // -----------------------------------
2913 Label miss;
2914
2915 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002916 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002917
2918 GenerateLoadConstant(receiver, holder, a1, a2, a3, t0, value, name, &miss);
2919 __ bind(&miss);
2920 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2921
2922 // Return the generated code.
2923 return GetCode(CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002924}
2925
2926
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002927Handle<Code> KeyedLoadStubCompiler::CompileLoadInterceptor(
2928 Handle<JSObject> receiver,
2929 Handle<JSObject> holder,
2930 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002931 // ----------- S t a t e -------------
2932 // -- ra : return address
2933 // -- a0 : key
2934 // -- a1 : receiver
2935 // -----------------------------------
2936 Label miss;
2937
2938 // Check the key is the cached one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002939 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002940
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002941 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002942 LookupPostInterceptor(holder, name, &lookup);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002943 GenerateLoadInterceptor(receiver, holder, &lookup, a1, a0, a2, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002944 &miss);
2945 __ bind(&miss);
2946 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2947
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002948 return GetCode(INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002949}
2950
2951
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002952Handle<Code> KeyedLoadStubCompiler::CompileLoadArrayLength(
2953 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002954 // ----------- S t a t e -------------
2955 // -- ra : return address
2956 // -- a0 : key
2957 // -- a1 : receiver
2958 // -----------------------------------
2959 Label miss;
2960
2961 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002962 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002963
2964 GenerateLoadArrayLength(masm(), a1, a2, &miss);
2965 __ bind(&miss);
2966 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2967
2968 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002969}
2970
2971
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002972Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength(
2973 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002974 // ----------- S t a t e -------------
2975 // -- ra : return address
2976 // -- a0 : key
2977 // -- a1 : receiver
2978 // -----------------------------------
2979 Label miss;
2980
2981 Counters* counters = masm()->isolate()->counters();
2982 __ IncrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
2983
2984 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002985 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002986
2987 GenerateLoadStringLength(masm(), a1, a2, a3, &miss, true);
2988 __ bind(&miss);
2989 __ DecrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
2990
2991 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2992
2993 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002994}
2995
2996
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002997Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype(
2998 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002999 // ----------- S t a t e -------------
3000 // -- ra : return address
3001 // -- a0 : key
3002 // -- a1 : receiver
3003 // -----------------------------------
3004 Label miss;
3005
3006 Counters* counters = masm()->isolate()->counters();
3007 __ IncrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
3008
3009 // Check the name hasn't changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003010 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003011
3012 GenerateLoadFunctionPrototype(masm(), a1, a2, a3, &miss);
3013 __ bind(&miss);
3014 __ DecrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
3015 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3016
3017 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003018}
3019
3020
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003021Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
3022 Handle<Map> receiver_map) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003023 // ----------- S t a t e -------------
3024 // -- ra : return address
3025 // -- a0 : key
3026 // -- a1 : receiver
3027 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003028 ElementsKind elements_kind = receiver_map->elements_kind();
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003029 Handle<Code> stub = KeyedLoadElementStub(elements_kind).GetCode();
3030
3031 __ DispatchMap(a1, a2, receiver_map, stub, DO_SMI_CHECK);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003032
3033 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
3034 __ Jump(ic, RelocInfo::CODE_TARGET);
3035
3036 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003037 return GetCode(NORMAL, factory()->empty_string());
danno@chromium.org40cb8782011-05-25 07:58:50 +00003038}
3039
3040
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003041Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
3042 MapHandleList* receiver_maps,
3043 CodeHandleList* handler_ics) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003044 // ----------- S t a t e -------------
3045 // -- ra : return address
3046 // -- a0 : key
3047 // -- a1 : receiver
3048 // -----------------------------------
3049 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003050 __ JumpIfSmi(a1, &miss);
3051
danno@chromium.org40cb8782011-05-25 07:58:50 +00003052 int receiver_count = receiver_maps->length();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003053 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003054 for (int current = 0; current < receiver_count; ++current) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003055 __ Jump(handler_ics->at(current), RelocInfo::CODE_TARGET,
3056 eq, a2, Operand(receiver_maps->at(current)));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003057 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003058
3059 __ bind(&miss);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003060 Handle<Code> miss_ic = isolate()->builtins()->KeyedLoadIC_Miss();
3061 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003062
3063 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003064 return GetCode(NORMAL, factory()->empty_string(), MEGAMORPHIC);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003065}
3066
3067
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003068Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +00003069 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003070 Handle<Map> transition,
3071 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003072 // ----------- S t a t e -------------
3073 // -- a0 : value
3074 // -- a1 : key
3075 // -- a2 : receiver
3076 // -- ra : return address
3077 // -----------------------------------
3078
3079 Label miss;
3080
3081 Counters* counters = masm()->isolate()->counters();
3082 __ IncrementCounter(counters->keyed_store_field(), 1, a3, t0);
3083
3084 // Check that the name has not changed.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003085 __ Branch(&miss, ne, a1, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003086
3087 // a3 is used as scratch register. a1 and a2 keep their values if a jump to
3088 // the miss label is generated.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003089 GenerateStoreField(masm(), object, index, transition, a2, a1, a3, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003090 __ bind(&miss);
3091
3092 __ DecrementCounter(counters->keyed_store_field(), 1, a3, t0);
3093 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss();
3094 __ Jump(ic, RelocInfo::CODE_TARGET);
3095
3096 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003097 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003098}
3099
3100
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003101Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
3102 Handle<Map> receiver_map) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003103 // ----------- S t a t e -------------
3104 // -- a0 : value
3105 // -- a1 : key
3106 // -- a2 : receiver
3107 // -- ra : return address
3108 // -- a3 : scratch
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003109 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003110 ElementsKind elements_kind = receiver_map->elements_kind();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003111 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003112 Handle<Code> stub =
yangguo@chromium.org56454712012-02-16 15:33:53 +00003113 KeyedStoreElementStub(is_js_array, elements_kind, grow_mode_).GetCode();
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003114
3115 __ DispatchMap(a2, a3, receiver_map, stub, DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003116
danno@chromium.org40cb8782011-05-25 07:58:50 +00003117 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003118 __ Jump(ic, RelocInfo::CODE_TARGET);
3119
3120 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003121 return GetCode(NORMAL, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00003122}
3123
3124
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003125Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
3126 MapHandleList* receiver_maps,
3127 CodeHandleList* handler_stubs,
3128 MapHandleList* transitioned_maps) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003129 // ----------- S t a t e -------------
3130 // -- a0 : value
3131 // -- a1 : key
3132 // -- a2 : receiver
3133 // -- ra : return address
3134 // -- a3 : scratch
3135 // -----------------------------------
3136 Label miss;
3137 __ JumpIfSmi(a2, &miss);
3138
3139 int receiver_count = receiver_maps->length();
3140 __ lw(a3, FieldMemOperand(a2, HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003141 for (int i = 0; i < receiver_count; ++i) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003142 if (transitioned_maps->at(i).is_null()) {
3143 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq,
3144 a3, Operand(receiver_maps->at(i)));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003145 } else {
3146 Label next_map;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003147 __ Branch(&next_map, ne, a3, Operand(receiver_maps->at(i)));
3148 __ li(a3, Operand(transitioned_maps->at(i)));
3149 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003150 __ bind(&next_map);
3151 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003152 }
3153
3154 __ bind(&miss);
3155 Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
3156 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3157
3158 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003159 return GetCode(NORMAL, factory()->empty_string(), MEGAMORPHIC);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003160}
3161
3162
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003163Handle<Code> ConstructStubCompiler::CompileConstructStub(
3164 Handle<JSFunction> function) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003165 // a0 : argc
3166 // a1 : constructor
3167 // ra : return address
3168 // [sp] : last argument
3169 Label generic_stub_call;
3170
3171 // Use t7 for holding undefined which is used in several places below.
3172 __ LoadRoot(t7, Heap::kUndefinedValueRootIndex);
3173
3174#ifdef ENABLE_DEBUGGER_SUPPORT
3175 // Check to see whether there are any break points in the function code. If
3176 // there are jump to the generic constructor stub which calls the actual
3177 // code for the function thereby hitting the break points.
3178 __ lw(t5, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3179 __ lw(a2, FieldMemOperand(t5, SharedFunctionInfo::kDebugInfoOffset));
3180 __ Branch(&generic_stub_call, ne, a2, Operand(t7));
3181#endif
3182
3183 // Load the initial map and verify that it is in fact a map.
3184 // a1: constructor function
3185 // t7: undefined
3186 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003187 __ JumpIfSmi(a2, &generic_stub_call);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003188 __ GetObjectType(a2, a3, t0);
3189 __ Branch(&generic_stub_call, ne, t0, Operand(MAP_TYPE));
3190
3191#ifdef DEBUG
3192 // Cannot construct functions this way.
3193 // a0: argc
3194 // a1: constructor function
3195 // a2: initial map
3196 // t7: undefined
3197 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
3198 __ Check(ne, "Function constructed by construct stub.",
3199 a3, Operand(JS_FUNCTION_TYPE));
3200#endif
3201
3202 // Now allocate the JSObject in new space.
3203 // a0: argc
3204 // a1: constructor function
3205 // a2: initial map
3206 // t7: undefined
3207 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003208 __ AllocateInNewSpace(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003209
3210 // Allocated the JSObject, now initialize the fields. Map is set to initial
3211 // map and properties and elements are set to empty fixed array.
3212 // a0: argc
3213 // a1: constructor function
3214 // a2: initial map
3215 // a3: object size (in words)
3216 // t4: JSObject (not tagged)
3217 // t7: undefined
3218 __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex);
3219 __ mov(t5, t4);
3220 __ sw(a2, MemOperand(t5, JSObject::kMapOffset));
3221 __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset));
3222 __ sw(t6, MemOperand(t5, JSObject::kElementsOffset));
3223 __ Addu(t5, t5, Operand(3 * kPointerSize));
3224 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
3225 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
3226 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
3227
3228
3229 // Calculate the location of the first argument. The stack contains only the
3230 // argc arguments.
3231 __ sll(a1, a0, kPointerSizeLog2);
3232 __ Addu(a1, a1, sp);
3233
3234 // Fill all the in-object properties with undefined.
3235 // a0: argc
3236 // a1: first argument
3237 // a3: object size (in words)
3238 // t4: JSObject (not tagged)
3239 // t5: First in-object property of JSObject (not tagged)
3240 // t7: undefined
3241 // Fill the initialized properties with a constant value or a passed argument
3242 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003243 Handle<SharedFunctionInfo> shared(function->shared());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003244 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3245 if (shared->IsThisPropertyAssignmentArgument(i)) {
3246 Label not_passed, next;
3247 // Check if the argument assigned to the property is actually passed.
3248 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3249 __ Branch(&not_passed, less_equal, a0, Operand(arg_number));
3250 // Argument passed - find it on the stack.
3251 __ lw(a2, MemOperand(a1, (arg_number + 1) * -kPointerSize));
3252 __ sw(a2, MemOperand(t5));
3253 __ Addu(t5, t5, kPointerSize);
3254 __ jmp(&next);
3255 __ bind(&not_passed);
3256 // Set the property to undefined.
3257 __ sw(t7, MemOperand(t5));
3258 __ Addu(t5, t5, Operand(kPointerSize));
3259 __ bind(&next);
3260 } else {
3261 // Set the property to the constant value.
3262 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
3263 __ li(a2, Operand(constant));
3264 __ sw(a2, MemOperand(t5));
3265 __ Addu(t5, t5, kPointerSize);
3266 }
3267 }
3268
3269 // Fill the unused in-object property fields with undefined.
3270 ASSERT(function->has_initial_map());
3271 for (int i = shared->this_property_assignments_count();
3272 i < function->initial_map()->inobject_properties();
3273 i++) {
3274 __ sw(t7, MemOperand(t5));
3275 __ Addu(t5, t5, kPointerSize);
3276 }
3277
3278 // a0: argc
3279 // t4: JSObject (not tagged)
3280 // Move argc to a1 and the JSObject to return to v0 and tag it.
3281 __ mov(a1, a0);
3282 __ mov(v0, t4);
3283 __ Or(v0, v0, Operand(kHeapObjectTag));
3284
3285 // v0: JSObject
3286 // a1: argc
3287 // Remove caller arguments and receiver from the stack and return.
3288 __ sll(t0, a1, kPointerSizeLog2);
3289 __ Addu(sp, sp, t0);
3290 __ Addu(sp, sp, Operand(kPointerSize));
3291 Counters* counters = masm()->isolate()->counters();
3292 __ IncrementCounter(counters->constructed_objects(), 1, a1, a2);
3293 __ IncrementCounter(counters->constructed_objects_stub(), 1, a1, a2);
3294 __ Ret();
3295
3296 // Jump to the generic stub in case the specialized code cannot handle the
3297 // construction.
3298 __ bind(&generic_stub_call);
3299 Handle<Code> generic_construct_stub =
3300 masm()->isolate()->builtins()->JSConstructStubGeneric();
3301 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
3302
3303 // Return the generated code.
3304 return GetCode();
3305}
3306
3307
danno@chromium.org40cb8782011-05-25 07:58:50 +00003308#undef __
3309#define __ ACCESS_MASM(masm)
3310
3311
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003312void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3313 MacroAssembler* masm) {
3314 // ---------- S t a t e --------------
3315 // -- ra : return address
3316 // -- a0 : key
3317 // -- a1 : receiver
3318 // -----------------------------------
3319 Label slow, miss_force_generic;
3320
3321 Register key = a0;
3322 Register receiver = a1;
3323
3324 __ JumpIfNotSmi(key, &miss_force_generic);
3325 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
3326 __ sra(a2, a0, kSmiTagSize);
3327 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
3328 __ Ret();
3329
3330 // Slow case, key and receiver still in a0 and a1.
3331 __ bind(&slow);
3332 __ IncrementCounter(
3333 masm->isolate()->counters()->keyed_load_external_array_slow(),
3334 1, a2, a3);
3335 // Entry registers are intact.
3336 // ---------- S t a t e --------------
3337 // -- ra : return address
3338 // -- a0 : key
3339 // -- a1 : receiver
3340 // -----------------------------------
3341 Handle<Code> slow_ic =
3342 masm->isolate()->builtins()->KeyedLoadIC_Slow();
3343 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
3344
3345 // Miss case, call the runtime.
3346 __ bind(&miss_force_generic);
3347
3348 // ---------- S t a t e --------------
3349 // -- ra : return address
3350 // -- a0 : key
3351 // -- a1 : receiver
3352 // -----------------------------------
3353
3354 Handle<Code> miss_ic =
3355 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3356 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3357}
3358
3359
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003360static bool IsElementTypeSigned(ElementsKind elements_kind) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003361 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003362 case EXTERNAL_BYTE_ELEMENTS:
3363 case EXTERNAL_SHORT_ELEMENTS:
3364 case EXTERNAL_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003365 return true;
3366
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003367 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3368 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3369 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3370 case EXTERNAL_PIXEL_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003371 return false;
3372
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003373 case EXTERNAL_FLOAT_ELEMENTS:
3374 case EXTERNAL_DOUBLE_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003375 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003376 case FAST_ELEMENTS:
3377 case FAST_DOUBLE_ELEMENTS:
3378 case DICTIONARY_ELEMENTS:
3379 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003380 UNREACHABLE();
3381 return false;
3382 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003383 return false;
lrn@chromium.org7516f052011-03-30 08:52:27 +00003384}
3385
3386
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003387static void GenerateSmiKeyCheck(MacroAssembler* masm,
3388 Register key,
3389 Register scratch0,
3390 Register scratch1,
3391 FPURegister double_scratch0,
3392 Label* fail) {
3393 if (CpuFeatures::IsSupported(FPU)) {
3394 CpuFeatures::Scope scope(FPU);
3395 Label key_ok;
3396 // Check for smi or a smi inside a heap number. We convert the heap
3397 // number and check if the conversion is exact and fits into the smi
3398 // range.
3399 __ JumpIfSmi(key, &key_ok);
3400 __ CheckMap(key,
3401 scratch0,
3402 Heap::kHeapNumberMapRootIndex,
3403 fail,
3404 DONT_DO_SMI_CHECK);
3405 __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
3406 __ EmitFPUTruncate(kRoundToZero,
3407 double_scratch0,
3408 double_scratch0,
3409 scratch0,
3410 scratch1,
3411 kCheckForInexactConversion);
3412
3413 __ Branch(fail, ne, scratch1, Operand(zero_reg));
3414
3415 __ mfc1(scratch0, double_scratch0);
3416 __ SmiTagCheckOverflow(key, scratch0, scratch1);
3417 __ BranchOnOverflow(fail, scratch1);
3418 __ bind(&key_ok);
3419 } else {
3420 // Check that the key is a smi.
3421 __ JumpIfNotSmi(key, fail);
3422 }
3423}
3424
3425
danno@chromium.org40cb8782011-05-25 07:58:50 +00003426void KeyedLoadStubCompiler::GenerateLoadExternalArray(
3427 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003428 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003429 // ---------- S t a t e --------------
3430 // -- ra : return address
3431 // -- a0 : key
3432 // -- a1 : receiver
3433 // -----------------------------------
danno@chromium.org40cb8782011-05-25 07:58:50 +00003434 Label miss_force_generic, slow, failed_allocation;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003435
3436 Register key = a0;
3437 Register receiver = a1;
3438
danno@chromium.org40cb8782011-05-25 07:58:50 +00003439 // This stub is meant to be tail-jumped to, the receiver must already
3440 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003441
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003442 // Check that the key is a smi or a heap number convertible to a smi.
3443 GenerateSmiKeyCheck(masm, key, t0, t1, f2, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003444
3445 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3446 // a3: elements array
3447
3448 // Check that the index is in range.
3449 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3450 __ sra(t2, key, kSmiTagSize);
3451 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003452 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003453
3454 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3455 // a3: base pointer of external storage
3456
3457 // We are not untagging smi key and instead work with it
3458 // as if it was premultiplied by 2.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003459 STATIC_ASSERT((kSmiTag == 0) && (kSmiTagSize == 1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003460
3461 Register value = a2;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003462 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003463 case EXTERNAL_BYTE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003464 __ srl(t2, key, 1);
3465 __ addu(t3, a3, t2);
3466 __ lb(value, MemOperand(t3, 0));
3467 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003468 case EXTERNAL_PIXEL_ELEMENTS:
3469 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003470 __ srl(t2, key, 1);
3471 __ addu(t3, a3, t2);
3472 __ lbu(value, MemOperand(t3, 0));
3473 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003474 case EXTERNAL_SHORT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003475 __ addu(t3, a3, key);
3476 __ lh(value, MemOperand(t3, 0));
3477 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003478 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003479 __ addu(t3, a3, key);
3480 __ lhu(value, MemOperand(t3, 0));
3481 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003482 case EXTERNAL_INT_ELEMENTS:
3483 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003484 __ sll(t2, key, 1);
3485 __ addu(t3, a3, t2);
3486 __ lw(value, MemOperand(t3, 0));
3487 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003488 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003489 __ sll(t3, t2, 2);
3490 __ addu(t3, a3, t3);
3491 if (CpuFeatures::IsSupported(FPU)) {
3492 CpuFeatures::Scope scope(FPU);
3493 __ lwc1(f0, MemOperand(t3, 0));
3494 } else {
3495 __ lw(value, MemOperand(t3, 0));
3496 }
3497 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003498 case EXTERNAL_DOUBLE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003499 __ sll(t2, key, 2);
3500 __ addu(t3, a3, t2);
3501 if (CpuFeatures::IsSupported(FPU)) {
3502 CpuFeatures::Scope scope(FPU);
3503 __ ldc1(f0, MemOperand(t3, 0));
3504 } else {
3505 // t3: pointer to the beginning of the double we want to load.
3506 __ lw(a2, MemOperand(t3, 0));
3507 __ lw(a3, MemOperand(t3, Register::kSizeInBytes));
3508 }
3509 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003510 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003511 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003512 case FAST_DOUBLE_ELEMENTS:
3513 case DICTIONARY_ELEMENTS:
3514 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003515 UNREACHABLE();
3516 break;
3517 }
3518
3519 // For integer array types:
3520 // a2: value
3521 // For float array type:
3522 // f0: value (if FPU is supported)
3523 // a2: value (if FPU is not supported)
3524 // For double array type:
3525 // f0: value (if FPU is supported)
3526 // a2/a3: value (if FPU is not supported)
3527
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003528 if (elements_kind == EXTERNAL_INT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003529 // For the Int and UnsignedInt array types, we need to see whether
3530 // the value can be represented in a Smi. If not, we need to convert
3531 // it to a HeapNumber.
3532 Label box_int;
3533 __ Subu(t3, value, Operand(0xC0000000)); // Non-smi value gives neg result.
3534 __ Branch(&box_int, lt, t3, Operand(zero_reg));
3535 // Tag integer as smi and return it.
3536 __ sll(v0, value, kSmiTagSize);
3537 __ Ret();
3538
3539 __ bind(&box_int);
3540 // Allocate a HeapNumber for the result and perform int-to-double
3541 // conversion.
3542 // The arm version uses a temporary here to save r0, but we don't need to
3543 // (a0 is not modified).
3544 __ LoadRoot(t1, Heap::kHeapNumberMapRootIndex);
3545 __ AllocateHeapNumber(v0, a3, t0, t1, &slow);
3546
3547 if (CpuFeatures::IsSupported(FPU)) {
3548 CpuFeatures::Scope scope(FPU);
3549 __ mtc1(value, f0);
3550 __ cvt_d_w(f0, f0);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00003551 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003552 __ Ret();
3553 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003554 Register dst1 = t2;
3555 Register dst2 = t3;
3556 FloatingPointHelper::Destination dest =
3557 FloatingPointHelper::kCoreRegisters;
3558 FloatingPointHelper::ConvertIntToDouble(masm,
3559 value,
3560 dest,
3561 f0,
3562 dst1,
3563 dst2,
3564 t1,
3565 f2);
3566 __ sw(dst1, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3567 __ sw(dst2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3568 __ Ret();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003569 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003570 } else if (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003571 // The test is different for unsigned int values. Since we need
3572 // the value to be in the range of a positive smi, we can't
3573 // handle either of the top two bits being set in the value.
3574 if (CpuFeatures::IsSupported(FPU)) {
3575 CpuFeatures::Scope scope(FPU);
3576 Label pl_box_int;
3577 __ And(t2, value, Operand(0xC0000000));
3578 __ Branch(&pl_box_int, ne, t2, Operand(zero_reg));
3579
3580 // It can fit in an Smi.
3581 // Tag integer as smi and return it.
3582 __ sll(v0, value, kSmiTagSize);
3583 __ Ret();
3584
3585 __ bind(&pl_box_int);
3586 // Allocate a HeapNumber for the result and perform int-to-double
3587 // conversion. Don't use a0 and a1 as AllocateHeapNumber clobbers all
3588 // registers - also when jumping due to exhausted young space.
3589 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3590 __ AllocateHeapNumber(v0, t2, t3, t6, &slow);
3591
3592 // This is replaced by a macro:
3593 // __ mtc1(value, f0); // LS 32-bits.
3594 // __ mtc1(zero_reg, f1); // MS 32-bits are all zero.
3595 // __ cvt_d_l(f0, f0); // Use 64 bit conv to get correct unsigned 32-bit.
3596
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003597 __ Cvt_d_uw(f0, value, f22);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003598
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00003599 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003600
3601 __ Ret();
3602 } else {
3603 // Check whether unsigned integer fits into smi.
3604 Label box_int_0, box_int_1, done;
3605 __ And(t2, value, Operand(0x80000000));
3606 __ Branch(&box_int_0, ne, t2, Operand(zero_reg));
3607 __ And(t2, value, Operand(0x40000000));
3608 __ Branch(&box_int_1, ne, t2, Operand(zero_reg));
3609
3610 // Tag integer as smi and return it.
3611 __ sll(v0, value, kSmiTagSize);
3612 __ Ret();
3613
3614 Register hiword = value; // a2.
3615 Register loword = a3;
3616
3617 __ bind(&box_int_0);
3618 // Integer does not have leading zeros.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003619 GenerateUInt2Double(masm, hiword, loword, t0, 0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003620 __ Branch(&done);
3621
3622 __ bind(&box_int_1);
3623 // Integer has one leading zero.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003624 GenerateUInt2Double(masm, hiword, loword, t0, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003625
3626
3627 __ bind(&done);
3628 // Integer was converted to double in registers hiword:loword.
3629 // Wrap it into a HeapNumber. Don't use a0 and a1 as AllocateHeapNumber
3630 // clobbers all registers - also when jumping due to exhausted young
3631 // space.
3632 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3633 __ AllocateHeapNumber(t2, t3, t5, t6, &slow);
3634
3635 __ sw(hiword, FieldMemOperand(t2, HeapNumber::kExponentOffset));
3636 __ sw(loword, FieldMemOperand(t2, HeapNumber::kMantissaOffset));
3637
3638 __ mov(v0, t2);
3639 __ Ret();
3640 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003641 } else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003642 // For the floating-point array type, we need to always allocate a
3643 // HeapNumber.
3644 if (CpuFeatures::IsSupported(FPU)) {
3645 CpuFeatures::Scope scope(FPU);
3646 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3647 // AllocateHeapNumber clobbers all registers - also when jumping due to
3648 // exhausted young space.
3649 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3650 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3651 // The float (single) value is already in fpu reg f0 (if we use float).
3652 __ cvt_d_s(f0, f0);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00003653 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003654 __ Ret();
3655 } else {
3656 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3657 // AllocateHeapNumber clobbers all registers - also when jumping due to
3658 // exhausted young space.
3659 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3660 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3661 // FPU is not available, do manual single to double conversion.
3662
3663 // a2: floating point value (binary32).
3664 // v0: heap number for result
3665
3666 // Extract mantissa to t4.
3667 __ And(t4, value, Operand(kBinary32MantissaMask));
3668
3669 // Extract exponent to t5.
3670 __ srl(t5, value, kBinary32MantissaBits);
3671 __ And(t5, t5, Operand(kBinary32ExponentMask >> kBinary32MantissaBits));
3672
3673 Label exponent_rebiased;
3674 __ Branch(&exponent_rebiased, eq, t5, Operand(zero_reg));
3675
3676 __ li(t0, 0x7ff);
3677 __ Xor(t1, t5, Operand(0xFF));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003678 __ Movz(t5, t0, t1); // Set t5 to 0x7ff only if t5 is equal to 0xff.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003679 __ Branch(&exponent_rebiased, eq, t0, Operand(0xff));
3680
3681 // Rebias exponent.
3682 __ Addu(t5,
3683 t5,
3684 Operand(-kBinary32ExponentBias + HeapNumber::kExponentBias));
3685
3686 __ bind(&exponent_rebiased);
3687 __ And(a2, value, Operand(kBinary32SignMask));
3688 value = no_reg;
3689 __ sll(t0, t5, HeapNumber::kMantissaBitsInTopWord);
3690 __ or_(a2, a2, t0);
3691
3692 // Shift mantissa.
3693 static const int kMantissaShiftForHiWord =
3694 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3695
3696 static const int kMantissaShiftForLoWord =
3697 kBitsPerInt - kMantissaShiftForHiWord;
3698
3699 __ srl(t0, t4, kMantissaShiftForHiWord);
3700 __ or_(a2, a2, t0);
3701 __ sll(a0, t4, kMantissaShiftForLoWord);
3702
3703 __ sw(a2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3704 __ sw(a0, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3705 __ Ret();
3706 }
3707
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003708 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003709 if (CpuFeatures::IsSupported(FPU)) {
3710 CpuFeatures::Scope scope(FPU);
3711 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3712 // AllocateHeapNumber clobbers all registers - also when jumping due to
3713 // exhausted young space.
3714 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3715 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3716 // The double value is already in f0
3717 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
3718 __ Ret();
3719 } else {
3720 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3721 // AllocateHeapNumber clobbers all registers - also when jumping due to
3722 // exhausted young space.
3723 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3724 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3725
3726 __ sw(a2, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3727 __ sw(a3, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3728 __ Ret();
3729 }
3730
3731 } else {
3732 // Tag integer as smi and return it.
3733 __ sll(v0, value, kSmiTagSize);
3734 __ Ret();
3735 }
3736
3737 // Slow case, key and receiver still in a0 and a1.
3738 __ bind(&slow);
3739 __ IncrementCounter(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003740 masm->isolate()->counters()->keyed_load_external_array_slow(),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003741 1, a2, a3);
3742
3743 // ---------- S t a t e --------------
3744 // -- ra : return address
3745 // -- a0 : key
3746 // -- a1 : receiver
3747 // -----------------------------------
3748
3749 __ Push(a1, a0);
3750
3751 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
3752
danno@chromium.org40cb8782011-05-25 07:58:50 +00003753 __ bind(&miss_force_generic);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003754 Handle<Code> stub =
3755 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3756 __ Jump(stub, RelocInfo::CODE_TARGET);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003757}
3758
3759
danno@chromium.org40cb8782011-05-25 07:58:50 +00003760void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3761 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003762 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003763 // ---------- S t a t e --------------
3764 // -- a0 : value
3765 // -- a1 : key
3766 // -- a2 : receiver
3767 // -- ra : return address
3768 // -----------------------------------
3769
danno@chromium.org40cb8782011-05-25 07:58:50 +00003770 Label slow, check_heap_number, miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003771
3772 // Register usage.
3773 Register value = a0;
3774 Register key = a1;
3775 Register receiver = a2;
3776 // a3 mostly holds the elements array or the destination external array.
3777
danno@chromium.org40cb8782011-05-25 07:58:50 +00003778 // This stub is meant to be tail-jumped to, the receiver must already
3779 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003780
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003781 // Check that the key is a smi or a heap number convertible to a smi.
3782 GenerateSmiKeyCheck(masm, key, t0, t1, f2, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003783
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003784 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3785
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003786 // Check that the index is in range.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003787 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3788 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003789 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003790
3791 // Handle both smis and HeapNumbers in the fast path. Go to the
3792 // runtime for all other kinds of values.
3793 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003794
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003795 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003796 // Double to pixel conversion is only implemented in the runtime for now.
3797 __ JumpIfNotSmi(value, &slow);
3798 } else {
3799 __ JumpIfNotSmi(value, &check_heap_number);
3800 }
3801 __ SmiUntag(t1, value);
3802 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3803
3804 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003805 // t1: value (integer).
3806
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003807 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003808 case EXTERNAL_PIXEL_ELEMENTS: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003809 // Clamp the value to [0..255].
3810 // v0 is used as a scratch register here.
3811 Label done;
3812 __ li(v0, Operand(255));
3813 // Normal branch: nop in delay slot.
3814 __ Branch(&done, gt, t1, Operand(v0));
3815 // Use delay slot in this branch.
3816 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg));
3817 __ mov(v0, zero_reg); // In delay slot.
3818 __ mov(v0, t1); // Value is in range 0..255.
3819 __ bind(&done);
3820 __ mov(t1, v0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003821
3822 __ srl(t8, key, 1);
3823 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003824 __ sb(t1, MemOperand(t8, 0));
3825 }
3826 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003827 case EXTERNAL_BYTE_ELEMENTS:
3828 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003829 __ srl(t8, key, 1);
3830 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003831 __ sb(t1, MemOperand(t8, 0));
3832 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003833 case EXTERNAL_SHORT_ELEMENTS:
3834 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003835 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003836 __ sh(t1, MemOperand(t8, 0));
3837 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003838 case EXTERNAL_INT_ELEMENTS:
3839 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003840 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003841 __ addu(t8, a3, t8);
3842 __ sw(t1, MemOperand(t8, 0));
3843 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003844 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003845 // Perform int-to-float conversion and store to memory.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003846 __ SmiUntag(t0, key);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003847 StoreIntAsFloat(masm, a3, t0, t1, t2, t3, t4);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003848 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003849 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003850 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003851 __ addu(a3, a3, t8);
3852 // a3: effective address of the double element
3853 FloatingPointHelper::Destination destination;
3854 if (CpuFeatures::IsSupported(FPU)) {
3855 destination = FloatingPointHelper::kFPURegisters;
3856 } else {
3857 destination = FloatingPointHelper::kCoreRegisters;
3858 }
3859 FloatingPointHelper::ConvertIntToDouble(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003860 masm, t1, destination,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003861 f0, t2, t3, // These are: double_dst, dst1, dst2.
3862 t0, f2); // These are: scratch2, single_scratch.
3863 if (destination == FloatingPointHelper::kFPURegisters) {
3864 CpuFeatures::Scope scope(FPU);
3865 __ sdc1(f0, MemOperand(a3, 0));
3866 } else {
3867 __ sw(t2, MemOperand(a3, 0));
3868 __ sw(t3, MemOperand(a3, Register::kSizeInBytes));
3869 }
3870 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003871 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003872 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003873 case FAST_DOUBLE_ELEMENTS:
3874 case DICTIONARY_ELEMENTS:
3875 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003876 UNREACHABLE();
3877 break;
3878 }
3879
3880 // Entry registers are intact, a0 holds the value which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003881 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003882 __ Ret();
3883
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003884 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003885 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003886 __ bind(&check_heap_number);
3887 __ GetObjectType(value, t1, t2);
3888 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE));
3889
3890 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3891
3892 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003893
3894 // The WebGL specification leaves the behavior of storing NaN and
3895 // +/-Infinity into integer arrays basically undefined. For more
3896 // reproducible behavior, convert these to zero.
3897
3898 if (CpuFeatures::IsSupported(FPU)) {
3899 CpuFeatures::Scope scope(FPU);
3900
3901 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
3902
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003903 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003904 __ cvt_s_d(f0, f0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003905 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003906 __ addu(t8, a3, t8);
3907 __ swc1(f0, MemOperand(t8, 0));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003908 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003909 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003910 __ addu(t8, a3, t8);
3911 __ sdc1(f0, MemOperand(t8, 0));
3912 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003913 __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003914
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003915 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003916 case EXTERNAL_BYTE_ELEMENTS:
3917 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003918 __ srl(t8, key, 1);
3919 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003920 __ sb(t3, MemOperand(t8, 0));
3921 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003922 case EXTERNAL_SHORT_ELEMENTS:
3923 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003924 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003925 __ sh(t3, MemOperand(t8, 0));
3926 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003927 case EXTERNAL_INT_ELEMENTS:
3928 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003929 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003930 __ addu(t8, a3, t8);
3931 __ sw(t3, MemOperand(t8, 0));
3932 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003933 case EXTERNAL_PIXEL_ELEMENTS:
3934 case EXTERNAL_FLOAT_ELEMENTS:
3935 case EXTERNAL_DOUBLE_ELEMENTS:
3936 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003937 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003938 case FAST_DOUBLE_ELEMENTS:
3939 case DICTIONARY_ELEMENTS:
3940 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003941 UNREACHABLE();
3942 break;
3943 }
3944 }
3945
3946 // Entry registers are intact, a0 holds the value
3947 // which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003948 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003949 __ Ret();
3950 } else {
3951 // FPU is not available, do manual conversions.
3952
3953 __ lw(t3, FieldMemOperand(value, HeapNumber::kExponentOffset));
3954 __ lw(t4, FieldMemOperand(value, HeapNumber::kMantissaOffset));
3955
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003956 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003957 Label done, nan_or_infinity_or_zero;
3958 static const int kMantissaInHiWordShift =
3959 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3960
3961 static const int kMantissaInLoWordShift =
3962 kBitsPerInt - kMantissaInHiWordShift;
3963
3964 // Test for all special exponent values: zeros, subnormal numbers, NaNs
3965 // and infinities. All these should be converted to 0.
3966 __ li(t5, HeapNumber::kExponentMask);
3967 __ and_(t6, t3, t5);
3968 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(zero_reg));
3969
3970 __ xor_(t1, t6, t5);
3971 __ li(t2, kBinary32ExponentMask);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003972 __ Movz(t6, t2, t1); // Only if t6 is equal to t5.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003973 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(t5));
3974
3975 // Rebias exponent.
3976 __ srl(t6, t6, HeapNumber::kExponentShift);
3977 __ Addu(t6,
3978 t6,
3979 Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
3980
3981 __ li(t1, Operand(kBinary32MaxExponent));
3982 __ Slt(t1, t1, t6);
3983 __ And(t2, t3, Operand(HeapNumber::kSignMask));
3984 __ Or(t2, t2, Operand(kBinary32ExponentMask));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003985 __ Movn(t3, t2, t1); // Only if t6 is gt kBinary32MaxExponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003986 __ Branch(&done, gt, t6, Operand(kBinary32MaxExponent));
3987
3988 __ Slt(t1, t6, Operand(kBinary32MinExponent));
3989 __ And(t2, t3, Operand(HeapNumber::kSignMask));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003990 __ Movn(t3, t2, t1); // Only if t6 is lt kBinary32MinExponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003991 __ Branch(&done, lt, t6, Operand(kBinary32MinExponent));
3992
3993 __ And(t7, t3, Operand(HeapNumber::kSignMask));
3994 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3995 __ sll(t3, t3, kMantissaInHiWordShift);
3996 __ or_(t7, t7, t3);
3997 __ srl(t4, t4, kMantissaInLoWordShift);
3998 __ or_(t7, t7, t4);
3999 __ sll(t6, t6, kBinary32ExponentShift);
4000 __ or_(t3, t7, t6);
4001
4002 __ bind(&done);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004003 __ sll(t9, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004004 __ addu(t9, a2, t9);
4005 __ sw(t3, MemOperand(t9, 0));
4006
4007 // Entry registers are intact, a0 holds the value which is the return
4008 // value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004009 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004010 __ Ret();
4011
4012 __ bind(&nan_or_infinity_or_zero);
4013 __ And(t7, t3, Operand(HeapNumber::kSignMask));
4014 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4015 __ or_(t6, t6, t7);
4016 __ sll(t3, t3, kMantissaInHiWordShift);
4017 __ or_(t6, t6, t3);
4018 __ srl(t4, t4, kMantissaInLoWordShift);
4019 __ or_(t3, t6, t4);
4020 __ Branch(&done);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004021 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004022 __ sll(t8, t0, 3);
4023 __ addu(t8, a3, t8);
4024 // t8: effective address of destination element.
4025 __ sw(t4, MemOperand(t8, 0));
4026 __ sw(t3, MemOperand(t8, Register::kSizeInBytes));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004027 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004028 __ Ret();
4029 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004030 bool is_signed_type = IsElementTypeSigned(elements_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004031 int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
4032 int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
4033
4034 Label done, sign;
4035
4036 // Test for all special exponent values: zeros, subnormal numbers, NaNs
4037 // and infinities. All these should be converted to 0.
4038 __ li(t5, HeapNumber::kExponentMask);
4039 __ and_(t6, t3, t5);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004040 __ Movz(t3, zero_reg, t6); // Only if t6 is equal to zero.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004041 __ Branch(&done, eq, t6, Operand(zero_reg));
4042
4043 __ xor_(t2, t6, t5);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004044 __ Movz(t3, zero_reg, t2); // Only if t6 is equal to t5.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004045 __ Branch(&done, eq, t6, Operand(t5));
4046
4047 // Unbias exponent.
4048 __ srl(t6, t6, HeapNumber::kExponentShift);
4049 __ Subu(t6, t6, Operand(HeapNumber::kExponentBias));
4050 // If exponent is negative then result is 0.
4051 __ slt(t2, t6, zero_reg);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004052 __ Movn(t3, zero_reg, t2); // Only if exponent is negative.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004053 __ Branch(&done, lt, t6, Operand(zero_reg));
4054
4055 // If exponent is too big then result is minimal value.
4056 __ slti(t1, t6, meaningfull_bits - 1);
4057 __ li(t2, min_value);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004058 __ Movz(t3, t2, t1); // Only if t6 is ge meaningfull_bits - 1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004059 __ Branch(&done, ge, t6, Operand(meaningfull_bits - 1));
4060
4061 __ And(t5, t3, Operand(HeapNumber::kSignMask));
4062 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4063 __ Or(t3, t3, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
4064
4065 __ li(t9, HeapNumber::kMantissaBitsInTopWord);
4066 __ subu(t6, t9, t6);
4067 __ slt(t1, t6, zero_reg);
4068 __ srlv(t2, t3, t6);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004069 __ Movz(t3, t2, t1); // Only if t6 is positive.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004070 __ Branch(&sign, ge, t6, Operand(zero_reg));
4071
4072 __ subu(t6, zero_reg, t6);
4073 __ sllv(t3, t3, t6);
4074 __ li(t9, meaningfull_bits);
4075 __ subu(t6, t9, t6);
4076 __ srlv(t4, t4, t6);
4077 __ or_(t3, t3, t4);
4078
4079 __ bind(&sign);
4080 __ subu(t2, t3, zero_reg);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004081 __ Movz(t3, t2, t5); // Only if t5 is zero.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004082
4083 __ bind(&done);
4084
4085 // Result is in t3.
4086 // This switch block should be exactly the same as above (FPU mode).
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004087 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004088 case EXTERNAL_BYTE_ELEMENTS:
4089 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004090 __ srl(t8, key, 1);
4091 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004092 __ sb(t3, MemOperand(t8, 0));
4093 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004094 case EXTERNAL_SHORT_ELEMENTS:
4095 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004096 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004097 __ sh(t3, MemOperand(t8, 0));
4098 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004099 case EXTERNAL_INT_ELEMENTS:
4100 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004101 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004102 __ addu(t8, a3, t8);
4103 __ sw(t3, MemOperand(t8, 0));
4104 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004105 case EXTERNAL_PIXEL_ELEMENTS:
4106 case EXTERNAL_FLOAT_ELEMENTS:
4107 case EXTERNAL_DOUBLE_ELEMENTS:
4108 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004109 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004110 case FAST_DOUBLE_ELEMENTS:
4111 case DICTIONARY_ELEMENTS:
4112 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004113 UNREACHABLE();
4114 break;
4115 }
4116 }
4117 }
4118 }
4119
danno@chromium.org40cb8782011-05-25 07:58:50 +00004120 // Slow case, key and receiver still in a0 and a1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004121 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004122 __ IncrementCounter(
4123 masm->isolate()->counters()->keyed_load_external_array_slow(),
4124 1, a2, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004125 // Entry registers are intact.
4126 // ---------- S t a t e --------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004127 // -- ra : return address
danno@chromium.org40cb8782011-05-25 07:58:50 +00004128 // -- a0 : key
4129 // -- a1 : receiver
4130 // -----------------------------------
4131 Handle<Code> slow_ic =
4132 masm->isolate()->builtins()->KeyedStoreIC_Slow();
4133 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4134
4135 // Miss case, call the runtime.
4136 __ bind(&miss_force_generic);
4137
4138 // ---------- S t a t e --------------
4139 // -- ra : return address
4140 // -- a0 : key
4141 // -- a1 : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004142 // -----------------------------------
4143
danno@chromium.org40cb8782011-05-25 07:58:50 +00004144 Handle<Code> miss_ic =
4145 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4146 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
4147}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004148
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004149
danno@chromium.org40cb8782011-05-25 07:58:50 +00004150void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
4151 // ----------- S t a t e -------------
4152 // -- ra : return address
4153 // -- a0 : key
4154 // -- a1 : receiver
4155 // -----------------------------------
4156 Label miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004157
danno@chromium.org40cb8782011-05-25 07:58:50 +00004158 // This stub is meant to be tail-jumped to, the receiver must already
4159 // have been verified by the caller to not be a smi.
4160
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004161 // Check that the key is a smi or a heap number convertible to a smi.
4162 GenerateSmiKeyCheck(masm, a0, t0, t1, f2, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004163
4164 // Get the elements array.
4165 __ lw(a2, FieldMemOperand(a1, JSObject::kElementsOffset));
4166 __ AssertFastElements(a2);
4167
4168 // Check that the key is within bounds.
4169 __ lw(a3, FieldMemOperand(a2, FixedArray::kLengthOffset));
ulan@chromium.org6ff65142012-03-21 09:52:17 +00004170 __ Branch(USE_DELAY_SLOT, &miss_force_generic, hs, a0, Operand(a3));
danno@chromium.org40cb8782011-05-25 07:58:50 +00004171
4172 // Load the result and make sure it's not the hole.
4173 __ Addu(a3, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004174 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004175 __ sll(t0, a0, kPointerSizeLog2 - kSmiTagSize);
4176 __ Addu(t0, t0, a3);
4177 __ lw(t0, MemOperand(t0));
4178 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
4179 __ Branch(&miss_force_generic, eq, t0, Operand(t1));
ulan@chromium.org6ff65142012-03-21 09:52:17 +00004180 __ Ret(USE_DELAY_SLOT);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004181 __ mov(v0, t0);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004182
4183 __ bind(&miss_force_generic);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004184 Handle<Code> stub =
4185 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4186 __ Jump(stub, RelocInfo::CODE_TARGET);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004187}
4188
4189
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004190void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
4191 MacroAssembler* masm) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004192 // ----------- S t a t e -------------
4193 // -- ra : return address
4194 // -- a0 : key
4195 // -- a1 : receiver
4196 // -----------------------------------
4197 Label miss_force_generic, slow_allocate_heapnumber;
4198
4199 Register key_reg = a0;
4200 Register receiver_reg = a1;
4201 Register elements_reg = a2;
4202 Register heap_number_reg = a2;
4203 Register indexed_double_offset = a3;
4204 Register scratch = t0;
4205 Register scratch2 = t1;
4206 Register scratch3 = t2;
4207 Register heap_number_map = t3;
4208
4209 // This stub is meant to be tail-jumped to, the receiver must already
4210 // have been verified by the caller to not be a smi.
4211
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004212 // Check that the key is a smi or a heap number convertible to a smi.
4213 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004214
4215 // Get the elements array.
4216 __ lw(elements_reg,
4217 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4218
4219 // Check that the key is within bounds.
4220 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4221 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4222
4223 // Load the upper word of the double in the fixed array and test for NaN.
4224 __ sll(scratch2, key_reg, kDoubleSizeLog2 - kSmiTagSize);
4225 __ Addu(indexed_double_offset, elements_reg, Operand(scratch2));
4226 uint32_t upper_32_offset = FixedArray::kHeaderSize + sizeof(kHoleNanLower32);
4227 __ lw(scratch, FieldMemOperand(indexed_double_offset, upper_32_offset));
4228 __ Branch(&miss_force_generic, eq, scratch, Operand(kHoleNanUpper32));
4229
4230 // Non-NaN. Allocate a new heap number and copy the double value into it.
4231 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
4232 __ AllocateHeapNumber(heap_number_reg, scratch2, scratch3,
4233 heap_number_map, &slow_allocate_heapnumber);
4234
4235 // Don't need to reload the upper 32 bits of the double, it's already in
4236 // scratch.
4237 __ sw(scratch, FieldMemOperand(heap_number_reg,
4238 HeapNumber::kExponentOffset));
4239 __ lw(scratch, FieldMemOperand(indexed_double_offset,
4240 FixedArray::kHeaderSize));
4241 __ sw(scratch, FieldMemOperand(heap_number_reg,
4242 HeapNumber::kMantissaOffset));
4243
4244 __ mov(v0, heap_number_reg);
4245 __ Ret();
4246
4247 __ bind(&slow_allocate_heapnumber);
4248 Handle<Code> slow_ic =
4249 masm->isolate()->builtins()->KeyedLoadIC_Slow();
4250 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4251
4252 __ bind(&miss_force_generic);
4253 Handle<Code> miss_ic =
4254 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4255 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004256}
4257
4258
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004259void KeyedStoreStubCompiler::GenerateStoreFastElement(
4260 MacroAssembler* masm,
4261 bool is_js_array,
yangguo@chromium.org56454712012-02-16 15:33:53 +00004262 ElementsKind elements_kind,
4263 KeyedAccessGrowMode grow_mode) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00004264 // ----------- S t a t e -------------
4265 // -- a0 : value
4266 // -- a1 : key
4267 // -- a2 : receiver
4268 // -- ra : return address
4269 // -- a3 : scratch
4270 // -- a4 : scratch (elements)
4271 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00004272 Label miss_force_generic, transition_elements_kind, grow, slow;
4273 Label finish_store, check_capacity;
danno@chromium.org40cb8782011-05-25 07:58:50 +00004274
4275 Register value_reg = a0;
4276 Register key_reg = a1;
4277 Register receiver_reg = a2;
yangguo@chromium.org56454712012-02-16 15:33:53 +00004278 Register scratch = t0;
4279 Register elements_reg = a3;
4280 Register length_reg = t1;
4281 Register scratch2 = t2;
danno@chromium.org40cb8782011-05-25 07:58:50 +00004282
4283 // This stub is meant to be tail-jumped to, the receiver must already
4284 // have been verified by the caller to not be a smi.
4285
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004286 // Check that the key is a smi or a heap number convertible to a smi.
4287 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004288
yangguo@chromium.org56454712012-02-16 15:33:53 +00004289 if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
4290 __ JumpIfNotSmi(value_reg, &transition_elements_kind);
4291 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004292
4293 // Check that the key is within bounds.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004294 __ lw(elements_reg,
4295 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00004296 if (is_js_array) {
4297 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4298 } else {
4299 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4300 }
4301 // Compare smis.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004302 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4303 __ Branch(&grow, hs, key_reg, Operand(scratch));
4304 } else {
4305 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4306 }
4307
4308 // Make sure elements is a fast element array, not 'cow'.
4309 __ CheckMap(elements_reg,
4310 scratch,
4311 Heap::kFixedArrayMapRootIndex,
4312 &miss_force_generic,
4313 DONT_DO_SMI_CHECK);
4314
4315 __ bind(&finish_store);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004316
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004317 if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004318 __ Addu(scratch,
4319 elements_reg,
4320 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4321 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4322 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4323 __ Addu(scratch, scratch, scratch2);
4324 __ sw(value_reg, MemOperand(scratch));
4325 } else {
4326 ASSERT(elements_kind == FAST_ELEMENTS);
4327 __ Addu(scratch,
4328 elements_reg,
4329 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4330 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4331 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4332 __ Addu(scratch, scratch, scratch2);
4333 __ sw(value_reg, MemOperand(scratch));
4334 __ mov(receiver_reg, value_reg);
4335 ASSERT(elements_kind == FAST_ELEMENTS);
4336 __ RecordWrite(elements_reg, // Object.
4337 scratch, // Address.
4338 receiver_reg, // Value.
4339 kRAHasNotBeenSaved,
4340 kDontSaveFPRegs);
4341 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004342 // value_reg (a0) is preserved.
4343 // Done.
4344 __ Ret();
4345
4346 __ bind(&miss_force_generic);
4347 Handle<Code> ic =
4348 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4349 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004350
4351 __ bind(&transition_elements_kind);
4352 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4353 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
yangguo@chromium.org56454712012-02-16 15:33:53 +00004354
4355 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4356 // Grow the array by a single element if possible.
4357 __ bind(&grow);
4358
4359 // Make sure the array is only growing by a single element, anything else
4360 // must be handled by the runtime.
4361 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch));
4362
4363 // Check for the empty array, and preallocate a small backing store if
4364 // possible.
4365 __ lw(length_reg,
4366 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4367 __ lw(elements_reg,
4368 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4369 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
4370 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
4371
4372 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
4373 __ AllocateInNewSpace(size, elements_reg, scratch, scratch2, &slow,
4374 TAG_OBJECT);
4375
4376 __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex);
4377 __ sw(scratch, FieldMemOperand(elements_reg, JSObject::kMapOffset));
4378 __ li(scratch, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4379 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4380 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
4381 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
4382 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::SizeFor(i)));
4383 }
4384
4385 // Store the element at index zero.
4386 __ sw(value_reg, FieldMemOperand(elements_reg, FixedArray::SizeFor(0)));
4387
4388 // Install the new backing store in the JSArray.
4389 __ sw(elements_reg,
4390 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4391 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
4392 scratch, kRAHasNotBeenSaved, kDontSaveFPRegs,
4393 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4394
4395 // Increment the length of the array.
4396 __ li(length_reg, Operand(Smi::FromInt(1)));
4397 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4398 __ Ret();
4399
4400 __ bind(&check_capacity);
4401 // Check for cow elements, in general they are not handled by this stub
4402 __ CheckMap(elements_reg,
4403 scratch,
4404 Heap::kFixedCOWArrayMapRootIndex,
4405 &miss_force_generic,
4406 DONT_DO_SMI_CHECK);
4407
4408 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4409 __ Branch(&slow, hs, length_reg, Operand(scratch));
4410
4411 // Grow the array and finish the store.
4412 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
4413 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4414 __ jmp(&finish_store);
4415
4416 __ bind(&slow);
4417 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4418 __ Jump(ic_slow, RelocInfo::CODE_TARGET);
4419 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004420}
4421
4422
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004423void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
4424 MacroAssembler* masm,
yangguo@chromium.org56454712012-02-16 15:33:53 +00004425 bool is_js_array,
4426 KeyedAccessGrowMode grow_mode) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004427 // ----------- S t a t e -------------
4428 // -- a0 : value
4429 // -- a1 : key
4430 // -- a2 : receiver
4431 // -- ra : return address
4432 // -- a3 : scratch
4433 // -- t0 : scratch (elements_reg)
4434 // -- t1 : scratch (mantissa_reg)
4435 // -- t2 : scratch (exponent_reg)
4436 // -- t3 : scratch4
4437 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00004438 Label miss_force_generic, transition_elements_kind, grow, slow;
4439 Label finish_store, check_capacity;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004440
4441 Register value_reg = a0;
4442 Register key_reg = a1;
4443 Register receiver_reg = a2;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004444 Register elements_reg = a3;
4445 Register scratch1 = t0;
4446 Register scratch2 = t1;
4447 Register scratch3 = t2;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004448 Register scratch4 = t3;
yangguo@chromium.org56454712012-02-16 15:33:53 +00004449 Register length_reg = t3;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004450
4451 // This stub is meant to be tail-jumped to, the receiver must already
4452 // have been verified by the caller to not be a smi.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004453
4454 // Check that the key is a smi or a heap number convertible to a smi.
4455 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004456
4457 __ lw(elements_reg,
4458 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4459
4460 // Check that the key is within bounds.
4461 if (is_js_array) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004462 __ lw(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004463 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004464 __ lw(scratch1,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004465 FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4466 }
4467 // Compare smis, unsigned compare catches both negative and out-of-bound
4468 // indexes.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004469 if (grow_mode == ALLOW_JSARRAY_GROWTH) {
4470 __ Branch(&grow, hs, key_reg, Operand(scratch1));
4471 } else {
4472 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch1));
4473 }
4474
4475 __ bind(&finish_store);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004476
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004477 __ StoreNumberToDoubleElements(value_reg,
4478 key_reg,
4479 receiver_reg,
4480 elements_reg,
4481 scratch1,
4482 scratch2,
4483 scratch3,
4484 scratch4,
4485 &transition_elements_kind);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004486
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004487 __ Ret(USE_DELAY_SLOT);
4488 __ mov(v0, value_reg); // In delay slot.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004489
4490 // Handle store cache miss, replacing the ic with the generic stub.
4491 __ bind(&miss_force_generic);
4492 Handle<Code> ic =
4493 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4494 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004495
4496 __ bind(&transition_elements_kind);
4497 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4498 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
yangguo@chromium.org56454712012-02-16 15:33:53 +00004499
4500 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4501 // Grow the array by a single element if possible.
4502 __ bind(&grow);
4503
4504 // Make sure the array is only growing by a single element, anything else
4505 // must be handled by the runtime.
4506 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch1));
4507
4508 // Transition on values that can't be stored in a FixedDoubleArray.
4509 Label value_is_smi;
4510 __ JumpIfSmi(value_reg, &value_is_smi);
4511 __ lw(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
4512 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
4513 __ Branch(&transition_elements_kind, ne, scratch1, Operand(at));
4514 __ bind(&value_is_smi);
4515
4516 // Check for the empty array, and preallocate a small backing store if
4517 // possible.
4518 __ lw(length_reg,
4519 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4520 __ lw(elements_reg,
4521 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4522 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
4523 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
4524
4525 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
4526 __ AllocateInNewSpace(size, elements_reg, scratch1, scratch2, &slow,
4527 TAG_OBJECT);
4528
4529 // Initialize the new FixedDoubleArray. Leave elements unitialized for
4530 // efficiency, they are guaranteed to be initialized before use.
4531 __ LoadRoot(scratch1, Heap::kFixedDoubleArrayMapRootIndex);
4532 __ sw(scratch1, FieldMemOperand(elements_reg, JSObject::kMapOffset));
4533 __ li(scratch1, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4534 __ sw(scratch1,
4535 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
4536
4537 // Install the new backing store in the JSArray.
4538 __ sw(elements_reg,
4539 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4540 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
4541 scratch1, kRAHasNotBeenSaved, kDontSaveFPRegs,
4542 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4543
4544 // Increment the length of the array.
4545 __ li(length_reg, Operand(Smi::FromInt(1)));
4546 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
danno@chromium.org00379b82012-05-04 09:16:29 +00004547 __ lw(elements_reg,
4548 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
yangguo@chromium.org56454712012-02-16 15:33:53 +00004549 __ jmp(&finish_store);
4550
4551 __ bind(&check_capacity);
4552 // Make sure that the backing store can hold additional elements.
4553 __ lw(scratch1,
4554 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
4555 __ Branch(&slow, hs, length_reg, Operand(scratch1));
4556
4557 // Grow the array and finish the store.
4558 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
4559 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4560 __ jmp(&finish_store);
4561
4562 __ bind(&slow);
4563 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4564 __ Jump(ic_slow, RelocInfo::CODE_TARGET);
4565 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004566}
4567
4568
ager@chromium.org5c838252010-02-19 08:53:10 +00004569#undef __
4570
4571} } // namespace v8::internal
4572
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004573#endif // V8_TARGET_ARCH_MIPS