blob: d4d4de0a6f73b884b72297023ee11924d8803554 [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,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000425 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +0000426 Register receiver_reg,
427 Register name_reg,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000428 Register scratch1,
429 Register scratch2,
ager@chromium.org5c838252010-02-19 08:53:10 +0000430 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000431 // a0 : value.
432 Label exit;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000433
434 LookupResult lookup(masm->isolate());
435 object->Lookup(*name, &lookup);
436 if (lookup.IsFound() && (lookup.IsReadOnly() || !lookup.IsCacheable())) {
437 // In sloppy mode, we could just return the value and be done. However, we
438 // might be in strict mode, where we have to throw. Since we cannot tell,
439 // go into slow case unconditionally.
440 __ jmp(miss_label);
441 return;
442 }
443
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000444 // Check that the map of the object hasn't changed.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000445 CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
446 : REQUIRE_EXACT_MAP;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000447 __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000448 DO_SMI_CHECK, mode);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000449
450 // Perform global security token check if needed.
451 if (object->IsJSGlobalProxy()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000452 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
453 }
454
455 // Check that we are allowed to write this.
456 if (!transition.is_null() && object->GetPrototype()->IsJSObject()) {
457 JSObject* holder;
458 if (lookup.IsFound()) {
459 holder = lookup.holder();
460 } else {
461 // Find the top object.
462 holder = *object;
463 do {
464 holder = JSObject::cast(holder->GetPrototype());
465 } while (holder->GetPrototype()->IsJSObject());
466 }
467 // We need an extra register, push
468 __ push(name_reg);
469 Label miss_pop, done_check;
470 CheckPrototypes(object, receiver_reg, Handle<JSObject>(holder), name_reg,
471 scratch1, scratch2, name, &miss_pop);
472 __ jmp(&done_check);
473 __ bind(&miss_pop);
474 __ pop(name_reg);
475 __ jmp(miss_label);
476 __ bind(&done_check);
477 __ pop(name_reg);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000478 }
479
480 // Stub never generated for non-global objects that require access
481 // checks.
482 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
483
484 // Perform map transition for the receiver if necessary.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000485 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000486 // The properties must be extended before we can store the value.
487 // We jump to a runtime call that extends the properties array.
488 __ push(receiver_reg);
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000489 __ li(a2, Operand(transition));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000490 __ Push(a2, a0);
491 __ TailCallExternalReference(
492 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
493 masm->isolate()),
494 3, 1);
495 return;
496 }
497
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000498 if (!transition.is_null()) {
verwaest@chromium.org37141392012-05-31 13:27:02 +0000499 // Update the map of the object.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000500 __ li(scratch1, Operand(transition));
501 __ sw(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
verwaest@chromium.org37141392012-05-31 13:27:02 +0000502
503 // Update the write barrier for the map field and pass the now unused
504 // name_reg as scratch register.
505 __ RecordWriteField(receiver_reg,
506 HeapObject::kMapOffset,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000507 scratch1,
verwaest@chromium.org37141392012-05-31 13:27:02 +0000508 name_reg,
509 kRAHasNotBeenSaved,
510 kDontSaveFPRegs,
511 OMIT_REMEMBERED_SET,
512 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000513 }
514
515 // Adjust for the number of properties stored in the object. Even in the
516 // face of a transition we can use the old map here because the size of the
517 // object and the number of in-object properties is not going to change.
518 index -= object->map()->inobject_properties();
519
520 if (index < 0) {
521 // Set the property straight into the object.
522 int offset = object->map()->instance_size() + (index * kPointerSize);
523 __ sw(a0, FieldMemOperand(receiver_reg, offset));
524
525 // Skip updating write barrier if storing a smi.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000526 __ JumpIfSmi(a0, &exit, scratch1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000527
528 // Update the write barrier for the array address.
529 // Pass the now unused name_reg as a scratch register.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000530 __ mov(name_reg, a0);
531 __ RecordWriteField(receiver_reg,
532 offset,
533 name_reg,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000534 scratch1,
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000535 kRAHasNotBeenSaved,
536 kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000537 } else {
538 // Write to the properties array.
539 int offset = index * kPointerSize + FixedArray::kHeaderSize;
540 // Get the properties array.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000541 __ lw(scratch1,
542 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
543 __ sw(a0, FieldMemOperand(scratch1, offset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000544
545 // Skip updating write barrier if storing a smi.
546 __ JumpIfSmi(a0, &exit);
547
548 // Update the write barrier for the array address.
549 // Ok to clobber receiver_reg and name_reg, since we return.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000550 __ mov(name_reg, a0);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000551 __ RecordWriteField(scratch1,
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000552 offset,
553 name_reg,
554 receiver_reg,
555 kRAHasNotBeenSaved,
556 kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000557 }
558
559 // Return the value (register v0).
560 __ bind(&exit);
561 __ mov(v0, a0);
562 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000563}
564
565
566void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000567 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000568 Handle<Code> code = (kind == Code::LOAD_IC)
569 ? masm->isolate()->builtins()->LoadIC_Miss()
570 : masm->isolate()->builtins()->KeyedLoadIC_Miss();
571 __ Jump(code, RelocInfo::CODE_TARGET);
ager@chromium.org5c838252010-02-19 08:53:10 +0000572}
573
574
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000575static void GenerateCallFunction(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000576 Handle<Object> object,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000577 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000578 Label* miss,
579 Code::ExtraICState extra_ic_state) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000580 // ----------- S t a t e -------------
581 // -- a0: receiver
582 // -- a1: function to call
583 // -----------------------------------
584 // Check that the function really is a function.
585 __ JumpIfSmi(a1, miss);
586 __ GetObjectType(a1, a3, a3);
587 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
588
589 // Patch the receiver on the stack with the global proxy if
590 // necessary.
591 if (object->IsGlobalObject()) {
592 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
593 __ sw(a3, MemOperand(sp, arguments.immediate() * kPointerSize));
594 }
595
596 // Invoke the function.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000597 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
598 ? CALL_AS_FUNCTION
599 : CALL_AS_METHOD;
600 __ InvokeFunction(a1, arguments, JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000601}
602
603
604static void PushInterceptorArguments(MacroAssembler* masm,
605 Register receiver,
606 Register holder,
607 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000608 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000609 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000610 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
611 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000612 Register scratch = name;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000613 __ li(scratch, Operand(interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000614 __ Push(scratch, receiver, holder);
615 __ lw(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
616 __ push(scratch);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000617 __ li(scratch, Operand(ExternalReference::isolate_address()));
618 __ push(scratch);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000619}
620
621
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000622static void CompileCallLoadPropertyWithInterceptor(
623 MacroAssembler* masm,
624 Register receiver,
625 Register holder,
626 Register name,
627 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000628 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
629
630 ExternalReference ref =
631 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
632 masm->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000633 __ PrepareCEntryArgs(6);
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000634 __ PrepareCEntryFunction(ref);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000635
636 CEntryStub stub(1);
637 __ CallStub(&stub);
638}
639
640
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000641static const int kFastApiCallArguments = 4;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000642
643
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000644// Reserves space for the extra arguments to API function in the
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000645// caller's frame.
646//
647// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
648static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
649 Register scratch) {
650 ASSERT(Smi::FromInt(0) == 0);
651 for (int i = 0; i < kFastApiCallArguments; i++) {
652 __ push(zero_reg);
653 }
654}
655
656
657// Undoes the effects of ReserveSpaceForFastApiCall.
658static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
659 __ Drop(kFastApiCallArguments);
660}
661
662
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000663static void GenerateFastApiDirectCall(MacroAssembler* masm,
664 const CallOptimization& optimization,
665 int argc) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000666 // ----------- S t a t e -------------
667 // -- sp[0] : holder (set by CheckPrototypes)
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000668 // -- sp[4] : callee JS function
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000669 // -- sp[8] : call data
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000670 // -- sp[12] : isolate
671 // -- sp[16] : last JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000672 // -- ...
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000673 // -- sp[(argc + 3) * 4] : first JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000674 // -- sp[(argc + 4) * 4] : receiver
675 // -----------------------------------
676 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000677 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000678 __ LoadHeapObject(t1, function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000679 __ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset));
680
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000681 // Pass the additional arguments.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000682 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
683 Handle<Object> call_data(api_call_info->data());
684 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
685 __ li(a0, api_call_info);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000686 __ lw(t2, FieldMemOperand(a0, CallHandlerInfo::kDataOffset));
687 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000688 __ li(t2, call_data);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000689 }
690
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000691 __ li(t3, Operand(ExternalReference::isolate_address()));
692 // Store JS function, call data and isolate.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000693 __ sw(t1, MemOperand(sp, 1 * kPointerSize));
694 __ sw(t2, MemOperand(sp, 2 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000695 __ sw(t3, MemOperand(sp, 3 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000696
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000697 // Prepare arguments.
698 __ Addu(a2, sp, Operand(3 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000699
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000700 // Allocate the v8::Arguments structure in the arguments' space since
701 // it's not controlled by GC.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000702 const int kApiStackSpace = 4;
703
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000704 FrameScope frame_scope(masm, StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000705 __ EnterExitFrame(false, kApiStackSpace);
706
707 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
708 // struct from the function (which is currently the case). This means we pass
709 // the first argument in a1 instead of a0. TryCallApiFunctionAndReturn
710 // will handle setting up a0.
711
712 // a1 = v8::Arguments&
713 // Arguments is built at sp + 1 (sp is a reserved spot for ra).
714 __ Addu(a1, sp, kPointerSize);
715
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000716 // v8::Arguments::implicit_args_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000717 __ sw(a2, MemOperand(a1, 0 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000718 // v8::Arguments::values_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000719 __ Addu(t0, a2, Operand(argc * kPointerSize));
720 __ sw(t0, MemOperand(a1, 1 * kPointerSize));
721 // v8::Arguments::length_ = argc
722 __ li(t0, Operand(argc));
723 __ sw(t0, MemOperand(a1, 2 * kPointerSize));
724 // v8::Arguments::is_construct_call = 0
725 __ sw(zero_reg, MemOperand(a1, 3 * kPointerSize));
726
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000727 const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000728 Address function_address = v8::ToCData<Address>(api_call_info->callback());
729 ApiFunction fun(function_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000730 ExternalReference ref =
731 ExternalReference(&fun,
732 ExternalReference::DIRECT_API_CALL,
733 masm->isolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000734 AllowExternalCallThatCantCauseGC scope(masm);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000735 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000736}
737
lrn@chromium.org7516f052011-03-30 08:52:27 +0000738class CallInterceptorCompiler BASE_EMBEDDED {
739 public:
740 CallInterceptorCompiler(StubCompiler* stub_compiler,
741 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000742 Register name,
743 Code::ExtraICState extra_ic_state)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000744 : stub_compiler_(stub_compiler),
745 arguments_(arguments),
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000746 name_(name),
747 extra_ic_state_(extra_ic_state) {}
lrn@chromium.org7516f052011-03-30 08:52:27 +0000748
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000749 void Compile(MacroAssembler* masm,
750 Handle<JSObject> object,
751 Handle<JSObject> holder,
752 Handle<String> name,
753 LookupResult* lookup,
754 Register receiver,
755 Register scratch1,
756 Register scratch2,
757 Register scratch3,
758 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000759 ASSERT(holder->HasNamedInterceptor());
760 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
761
762 // Check that the receiver isn't a smi.
763 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000764 CallOptimization optimization(lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000765 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000766 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
767 holder, lookup, name, optimization, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000768 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000769 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
770 name, holder, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000771 }
772 }
773
774 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000775 void CompileCacheable(MacroAssembler* masm,
776 Handle<JSObject> object,
777 Register receiver,
778 Register scratch1,
779 Register scratch2,
780 Register scratch3,
781 Handle<JSObject> interceptor_holder,
782 LookupResult* lookup,
783 Handle<String> name,
784 const CallOptimization& optimization,
785 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000786 ASSERT(optimization.is_constant_call());
787 ASSERT(!lookup->holder()->IsGlobalObject());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000788 Counters* counters = masm->isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000789 int depth1 = kInvalidProtoDepth;
790 int depth2 = kInvalidProtoDepth;
791 bool can_do_fast_api_call = false;
792 if (optimization.is_simple_api_call() &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000793 !lookup->holder()->IsGlobalObject()) {
794 depth1 = optimization.GetPrototypeDepthOfExpectedType(
795 object, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000796 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000797 depth2 = optimization.GetPrototypeDepthOfExpectedType(
798 interceptor_holder, Handle<JSObject>(lookup->holder()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000799 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000800 can_do_fast_api_call =
801 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000802 }
803
804 __ IncrementCounter(counters->call_const_interceptor(), 1,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000805 scratch1, scratch2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000806
807 if (can_do_fast_api_call) {
808 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
809 scratch1, scratch2);
810 ReserveSpaceForFastApiCall(masm, scratch1);
811 }
812
813 // Check that the maps from receiver to interceptor's holder
814 // haven't changed and thus we can invoke interceptor.
815 Label miss_cleanup;
816 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
817 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000818 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
819 scratch1, scratch2, scratch3,
820 name, depth1, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000821
822 // Invoke an interceptor and if it provides a value,
823 // branch to |regular_invoke|.
824 Label regular_invoke;
825 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
826 &regular_invoke);
827
828 // Interceptor returned nothing for this property. Try to use cached
829 // constant function.
830
831 // Check that the maps from interceptor's holder to constant function's
832 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000833 if (*interceptor_holder != lookup->holder()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000834 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000835 Handle<JSObject>(lookup->holder()),
836 scratch1, scratch2, scratch3,
837 name, depth2, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000838 } else {
839 // CheckPrototypes has a side effect of fetching a 'holder'
840 // for API (object which is instanceof for the signature). It's
841 // safe to omit it here, as if present, it should be fetched
842 // by the previous CheckPrototypes.
843 ASSERT(depth2 == kInvalidProtoDepth);
844 }
845
846 // Invoke function.
847 if (can_do_fast_api_call) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000848 GenerateFastApiDirectCall(masm, optimization, arguments_.immediate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000849 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000850 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
851 ? CALL_AS_FUNCTION
852 : CALL_AS_METHOD;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000853 __ InvokeFunction(optimization.constant_function(), arguments_,
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000854 JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000855 }
856
857 // Deferred code for fast API call case---clean preallocated space.
858 if (can_do_fast_api_call) {
859 __ bind(&miss_cleanup);
860 FreeSpaceForFastApiCall(masm);
861 __ Branch(miss_label);
862 }
863
864 // Invoke a regular function.
865 __ bind(&regular_invoke);
866 if (can_do_fast_api_call) {
867 FreeSpaceForFastApiCall(masm);
868 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000869 }
870
871 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000872 Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000873 Register receiver,
874 Register scratch1,
875 Register scratch2,
876 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000877 Handle<String> name,
878 Handle<JSObject> interceptor_holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000879 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000880 Register holder =
881 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000882 scratch1, scratch2, scratch3,
883 name, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000884
885 // Call a runtime function to load the interceptor property.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000886 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000887 // Save the name_ register across the call.
888 __ push(name_);
889
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000890 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000891
892 __ CallExternalReference(
893 ExternalReference(
894 IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
895 masm->isolate()),
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000896 6);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000897 // Restore the name_ register.
898 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000899 // Leave the internal frame.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000900 }
901
902 void LoadWithInterceptor(MacroAssembler* masm,
903 Register receiver,
904 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000905 Handle<JSObject> holder_obj,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000906 Register scratch,
907 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000908 {
909 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000910
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000911 __ Push(holder, name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000912 CompileCallLoadPropertyWithInterceptor(masm,
913 receiver,
914 holder,
915 name_,
916 holder_obj);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000917 __ pop(name_); // Restore the name.
918 __ pop(receiver); // Restore the holder.
919 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000920 // If interceptor returns no-result sentinel, call the constant function.
921 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
922 __ Branch(interceptor_succeeded, ne, v0, Operand(scratch));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000923 }
924
925 StubCompiler* stub_compiler_;
926 const ParameterCount& arguments_;
927 Register name_;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000928 Code::ExtraICState extra_ic_state_;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000929};
930
931
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000932
933// Generate code to check that a global property cell is empty. Create
934// the property cell at compilation time if no cell exists for the
935// property.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000936static void GenerateCheckPropertyCell(MacroAssembler* masm,
937 Handle<GlobalObject> global,
938 Handle<String> name,
939 Register scratch,
940 Label* miss) {
941 Handle<JSGlobalPropertyCell> cell =
942 GlobalObject::EnsurePropertyCell(global, name);
943 ASSERT(cell->value()->IsTheHole());
944 __ li(scratch, Operand(cell));
945 __ lw(scratch,
946 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
947 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
948 __ Branch(miss, ne, scratch, Operand(at));
949}
950
951
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000952// Calls GenerateCheckPropertyCell for each global object in the prototype chain
953// from object to (but not including) holder.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000954static void GenerateCheckPropertyCells(MacroAssembler* masm,
955 Handle<JSObject> object,
956 Handle<JSObject> holder,
957 Handle<String> name,
958 Register scratch,
959 Label* miss) {
960 Handle<JSObject> current = object;
961 while (!current.is_identical_to(holder)) {
962 if (current->IsGlobalObject()) {
963 GenerateCheckPropertyCell(masm,
964 Handle<GlobalObject>::cast(current),
965 name,
966 scratch,
967 miss);
968 }
969 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
970 }
971}
972
973
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000974// Convert and store int passed in register ival to IEEE 754 single precision
975// floating point value at memory location (dst + 4 * wordoffset)
976// If FPU is available use it for conversion.
977static void StoreIntAsFloat(MacroAssembler* masm,
978 Register dst,
979 Register wordoffset,
980 Register ival,
981 Register fval,
982 Register scratch1,
983 Register scratch2) {
984 if (CpuFeatures::IsSupported(FPU)) {
985 CpuFeatures::Scope scope(FPU);
986 __ mtc1(ival, f0);
987 __ cvt_s_w(f0, f0);
988 __ sll(scratch1, wordoffset, 2);
989 __ addu(scratch1, dst, scratch1);
990 __ swc1(f0, MemOperand(scratch1, 0));
991 } else {
992 // FPU is not available, do manual conversions.
993
994 Label not_special, done;
995 // Move sign bit from source to destination. This works because the sign
996 // bit in the exponent word of the double has the same position and polarity
997 // as the 2's complement sign bit in a Smi.
998 ASSERT(kBinary32SignMask == 0x80000000u);
999
1000 __ And(fval, ival, Operand(kBinary32SignMask));
1001 // Negate value if it is negative.
1002 __ subu(scratch1, zero_reg, ival);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001003 __ Movn(ival, scratch1, fval);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001004
1005 // We have -1, 0 or 1, which we treat specially. Register ival contains
1006 // absolute value: it is either equal to 1 (special case of -1 and 1),
1007 // greater than 1 (not a special case) or less than 1 (special case of 0).
1008 __ Branch(&not_special, gt, ival, Operand(1));
1009
1010 // For 1 or -1 we need to or in the 0 exponent (biased).
1011 static const uint32_t exponent_word_for_1 =
1012 kBinary32ExponentBias << kBinary32ExponentShift;
1013
1014 __ Xor(scratch1, ival, Operand(1));
1015 __ li(scratch2, exponent_word_for_1);
1016 __ or_(scratch2, fval, scratch2);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001017 __ Movz(fval, scratch2, scratch1); // Only if ival is equal to 1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001018 __ Branch(&done);
1019
1020 __ bind(&not_special);
1021 // Count leading zeros.
1022 // Gets the wrong answer for 0, but we already checked for that case above.
1023 Register zeros = scratch2;
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001024 __ Clz(zeros, ival);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001025
1026 // Compute exponent and or it into the exponent register.
1027 __ li(scratch1, (kBitsPerInt - 1) + kBinary32ExponentBias);
1028 __ subu(scratch1, scratch1, zeros);
1029
1030 __ sll(scratch1, scratch1, kBinary32ExponentShift);
1031 __ or_(fval, fval, scratch1);
1032
1033 // Shift up the source chopping the top bit off.
1034 __ Addu(zeros, zeros, Operand(1));
1035 // This wouldn't work for 1 and -1 as the shift would be 32 which means 0.
1036 __ sllv(ival, ival, zeros);
1037 // And the top (top 20 bits).
1038 __ srl(scratch1, ival, kBitsPerInt - kBinary32MantissaBits);
1039 __ or_(fval, fval, scratch1);
1040
1041 __ bind(&done);
1042
1043 __ sll(scratch1, wordoffset, 2);
1044 __ addu(scratch1, dst, scratch1);
1045 __ sw(fval, MemOperand(scratch1, 0));
1046 }
1047}
1048
1049
1050// Convert unsigned integer with specified number of leading zeroes in binary
1051// representation to IEEE 754 double.
1052// Integer to convert is passed in register hiword.
1053// Resulting double is returned in registers hiword:loword.
1054// This functions does not work correctly for 0.
1055static void GenerateUInt2Double(MacroAssembler* masm,
1056 Register hiword,
1057 Register loword,
1058 Register scratch,
1059 int leading_zeroes) {
1060 const int meaningful_bits = kBitsPerInt - leading_zeroes - 1;
1061 const int biased_exponent = HeapNumber::kExponentBias + meaningful_bits;
1062
1063 const int mantissa_shift_for_hi_word =
1064 meaningful_bits - HeapNumber::kMantissaBitsInTopWord;
1065
1066 const int mantissa_shift_for_lo_word =
1067 kBitsPerInt - mantissa_shift_for_hi_word;
1068
1069 __ li(scratch, biased_exponent << HeapNumber::kExponentShift);
1070 if (mantissa_shift_for_hi_word > 0) {
1071 __ sll(loword, hiword, mantissa_shift_for_lo_word);
1072 __ srl(hiword, hiword, mantissa_shift_for_hi_word);
1073 __ or_(hiword, scratch, hiword);
1074 } else {
1075 __ mov(loword, zero_reg);
1076 __ sll(hiword, hiword, mantissa_shift_for_hi_word);
1077 __ or_(hiword, scratch, hiword);
1078 }
1079
1080 // If least significant bit of biased exponent was not 1 it was corrupted
1081 // by most significant bit of mantissa so we should fix that.
1082 if (!(biased_exponent & 1)) {
1083 __ li(scratch, 1 << HeapNumber::kExponentShift);
1084 __ nor(scratch, scratch, scratch);
1085 __ and_(hiword, hiword, scratch);
1086 }
1087}
1088
1089
ager@chromium.org5c838252010-02-19 08:53:10 +00001090#undef __
1091#define __ ACCESS_MASM(masm())
1092
1093
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001094Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
1095 Register object_reg,
1096 Handle<JSObject> holder,
1097 Register holder_reg,
1098 Register scratch1,
1099 Register scratch2,
1100 Handle<String> name,
1101 int save_at_depth,
1102 Label* miss) {
1103 // Make sure there's no overlap between holder and object registers.
1104 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1105 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1106 && !scratch2.is(scratch1));
1107
1108 // Keep track of the current object in register reg.
1109 Register reg = object_reg;
1110 int depth = 0;
1111
1112 if (save_at_depth == depth) {
1113 __ sw(reg, MemOperand(sp));
1114 }
1115
1116 // Check the maps in the prototype chain.
1117 // Traverse the prototype chain from the object and do map checks.
1118 Handle<JSObject> current = object;
1119 while (!current.is_identical_to(holder)) {
1120 ++depth;
1121
1122 // Only global objects and objects that do not require access
1123 // checks are allowed in stubs.
1124 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1125
1126 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
1127 if (!current->HasFastProperties() &&
1128 !current->IsJSGlobalObject() &&
1129 !current->IsJSGlobalProxy()) {
1130 if (!name->IsSymbol()) {
1131 name = factory()->LookupSymbol(name);
1132 }
1133 ASSERT(current->property_dictionary()->FindEntry(*name) ==
1134 StringDictionary::kNotFound);
1135
1136 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1137 scratch1, scratch2);
1138
1139 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1140 reg = holder_reg; // From now on the object will be in holder_reg.
1141 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1142 } else {
1143 Handle<Map> current_map(current->map());
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001144 __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK,
1145 ALLOW_ELEMENT_TRANSITION_MAPS);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001146 // Check access rights to the global object. This has to happen after
1147 // the map check so that we know that the object is actually a global
1148 // object.
1149 if (current->IsJSGlobalProxy()) {
1150 __ CheckAccessGlobalProxy(reg, scratch2, miss);
1151 }
1152 reg = holder_reg; // From now on the object will be in holder_reg.
1153
1154 if (heap()->InNewSpace(*prototype)) {
1155 // The prototype is in new space; we cannot store a reference to it
1156 // in the code. Load it from the map.
1157 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1158 } else {
1159 // The prototype is in old space; load it directly.
1160 __ li(reg, Operand(prototype));
1161 }
1162 }
1163
1164 if (save_at_depth == depth) {
1165 __ sw(reg, MemOperand(sp));
1166 }
1167
1168 // Go to the next object in the prototype chain.
1169 current = prototype;
1170 }
1171
1172 // Log the check depth.
1173 LOG(masm()->isolate(), IntEvent("check-maps-depth", depth + 1));
1174
1175 // Check the holder map.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001176 __ CheckMap(reg, scratch1, Handle<Map>(current->map()), miss,
1177 DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001178
1179 // Perform security check for access to the global object.
1180 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1181 if (holder->IsJSGlobalProxy()) {
1182 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1183 }
1184
1185 // If we've skipped any global objects, it's not enough to verify that
1186 // their maps haven't changed. We also need to check that the property
1187 // cell for the property is still empty.
1188 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1189
1190 // Return the register containing the holder.
1191 return reg;
1192}
1193
1194
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001195void StubCompiler::GenerateLoadField(Handle<JSObject> object,
1196 Handle<JSObject> holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001197 Register receiver,
1198 Register scratch1,
1199 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001200 Register scratch3,
ager@chromium.org5c838252010-02-19 08:53:10 +00001201 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001202 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001203 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001204 // Check that the receiver isn't a smi.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001205 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001206
1207 // Check that the maps haven't changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001208 Register reg = CheckPrototypes(
1209 object, receiver, holder, scratch1, scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001210 GenerateFastPropertyLoad(masm(), v0, reg, holder, index);
1211 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001212}
1213
1214
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001215void StubCompiler::GenerateLoadConstant(Handle<JSObject> object,
1216 Handle<JSObject> holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001217 Register receiver,
1218 Register scratch1,
1219 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001220 Register scratch3,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001221 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001222 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001223 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001224 // Check that the receiver isn't a smi.
1225 __ JumpIfSmi(receiver, miss, scratch1);
1226
1227 // Check that the maps haven't changed.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001228 CheckPrototypes(object, receiver, holder,
1229 scratch1, scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001230
1231 // Return the constant value.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001232 __ LoadHeapObject(v0, value);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001233 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001234}
1235
1236
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001237void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
1238 Handle<JSObject> holder,
1239 Register receiver,
1240 Register name_reg,
1241 Register scratch1,
1242 Register scratch2,
1243 Register scratch3,
1244 Handle<AccessorInfo> callback,
1245 Handle<String> name,
1246 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001247 // Check that the receiver isn't a smi.
1248 __ JumpIfSmi(receiver, miss, scratch1);
1249
1250 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001251 Register reg = CheckPrototypes(object, receiver, holder, scratch1,
1252 scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001253
1254 // Build AccessorInfo::args_ list on the stack and push property name below
1255 // the exit frame to make GC aware of them and store pointers to them.
1256 __ push(receiver);
1257 __ mov(scratch2, sp); // scratch2 = AccessorInfo::args_
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001258 if (heap()->InNewSpace(callback->data())) {
1259 __ li(scratch3, callback);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001260 __ lw(scratch3, FieldMemOperand(scratch3, AccessorInfo::kDataOffset));
1261 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001262 __ li(scratch3, Handle<Object>(callback->data()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001263 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001264 __ Subu(sp, sp, 4 * kPointerSize);
1265 __ sw(reg, MemOperand(sp, 3 * kPointerSize));
1266 __ sw(scratch3, MemOperand(sp, 2 * kPointerSize));
1267 __ li(scratch3, Operand(ExternalReference::isolate_address()));
1268 __ sw(scratch3, MemOperand(sp, 1 * kPointerSize));
1269 __ sw(name_reg, MemOperand(sp, 0 * kPointerSize));
1270
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001271 __ mov(a2, scratch2); // Saved in case scratch2 == a1.
1272 __ mov(a1, sp); // a1 (first argument - see note below) = Handle<String>
1273
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001274 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
1275 // struct from the function (which is currently the case). This means we pass
1276 // the arguments in a1-a2 instead of a0-a1. TryCallApiFunctionAndReturn
1277 // will handle setting up a0.
1278
1279 const int kApiStackSpace = 1;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001280 FrameScope frame_scope(masm(), StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001281 __ EnterExitFrame(false, kApiStackSpace);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001282
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001283 // Create AccessorInfo instance on the stack above the exit frame with
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001284 // scratch2 (internal::Object** args_) as the data.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001285 __ sw(a2, MemOperand(sp, kPointerSize));
1286 // a2 (second argument - see note above) = AccessorInfo&
1287 __ Addu(a2, sp, kPointerSize);
1288
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001289 const int kStackUnwindSpace = 5;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001290 Address getter_address = v8::ToCData<Address>(callback->getter());
1291 ApiFunction fun(getter_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001292 ExternalReference ref =
1293 ExternalReference(&fun,
1294 ExternalReference::DIRECT_GETTER_CALL,
1295 masm()->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001296 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
ager@chromium.org5c838252010-02-19 08:53:10 +00001297}
1298
1299
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001300void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
1301 Handle<JSObject> interceptor_holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001302 LookupResult* lookup,
1303 Register receiver,
1304 Register name_reg,
1305 Register scratch1,
1306 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001307 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001308 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001309 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001310 ASSERT(interceptor_holder->HasNamedInterceptor());
1311 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1312
1313 // Check that the receiver isn't a smi.
1314 __ JumpIfSmi(receiver, miss);
1315
1316 // So far the most popular follow ups for interceptor loads are FIELD
1317 // and CALLBACKS, so inline only them, other cases may be added
1318 // later.
1319 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001320 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001321 if (lookup->IsField()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001322 compile_followup_inline = true;
1323 } else if (lookup->type() == CALLBACKS &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001324 lookup->GetCallbackObject()->IsAccessorInfo()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001325 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
1326 compile_followup_inline = callback->getter() != NULL &&
1327 callback->IsCompatibleReceiver(*object);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001328 }
1329 }
1330
1331 if (compile_followup_inline) {
1332 // Compile the interceptor call, followed by inline code to load the
1333 // property from further up the prototype chain if the call fails.
1334 // Check that the maps haven't changed.
1335 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1336 scratch1, scratch2, scratch3,
1337 name, miss);
1338 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
1339
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001340 // Preserve the receiver register explicitly whenever it is different from
1341 // the holder and it is needed should the interceptor return without any
1342 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1343 // the FIELD case might cause a miss during the prototype check.
1344 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
1345 bool must_preserve_receiver_reg = !receiver.is(holder_reg) &&
1346 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1347
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001348 // Save necessary data before invoking an interceptor.
1349 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001350 {
1351 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001352 if (must_preserve_receiver_reg) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001353 __ Push(receiver, holder_reg, name_reg);
1354 } else {
1355 __ Push(holder_reg, name_reg);
1356 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001357 // Invoke an interceptor. Note: map checks from receiver to
1358 // interceptor's holder has been compiled before (see a caller
1359 // of this method).
1360 CompileCallLoadPropertyWithInterceptor(masm(),
1361 receiver,
1362 holder_reg,
1363 name_reg,
1364 interceptor_holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001365 // Check if interceptor provided a value for property. If it's
1366 // the case, return immediately.
1367 Label interceptor_failed;
1368 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
1369 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1));
1370 frame_scope.GenerateLeaveFrame();
1371 __ Ret();
1372
1373 __ bind(&interceptor_failed);
1374 __ pop(name_reg);
1375 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001376 if (must_preserve_receiver_reg) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001377 __ pop(receiver);
1378 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001379 // Leave the internal frame.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001380 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001381 // Check that the maps from interceptor's holder to lookup's holder
1382 // haven't changed. And load lookup's holder into |holder| register.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001383 if (must_perfrom_prototype_check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001384 holder_reg = CheckPrototypes(interceptor_holder,
1385 holder_reg,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001386 Handle<JSObject>(lookup->holder()),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001387 scratch1,
1388 scratch2,
1389 scratch3,
1390 name,
1391 miss);
1392 }
1393
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001394 if (lookup->IsField()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001395 // We found FIELD property in prototype chain of interceptor's holder.
1396 // Retrieve a field from field's holder.
1397 GenerateFastPropertyLoad(masm(), v0, holder_reg,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001398 Handle<JSObject>(lookup->holder()),
1399 lookup->GetFieldIndex());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001400 __ Ret();
1401 } else {
1402 // We found CALLBACKS property in prototype chain of interceptor's
1403 // holder.
1404 ASSERT(lookup->type() == CALLBACKS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001405 Handle<AccessorInfo> callback(
1406 AccessorInfo::cast(lookup->GetCallbackObject()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001407 ASSERT(callback->getter() != NULL);
1408
1409 // Tail call to runtime.
1410 // Important invariant in CALLBACKS case: the code above must be
1411 // structured to never clobber |receiver| register.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001412 __ li(scratch2, callback);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001413
1414 __ Push(receiver, holder_reg);
1415 __ lw(scratch3,
1416 FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
1417 __ li(scratch1, Operand(ExternalReference::isolate_address()));
1418 __ Push(scratch3, scratch1, scratch2, name_reg);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001419
1420 ExternalReference ref =
1421 ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
1422 masm()->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001423 __ TailCallExternalReference(ref, 6, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001424 }
1425 } else { // !compile_followup_inline
1426 // Call the runtime system to load the interceptor.
1427 // Check that the maps haven't changed.
1428 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1429 scratch1, scratch2, scratch3,
1430 name, miss);
1431 PushInterceptorArguments(masm(), receiver, holder_reg,
1432 name_reg, interceptor_holder);
1433
1434 ExternalReference ref = ExternalReference(
1435 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), masm()->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001436 __ TailCallExternalReference(ref, 6, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001437 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001438}
1439
1440
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001441void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001442 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001443 __ Branch(miss, ne, a2, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001444 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001445}
1446
1447
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001448void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1449 Handle<JSObject> holder,
1450 Handle<String> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001451 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001452 ASSERT(holder->IsGlobalObject());
1453
1454 // Get the number of arguments.
1455 const int argc = arguments().immediate();
1456
1457 // Get the receiver from the stack.
1458 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1459
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001460 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001461 __ JumpIfSmi(a0, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001462 CheckPrototypes(object, a0, holder, a3, a1, t0, name, miss);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001463}
1464
1465
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001466void CallStubCompiler::GenerateLoadFunctionFromCell(
1467 Handle<JSGlobalPropertyCell> cell,
1468 Handle<JSFunction> function,
1469 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001470 // Get the value from the cell.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001471 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001472 __ lw(a1, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
1473
1474 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001475 if (heap()->InNewSpace(*function)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001476 // We can't embed a pointer to a function in new space so we have
1477 // to verify that the shared function info is unchanged. This has
1478 // the nice side effect that multiple closures based on the same
1479 // function can all use this call IC. Before we load through the
1480 // function, we have to verify that it still is a function.
1481 __ JumpIfSmi(a1, miss);
1482 __ GetObjectType(a1, a3, a3);
1483 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
1484
1485 // Check the shared function info. Make sure it hasn't changed.
1486 __ li(a3, Handle<SharedFunctionInfo>(function->shared()));
1487 __ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
1488 __ Branch(miss, ne, t0, Operand(a3));
1489 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001490 __ Branch(miss, ne, a1, Operand(function));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001491 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001492}
1493
1494
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001495void CallStubCompiler::GenerateMissBranch() {
1496 Handle<Code> code =
danno@chromium.org40cb8782011-05-25 07:58:50 +00001497 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1498 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001499 extra_state_);
1500 __ Jump(code, RelocInfo::CODE_TARGET);
1501}
1502
1503
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001504Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1505 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001506 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001507 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001508 // ----------- S t a t e -------------
1509 // -- a2 : name
1510 // -- ra : return address
1511 // -----------------------------------
1512 Label miss;
1513
1514 GenerateNameCheck(name, &miss);
1515
1516 const int argc = arguments().immediate();
1517
1518 // Get the receiver of the function from the stack into a0.
1519 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1520 // Check that the receiver isn't a smi.
1521 __ JumpIfSmi(a0, &miss, t0);
1522
1523 // Do the right check and compute the holder register.
1524 Register reg = CheckPrototypes(object, a0, holder, a1, a3, t0, name, &miss);
1525 GenerateFastPropertyLoad(masm(), a1, reg, holder, index);
1526
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001527 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001528
1529 // Handle call cache miss.
1530 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001531 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001532
1533 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001534 return GetCode(Code::FIELD, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001535}
1536
1537
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001538Handle<Code> CallStubCompiler::CompileArrayPushCall(
1539 Handle<Object> object,
1540 Handle<JSObject> holder,
1541 Handle<JSGlobalPropertyCell> cell,
1542 Handle<JSFunction> function,
1543 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001544 // ----------- S t a t e -------------
1545 // -- a2 : name
1546 // -- ra : return address
1547 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1548 // -- ...
1549 // -- sp[argc * 4] : receiver
1550 // -----------------------------------
1551
1552 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001553 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001554
1555 Label miss;
1556
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001557 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001558
1559 Register receiver = a1;
1560
1561 // Get the receiver from the stack.
1562 const int argc = arguments().immediate();
1563 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1564
1565 // Check that the receiver isn't a smi.
1566 __ JumpIfSmi(receiver, &miss);
1567
1568 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001569 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, a3, v0, t0,
1570 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001571
1572 if (argc == 0) {
1573 // Nothing to do, just return the length.
1574 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1575 __ Drop(argc + 1);
1576 __ Ret();
1577 } else {
1578 Label call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001579 if (argc == 1) { // Otherwise fall through to call the builtin.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001580 Label attempt_to_grow_elements;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001581
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001582 Register elements = t2;
1583 Register end_elements = t1;
1584 // Get the elements array of the object.
1585 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1586
1587 // Check that the elements are in fast mode and writable.
1588 __ CheckMap(elements,
1589 v0,
1590 Heap::kFixedArrayMapRootIndex,
1591 &call_builtin,
1592 DONT_DO_SMI_CHECK);
1593
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001594 // Get the array's length into v0 and calculate new length.
1595 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1596 STATIC_ASSERT(kSmiTagSize == 1);
1597 STATIC_ASSERT(kSmiTag == 0);
1598 __ Addu(v0, v0, Operand(Smi::FromInt(argc)));
1599
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001600 // Get the elements' length.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001601 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1602
1603 // Check if we could survive without allocation.
1604 __ Branch(&attempt_to_grow_elements, gt, v0, Operand(t0));
1605
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001606 // Check if value is a smi.
1607 Label with_write_barrier;
1608 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1609 __ JumpIfNotSmi(t0, &with_write_barrier);
1610
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001611 // Save new length.
1612 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1613
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001614 // Store the value.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001615 // We may need a register containing the address end_elements below,
1616 // so write back the value in end_elements.
1617 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1618 __ Addu(end_elements, elements, end_elements);
1619 const int kEndElementsOffset =
1620 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001621 __ Addu(end_elements, end_elements, kEndElementsOffset);
1622 __ sw(t0, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001623
1624 // Check for a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001625 __ Drop(argc + 1);
1626 __ Ret();
1627
1628 __ bind(&with_write_barrier);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001629
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001630 __ lw(a3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1631
1632 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
1633 Label fast_object, not_fast_object;
1634 __ CheckFastObjectElements(a3, t3, &not_fast_object);
1635 __ jmp(&fast_object);
1636 // In case of fast smi-only, convert to fast object, otherwise bail out.
1637 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001638 __ CheckFastSmiElements(a3, t3, &call_builtin);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001639 // edx: receiver
1640 // r3: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001641 Label try_holey_map;
1642 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001643 FAST_ELEMENTS,
1644 a3,
1645 t3,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001646 &try_holey_map);
1647 __ mov(a2, receiver);
1648 ElementsTransitionGenerator::
1649 GenerateMapChangeElementsTransition(masm());
1650 __ jmp(&fast_object);
1651
1652 __ bind(&try_holey_map);
1653 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1654 FAST_HOLEY_ELEMENTS,
1655 a3,
1656 t3,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001657 &call_builtin);
1658 __ mov(a2, receiver);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001659 ElementsTransitionGenerator::
1660 GenerateMapChangeElementsTransition(masm());
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001661 __ bind(&fast_object);
1662 } else {
1663 __ CheckFastObjectElements(a3, a3, &call_builtin);
1664 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001665
1666 // Save new length.
1667 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1668
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001669 // Store the value.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001670 // We may need a register containing the address end_elements below,
1671 // so write back the value in end_elements.
1672 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1673 __ Addu(end_elements, elements, end_elements);
1674 __ Addu(end_elements, end_elements, kEndElementsOffset);
1675 __ sw(t0, MemOperand(end_elements));
1676
1677 __ RecordWrite(elements,
1678 end_elements,
1679 t0,
1680 kRAHasNotBeenSaved,
1681 kDontSaveFPRegs,
1682 EMIT_REMEMBERED_SET,
1683 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001684 __ Drop(argc + 1);
1685 __ Ret();
1686
1687 __ bind(&attempt_to_grow_elements);
1688 // v0: array's length + 1.
1689 // t0: elements' length.
1690
1691 if (!FLAG_inline_new) {
1692 __ Branch(&call_builtin);
1693 }
1694
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001695 __ lw(a2, MemOperand(sp, (argc - 1) * kPointerSize));
1696 // Growing elements that are SMI-only requires special handling in case
1697 // the new element is non-Smi. For now, delegate to the builtin.
1698 Label no_fast_elements_check;
1699 __ JumpIfSmi(a2, &no_fast_elements_check);
1700 __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1701 __ CheckFastObjectElements(t3, t3, &call_builtin);
1702 __ bind(&no_fast_elements_check);
1703
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001704 ExternalReference new_space_allocation_top =
1705 ExternalReference::new_space_allocation_top_address(
1706 masm()->isolate());
1707 ExternalReference new_space_allocation_limit =
1708 ExternalReference::new_space_allocation_limit_address(
1709 masm()->isolate());
1710
1711 const int kAllocationDelta = 4;
1712 // Load top and check if it is the end of elements.
1713 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1714 __ Addu(end_elements, elements, end_elements);
1715 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset));
1716 __ li(t3, Operand(new_space_allocation_top));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001717 __ lw(a3, MemOperand(t3));
1718 __ Branch(&call_builtin, ne, end_elements, Operand(a3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001719
1720 __ li(t5, Operand(new_space_allocation_limit));
1721 __ lw(t5, MemOperand(t5));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001722 __ Addu(a3, a3, Operand(kAllocationDelta * kPointerSize));
1723 __ Branch(&call_builtin, hi, a3, Operand(t5));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001724
1725 // We fit and could grow elements.
1726 // Update new_space_allocation_top.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001727 __ sw(a3, MemOperand(t3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001728 // Push the argument.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001729 __ sw(a2, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001730 // Fill the rest with holes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001731 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001732 for (int i = 1; i < kAllocationDelta; i++) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001733 __ sw(a3, MemOperand(end_elements, i * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001734 }
1735
1736 // Update elements' and array's sizes.
1737 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1738 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta)));
1739 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1740
1741 // Elements are in new space, so write barrier is not required.
1742 __ Drop(argc + 1);
1743 __ Ret();
1744 }
1745 __ bind(&call_builtin);
1746 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
1747 masm()->isolate()),
1748 argc + 1,
1749 1);
1750 }
1751
1752 // Handle call cache miss.
1753 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001754 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001755
1756 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001757 return GetCode(function);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001758}
1759
1760
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001761Handle<Code> CallStubCompiler::CompileArrayPopCall(
1762 Handle<Object> object,
1763 Handle<JSObject> holder,
1764 Handle<JSGlobalPropertyCell> cell,
1765 Handle<JSFunction> function,
1766 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001767 // ----------- S t a t e -------------
1768 // -- a2 : name
1769 // -- ra : return address
1770 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1771 // -- ...
1772 // -- sp[argc * 4] : receiver
1773 // -----------------------------------
1774
1775 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001776 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001777
1778 Label miss, return_undefined, call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001779 Register receiver = a1;
1780 Register elements = a3;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001781 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001782
1783 // Get the receiver from the stack.
1784 const int argc = arguments().immediate();
1785 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001786 // Check that the receiver isn't a smi.
1787 __ JumpIfSmi(receiver, &miss);
1788
1789 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001790 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, elements,
1791 t0, v0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001792
1793 // Get the elements array of the object.
1794 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1795
1796 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001797 __ CheckMap(elements,
1798 v0,
1799 Heap::kFixedArrayMapRootIndex,
1800 &call_builtin,
1801 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001802
1803 // Get the array's length into t0 and calculate new length.
1804 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1805 __ Subu(t0, t0, Operand(Smi::FromInt(1)));
1806 __ Branch(&return_undefined, lt, t0, Operand(zero_reg));
1807
1808 // Get the last element.
1809 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1810 STATIC_ASSERT(kSmiTagSize == 1);
1811 STATIC_ASSERT(kSmiTag == 0);
1812 // We can't address the last element in one operation. Compute the more
1813 // expensive shift first, and use an offset later on.
1814 __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize);
1815 __ Addu(elements, elements, t1);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001816 __ lw(v0, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001817 __ Branch(&call_builtin, eq, v0, Operand(t2));
1818
1819 // Set the array's length.
1820 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1821
1822 // Fill with the hole.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001823 __ sw(t2, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001824 __ Drop(argc + 1);
1825 __ Ret();
1826
1827 __ bind(&return_undefined);
1828 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
1829 __ Drop(argc + 1);
1830 __ Ret();
1831
1832 __ bind(&call_builtin);
1833 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop,
1834 masm()->isolate()),
1835 argc + 1,
1836 1);
1837
1838 // Handle call cache miss.
1839 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001840 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001841
1842 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001843 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001844}
1845
1846
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001847Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1848 Handle<Object> object,
1849 Handle<JSObject> holder,
1850 Handle<JSGlobalPropertyCell> cell,
1851 Handle<JSFunction> function,
1852 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001853 // ----------- S t a t e -------------
1854 // -- a2 : function name
1855 // -- ra : return address
1856 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1857 // -- ...
1858 // -- sp[argc * 4] : receiver
1859 // -----------------------------------
1860
1861 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001862 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001863
1864 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001865 Label miss;
1866 Label name_miss;
1867 Label index_out_of_range;
1868
1869 Label* index_out_of_range_label = &index_out_of_range;
1870
danno@chromium.org40cb8782011-05-25 07:58:50 +00001871 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001872 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001873 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001874 index_out_of_range_label = &miss;
1875 }
1876
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001877 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001878
1879 // Check that the maps starting from the prototype haven't changed.
1880 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1881 Context::STRING_FUNCTION_INDEX,
1882 v0,
1883 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001884 ASSERT(!object.is_identical_to(holder));
1885 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1886 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001887
1888 Register receiver = a1;
1889 Register index = t1;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001890 Register result = v0;
1891 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1892 if (argc > 0) {
1893 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1894 } else {
1895 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1896 }
1897
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001898 StringCharCodeAtGenerator generator(receiver,
1899 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001900 result,
1901 &miss, // When not a string.
1902 &miss, // When not a number.
1903 index_out_of_range_label,
1904 STRING_INDEX_IS_NUMBER);
1905 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001906 __ Drop(argc + 1);
1907 __ Ret();
1908
1909 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001910 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001911
1912 if (index_out_of_range.is_linked()) {
1913 __ bind(&index_out_of_range);
1914 __ LoadRoot(v0, Heap::kNanValueRootIndex);
1915 __ Drop(argc + 1);
1916 __ Ret();
1917 }
1918
1919 __ bind(&miss);
1920 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001921 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001922 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001923 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001924
1925 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001926 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001927}
1928
1929
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001930Handle<Code> CallStubCompiler::CompileStringCharAtCall(
1931 Handle<Object> object,
1932 Handle<JSObject> holder,
1933 Handle<JSGlobalPropertyCell> cell,
1934 Handle<JSFunction> function,
1935 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001936 // ----------- S t a t e -------------
1937 // -- a2 : function name
1938 // -- ra : return address
1939 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1940 // -- ...
1941 // -- sp[argc * 4] : receiver
1942 // -----------------------------------
1943
1944 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001945 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001946
1947 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001948 Label miss;
1949 Label name_miss;
1950 Label index_out_of_range;
1951 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00001952 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001953 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001954 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001955 index_out_of_range_label = &miss;
1956 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001957 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001958
1959 // Check that the maps starting from the prototype haven't changed.
1960 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1961 Context::STRING_FUNCTION_INDEX,
1962 v0,
1963 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001964 ASSERT(!object.is_identical_to(holder));
1965 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1966 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001967
1968 Register receiver = v0;
1969 Register index = t1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001970 Register scratch = a3;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001971 Register result = v0;
1972 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1973 if (argc > 0) {
1974 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1975 } else {
1976 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1977 }
1978
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001979 StringCharAtGenerator generator(receiver,
1980 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00001981 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001982 result,
1983 &miss, // When not a string.
1984 &miss, // When not a number.
1985 index_out_of_range_label,
1986 STRING_INDEX_IS_NUMBER);
1987 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001988 __ Drop(argc + 1);
1989 __ Ret();
1990
1991 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001992 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001993
1994 if (index_out_of_range.is_linked()) {
1995 __ bind(&index_out_of_range);
1996 __ LoadRoot(v0, Heap::kEmptyStringRootIndex);
1997 __ Drop(argc + 1);
1998 __ Ret();
1999 }
2000
2001 __ bind(&miss);
2002 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002003 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002004 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002005 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002006
2007 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002008 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002009}
2010
2011
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002012Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
2013 Handle<Object> object,
2014 Handle<JSObject> holder,
2015 Handle<JSGlobalPropertyCell> cell,
2016 Handle<JSFunction> function,
2017 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002018 // ----------- S t a t e -------------
2019 // -- a2 : function name
2020 // -- ra : return address
2021 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2022 // -- ...
2023 // -- sp[argc * 4] : receiver
2024 // -----------------------------------
2025
2026 const int argc = arguments().immediate();
2027
2028 // If the object is not a JSObject or we got an unexpected number of
2029 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002030 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002031
2032 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002033 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002034
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002035 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002036 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
2037
2038 STATIC_ASSERT(kSmiTag == 0);
2039 __ JumpIfSmi(a1, &miss);
2040
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002041 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2042 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002043 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002044 ASSERT(cell->value() == *function);
2045 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2046 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002047 GenerateLoadFunctionFromCell(cell, function, &miss);
2048 }
2049
2050 // Load the char code argument.
2051 Register code = a1;
2052 __ lw(code, MemOperand(sp, 0 * kPointerSize));
2053
2054 // Check the code is a smi.
2055 Label slow;
2056 STATIC_ASSERT(kSmiTag == 0);
2057 __ JumpIfNotSmi(code, &slow);
2058
2059 // Convert the smi code to uint16.
2060 __ And(code, code, Operand(Smi::FromInt(0xffff)));
2061
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002062 StringCharFromCodeGenerator generator(code, v0);
2063 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002064 __ Drop(argc + 1);
2065 __ Ret();
2066
2067 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002068 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002069
2070 // Tail call the full function. We do not have to patch the receiver
2071 // because the function makes no use of it.
2072 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002073 __ InvokeFunction(
2074 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002075
2076 __ bind(&miss);
2077 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002078 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002079
2080 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002081 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002082}
2083
2084
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002085Handle<Code> CallStubCompiler::CompileMathFloorCall(
2086 Handle<Object> object,
2087 Handle<JSObject> holder,
2088 Handle<JSGlobalPropertyCell> cell,
2089 Handle<JSFunction> function,
2090 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002091 // ----------- S t a t e -------------
2092 // -- a2 : function name
2093 // -- ra : return address
2094 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2095 // -- ...
2096 // -- sp[argc * 4] : receiver
2097 // -----------------------------------
2098
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002099 if (!CpuFeatures::IsSupported(FPU)) {
2100 return Handle<Code>::null();
2101 }
2102
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002103 CpuFeatures::Scope scope_fpu(FPU);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002104 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002105 // If the object is not a JSObject or we got an unexpected number of
2106 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002107 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002108
2109 Label miss, slow;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002110 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002111
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002112 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002113 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002114 STATIC_ASSERT(kSmiTag == 0);
2115 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002116 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2117 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002118 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002119 ASSERT(cell->value() == *function);
2120 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2121 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002122 GenerateLoadFunctionFromCell(cell, function, &miss);
2123 }
2124
2125 // Load the (only) argument into v0.
2126 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2127
2128 // If the argument is a smi, just return.
2129 STATIC_ASSERT(kSmiTag == 0);
2130 __ And(t0, v0, Operand(kSmiTagMask));
2131 __ Drop(argc + 1, eq, t0, Operand(zero_reg));
2132 __ Ret(eq, t0, Operand(zero_reg));
2133
danno@chromium.org40cb8782011-05-25 07:58:50 +00002134 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002135
2136 Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return;
2137
2138 // If fpu is enabled, we use the floor instruction.
2139
2140 // Load the HeapNumber value.
2141 __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2142
2143 // Backup FCSR.
2144 __ cfc1(a3, FCSR);
2145 // Clearing FCSR clears the exception mask with no side-effects.
2146 __ ctc1(zero_reg, FCSR);
2147 // Convert the argument to an integer.
2148 __ floor_w_d(f0, f0);
2149
2150 // Start checking for special cases.
2151 // Get the argument exponent and clear the sign bit.
2152 __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize));
2153 __ And(t2, t1, Operand(~HeapNumber::kSignMask));
2154 __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord);
2155
2156 // Retrieve FCSR and check for fpu errors.
2157 __ cfc1(t5, FCSR);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002158 __ And(t5, t5, Operand(kFCSRExceptionFlagMask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002159 __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));
2160
2161 // Check for NaN, Infinity, and -Infinity.
2162 // They are invariant through a Math.Floor call, so just
2163 // return the original argument.
2164 __ Subu(t3, t2, Operand(HeapNumber::kExponentMask
2165 >> HeapNumber::kMantissaBitsInTopWord));
2166 __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg));
2167 // We had an overflow or underflow in the conversion. Check if we
2168 // have a big exponent.
2169 // If greater or equal, the argument is already round and in v0.
2170 __ Branch(&restore_fcsr_and_return, ge, t3,
2171 Operand(HeapNumber::kMantissaBits));
2172 __ Branch(&wont_fit_smi);
2173
2174 __ bind(&no_fpu_error);
2175 // Move the result back to v0.
2176 __ mfc1(v0, f0);
2177 // Check if the result fits into a smi.
2178 __ Addu(a1, v0, Operand(0x40000000));
2179 __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg));
2180 // Tag the result.
2181 STATIC_ASSERT(kSmiTag == 0);
2182 __ sll(v0, v0, kSmiTagSize);
2183
2184 // Check for -0.
2185 __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg));
2186 // t1 already holds the HeapNumber exponent.
2187 __ And(t0, t1, Operand(HeapNumber::kSignMask));
2188 // If our HeapNumber is negative it was -0, so load its address and return.
2189 // Else v0 is loaded with 0, so we can also just return.
2190 __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg));
2191 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2192
2193 __ bind(&restore_fcsr_and_return);
2194 // Restore FCSR and return.
2195 __ ctc1(a3, FCSR);
2196
2197 __ Drop(argc + 1);
2198 __ Ret();
2199
2200 __ bind(&wont_fit_smi);
2201 // Restore FCSR and fall to slow case.
2202 __ ctc1(a3, FCSR);
2203
2204 __ bind(&slow);
2205 // Tail call the full function. We do not have to patch the receiver
2206 // because the function makes no use of it.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002207 __ InvokeFunction(
2208 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002209
2210 __ bind(&miss);
2211 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002212 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002213
2214 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002215 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002216}
2217
2218
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002219Handle<Code> CallStubCompiler::CompileMathAbsCall(
2220 Handle<Object> object,
2221 Handle<JSObject> holder,
2222 Handle<JSGlobalPropertyCell> cell,
2223 Handle<JSFunction> function,
2224 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002225 // ----------- S t a t e -------------
2226 // -- a2 : function name
2227 // -- ra : return address
2228 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2229 // -- ...
2230 // -- sp[argc * 4] : receiver
2231 // -----------------------------------
2232
2233 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002234 // If the object is not a JSObject or we got an unexpected number of
2235 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002236 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002237
2238 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002239
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002240 GenerateNameCheck(name, &miss);
2241 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002242 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002243 STATIC_ASSERT(kSmiTag == 0);
2244 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002245 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2246 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002247 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002248 ASSERT(cell->value() == *function);
2249 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2250 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002251 GenerateLoadFunctionFromCell(cell, function, &miss);
2252 }
2253
2254 // Load the (only) argument into v0.
2255 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2256
2257 // Check if the argument is a smi.
2258 Label not_smi;
2259 STATIC_ASSERT(kSmiTag == 0);
2260 __ JumpIfNotSmi(v0, &not_smi);
2261
2262 // Do bitwise not or do nothing depending on the sign of the
2263 // argument.
2264 __ sra(t0, v0, kBitsPerInt - 1);
2265 __ Xor(a1, v0, t0);
2266
2267 // Add 1 or do nothing depending on the sign of the argument.
2268 __ Subu(v0, a1, t0);
2269
2270 // If the result is still negative, go to the slow case.
2271 // This only happens for the most negative smi.
2272 Label slow;
2273 __ Branch(&slow, lt, v0, Operand(zero_reg));
2274
2275 // Smi case done.
2276 __ Drop(argc + 1);
2277 __ Ret();
2278
2279 // Check if the argument is a heap number and load its exponent and
2280 // sign.
2281 __ bind(&not_smi);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002282 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002283 __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2284
2285 // Check the sign of the argument. If the argument is positive,
2286 // just return it.
2287 Label negative_sign;
2288 __ And(t0, a1, Operand(HeapNumber::kSignMask));
2289 __ Branch(&negative_sign, ne, t0, Operand(zero_reg));
2290 __ Drop(argc + 1);
2291 __ Ret();
2292
2293 // If the argument is negative, clear the sign, and return a new
2294 // number.
2295 __ bind(&negative_sign);
2296 __ Xor(a1, a1, Operand(HeapNumber::kSignMask));
2297 __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2298 __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
2299 __ AllocateHeapNumber(v0, t0, t1, t2, &slow);
2300 __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2301 __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2302 __ Drop(argc + 1);
2303 __ Ret();
2304
2305 // Tail call the full function. We do not have to patch the receiver
2306 // because the function makes no use of it.
2307 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002308 __ InvokeFunction(
2309 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002310
2311 __ bind(&miss);
2312 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002313 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002314
2315 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002316 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002317}
2318
2319
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002320Handle<Code> CallStubCompiler::CompileFastApiCall(
lrn@chromium.org7516f052011-03-30 08:52:27 +00002321 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002322 Handle<Object> object,
2323 Handle<JSObject> holder,
2324 Handle<JSGlobalPropertyCell> cell,
2325 Handle<JSFunction> function,
2326 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002327
danno@chromium.org40cb8782011-05-25 07:58:50 +00002328 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002329
2330 ASSERT(optimization.is_simple_api_call());
2331 // Bail out if object is a global object as we don't want to
2332 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002333 if (object->IsGlobalObject()) return Handle<Code>::null();
2334 if (!cell.is_null()) return Handle<Code>::null();
2335 if (!object->IsJSObject()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002336 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002337 Handle<JSObject>::cast(object), holder);
2338 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002339
2340 Label miss, miss_before_stack_reserved;
2341
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002342 GenerateNameCheck(name, &miss_before_stack_reserved);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002343
2344 // Get the receiver from the stack.
2345 const int argc = arguments().immediate();
2346 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2347
2348 // Check that the receiver isn't a smi.
2349 __ JumpIfSmi(a1, &miss_before_stack_reserved);
2350
2351 __ IncrementCounter(counters->call_const(), 1, a0, a3);
2352 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2353
2354 ReserveSpaceForFastApiCall(masm(), a0);
2355
2356 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002357 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002358 depth, &miss);
2359
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002360 GenerateFastApiDirectCall(masm(), optimization, argc);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002361
2362 __ bind(&miss);
2363 FreeSpaceForFastApiCall(masm());
2364
2365 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002366 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002367
2368 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002369 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002370}
2371
2372
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002373Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object,
2374 Handle<JSObject> holder,
2375 Handle<JSFunction> function,
2376 Handle<String> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002377 CheckType check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002378 // ----------- S t a t e -------------
2379 // -- a2 : name
2380 // -- ra : return address
2381 // -----------------------------------
2382 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002383 Handle<Code> code = CompileCustomCall(object, holder,
2384 Handle<JSGlobalPropertyCell>::null(),
2385 function, name);
2386 // A null handle means bail out to the regular compiler code below.
2387 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002388 }
2389
2390 Label miss;
2391
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002392 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002393
2394 // Get the receiver from the stack.
2395 const int argc = arguments().immediate();
2396 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2397
2398 // Check that the receiver isn't a smi.
2399 if (check != NUMBER_CHECK) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002400 __ JumpIfSmi(a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002401 }
2402
2403 // Make sure that it's okay not to patch the on stack receiver
2404 // unless we're doing a receiver map check.
2405 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002406 switch (check) {
2407 case RECEIVER_MAP_CHECK:
2408 __ IncrementCounter(masm()->isolate()->counters()->call_const(),
2409 1, a0, a3);
2410
2411 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002412 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2413 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002414
2415 // Patch the receiver on the stack with the global proxy if
2416 // necessary.
2417 if (object->IsGlobalObject()) {
2418 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2419 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2420 }
2421 break;
2422
2423 case STRING_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002424 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002425 // Check that the object is a two-byte string or a symbol.
2426 __ GetObjectType(a1, a3, a3);
2427 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2428 // Check that the maps starting from the prototype haven't changed.
2429 GenerateDirectLoadGlobalFunctionPrototype(
2430 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002431 CheckPrototypes(
2432 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2433 a0, holder, a3, a1, t0, name, &miss);
2434 } else {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002435 // Calling non-strict non-builtins with a value as the receiver
2436 // requires boxing.
2437 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002438 }
2439 break;
2440
2441 case NUMBER_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002442 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002443 Label fast;
2444 // Check that the object is a smi or a heap number.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002445 __ JumpIfSmi(a1, &fast);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002446 __ GetObjectType(a1, a0, a0);
2447 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
2448 __ bind(&fast);
2449 // Check that the maps starting from the prototype haven't changed.
2450 GenerateDirectLoadGlobalFunctionPrototype(
2451 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002452 CheckPrototypes(
2453 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2454 a0, holder, a3, a1, t0, name, &miss);
2455 } else {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002456 // Calling non-strict non-builtins with a value as the receiver
2457 // requires boxing.
2458 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002459 }
2460 break;
2461
2462 case BOOLEAN_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002463 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002464 Label fast;
2465 // Check that the object is a boolean.
2466 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
2467 __ Branch(&fast, eq, a1, Operand(t0));
2468 __ LoadRoot(t0, Heap::kFalseValueRootIndex);
2469 __ Branch(&miss, ne, a1, Operand(t0));
2470 __ bind(&fast);
2471 // Check that the maps starting from the prototype haven't changed.
2472 GenerateDirectLoadGlobalFunctionPrototype(
2473 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002474 CheckPrototypes(
2475 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2476 a0, holder, a3, a1, t0, name, &miss);
2477 } else {
2478 // Calling non-strict non-builtins with a value as the receiver
2479 // requires boxing.
2480 __ jmp(&miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002481 }
2482 break;
2483 }
2484
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002485 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002486 ? CALL_AS_FUNCTION
2487 : CALL_AS_METHOD;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002488 __ InvokeFunction(
2489 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002490
2491 // Handle call cache miss.
2492 __ bind(&miss);
2493
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002494 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002495
2496 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002497 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002498}
2499
2500
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002501Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2502 Handle<JSObject> holder,
2503 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002504 // ----------- S t a t e -------------
2505 // -- a2 : name
2506 // -- ra : return address
2507 // -----------------------------------
2508
2509 Label miss;
2510
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002511 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002512
2513 // Get the number of arguments.
2514 const int argc = arguments().immediate();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002515 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002516 LookupPostInterceptor(holder, name, &lookup);
2517
2518 // Get the receiver from the stack.
2519 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2520
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002521 CallInterceptorCompiler compiler(this, arguments(), a2, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002522 compiler.Compile(masm(), object, holder, name, &lookup, a1, a3, t0, a0,
2523 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002524
2525 // Move returned value, the function to call, to a1.
2526 __ mov(a1, v0);
2527 // Restore receiver.
2528 __ lw(a0, MemOperand(sp, argc * kPointerSize));
2529
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002530 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002531
2532 // Handle call cache miss.
2533 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002534 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002535
2536 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002537 return GetCode(Code::INTERCEPTOR, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002538}
2539
2540
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002541Handle<Code> CallStubCompiler::CompileCallGlobal(
2542 Handle<JSObject> object,
2543 Handle<GlobalObject> holder,
2544 Handle<JSGlobalPropertyCell> cell,
2545 Handle<JSFunction> function,
2546 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002547 // ----------- S t a t e -------------
2548 // -- a2 : name
2549 // -- ra : return address
2550 // -----------------------------------
2551
2552 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002553 Handle<Code> code = CompileCustomCall(object, holder, cell, function, name);
2554 // A null handle means bail out to the regular compiler code below.
2555 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002556 }
2557
2558 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002559 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002560
2561 // Get the number of arguments.
2562 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002563 GenerateGlobalReceiverCheck(object, holder, name, &miss);
2564 GenerateLoadFunctionFromCell(cell, function, &miss);
2565
2566 // Patch the receiver on the stack with the global proxy if
2567 // necessary.
2568 if (object->IsGlobalObject()) {
2569 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
2570 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2571 }
2572
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002573 // Set up the context (function already in r1).
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002574 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
2575
2576 // Jump to the cached code (tail call).
2577 Counters* counters = masm()->isolate()->counters();
2578 __ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002579 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002580 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002581 ? CALL_AS_FUNCTION
2582 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002583 // We call indirectly through the code field in the function to
2584 // allow recompilation to take effect without changing any of the
2585 // call sites.
2586 __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
2587 __ InvokeCode(a3, expected, arguments(), JUMP_FUNCTION,
2588 NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002589
2590 // Handle call cache miss.
2591 __ bind(&miss);
2592 __ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002593 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002594
2595 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002596 return GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002597}
2598
2599
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002600Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +00002601 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002602 Handle<Map> transition,
2603 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002604 // ----------- S t a t e -------------
2605 // -- a0 : value
2606 // -- a1 : receiver
2607 // -- a2 : name
2608 // -- ra : return address
2609 // -----------------------------------
2610 Label miss;
2611
2612 // Name register might be clobbered.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002613 GenerateStoreField(masm(),
2614 object,
2615 index,
2616 transition,
2617 name,
2618 a1, a2, a3, t0,
2619 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002620 __ bind(&miss);
2621 __ li(a2, Operand(Handle<String>(name))); // Restore name.
2622 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2623 __ Jump(ic, RelocInfo::CODE_TARGET);
2624
2625 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002626 return GetCode(transition.is_null()
2627 ? Code::FIELD
2628 : Code::MAP_TRANSITION, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002629}
2630
2631
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002632Handle<Code> StoreStubCompiler::CompileStoreCallback(
2633 Handle<JSObject> object,
2634 Handle<AccessorInfo> callback,
2635 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002636 // ----------- S t a t e -------------
2637 // -- a0 : value
2638 // -- a1 : receiver
2639 // -- a2 : name
2640 // -- ra : return address
2641 // -----------------------------------
2642 Label miss;
2643
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002644 // Check that the map of the object hasn't changed.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002645 __ CheckMap(a1, a3, Handle<Map>(object->map()), &miss,
2646 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002647
2648 // Perform global security token check if needed.
2649 if (object->IsJSGlobalProxy()) {
2650 __ CheckAccessGlobalProxy(a1, a3, &miss);
2651 }
2652
2653 // Stub never generated for non-global objects that require access
2654 // checks.
2655 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
2656
2657 __ push(a1); // Receiver.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002658 __ li(a3, Operand(callback)); // Callback info.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002659 __ Push(a3, a2, a0);
2660
2661 // Do tail-call to the runtime system.
2662 ExternalReference store_callback_property =
2663 ExternalReference(IC_Utility(IC::kStoreCallbackProperty),
2664 masm()->isolate());
2665 __ TailCallExternalReference(store_callback_property, 4, 1);
2666
2667 // Handle store cache miss.
2668 __ bind(&miss);
2669 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2670 __ Jump(ic, RelocInfo::CODE_TARGET);
2671
2672 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002673 return GetCode(Code::CALLBACKS, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002674}
2675
2676
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002677Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
2678 Handle<JSObject> receiver,
2679 Handle<JSFunction> setter,
2680 Handle<String> name) {
2681 // ----------- S t a t e -------------
2682 // -- a0 : value
2683 // -- a1 : receiver
2684 // -- a2 : name
2685 // -- ra : return address
2686 // -----------------------------------
2687 Label miss;
2688
2689 // Check that the map of the object hasn't changed.
2690 __ CheckMap(a1, a3, Handle<Map>(receiver->map()), &miss, DO_SMI_CHECK,
2691 ALLOW_ELEMENT_TRANSITION_MAPS);
2692
2693 {
2694 FrameScope scope(masm(), StackFrame::INTERNAL);
2695
2696 // Save value register, so we can restore it later.
2697 __ push(a0);
2698
2699 // Call the JavaScript getter with the receiver and the value on the stack.
2700 __ push(a1);
2701 __ push(a0);
2702 ParameterCount actual(1);
2703 __ InvokeFunction(setter, actual, CALL_FUNCTION, NullCallWrapper(),
2704 CALL_AS_METHOD);
2705
2706 // We have to return the passed value, not the return value of the setter.
2707 __ pop(v0);
2708
2709 // Restore context register.
2710 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2711 }
2712 __ Ret();
2713
2714 __ bind(&miss);
2715 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2716 __ Jump(ic, RelocInfo::CODE_TARGET);
2717
2718 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002719 return GetCode(Code::CALLBACKS, name);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002720}
2721
2722
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002723Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
2724 Handle<JSObject> receiver,
2725 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002726 // ----------- S t a t e -------------
2727 // -- a0 : value
2728 // -- a1 : receiver
2729 // -- a2 : name
2730 // -- ra : return address
2731 // -----------------------------------
2732 Label miss;
2733
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002734 // Check that the map of the object hasn't changed.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002735 __ CheckMap(a1, a3, Handle<Map>(receiver->map()), &miss,
2736 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002737
2738 // Perform global security token check if needed.
2739 if (receiver->IsJSGlobalProxy()) {
2740 __ CheckAccessGlobalProxy(a1, a3, &miss);
2741 }
2742
2743 // Stub is never generated for non-global objects that require access
2744 // checks.
2745 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2746
2747 __ Push(a1, a2, a0); // Receiver, name, value.
2748
2749 __ li(a0, Operand(Smi::FromInt(strict_mode_)));
2750 __ push(a0); // Strict mode.
2751
2752 // Do tail-call to the runtime system.
2753 ExternalReference store_ic_property =
2754 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty),
2755 masm()->isolate());
2756 __ TailCallExternalReference(store_ic_property, 4, 1);
2757
2758 // Handle store cache miss.
2759 __ bind(&miss);
2760 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2761 __ Jump(ic, RelocInfo::CODE_TARGET);
2762
2763 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002764 return GetCode(Code::INTERCEPTOR, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002765}
2766
2767
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002768Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2769 Handle<GlobalObject> object,
2770 Handle<JSGlobalPropertyCell> cell,
2771 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002772 // ----------- S t a t e -------------
2773 // -- a0 : value
2774 // -- a1 : receiver
2775 // -- a2 : name
2776 // -- ra : return address
2777 // -----------------------------------
2778 Label miss;
2779
2780 // Check that the map of the global has not changed.
2781 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2782 __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map())));
2783
2784 // Check that the value in the cell is not the hole. If it is, this
2785 // cell could have been deleted and reintroducing the global needs
2786 // to update the property details in the property dictionary of the
2787 // global object. We bail out to the runtime system to do that.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002788 __ li(t0, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002789 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
2790 __ lw(t2, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2791 __ Branch(&miss, eq, t1, Operand(t2));
2792
2793 // Store the value in the cell.
2794 __ sw(a0, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2795 __ mov(v0, a0); // Stored value must be returned in v0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002796 // Cells are always rescanned, so no write barrier here.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002797
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002798 Counters* counters = masm()->isolate()->counters();
2799 __ IncrementCounter(counters->named_store_global_inline(), 1, a1, a3);
2800 __ Ret();
2801
2802 // Handle store cache miss.
2803 __ bind(&miss);
2804 __ IncrementCounter(counters->named_store_global_inline_miss(), 1, a1, a3);
2805 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2806 __ Jump(ic, RelocInfo::CODE_TARGET);
2807
2808 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002809 return GetCode(Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002810}
2811
2812
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002813Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
2814 Handle<JSObject> object,
2815 Handle<JSObject> last) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002816 // ----------- S t a t e -------------
2817 // -- a0 : receiver
2818 // -- ra : return address
2819 // -----------------------------------
2820 Label miss;
2821
2822 // Check that the receiver is not a smi.
2823 __ JumpIfSmi(a0, &miss);
2824
2825 // Check the maps of the full prototype chain.
2826 CheckPrototypes(object, a0, last, a3, a1, t0, name, &miss);
2827
2828 // If the last object in the prototype chain is a global object,
2829 // check that the global property cell is empty.
2830 if (last->IsGlobalObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002831 GenerateCheckPropertyCell(
2832 masm(), Handle<GlobalObject>::cast(last), name, a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002833 }
2834
2835 // Return undefined if maps of the full prototype chain is still the same.
2836 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2837 __ Ret();
2838
2839 __ bind(&miss);
2840 GenerateLoadMiss(masm(), Code::LOAD_IC);
2841
2842 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002843 return GetCode(Code::NONEXISTENT, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00002844}
2845
2846
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002847Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object,
2848 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002849 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002850 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002851 // ----------- S t a t e -------------
2852 // -- a0 : receiver
2853 // -- a2 : name
2854 // -- ra : return address
2855 // -----------------------------------
2856 Label miss;
2857
2858 __ mov(v0, a0);
2859
2860 GenerateLoadField(object, holder, v0, a3, a1, t0, index, name, &miss);
2861 __ bind(&miss);
2862 GenerateLoadMiss(masm(), Code::LOAD_IC);
2863
2864 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002865 return GetCode(Code::FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002866}
2867
2868
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002869Handle<Code> LoadStubCompiler::CompileLoadCallback(
2870 Handle<String> name,
2871 Handle<JSObject> object,
2872 Handle<JSObject> holder,
2873 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002874 // ----------- S t a t e -------------
2875 // -- a0 : receiver
2876 // -- a2 : name
2877 // -- ra : return address
2878 // -----------------------------------
2879 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002880 GenerateLoadCallback(object, holder, a0, a2, a3, a1, t0, callback, name,
2881 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002882 __ bind(&miss);
2883 GenerateLoadMiss(masm(), Code::LOAD_IC);
2884
2885 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002886 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002887}
2888
2889
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002890Handle<Code> LoadStubCompiler::CompileLoadViaGetter(
2891 Handle<String> name,
2892 Handle<JSObject> receiver,
2893 Handle<JSObject> holder,
2894 Handle<JSFunction> getter) {
2895 // ----------- S t a t e -------------
2896 // -- a0 : receiver
2897 // -- a2 : name
2898 // -- ra : return address
2899 // -----------------------------------
2900 Label miss;
2901
2902 // Check that the maps haven't changed.
2903 __ JumpIfSmi(a0, &miss);
2904 CheckPrototypes(receiver, a0, holder, a3, t0, a1, name, &miss);
2905
2906 {
2907 FrameScope scope(masm(), StackFrame::INTERNAL);
2908
2909 // Call the JavaScript getter with the receiver on the stack.
2910 __ push(a0);
2911 ParameterCount actual(0);
2912 __ InvokeFunction(getter, actual, CALL_FUNCTION, NullCallWrapper(),
2913 CALL_AS_METHOD);
2914
2915 // Restore context register.
2916 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2917 }
2918 __ Ret();
2919
2920 __ bind(&miss);
2921 GenerateLoadMiss(masm(), Code::LOAD_IC);
2922
2923 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002924 return GetCode(Code::CALLBACKS, name);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002925}
2926
2927
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002928Handle<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object,
2929 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002930 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002931 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002932 // ----------- S t a t e -------------
2933 // -- a0 : receiver
2934 // -- a2 : name
2935 // -- ra : return address
2936 // -----------------------------------
2937 Label miss;
2938
2939 GenerateLoadConstant(object, holder, a0, a3, a1, t0, value, name, &miss);
2940 __ bind(&miss);
2941 GenerateLoadMiss(masm(), Code::LOAD_IC);
2942
2943 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002944 return GetCode(Code::CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002945}
2946
2947
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002948Handle<Code> LoadStubCompiler::CompileLoadInterceptor(Handle<JSObject> object,
2949 Handle<JSObject> holder,
2950 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002951 // ----------- S t a t e -------------
2952 // -- a0 : receiver
2953 // -- a2 : name
2954 // -- ra : return address
2955 // -- [sp] : receiver
2956 // -----------------------------------
2957 Label miss;
2958
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002959 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002960 LookupPostInterceptor(holder, name, &lookup);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002961 GenerateLoadInterceptor(object, holder, &lookup, a0, a2, a3, a1, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002962 &miss);
2963 __ bind(&miss);
2964 GenerateLoadMiss(masm(), Code::LOAD_IC);
2965
2966 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002967 return GetCode(Code::INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002968}
2969
2970
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002971Handle<Code> LoadStubCompiler::CompileLoadGlobal(
2972 Handle<JSObject> object,
2973 Handle<GlobalObject> holder,
2974 Handle<JSGlobalPropertyCell> cell,
2975 Handle<String> name,
2976 bool is_dont_delete) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002977 // ----------- S t a t e -------------
2978 // -- a0 : receiver
2979 // -- a2 : name
2980 // -- ra : return address
2981 // -----------------------------------
2982 Label miss;
2983
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002984 // Check that the map of the global has not changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00002985 __ JumpIfSmi(a0, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002986 CheckPrototypes(object, a0, holder, a3, t0, a1, name, &miss);
2987
2988 // Get the value from the cell.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002989 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002990 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
2991
2992 // Check for deleted property if property can actually be deleted.
2993 if (!is_dont_delete) {
2994 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
2995 __ Branch(&miss, eq, t0, Operand(at));
2996 }
2997
2998 __ mov(v0, t0);
2999 Counters* counters = masm()->isolate()->counters();
3000 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
3001 __ Ret();
3002
3003 __ bind(&miss);
3004 __ IncrementCounter(counters->named_load_global_stub_miss(), 1, a1, a3);
3005 GenerateLoadMiss(masm(), Code::LOAD_IC);
3006
3007 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003008 return GetCode(Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003009}
3010
3011
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003012Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
3013 Handle<JSObject> receiver,
3014 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00003015 int index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003016 // ----------- S t a t e -------------
3017 // -- ra : return address
3018 // -- a0 : key
3019 // -- a1 : receiver
3020 // -----------------------------------
3021 Label miss;
3022
3023 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003024 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003025
3026 GenerateLoadField(receiver, holder, a1, a2, a3, t0, index, name, &miss);
3027 __ bind(&miss);
3028 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3029
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003030 return GetCode(Code::FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003031}
3032
3033
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003034Handle<Code> KeyedLoadStubCompiler::CompileLoadCallback(
3035 Handle<String> name,
3036 Handle<JSObject> receiver,
3037 Handle<JSObject> holder,
3038 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003039 // ----------- S t a t e -------------
3040 // -- ra : return address
3041 // -- a0 : key
3042 // -- a1 : receiver
3043 // -----------------------------------
3044 Label miss;
3045
3046 // Check the key is the cached one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003047 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003048
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003049 GenerateLoadCallback(receiver, holder, a1, a0, a2, a3, t0, callback, name,
3050 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003051 __ bind(&miss);
3052 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3053
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003054 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003055}
3056
3057
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003058Handle<Code> KeyedLoadStubCompiler::CompileLoadConstant(
3059 Handle<String> name,
3060 Handle<JSObject> receiver,
3061 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003062 Handle<JSFunction> value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003063 // ----------- S t a t e -------------
3064 // -- ra : return address
3065 // -- a0 : key
3066 // -- a1 : receiver
3067 // -----------------------------------
3068 Label miss;
3069
3070 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003071 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003072
3073 GenerateLoadConstant(receiver, holder, a1, a2, a3, t0, value, name, &miss);
3074 __ bind(&miss);
3075 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3076
3077 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003078 return GetCode(Code::CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003079}
3080
3081
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003082Handle<Code> KeyedLoadStubCompiler::CompileLoadInterceptor(
3083 Handle<JSObject> receiver,
3084 Handle<JSObject> holder,
3085 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003086 // ----------- S t a t e -------------
3087 // -- ra : return address
3088 // -- a0 : key
3089 // -- a1 : receiver
3090 // -----------------------------------
3091 Label miss;
3092
3093 // Check the key is the cached one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003094 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003095
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003096 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003097 LookupPostInterceptor(holder, name, &lookup);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003098 GenerateLoadInterceptor(receiver, holder, &lookup, a1, a0, a2, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003099 &miss);
3100 __ bind(&miss);
3101 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3102
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003103 return GetCode(Code::INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003104}
3105
3106
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003107Handle<Code> KeyedLoadStubCompiler::CompileLoadArrayLength(
3108 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003109 // ----------- S t a t e -------------
3110 // -- ra : return address
3111 // -- a0 : key
3112 // -- a1 : receiver
3113 // -----------------------------------
3114 Label miss;
3115
3116 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003117 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003118
3119 GenerateLoadArrayLength(masm(), a1, a2, &miss);
3120 __ bind(&miss);
3121 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3122
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003123 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003124}
3125
3126
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003127Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength(
3128 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003129 // ----------- S t a t e -------------
3130 // -- ra : return address
3131 // -- a0 : key
3132 // -- a1 : receiver
3133 // -----------------------------------
3134 Label miss;
3135
3136 Counters* counters = masm()->isolate()->counters();
3137 __ IncrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
3138
3139 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003140 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003141
3142 GenerateLoadStringLength(masm(), a1, a2, a3, &miss, true);
3143 __ bind(&miss);
3144 __ DecrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
3145
3146 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3147
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003148 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003149}
3150
3151
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003152Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype(
3153 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003154 // ----------- S t a t e -------------
3155 // -- ra : return address
3156 // -- a0 : key
3157 // -- a1 : receiver
3158 // -----------------------------------
3159 Label miss;
3160
3161 Counters* counters = masm()->isolate()->counters();
3162 __ IncrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
3163
3164 // Check the name hasn't changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003165 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003166
3167 GenerateLoadFunctionPrototype(masm(), a1, a2, a3, &miss);
3168 __ bind(&miss);
3169 __ DecrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
3170 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3171
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003172 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003173}
3174
3175
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003176Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
3177 Handle<Map> receiver_map) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003178 // ----------- S t a t e -------------
3179 // -- ra : return address
3180 // -- a0 : key
3181 // -- a1 : receiver
3182 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003183 ElementsKind elements_kind = receiver_map->elements_kind();
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003184 Handle<Code> stub = KeyedLoadElementStub(elements_kind).GetCode();
3185
3186 __ DispatchMap(a1, a2, receiver_map, stub, DO_SMI_CHECK);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003187
3188 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
3189 __ Jump(ic, RelocInfo::CODE_TARGET);
3190
3191 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003192 return GetCode(Code::NORMAL, factory()->empty_string());
danno@chromium.org40cb8782011-05-25 07:58:50 +00003193}
3194
3195
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003196Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
3197 MapHandleList* receiver_maps,
3198 CodeHandleList* handler_ics) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003199 // ----------- S t a t e -------------
3200 // -- ra : return address
3201 // -- a0 : key
3202 // -- a1 : receiver
3203 // -----------------------------------
3204 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003205 __ JumpIfSmi(a1, &miss);
3206
danno@chromium.org40cb8782011-05-25 07:58:50 +00003207 int receiver_count = receiver_maps->length();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003208 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003209 for (int current = 0; current < receiver_count; ++current) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003210 __ Jump(handler_ics->at(current), RelocInfo::CODE_TARGET,
3211 eq, a2, Operand(receiver_maps->at(current)));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003212 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003213
3214 __ bind(&miss);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003215 Handle<Code> miss_ic = isolate()->builtins()->KeyedLoadIC_Miss();
3216 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003217
3218 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003219 return GetCode(Code::NORMAL, factory()->empty_string(), MEGAMORPHIC);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003220}
3221
3222
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003223Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +00003224 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003225 Handle<Map> transition,
3226 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003227 // ----------- S t a t e -------------
3228 // -- a0 : value
3229 // -- a1 : key
3230 // -- a2 : receiver
3231 // -- ra : return address
3232 // -----------------------------------
3233
3234 Label miss;
3235
3236 Counters* counters = masm()->isolate()->counters();
3237 __ IncrementCounter(counters->keyed_store_field(), 1, a3, t0);
3238
3239 // Check that the name has not changed.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003240 __ Branch(&miss, ne, a1, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003241
3242 // a3 is used as scratch register. a1 and a2 keep their values if a jump to
3243 // the miss label is generated.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003244 GenerateStoreField(masm(),
3245 object,
3246 index,
3247 transition,
3248 name,
3249 a2, a1, a3, t0,
3250 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003251 __ bind(&miss);
3252
3253 __ DecrementCounter(counters->keyed_store_field(), 1, a3, t0);
3254 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss();
3255 __ Jump(ic, RelocInfo::CODE_TARGET);
3256
3257 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003258 return GetCode(transition.is_null()
3259 ? Code::FIELD
3260 : Code::MAP_TRANSITION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003261}
3262
3263
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003264Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
3265 Handle<Map> receiver_map) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003266 // ----------- S t a t e -------------
3267 // -- a0 : value
3268 // -- a1 : key
3269 // -- a2 : receiver
3270 // -- ra : return address
3271 // -- a3 : scratch
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003272 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003273 ElementsKind elements_kind = receiver_map->elements_kind();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003274 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003275 Handle<Code> stub =
yangguo@chromium.org56454712012-02-16 15:33:53 +00003276 KeyedStoreElementStub(is_js_array, elements_kind, grow_mode_).GetCode();
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003277
3278 __ DispatchMap(a2, a3, receiver_map, stub, DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003279
danno@chromium.org40cb8782011-05-25 07:58:50 +00003280 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003281 __ Jump(ic, RelocInfo::CODE_TARGET);
3282
3283 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003284 return GetCode(Code::NORMAL, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00003285}
3286
3287
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003288Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
3289 MapHandleList* receiver_maps,
3290 CodeHandleList* handler_stubs,
3291 MapHandleList* transitioned_maps) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003292 // ----------- S t a t e -------------
3293 // -- a0 : value
3294 // -- a1 : key
3295 // -- a2 : receiver
3296 // -- ra : return address
3297 // -- a3 : scratch
3298 // -----------------------------------
3299 Label miss;
3300 __ JumpIfSmi(a2, &miss);
3301
3302 int receiver_count = receiver_maps->length();
3303 __ lw(a3, FieldMemOperand(a2, HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003304 for (int i = 0; i < receiver_count; ++i) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003305 if (transitioned_maps->at(i).is_null()) {
3306 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq,
3307 a3, Operand(receiver_maps->at(i)));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003308 } else {
3309 Label next_map;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003310 __ Branch(&next_map, ne, a3, Operand(receiver_maps->at(i)));
3311 __ li(a3, Operand(transitioned_maps->at(i)));
3312 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003313 __ bind(&next_map);
3314 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003315 }
3316
3317 __ bind(&miss);
3318 Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
3319 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3320
3321 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003322 return GetCode(Code::NORMAL, factory()->empty_string(), MEGAMORPHIC);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003323}
3324
3325
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003326Handle<Code> ConstructStubCompiler::CompileConstructStub(
3327 Handle<JSFunction> function) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003328 // a0 : argc
3329 // a1 : constructor
3330 // ra : return address
3331 // [sp] : last argument
3332 Label generic_stub_call;
3333
3334 // Use t7 for holding undefined which is used in several places below.
3335 __ LoadRoot(t7, Heap::kUndefinedValueRootIndex);
3336
3337#ifdef ENABLE_DEBUGGER_SUPPORT
3338 // Check to see whether there are any break points in the function code. If
3339 // there are jump to the generic constructor stub which calls the actual
3340 // code for the function thereby hitting the break points.
3341 __ lw(t5, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3342 __ lw(a2, FieldMemOperand(t5, SharedFunctionInfo::kDebugInfoOffset));
3343 __ Branch(&generic_stub_call, ne, a2, Operand(t7));
3344#endif
3345
3346 // Load the initial map and verify that it is in fact a map.
3347 // a1: constructor function
3348 // t7: undefined
3349 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003350 __ JumpIfSmi(a2, &generic_stub_call);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003351 __ GetObjectType(a2, a3, t0);
3352 __ Branch(&generic_stub_call, ne, t0, Operand(MAP_TYPE));
3353
3354#ifdef DEBUG
3355 // Cannot construct functions this way.
3356 // a0: argc
3357 // a1: constructor function
3358 // a2: initial map
3359 // t7: undefined
3360 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
3361 __ Check(ne, "Function constructed by construct stub.",
3362 a3, Operand(JS_FUNCTION_TYPE));
3363#endif
3364
3365 // Now allocate the JSObject in new space.
3366 // a0: argc
3367 // a1: constructor function
3368 // a2: initial map
3369 // t7: undefined
3370 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003371 __ AllocateInNewSpace(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003372
3373 // Allocated the JSObject, now initialize the fields. Map is set to initial
3374 // map and properties and elements are set to empty fixed array.
3375 // a0: argc
3376 // a1: constructor function
3377 // a2: initial map
3378 // a3: object size (in words)
3379 // t4: JSObject (not tagged)
3380 // t7: undefined
3381 __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex);
3382 __ mov(t5, t4);
3383 __ sw(a2, MemOperand(t5, JSObject::kMapOffset));
3384 __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset));
3385 __ sw(t6, MemOperand(t5, JSObject::kElementsOffset));
3386 __ Addu(t5, t5, Operand(3 * kPointerSize));
3387 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
3388 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
3389 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
3390
3391
3392 // Calculate the location of the first argument. The stack contains only the
3393 // argc arguments.
3394 __ sll(a1, a0, kPointerSizeLog2);
3395 __ Addu(a1, a1, sp);
3396
3397 // Fill all the in-object properties with undefined.
3398 // a0: argc
3399 // a1: first argument
3400 // a3: object size (in words)
3401 // t4: JSObject (not tagged)
3402 // t5: First in-object property of JSObject (not tagged)
3403 // t7: undefined
3404 // Fill the initialized properties with a constant value or a passed argument
3405 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003406 Handle<SharedFunctionInfo> shared(function->shared());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003407 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3408 if (shared->IsThisPropertyAssignmentArgument(i)) {
3409 Label not_passed, next;
3410 // Check if the argument assigned to the property is actually passed.
3411 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3412 __ Branch(&not_passed, less_equal, a0, Operand(arg_number));
3413 // Argument passed - find it on the stack.
3414 __ lw(a2, MemOperand(a1, (arg_number + 1) * -kPointerSize));
3415 __ sw(a2, MemOperand(t5));
3416 __ Addu(t5, t5, kPointerSize);
3417 __ jmp(&next);
3418 __ bind(&not_passed);
3419 // Set the property to undefined.
3420 __ sw(t7, MemOperand(t5));
3421 __ Addu(t5, t5, Operand(kPointerSize));
3422 __ bind(&next);
3423 } else {
3424 // Set the property to the constant value.
3425 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
3426 __ li(a2, Operand(constant));
3427 __ sw(a2, MemOperand(t5));
3428 __ Addu(t5, t5, kPointerSize);
3429 }
3430 }
3431
3432 // Fill the unused in-object property fields with undefined.
3433 ASSERT(function->has_initial_map());
3434 for (int i = shared->this_property_assignments_count();
3435 i < function->initial_map()->inobject_properties();
3436 i++) {
3437 __ sw(t7, MemOperand(t5));
3438 __ Addu(t5, t5, kPointerSize);
3439 }
3440
3441 // a0: argc
3442 // t4: JSObject (not tagged)
3443 // Move argc to a1 and the JSObject to return to v0 and tag it.
3444 __ mov(a1, a0);
3445 __ mov(v0, t4);
3446 __ Or(v0, v0, Operand(kHeapObjectTag));
3447
3448 // v0: JSObject
3449 // a1: argc
3450 // Remove caller arguments and receiver from the stack and return.
3451 __ sll(t0, a1, kPointerSizeLog2);
3452 __ Addu(sp, sp, t0);
3453 __ Addu(sp, sp, Operand(kPointerSize));
3454 Counters* counters = masm()->isolate()->counters();
3455 __ IncrementCounter(counters->constructed_objects(), 1, a1, a2);
3456 __ IncrementCounter(counters->constructed_objects_stub(), 1, a1, a2);
3457 __ Ret();
3458
3459 // Jump to the generic stub in case the specialized code cannot handle the
3460 // construction.
3461 __ bind(&generic_stub_call);
3462 Handle<Code> generic_construct_stub =
3463 masm()->isolate()->builtins()->JSConstructStubGeneric();
3464 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
3465
3466 // Return the generated code.
3467 return GetCode();
3468}
3469
3470
danno@chromium.org40cb8782011-05-25 07:58:50 +00003471#undef __
3472#define __ ACCESS_MASM(masm)
3473
3474
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003475void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3476 MacroAssembler* masm) {
3477 // ---------- S t a t e --------------
3478 // -- ra : return address
3479 // -- a0 : key
3480 // -- a1 : receiver
3481 // -----------------------------------
3482 Label slow, miss_force_generic;
3483
3484 Register key = a0;
3485 Register receiver = a1;
3486
3487 __ JumpIfNotSmi(key, &miss_force_generic);
3488 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
3489 __ sra(a2, a0, kSmiTagSize);
3490 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
3491 __ Ret();
3492
3493 // Slow case, key and receiver still in a0 and a1.
3494 __ bind(&slow);
3495 __ IncrementCounter(
3496 masm->isolate()->counters()->keyed_load_external_array_slow(),
3497 1, a2, a3);
3498 // Entry registers are intact.
3499 // ---------- S t a t e --------------
3500 // -- ra : return address
3501 // -- a0 : key
3502 // -- a1 : receiver
3503 // -----------------------------------
3504 Handle<Code> slow_ic =
3505 masm->isolate()->builtins()->KeyedLoadIC_Slow();
3506 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
3507
3508 // Miss case, call the runtime.
3509 __ bind(&miss_force_generic);
3510
3511 // ---------- S t a t e --------------
3512 // -- ra : return address
3513 // -- a0 : key
3514 // -- a1 : receiver
3515 // -----------------------------------
3516
3517 Handle<Code> miss_ic =
3518 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3519 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3520}
3521
3522
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003523static bool IsElementTypeSigned(ElementsKind elements_kind) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003524 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003525 case EXTERNAL_BYTE_ELEMENTS:
3526 case EXTERNAL_SHORT_ELEMENTS:
3527 case EXTERNAL_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003528 return true;
3529
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003530 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3531 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3532 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3533 case EXTERNAL_PIXEL_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003534 return false;
3535
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003536 case EXTERNAL_FLOAT_ELEMENTS:
3537 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003538 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003539 case FAST_ELEMENTS:
3540 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003541 case FAST_HOLEY_SMI_ELEMENTS:
3542 case FAST_HOLEY_ELEMENTS:
3543 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003544 case DICTIONARY_ELEMENTS:
3545 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003546 UNREACHABLE();
3547 return false;
3548 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003549 return false;
lrn@chromium.org7516f052011-03-30 08:52:27 +00003550}
3551
3552
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003553static void GenerateSmiKeyCheck(MacroAssembler* masm,
3554 Register key,
3555 Register scratch0,
3556 Register scratch1,
3557 FPURegister double_scratch0,
3558 Label* fail) {
3559 if (CpuFeatures::IsSupported(FPU)) {
3560 CpuFeatures::Scope scope(FPU);
3561 Label key_ok;
3562 // Check for smi or a smi inside a heap number. We convert the heap
3563 // number and check if the conversion is exact and fits into the smi
3564 // range.
3565 __ JumpIfSmi(key, &key_ok);
3566 __ CheckMap(key,
3567 scratch0,
3568 Heap::kHeapNumberMapRootIndex,
3569 fail,
3570 DONT_DO_SMI_CHECK);
3571 __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
3572 __ EmitFPUTruncate(kRoundToZero,
3573 double_scratch0,
3574 double_scratch0,
3575 scratch0,
3576 scratch1,
3577 kCheckForInexactConversion);
3578
3579 __ Branch(fail, ne, scratch1, Operand(zero_reg));
3580
3581 __ mfc1(scratch0, double_scratch0);
3582 __ SmiTagCheckOverflow(key, scratch0, scratch1);
3583 __ BranchOnOverflow(fail, scratch1);
3584 __ bind(&key_ok);
3585 } else {
3586 // Check that the key is a smi.
3587 __ JumpIfNotSmi(key, fail);
3588 }
3589}
3590
3591
danno@chromium.org40cb8782011-05-25 07:58:50 +00003592void KeyedLoadStubCompiler::GenerateLoadExternalArray(
3593 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003594 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003595 // ---------- S t a t e --------------
3596 // -- ra : return address
3597 // -- a0 : key
3598 // -- a1 : receiver
3599 // -----------------------------------
danno@chromium.org40cb8782011-05-25 07:58:50 +00003600 Label miss_force_generic, slow, failed_allocation;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003601
3602 Register key = a0;
3603 Register receiver = a1;
3604
danno@chromium.org40cb8782011-05-25 07:58:50 +00003605 // This stub is meant to be tail-jumped to, the receiver must already
3606 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003607
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003608 // Check that the key is a smi or a heap number convertible to a smi.
3609 GenerateSmiKeyCheck(masm, key, t0, t1, f2, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003610
3611 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3612 // a3: elements array
3613
3614 // Check that the index is in range.
3615 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3616 __ sra(t2, key, kSmiTagSize);
3617 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003618 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003619
3620 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3621 // a3: base pointer of external storage
3622
3623 // We are not untagging smi key and instead work with it
3624 // as if it was premultiplied by 2.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003625 STATIC_ASSERT((kSmiTag == 0) && (kSmiTagSize == 1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003626
3627 Register value = a2;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003628 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003629 case EXTERNAL_BYTE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003630 __ srl(t2, key, 1);
3631 __ addu(t3, a3, t2);
3632 __ lb(value, MemOperand(t3, 0));
3633 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003634 case EXTERNAL_PIXEL_ELEMENTS:
3635 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003636 __ srl(t2, key, 1);
3637 __ addu(t3, a3, t2);
3638 __ lbu(value, MemOperand(t3, 0));
3639 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003640 case EXTERNAL_SHORT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003641 __ addu(t3, a3, key);
3642 __ lh(value, MemOperand(t3, 0));
3643 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003644 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003645 __ addu(t3, a3, key);
3646 __ lhu(value, MemOperand(t3, 0));
3647 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003648 case EXTERNAL_INT_ELEMENTS:
3649 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003650 __ sll(t2, key, 1);
3651 __ addu(t3, a3, t2);
3652 __ lw(value, MemOperand(t3, 0));
3653 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003654 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003655 __ sll(t3, t2, 2);
3656 __ addu(t3, a3, t3);
3657 if (CpuFeatures::IsSupported(FPU)) {
3658 CpuFeatures::Scope scope(FPU);
3659 __ lwc1(f0, MemOperand(t3, 0));
3660 } else {
3661 __ lw(value, MemOperand(t3, 0));
3662 }
3663 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003664 case EXTERNAL_DOUBLE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003665 __ sll(t2, key, 2);
3666 __ addu(t3, a3, t2);
3667 if (CpuFeatures::IsSupported(FPU)) {
3668 CpuFeatures::Scope scope(FPU);
3669 __ ldc1(f0, MemOperand(t3, 0));
3670 } else {
3671 // t3: pointer to the beginning of the double we want to load.
3672 __ lw(a2, MemOperand(t3, 0));
3673 __ lw(a3, MemOperand(t3, Register::kSizeInBytes));
3674 }
3675 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003676 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003677 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003678 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003679 case FAST_HOLEY_ELEMENTS:
3680 case FAST_HOLEY_SMI_ELEMENTS:
3681 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003682 case DICTIONARY_ELEMENTS:
3683 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003684 UNREACHABLE();
3685 break;
3686 }
3687
3688 // For integer array types:
3689 // a2: value
3690 // For float array type:
3691 // f0: value (if FPU is supported)
3692 // a2: value (if FPU is not supported)
3693 // For double array type:
3694 // f0: value (if FPU is supported)
3695 // a2/a3: value (if FPU is not supported)
3696
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003697 if (elements_kind == EXTERNAL_INT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003698 // For the Int and UnsignedInt array types, we need to see whether
3699 // the value can be represented in a Smi. If not, we need to convert
3700 // it to a HeapNumber.
3701 Label box_int;
3702 __ Subu(t3, value, Operand(0xC0000000)); // Non-smi value gives neg result.
3703 __ Branch(&box_int, lt, t3, Operand(zero_reg));
3704 // Tag integer as smi and return it.
3705 __ sll(v0, value, kSmiTagSize);
3706 __ Ret();
3707
3708 __ bind(&box_int);
3709 // Allocate a HeapNumber for the result and perform int-to-double
3710 // conversion.
3711 // The arm version uses a temporary here to save r0, but we don't need to
3712 // (a0 is not modified).
3713 __ LoadRoot(t1, Heap::kHeapNumberMapRootIndex);
3714 __ AllocateHeapNumber(v0, a3, t0, t1, &slow);
3715
3716 if (CpuFeatures::IsSupported(FPU)) {
3717 CpuFeatures::Scope scope(FPU);
3718 __ mtc1(value, f0);
3719 __ cvt_d_w(f0, f0);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00003720 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003721 __ Ret();
3722 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003723 Register dst1 = t2;
3724 Register dst2 = t3;
3725 FloatingPointHelper::Destination dest =
3726 FloatingPointHelper::kCoreRegisters;
3727 FloatingPointHelper::ConvertIntToDouble(masm,
3728 value,
3729 dest,
3730 f0,
3731 dst1,
3732 dst2,
3733 t1,
3734 f2);
3735 __ sw(dst1, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3736 __ sw(dst2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3737 __ Ret();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003738 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003739 } else if (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003740 // The test is different for unsigned int values. Since we need
3741 // the value to be in the range of a positive smi, we can't
3742 // handle either of the top two bits being set in the value.
3743 if (CpuFeatures::IsSupported(FPU)) {
3744 CpuFeatures::Scope scope(FPU);
3745 Label pl_box_int;
3746 __ And(t2, value, Operand(0xC0000000));
3747 __ Branch(&pl_box_int, ne, t2, Operand(zero_reg));
3748
3749 // It can fit in an Smi.
3750 // Tag integer as smi and return it.
3751 __ sll(v0, value, kSmiTagSize);
3752 __ Ret();
3753
3754 __ bind(&pl_box_int);
3755 // Allocate a HeapNumber for the result and perform int-to-double
3756 // conversion. Don't use a0 and a1 as AllocateHeapNumber clobbers all
3757 // registers - also when jumping due to exhausted young space.
3758 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3759 __ AllocateHeapNumber(v0, t2, t3, t6, &slow);
3760
3761 // This is replaced by a macro:
3762 // __ mtc1(value, f0); // LS 32-bits.
3763 // __ mtc1(zero_reg, f1); // MS 32-bits are all zero.
3764 // __ cvt_d_l(f0, f0); // Use 64 bit conv to get correct unsigned 32-bit.
3765
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003766 __ Cvt_d_uw(f0, value, f22);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003767
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00003768 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003769
3770 __ Ret();
3771 } else {
3772 // Check whether unsigned integer fits into smi.
3773 Label box_int_0, box_int_1, done;
3774 __ And(t2, value, Operand(0x80000000));
3775 __ Branch(&box_int_0, ne, t2, Operand(zero_reg));
3776 __ And(t2, value, Operand(0x40000000));
3777 __ Branch(&box_int_1, ne, t2, Operand(zero_reg));
3778
3779 // Tag integer as smi and return it.
3780 __ sll(v0, value, kSmiTagSize);
3781 __ Ret();
3782
3783 Register hiword = value; // a2.
3784 Register loword = a3;
3785
3786 __ bind(&box_int_0);
3787 // Integer does not have leading zeros.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003788 GenerateUInt2Double(masm, hiword, loword, t0, 0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003789 __ Branch(&done);
3790
3791 __ bind(&box_int_1);
3792 // Integer has one leading zero.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003793 GenerateUInt2Double(masm, hiword, loword, t0, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003794
3795
3796 __ bind(&done);
3797 // Integer was converted to double in registers hiword:loword.
3798 // Wrap it into a HeapNumber. Don't use a0 and a1 as AllocateHeapNumber
3799 // clobbers all registers - also when jumping due to exhausted young
3800 // space.
3801 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3802 __ AllocateHeapNumber(t2, t3, t5, t6, &slow);
3803
3804 __ sw(hiword, FieldMemOperand(t2, HeapNumber::kExponentOffset));
3805 __ sw(loword, FieldMemOperand(t2, HeapNumber::kMantissaOffset));
3806
3807 __ mov(v0, t2);
3808 __ Ret();
3809 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003810 } else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003811 // For the floating-point array type, we need to always allocate a
3812 // HeapNumber.
3813 if (CpuFeatures::IsSupported(FPU)) {
3814 CpuFeatures::Scope scope(FPU);
3815 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3816 // AllocateHeapNumber clobbers all registers - also when jumping due to
3817 // exhausted young space.
3818 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3819 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3820 // The float (single) value is already in fpu reg f0 (if we use float).
3821 __ cvt_d_s(f0, f0);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00003822 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003823 __ Ret();
3824 } else {
3825 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3826 // AllocateHeapNumber clobbers all registers - also when jumping due to
3827 // exhausted young space.
3828 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3829 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3830 // FPU is not available, do manual single to double conversion.
3831
3832 // a2: floating point value (binary32).
3833 // v0: heap number for result
3834
3835 // Extract mantissa to t4.
3836 __ And(t4, value, Operand(kBinary32MantissaMask));
3837
3838 // Extract exponent to t5.
3839 __ srl(t5, value, kBinary32MantissaBits);
3840 __ And(t5, t5, Operand(kBinary32ExponentMask >> kBinary32MantissaBits));
3841
3842 Label exponent_rebiased;
3843 __ Branch(&exponent_rebiased, eq, t5, Operand(zero_reg));
3844
3845 __ li(t0, 0x7ff);
3846 __ Xor(t1, t5, Operand(0xFF));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003847 __ Movz(t5, t0, t1); // Set t5 to 0x7ff only if t5 is equal to 0xff.
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003848 __ Branch(&exponent_rebiased, eq, t1, Operand(zero_reg));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003849
3850 // Rebias exponent.
3851 __ Addu(t5,
3852 t5,
3853 Operand(-kBinary32ExponentBias + HeapNumber::kExponentBias));
3854
3855 __ bind(&exponent_rebiased);
3856 __ And(a2, value, Operand(kBinary32SignMask));
3857 value = no_reg;
3858 __ sll(t0, t5, HeapNumber::kMantissaBitsInTopWord);
3859 __ or_(a2, a2, t0);
3860
3861 // Shift mantissa.
3862 static const int kMantissaShiftForHiWord =
3863 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3864
3865 static const int kMantissaShiftForLoWord =
3866 kBitsPerInt - kMantissaShiftForHiWord;
3867
3868 __ srl(t0, t4, kMantissaShiftForHiWord);
3869 __ or_(a2, a2, t0);
3870 __ sll(a0, t4, kMantissaShiftForLoWord);
3871
3872 __ sw(a2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3873 __ sw(a0, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3874 __ Ret();
3875 }
3876
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003877 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003878 if (CpuFeatures::IsSupported(FPU)) {
3879 CpuFeatures::Scope scope(FPU);
3880 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3881 // AllocateHeapNumber clobbers all registers - also when jumping due to
3882 // exhausted young space.
3883 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3884 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3885 // The double value is already in f0
3886 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
3887 __ Ret();
3888 } else {
3889 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3890 // AllocateHeapNumber clobbers all registers - also when jumping due to
3891 // exhausted young space.
3892 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3893 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3894
3895 __ sw(a2, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3896 __ sw(a3, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3897 __ Ret();
3898 }
3899
3900 } else {
3901 // Tag integer as smi and return it.
3902 __ sll(v0, value, kSmiTagSize);
3903 __ Ret();
3904 }
3905
3906 // Slow case, key and receiver still in a0 and a1.
3907 __ bind(&slow);
3908 __ IncrementCounter(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003909 masm->isolate()->counters()->keyed_load_external_array_slow(),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003910 1, a2, a3);
3911
3912 // ---------- S t a t e --------------
3913 // -- ra : return address
3914 // -- a0 : key
3915 // -- a1 : receiver
3916 // -----------------------------------
3917
3918 __ Push(a1, a0);
3919
3920 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
3921
danno@chromium.org40cb8782011-05-25 07:58:50 +00003922 __ bind(&miss_force_generic);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003923 Handle<Code> stub =
3924 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3925 __ Jump(stub, RelocInfo::CODE_TARGET);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003926}
3927
3928
danno@chromium.org40cb8782011-05-25 07:58:50 +00003929void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3930 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003931 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003932 // ---------- S t a t e --------------
3933 // -- a0 : value
3934 // -- a1 : key
3935 // -- a2 : receiver
3936 // -- ra : return address
3937 // -----------------------------------
3938
danno@chromium.org40cb8782011-05-25 07:58:50 +00003939 Label slow, check_heap_number, miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003940
3941 // Register usage.
3942 Register value = a0;
3943 Register key = a1;
3944 Register receiver = a2;
3945 // a3 mostly holds the elements array or the destination external array.
3946
danno@chromium.org40cb8782011-05-25 07:58:50 +00003947 // This stub is meant to be tail-jumped to, the receiver must already
3948 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003949
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003950 // Check that the key is a smi or a heap number convertible to a smi.
3951 GenerateSmiKeyCheck(masm, key, t0, t1, f2, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003952
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003953 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3954
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003955 // Check that the index is in range.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003956 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3957 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003958 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003959
3960 // Handle both smis and HeapNumbers in the fast path. Go to the
3961 // runtime for all other kinds of values.
3962 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003963
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003964 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003965 // Double to pixel conversion is only implemented in the runtime for now.
3966 __ JumpIfNotSmi(value, &slow);
3967 } else {
3968 __ JumpIfNotSmi(value, &check_heap_number);
3969 }
3970 __ SmiUntag(t1, value);
3971 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3972
3973 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003974 // t1: value (integer).
3975
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003976 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003977 case EXTERNAL_PIXEL_ELEMENTS: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003978 // Clamp the value to [0..255].
3979 // v0 is used as a scratch register here.
3980 Label done;
3981 __ li(v0, Operand(255));
3982 // Normal branch: nop in delay slot.
3983 __ Branch(&done, gt, t1, Operand(v0));
3984 // Use delay slot in this branch.
3985 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg));
3986 __ mov(v0, zero_reg); // In delay slot.
3987 __ mov(v0, t1); // Value is in range 0..255.
3988 __ bind(&done);
3989 __ mov(t1, v0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003990
3991 __ srl(t8, key, 1);
3992 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003993 __ sb(t1, MemOperand(t8, 0));
3994 }
3995 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003996 case EXTERNAL_BYTE_ELEMENTS:
3997 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003998 __ srl(t8, key, 1);
3999 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004000 __ sb(t1, MemOperand(t8, 0));
4001 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004002 case EXTERNAL_SHORT_ELEMENTS:
4003 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004004 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004005 __ sh(t1, MemOperand(t8, 0));
4006 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004007 case EXTERNAL_INT_ELEMENTS:
4008 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004009 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004010 __ addu(t8, a3, t8);
4011 __ sw(t1, MemOperand(t8, 0));
4012 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004013 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004014 // Perform int-to-float conversion and store to memory.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004015 __ SmiUntag(t0, key);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004016 StoreIntAsFloat(masm, a3, t0, t1, t2, t3, t4);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004017 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004018 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004019 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004020 __ addu(a3, a3, t8);
4021 // a3: effective address of the double element
4022 FloatingPointHelper::Destination destination;
4023 if (CpuFeatures::IsSupported(FPU)) {
4024 destination = FloatingPointHelper::kFPURegisters;
4025 } else {
4026 destination = FloatingPointHelper::kCoreRegisters;
4027 }
4028 FloatingPointHelper::ConvertIntToDouble(
danno@chromium.org40cb8782011-05-25 07:58:50 +00004029 masm, t1, destination,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004030 f0, t2, t3, // These are: double_dst, dst1, dst2.
4031 t0, f2); // These are: scratch2, single_scratch.
4032 if (destination == FloatingPointHelper::kFPURegisters) {
4033 CpuFeatures::Scope scope(FPU);
4034 __ sdc1(f0, MemOperand(a3, 0));
4035 } else {
4036 __ sw(t2, MemOperand(a3, 0));
4037 __ sw(t3, MemOperand(a3, Register::kSizeInBytes));
4038 }
4039 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004040 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004041 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004042 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004043 case FAST_HOLEY_ELEMENTS:
4044 case FAST_HOLEY_SMI_ELEMENTS:
4045 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004046 case DICTIONARY_ELEMENTS:
4047 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004048 UNREACHABLE();
4049 break;
4050 }
4051
4052 // Entry registers are intact, a0 holds the value which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004053 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004054 __ Ret();
4055
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004056 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004057 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004058 __ bind(&check_heap_number);
4059 __ GetObjectType(value, t1, t2);
4060 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE));
4061
4062 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
4063
4064 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004065
4066 // The WebGL specification leaves the behavior of storing NaN and
4067 // +/-Infinity into integer arrays basically undefined. For more
4068 // reproducible behavior, convert these to zero.
4069
4070 if (CpuFeatures::IsSupported(FPU)) {
4071 CpuFeatures::Scope scope(FPU);
4072
4073 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
4074
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004075 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004076 __ cvt_s_d(f0, f0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004077 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004078 __ addu(t8, a3, t8);
4079 __ swc1(f0, MemOperand(t8, 0));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004080 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004081 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004082 __ addu(t8, a3, t8);
4083 __ sdc1(f0, MemOperand(t8, 0));
4084 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00004085 __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004086
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:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004109 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004110 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004111 case FAST_HOLEY_ELEMENTS:
4112 case FAST_HOLEY_SMI_ELEMENTS:
4113 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004114 case DICTIONARY_ELEMENTS:
4115 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004116 UNREACHABLE();
4117 break;
4118 }
4119 }
4120
4121 // Entry registers are intact, a0 holds the value
4122 // which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004123 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004124 __ Ret();
4125 } else {
4126 // FPU is not available, do manual conversions.
4127
4128 __ lw(t3, FieldMemOperand(value, HeapNumber::kExponentOffset));
4129 __ lw(t4, FieldMemOperand(value, HeapNumber::kMantissaOffset));
4130
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004131 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004132 Label done, nan_or_infinity_or_zero;
4133 static const int kMantissaInHiWordShift =
4134 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
4135
4136 static const int kMantissaInLoWordShift =
4137 kBitsPerInt - kMantissaInHiWordShift;
4138
4139 // Test for all special exponent values: zeros, subnormal numbers, NaNs
4140 // and infinities. All these should be converted to 0.
4141 __ li(t5, HeapNumber::kExponentMask);
4142 __ and_(t6, t3, t5);
4143 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(zero_reg));
4144
4145 __ xor_(t1, t6, t5);
4146 __ li(t2, kBinary32ExponentMask);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004147 __ Movz(t6, t2, t1); // Only if t6 is equal to t5.
rossberg@chromium.org400388e2012-06-06 09:29:22 +00004148 __ Branch(&nan_or_infinity_or_zero, eq, t1, Operand(zero_reg));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004149
4150 // Rebias exponent.
4151 __ srl(t6, t6, HeapNumber::kExponentShift);
4152 __ Addu(t6,
4153 t6,
4154 Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
4155
4156 __ li(t1, Operand(kBinary32MaxExponent));
4157 __ Slt(t1, t1, t6);
4158 __ And(t2, t3, Operand(HeapNumber::kSignMask));
4159 __ Or(t2, t2, Operand(kBinary32ExponentMask));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004160 __ Movn(t3, t2, t1); // Only if t6 is gt kBinary32MaxExponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004161 __ Branch(&done, gt, t6, Operand(kBinary32MaxExponent));
4162
4163 __ Slt(t1, t6, Operand(kBinary32MinExponent));
4164 __ And(t2, t3, Operand(HeapNumber::kSignMask));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004165 __ Movn(t3, t2, t1); // Only if t6 is lt kBinary32MinExponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004166 __ Branch(&done, lt, t6, Operand(kBinary32MinExponent));
4167
4168 __ And(t7, t3, Operand(HeapNumber::kSignMask));
4169 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4170 __ sll(t3, t3, kMantissaInHiWordShift);
4171 __ or_(t7, t7, t3);
4172 __ srl(t4, t4, kMantissaInLoWordShift);
4173 __ or_(t7, t7, t4);
4174 __ sll(t6, t6, kBinary32ExponentShift);
4175 __ or_(t3, t7, t6);
4176
4177 __ bind(&done);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004178 __ sll(t9, key, 1);
rossberg@chromium.org400388e2012-06-06 09:29:22 +00004179 __ addu(t9, a3, t9);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004180 __ sw(t3, MemOperand(t9, 0));
4181
4182 // Entry registers are intact, a0 holds the value which is the return
4183 // value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004184 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004185 __ Ret();
4186
4187 __ bind(&nan_or_infinity_or_zero);
4188 __ And(t7, t3, Operand(HeapNumber::kSignMask));
4189 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4190 __ or_(t6, t6, t7);
4191 __ sll(t3, t3, kMantissaInHiWordShift);
4192 __ or_(t6, t6, t3);
4193 __ srl(t4, t4, kMantissaInLoWordShift);
4194 __ or_(t3, t6, t4);
4195 __ Branch(&done);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004196 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00004197 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004198 __ addu(t8, a3, t8);
4199 // t8: effective address of destination element.
4200 __ sw(t4, MemOperand(t8, 0));
4201 __ sw(t3, MemOperand(t8, Register::kSizeInBytes));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004202 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004203 __ Ret();
4204 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004205 bool is_signed_type = IsElementTypeSigned(elements_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004206 int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
4207 int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
4208
4209 Label done, sign;
4210
4211 // Test for all special exponent values: zeros, subnormal numbers, NaNs
4212 // and infinities. All these should be converted to 0.
4213 __ li(t5, HeapNumber::kExponentMask);
4214 __ and_(t6, t3, t5);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004215 __ Movz(t3, zero_reg, t6); // Only if t6 is equal to zero.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004216 __ Branch(&done, eq, t6, Operand(zero_reg));
4217
4218 __ xor_(t2, t6, t5);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004219 __ Movz(t3, zero_reg, t2); // Only if t6 is equal to t5.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004220 __ Branch(&done, eq, t6, Operand(t5));
4221
4222 // Unbias exponent.
4223 __ srl(t6, t6, HeapNumber::kExponentShift);
4224 __ Subu(t6, t6, Operand(HeapNumber::kExponentBias));
4225 // If exponent is negative then result is 0.
4226 __ slt(t2, t6, zero_reg);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004227 __ Movn(t3, zero_reg, t2); // Only if exponent is negative.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004228 __ Branch(&done, lt, t6, Operand(zero_reg));
4229
4230 // If exponent is too big then result is minimal value.
4231 __ slti(t1, t6, meaningfull_bits - 1);
4232 __ li(t2, min_value);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004233 __ Movz(t3, t2, t1); // Only if t6 is ge meaningfull_bits - 1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004234 __ Branch(&done, ge, t6, Operand(meaningfull_bits - 1));
4235
4236 __ And(t5, t3, Operand(HeapNumber::kSignMask));
4237 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4238 __ Or(t3, t3, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
4239
4240 __ li(t9, HeapNumber::kMantissaBitsInTopWord);
4241 __ subu(t6, t9, t6);
4242 __ slt(t1, t6, zero_reg);
4243 __ srlv(t2, t3, t6);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004244 __ Movz(t3, t2, t1); // Only if t6 is positive.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004245 __ Branch(&sign, ge, t6, Operand(zero_reg));
4246
4247 __ subu(t6, zero_reg, t6);
4248 __ sllv(t3, t3, t6);
4249 __ li(t9, meaningfull_bits);
4250 __ subu(t6, t9, t6);
4251 __ srlv(t4, t4, t6);
4252 __ or_(t3, t3, t4);
4253
4254 __ bind(&sign);
4255 __ subu(t2, t3, zero_reg);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004256 __ Movz(t3, t2, t5); // Only if t5 is zero.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004257
4258 __ bind(&done);
4259
4260 // Result is in t3.
4261 // This switch block should be exactly the same as above (FPU mode).
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004262 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004263 case EXTERNAL_BYTE_ELEMENTS:
4264 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004265 __ srl(t8, key, 1);
4266 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004267 __ sb(t3, MemOperand(t8, 0));
4268 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004269 case EXTERNAL_SHORT_ELEMENTS:
4270 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004271 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004272 __ sh(t3, MemOperand(t8, 0));
4273 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004274 case EXTERNAL_INT_ELEMENTS:
4275 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004276 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004277 __ addu(t8, a3, t8);
4278 __ sw(t3, MemOperand(t8, 0));
4279 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004280 case EXTERNAL_PIXEL_ELEMENTS:
4281 case EXTERNAL_FLOAT_ELEMENTS:
4282 case EXTERNAL_DOUBLE_ELEMENTS:
4283 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004284 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004285 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004286 case FAST_HOLEY_ELEMENTS:
4287 case FAST_HOLEY_SMI_ELEMENTS:
4288 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004289 case DICTIONARY_ELEMENTS:
4290 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004291 UNREACHABLE();
4292 break;
4293 }
4294 }
4295 }
4296 }
4297
danno@chromium.org40cb8782011-05-25 07:58:50 +00004298 // Slow case, key and receiver still in a0 and a1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004299 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004300 __ IncrementCounter(
4301 masm->isolate()->counters()->keyed_load_external_array_slow(),
4302 1, a2, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004303 // Entry registers are intact.
4304 // ---------- S t a t e --------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004305 // -- ra : return address
danno@chromium.org40cb8782011-05-25 07:58:50 +00004306 // -- a0 : key
4307 // -- a1 : receiver
4308 // -----------------------------------
4309 Handle<Code> slow_ic =
4310 masm->isolate()->builtins()->KeyedStoreIC_Slow();
4311 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4312
4313 // Miss case, call the runtime.
4314 __ bind(&miss_force_generic);
4315
4316 // ---------- S t a t e --------------
4317 // -- ra : return address
4318 // -- a0 : key
4319 // -- a1 : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004320 // -----------------------------------
4321
danno@chromium.org40cb8782011-05-25 07:58:50 +00004322 Handle<Code> miss_ic =
4323 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4324 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
4325}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004326
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004327
danno@chromium.org40cb8782011-05-25 07:58:50 +00004328void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
4329 // ----------- S t a t e -------------
4330 // -- ra : return address
4331 // -- a0 : key
4332 // -- a1 : receiver
4333 // -----------------------------------
4334 Label miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004335
danno@chromium.org40cb8782011-05-25 07:58:50 +00004336 // This stub is meant to be tail-jumped to, the receiver must already
4337 // have been verified by the caller to not be a smi.
4338
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004339 // Check that the key is a smi or a heap number convertible to a smi.
4340 GenerateSmiKeyCheck(masm, a0, t0, t1, f2, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004341
4342 // Get the elements array.
4343 __ lw(a2, FieldMemOperand(a1, JSObject::kElementsOffset));
4344 __ AssertFastElements(a2);
4345
4346 // Check that the key is within bounds.
4347 __ lw(a3, FieldMemOperand(a2, FixedArray::kLengthOffset));
ulan@chromium.org6ff65142012-03-21 09:52:17 +00004348 __ Branch(USE_DELAY_SLOT, &miss_force_generic, hs, a0, Operand(a3));
danno@chromium.org40cb8782011-05-25 07:58:50 +00004349
4350 // Load the result and make sure it's not the hole.
4351 __ Addu(a3, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004352 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004353 __ sll(t0, a0, kPointerSizeLog2 - kSmiTagSize);
4354 __ Addu(t0, t0, a3);
4355 __ lw(t0, MemOperand(t0));
4356 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
4357 __ Branch(&miss_force_generic, eq, t0, Operand(t1));
ulan@chromium.org6ff65142012-03-21 09:52:17 +00004358 __ Ret(USE_DELAY_SLOT);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004359 __ mov(v0, t0);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004360
4361 __ bind(&miss_force_generic);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004362 Handle<Code> stub =
4363 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4364 __ Jump(stub, RelocInfo::CODE_TARGET);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004365}
4366
4367
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004368void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
4369 MacroAssembler* masm) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004370 // ----------- S t a t e -------------
4371 // -- ra : return address
4372 // -- a0 : key
4373 // -- a1 : receiver
4374 // -----------------------------------
4375 Label miss_force_generic, slow_allocate_heapnumber;
4376
4377 Register key_reg = a0;
4378 Register receiver_reg = a1;
4379 Register elements_reg = a2;
4380 Register heap_number_reg = a2;
4381 Register indexed_double_offset = a3;
4382 Register scratch = t0;
4383 Register scratch2 = t1;
4384 Register scratch3 = t2;
4385 Register heap_number_map = t3;
4386
4387 // This stub is meant to be tail-jumped to, the receiver must already
4388 // have been verified by the caller to not be a smi.
4389
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004390 // Check that the key is a smi or a heap number convertible to a smi.
4391 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004392
4393 // Get the elements array.
4394 __ lw(elements_reg,
4395 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4396
4397 // Check that the key is within bounds.
4398 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4399 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4400
4401 // Load the upper word of the double in the fixed array and test for NaN.
4402 __ sll(scratch2, key_reg, kDoubleSizeLog2 - kSmiTagSize);
4403 __ Addu(indexed_double_offset, elements_reg, Operand(scratch2));
4404 uint32_t upper_32_offset = FixedArray::kHeaderSize + sizeof(kHoleNanLower32);
4405 __ lw(scratch, FieldMemOperand(indexed_double_offset, upper_32_offset));
4406 __ Branch(&miss_force_generic, eq, scratch, Operand(kHoleNanUpper32));
4407
4408 // Non-NaN. Allocate a new heap number and copy the double value into it.
4409 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
4410 __ AllocateHeapNumber(heap_number_reg, scratch2, scratch3,
4411 heap_number_map, &slow_allocate_heapnumber);
4412
4413 // Don't need to reload the upper 32 bits of the double, it's already in
4414 // scratch.
4415 __ sw(scratch, FieldMemOperand(heap_number_reg,
4416 HeapNumber::kExponentOffset));
4417 __ lw(scratch, FieldMemOperand(indexed_double_offset,
4418 FixedArray::kHeaderSize));
4419 __ sw(scratch, FieldMemOperand(heap_number_reg,
4420 HeapNumber::kMantissaOffset));
4421
4422 __ mov(v0, heap_number_reg);
4423 __ Ret();
4424
4425 __ bind(&slow_allocate_heapnumber);
4426 Handle<Code> slow_ic =
4427 masm->isolate()->builtins()->KeyedLoadIC_Slow();
4428 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4429
4430 __ bind(&miss_force_generic);
4431 Handle<Code> miss_ic =
4432 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4433 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004434}
4435
4436
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004437void KeyedStoreStubCompiler::GenerateStoreFastElement(
4438 MacroAssembler* masm,
4439 bool is_js_array,
yangguo@chromium.org56454712012-02-16 15:33:53 +00004440 ElementsKind elements_kind,
4441 KeyedAccessGrowMode grow_mode) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00004442 // ----------- S t a t e -------------
4443 // -- a0 : value
4444 // -- a1 : key
4445 // -- a2 : receiver
4446 // -- ra : return address
4447 // -- a3 : scratch
4448 // -- a4 : scratch (elements)
4449 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00004450 Label miss_force_generic, transition_elements_kind, grow, slow;
4451 Label finish_store, check_capacity;
danno@chromium.org40cb8782011-05-25 07:58:50 +00004452
4453 Register value_reg = a0;
4454 Register key_reg = a1;
4455 Register receiver_reg = a2;
yangguo@chromium.org56454712012-02-16 15:33:53 +00004456 Register scratch = t0;
4457 Register elements_reg = a3;
4458 Register length_reg = t1;
4459 Register scratch2 = t2;
danno@chromium.org40cb8782011-05-25 07:58:50 +00004460
4461 // This stub is meant to be tail-jumped to, the receiver must already
4462 // have been verified by the caller to not be a smi.
4463
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004464 // Check that the key is a smi or a heap number convertible to a smi.
4465 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004466
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004467 if (IsFastSmiElementsKind(elements_kind)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00004468 __ JumpIfNotSmi(value_reg, &transition_elements_kind);
4469 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004470
4471 // Check that the key is within bounds.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004472 __ lw(elements_reg,
4473 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00004474 if (is_js_array) {
4475 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4476 } else {
4477 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4478 }
4479 // Compare smis.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004480 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4481 __ Branch(&grow, hs, key_reg, Operand(scratch));
4482 } else {
4483 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4484 }
4485
4486 // Make sure elements is a fast element array, not 'cow'.
4487 __ CheckMap(elements_reg,
4488 scratch,
4489 Heap::kFixedArrayMapRootIndex,
4490 &miss_force_generic,
4491 DONT_DO_SMI_CHECK);
4492
4493 __ bind(&finish_store);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004494
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004495 if (IsFastSmiElementsKind(elements_kind)) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004496 __ Addu(scratch,
4497 elements_reg,
4498 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4499 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4500 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4501 __ Addu(scratch, scratch, scratch2);
4502 __ sw(value_reg, MemOperand(scratch));
4503 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004504 ASSERT(IsFastObjectElementsKind(elements_kind));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004505 __ Addu(scratch,
4506 elements_reg,
4507 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4508 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4509 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4510 __ Addu(scratch, scratch, scratch2);
4511 __ sw(value_reg, MemOperand(scratch));
4512 __ mov(receiver_reg, value_reg);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004513 __ RecordWrite(elements_reg, // Object.
4514 scratch, // Address.
4515 receiver_reg, // Value.
4516 kRAHasNotBeenSaved,
4517 kDontSaveFPRegs);
4518 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004519 // value_reg (a0) is preserved.
4520 // Done.
4521 __ Ret();
4522
4523 __ bind(&miss_force_generic);
4524 Handle<Code> ic =
4525 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4526 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004527
4528 __ bind(&transition_elements_kind);
4529 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4530 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
yangguo@chromium.org56454712012-02-16 15:33:53 +00004531
4532 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4533 // Grow the array by a single element if possible.
4534 __ bind(&grow);
4535
4536 // Make sure the array is only growing by a single element, anything else
4537 // must be handled by the runtime.
4538 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch));
4539
4540 // Check for the empty array, and preallocate a small backing store if
4541 // possible.
4542 __ lw(length_reg,
4543 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4544 __ lw(elements_reg,
4545 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4546 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
4547 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
4548
4549 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
4550 __ AllocateInNewSpace(size, elements_reg, scratch, scratch2, &slow,
4551 TAG_OBJECT);
4552
4553 __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex);
4554 __ sw(scratch, FieldMemOperand(elements_reg, JSObject::kMapOffset));
4555 __ li(scratch, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4556 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4557 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
4558 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
4559 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::SizeFor(i)));
4560 }
4561
4562 // Store the element at index zero.
4563 __ sw(value_reg, FieldMemOperand(elements_reg, FixedArray::SizeFor(0)));
4564
4565 // Install the new backing store in the JSArray.
4566 __ sw(elements_reg,
4567 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4568 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
4569 scratch, kRAHasNotBeenSaved, kDontSaveFPRegs,
4570 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4571
4572 // Increment the length of the array.
4573 __ li(length_reg, Operand(Smi::FromInt(1)));
4574 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4575 __ Ret();
4576
4577 __ bind(&check_capacity);
4578 // Check for cow elements, in general they are not handled by this stub
4579 __ CheckMap(elements_reg,
4580 scratch,
4581 Heap::kFixedCOWArrayMapRootIndex,
4582 &miss_force_generic,
4583 DONT_DO_SMI_CHECK);
4584
4585 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4586 __ Branch(&slow, hs, length_reg, Operand(scratch));
4587
4588 // Grow the array and finish the store.
4589 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
4590 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4591 __ jmp(&finish_store);
4592
4593 __ bind(&slow);
4594 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4595 __ Jump(ic_slow, RelocInfo::CODE_TARGET);
4596 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004597}
4598
4599
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004600void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
4601 MacroAssembler* masm,
yangguo@chromium.org56454712012-02-16 15:33:53 +00004602 bool is_js_array,
4603 KeyedAccessGrowMode grow_mode) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004604 // ----------- S t a t e -------------
4605 // -- a0 : value
4606 // -- a1 : key
4607 // -- a2 : receiver
4608 // -- ra : return address
4609 // -- a3 : scratch
4610 // -- t0 : scratch (elements_reg)
4611 // -- t1 : scratch (mantissa_reg)
4612 // -- t2 : scratch (exponent_reg)
4613 // -- t3 : scratch4
4614 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00004615 Label miss_force_generic, transition_elements_kind, grow, slow;
4616 Label finish_store, check_capacity;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004617
4618 Register value_reg = a0;
4619 Register key_reg = a1;
4620 Register receiver_reg = a2;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004621 Register elements_reg = a3;
4622 Register scratch1 = t0;
4623 Register scratch2 = t1;
4624 Register scratch3 = t2;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004625 Register scratch4 = t3;
yangguo@chromium.org56454712012-02-16 15:33:53 +00004626 Register length_reg = t3;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004627
4628 // This stub is meant to be tail-jumped to, the receiver must already
4629 // have been verified by the caller to not be a smi.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004630
4631 // Check that the key is a smi or a heap number convertible to a smi.
4632 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004633
4634 __ lw(elements_reg,
4635 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4636
4637 // Check that the key is within bounds.
4638 if (is_js_array) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004639 __ lw(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004640 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004641 __ lw(scratch1,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004642 FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4643 }
4644 // Compare smis, unsigned compare catches both negative and out-of-bound
4645 // indexes.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004646 if (grow_mode == ALLOW_JSARRAY_GROWTH) {
4647 __ Branch(&grow, hs, key_reg, Operand(scratch1));
4648 } else {
4649 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch1));
4650 }
4651
4652 __ bind(&finish_store);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004653
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004654 __ StoreNumberToDoubleElements(value_reg,
4655 key_reg,
4656 receiver_reg,
4657 elements_reg,
4658 scratch1,
4659 scratch2,
4660 scratch3,
4661 scratch4,
4662 &transition_elements_kind);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004663
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004664 __ Ret(USE_DELAY_SLOT);
4665 __ mov(v0, value_reg); // In delay slot.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004666
4667 // Handle store cache miss, replacing the ic with the generic stub.
4668 __ bind(&miss_force_generic);
4669 Handle<Code> ic =
4670 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4671 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004672
4673 __ bind(&transition_elements_kind);
4674 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4675 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
yangguo@chromium.org56454712012-02-16 15:33:53 +00004676
4677 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4678 // Grow the array by a single element if possible.
4679 __ bind(&grow);
4680
4681 // Make sure the array is only growing by a single element, anything else
4682 // must be handled by the runtime.
4683 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch1));
4684
4685 // Transition on values that can't be stored in a FixedDoubleArray.
4686 Label value_is_smi;
4687 __ JumpIfSmi(value_reg, &value_is_smi);
4688 __ lw(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
4689 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
4690 __ Branch(&transition_elements_kind, ne, scratch1, Operand(at));
4691 __ bind(&value_is_smi);
4692
4693 // Check for the empty array, and preallocate a small backing store if
4694 // possible.
4695 __ lw(length_reg,
4696 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4697 __ lw(elements_reg,
4698 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4699 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
4700 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
4701
4702 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
4703 __ AllocateInNewSpace(size, elements_reg, scratch1, scratch2, &slow,
4704 TAG_OBJECT);
4705
4706 // Initialize the new FixedDoubleArray. Leave elements unitialized for
4707 // efficiency, they are guaranteed to be initialized before use.
4708 __ LoadRoot(scratch1, Heap::kFixedDoubleArrayMapRootIndex);
4709 __ sw(scratch1, FieldMemOperand(elements_reg, JSObject::kMapOffset));
4710 __ li(scratch1, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4711 __ sw(scratch1,
4712 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
4713
4714 // Install the new backing store in the JSArray.
4715 __ sw(elements_reg,
4716 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4717 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
4718 scratch1, kRAHasNotBeenSaved, kDontSaveFPRegs,
4719 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4720
4721 // Increment the length of the array.
4722 __ li(length_reg, Operand(Smi::FromInt(1)));
4723 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
danno@chromium.org00379b82012-05-04 09:16:29 +00004724 __ lw(elements_reg,
4725 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
yangguo@chromium.org56454712012-02-16 15:33:53 +00004726 __ jmp(&finish_store);
4727
4728 __ bind(&check_capacity);
4729 // Make sure that the backing store can hold additional elements.
4730 __ lw(scratch1,
4731 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
4732 __ Branch(&slow, hs, length_reg, Operand(scratch1));
4733
4734 // Grow the array and finish the store.
4735 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
4736 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4737 __ jmp(&finish_store);
4738
4739 __ bind(&slow);
4740 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4741 __ Jump(ic_slow, RelocInfo::CODE_TARGET);
4742 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004743}
4744
4745
ager@chromium.org5c838252010-02-19 08:53:10 +00004746#undef __
4747
4748} } // namespace v8::internal
4749
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004750#endif // V8_TARGET_ARCH_MIPS