blob: 2594f491abcd35b44cf1d446bb9ff36786871701 [file] [log] [blame]
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001// Copyright 2012 the V8 project authors. All rights reserved.
ager@chromium.org5c838252010-02-19 08:53:10 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000030#if defined(V8_TARGET_ARCH_MIPS)
31
ager@chromium.org5c838252010-02-19 08:53:10 +000032#include "ic-inl.h"
karlklose@chromium.org83a47282011-05-11 11:54:09 +000033#include "codegen.h"
ager@chromium.org5c838252010-02-19 08:53:10 +000034#include "stub-cache.h"
35
36namespace v8 {
37namespace internal {
38
39#define __ ACCESS_MASM(masm)
40
41
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000042static void ProbeTable(Isolate* isolate,
43 MacroAssembler* masm,
44 Code::Flags flags,
45 StubCache::Table table,
fschneider@chromium.org35814e52012-03-01 15:43:35 +000046 Register receiver,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000047 Register name,
fschneider@chromium.org35814e52012-03-01 15:43:35 +000048 // Number of the cache entry, not scaled.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000049 Register offset,
50 Register scratch,
fschneider@chromium.org35814e52012-03-01 15:43:35 +000051 Register scratch2,
52 Register offset_scratch) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000053 ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
54 ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
fschneider@chromium.org35814e52012-03-01 15:43:35 +000055 ExternalReference map_offset(isolate->stub_cache()->map_reference(table));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000056
57 uint32_t key_off_addr = reinterpret_cast<uint32_t>(key_offset.address());
58 uint32_t value_off_addr = reinterpret_cast<uint32_t>(value_offset.address());
fschneider@chromium.org35814e52012-03-01 15:43:35 +000059 uint32_t map_off_addr = reinterpret_cast<uint32_t>(map_offset.address());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000060
61 // Check the relative positions of the address fields.
62 ASSERT(value_off_addr > key_off_addr);
63 ASSERT((value_off_addr - key_off_addr) % 4 == 0);
64 ASSERT((value_off_addr - key_off_addr) < (256 * 4));
fschneider@chromium.org35814e52012-03-01 15:43:35 +000065 ASSERT(map_off_addr > key_off_addr);
66 ASSERT((map_off_addr - key_off_addr) % 4 == 0);
67 ASSERT((map_off_addr - key_off_addr) < (256 * 4));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000068
69 Label miss;
fschneider@chromium.org35814e52012-03-01 15:43:35 +000070 Register base_addr = scratch;
71 scratch = no_reg;
72
73 // Multiply by 3 because there are 3 fields per entry (name, code, map).
74 __ sll(offset_scratch, offset, 1);
75 __ Addu(offset_scratch, offset_scratch, offset);
76
77 // Calculate the base address of the entry.
78 __ li(base_addr, Operand(key_offset));
79 __ sll(at, offset_scratch, kPointerSizeLog2);
80 __ Addu(base_addr, base_addr, at);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000081
82 // Check that the key in the entry matches the name.
fschneider@chromium.org35814e52012-03-01 15:43:35 +000083 __ lw(at, MemOperand(base_addr, 0));
84 __ Branch(&miss, ne, name, Operand(at));
85
86 // Check the map matches.
87 __ lw(at, MemOperand(base_addr, map_off_addr - key_off_addr));
88 __ lw(scratch2, FieldMemOperand(receiver, HeapObject::kMapOffset));
89 __ Branch(&miss, ne, at, Operand(scratch2));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000090
91 // Get the code entry from the cache.
fschneider@chromium.org35814e52012-03-01 15:43:35 +000092 Register code = scratch2;
93 scratch2 = no_reg;
94 __ lw(code, MemOperand(base_addr, value_off_addr - key_off_addr));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000095
96 // Check that the flags match what we're looking for.
fschneider@chromium.org35814e52012-03-01 15:43:35 +000097 Register flags_reg = base_addr;
98 base_addr = no_reg;
99 __ lw(flags_reg, FieldMemOperand(code, Code::kFlagsOffset));
100 __ And(flags_reg, flags_reg, Operand(~Code::kFlagsNotUsedInLookup));
101 __ Branch(&miss, ne, flags_reg, Operand(flags));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000102
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000103#ifdef DEBUG
104 if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
105 __ jmp(&miss);
106 } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
107 __ jmp(&miss);
108 }
109#endif
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000110
111 // Jump to the first instruction in the code stub.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000112 __ Addu(at, code, Operand(Code::kHeaderSize - kHeapObjectTag));
113 __ Jump(at);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000114
115 // Miss: fall through.
116 __ bind(&miss);
117}
118
119
120// Helper function used to check that the dictionary doesn't contain
121// the property. This function may return false negatives, so miss_label
122// must always call a backup property check that is complete.
123// This function is safe to call if the receiver has fast properties.
124// Name must be a symbol and receiver must be a heap object.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000125static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
126 Label* miss_label,
127 Register receiver,
128 Handle<String> name,
129 Register scratch0,
130 Register scratch1) {
131 ASSERT(name->IsSymbol());
132 Counters* counters = masm->isolate()->counters();
133 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
134 __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
135
136 Label done;
137
138 const int kInterceptorOrAccessCheckNeededMask =
139 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
140
141 // Bail out if the receiver has a named interceptor or requires access checks.
142 Register map = scratch1;
143 __ lw(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
144 __ lbu(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
145 __ And(scratch0, scratch0, Operand(kInterceptorOrAccessCheckNeededMask));
146 __ Branch(miss_label, ne, scratch0, Operand(zero_reg));
147
148 // Check that receiver is a JSObject.
149 __ lbu(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
150 __ Branch(miss_label, lt, scratch0, Operand(FIRST_SPEC_OBJECT_TYPE));
151
152 // Load properties array.
153 Register properties = scratch0;
154 __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
155 // Check that the properties array is a dictionary.
156 __ lw(map, FieldMemOperand(properties, HeapObject::kMapOffset));
157 Register tmp = properties;
158 __ LoadRoot(tmp, Heap::kHashTableMapRootIndex);
159 __ Branch(miss_label, ne, map, Operand(tmp));
160
161 // Restore the temporarily used register.
162 __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
163
164
165 StringDictionaryLookupStub::GenerateNegativeLookup(masm,
166 miss_label,
167 &done,
168 receiver,
169 properties,
170 name,
171 scratch1);
172 __ bind(&done);
173 __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
174}
175
176
ager@chromium.org5c838252010-02-19 08:53:10 +0000177void StubCache::GenerateProbe(MacroAssembler* masm,
178 Code::Flags flags,
179 Register receiver,
180 Register name,
181 Register scratch,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000182 Register extra,
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000183 Register extra2,
184 Register extra3) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000185 Isolate* isolate = masm->isolate();
186 Label miss;
187
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000188 // Make sure that code is valid. The multiplying code relies on the
189 // entry size being 12.
190 ASSERT(sizeof(Entry) == 12);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000191
192 // Make sure the flags does not name a specific type.
193 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
194
195 // Make sure that there are no register conflicts.
196 ASSERT(!scratch.is(receiver));
197 ASSERT(!scratch.is(name));
198 ASSERT(!extra.is(receiver));
199 ASSERT(!extra.is(name));
200 ASSERT(!extra.is(scratch));
201 ASSERT(!extra2.is(receiver));
202 ASSERT(!extra2.is(name));
203 ASSERT(!extra2.is(scratch));
204 ASSERT(!extra2.is(extra));
205
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000206 // Check register validity.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000207 ASSERT(!scratch.is(no_reg));
208 ASSERT(!extra.is(no_reg));
209 ASSERT(!extra2.is(no_reg));
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000210 ASSERT(!extra3.is(no_reg));
211
212 Counters* counters = masm->isolate()->counters();
213 __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1,
214 extra2, extra3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000215
216 // Check that the receiver isn't a smi.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000217 __ JumpIfSmi(receiver, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000218
219 // Get the map of the receiver and compute the hash.
220 __ lw(scratch, FieldMemOperand(name, String::kHashFieldOffset));
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000221 __ lw(at, FieldMemOperand(receiver, HeapObject::kMapOffset));
222 __ Addu(scratch, scratch, at);
223 uint32_t mask = kPrimaryTableSize - 1;
224 // We shift out the last two bits because they are not part of the hash and
225 // they are always 01 for maps.
226 __ srl(scratch, scratch, kHeapObjectTagSize);
227 __ Xor(scratch, scratch, Operand((flags >> kHeapObjectTagSize) & mask));
228 __ And(scratch, scratch, Operand(mask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000229
230 // Probe the primary table.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000231 ProbeTable(isolate,
232 masm,
233 flags,
234 kPrimary,
235 receiver,
236 name,
237 scratch,
238 extra,
239 extra2,
240 extra3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000241
242 // Primary miss: Compute hash for secondary probe.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000243 __ srl(at, name, kHeapObjectTagSize);
244 __ Subu(scratch, scratch, at);
245 uint32_t mask2 = kSecondaryTableSize - 1;
246 __ Addu(scratch, scratch, Operand((flags >> kHeapObjectTagSize) & mask2));
247 __ And(scratch, scratch, Operand(mask2));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000248
249 // Probe the secondary table.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000250 ProbeTable(isolate,
251 masm,
252 flags,
253 kSecondary,
254 receiver,
255 name,
256 scratch,
257 extra,
258 extra2,
259 extra3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000260
261 // Cache miss: Fall-through and let caller handle the miss by
262 // entering the runtime system.
263 __ bind(&miss);
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000264 __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1,
265 extra2, extra3);
ager@chromium.org5c838252010-02-19 08:53:10 +0000266}
267
268
269void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
270 int index,
271 Register prototype) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000272 // Load the global or builtins object from the current context.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000273 __ lw(prototype,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000274 MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
275 // Load the native context from the global or builtins object.
276 __ lw(prototype,
277 FieldMemOperand(prototype, GlobalObject::kNativeContextOffset));
278 // Load the function from the native context.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000279 __ lw(prototype, MemOperand(prototype, Context::SlotOffset(index)));
280 // Load the initial map. The global functions all have initial maps.
281 __ lw(prototype,
282 FieldMemOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
283 // Load the prototype from the initial map.
284 __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000285}
286
287
lrn@chromium.org7516f052011-03-30 08:52:27 +0000288void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000289 MacroAssembler* masm,
290 int index,
291 Register prototype,
292 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000293 Isolate* isolate = masm->isolate();
294 // Check we're still in the same context.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000295 __ lw(prototype,
296 MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000297 ASSERT(!prototype.is(at));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000298 __ li(at, isolate->global_object());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000299 __ Branch(miss, ne, prototype, Operand(at));
300 // Get the global function with the given index.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000301 Handle<JSFunction> function(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000302 JSFunction::cast(isolate->native_context()->get(index)));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000303 // Load its initial map. The global functions all have initial maps.
304 __ li(prototype, Handle<Map>(function->initial_map()));
305 // Load the prototype from the initial map.
306 __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000307}
308
309
ager@chromium.org5c838252010-02-19 08:53:10 +0000310// Load a fast property out of a holder object (src). In-object properties
311// are loaded directly otherwise the property is loaded from the properties
312// fixed array.
313void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000314 Register dst,
315 Register src,
316 Handle<JSObject> holder,
317 int index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000318 // Adjust for the number of properties stored in the holder.
319 index -= holder->map()->inobject_properties();
320 if (index < 0) {
321 // Get the property straight out of the holder.
322 int offset = holder->map()->instance_size() + (index * kPointerSize);
323 __ lw(dst, FieldMemOperand(src, offset));
324 } else {
325 // Calculate the offset into the properties array.
326 int offset = index * kPointerSize + FixedArray::kHeaderSize;
327 __ lw(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
328 __ lw(dst, FieldMemOperand(dst, offset));
329 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000330}
331
332
333void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
334 Register receiver,
335 Register scratch,
336 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000337 // Check that the receiver isn't a smi.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000338 __ JumpIfSmi(receiver, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000339
340 // Check that the object is a JS array.
341 __ GetObjectType(receiver, scratch, scratch);
342 __ Branch(miss_label, ne, scratch, Operand(JS_ARRAY_TYPE));
343
344 // Load length directly from the JS array.
345 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
346 __ Ret();
347}
348
349
350// Generate code to check if an object is a string. If the object is a
351// heap object, its map's instance type is left in the scratch1 register.
352// If this is not needed, scratch1 and scratch2 may be the same register.
353static void GenerateStringCheck(MacroAssembler* masm,
354 Register receiver,
355 Register scratch1,
356 Register scratch2,
357 Label* smi,
358 Label* non_string_object) {
359 // Check that the receiver isn't a smi.
360 __ JumpIfSmi(receiver, smi, t0);
361
362 // Check that the object is a string.
363 __ lw(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
364 __ lbu(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
365 __ And(scratch2, scratch1, Operand(kIsNotStringMask));
366 // The cast is to resolve the overload for the argument of 0x0.
367 __ Branch(non_string_object,
368 ne,
369 scratch2,
370 Operand(static_cast<int32_t>(kStringTag)));
ager@chromium.org5c838252010-02-19 08:53:10 +0000371}
372
373
lrn@chromium.org7516f052011-03-30 08:52:27 +0000374// Generate code to load the length from a string object and return the length.
375// If the receiver object is not a string or a wrapped string object the
376// execution continues at the miss label. The register containing the
377// receiver is potentially clobbered.
378void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
379 Register receiver,
380 Register scratch1,
381 Register scratch2,
382 Label* miss,
383 bool support_wrappers) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000384 Label check_wrapper;
385
386 // Check if the object is a string leaving the instance type in the
387 // scratch1 register.
388 GenerateStringCheck(masm, receiver, scratch1, scratch2, miss,
389 support_wrappers ? &check_wrapper : miss);
390
391 // Load length directly from the string.
392 __ lw(v0, FieldMemOperand(receiver, String::kLengthOffset));
393 __ Ret();
394
395 if (support_wrappers) {
396 // Check if the object is a JSValue wrapper.
397 __ bind(&check_wrapper);
398 __ Branch(miss, ne, scratch1, Operand(JS_VALUE_TYPE));
399
400 // Unwrap the value and check if the wrapped value is a string.
401 __ lw(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
402 GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
403 __ lw(v0, FieldMemOperand(scratch1, String::kLengthOffset));
404 __ Ret();
405 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000406}
407
408
ager@chromium.org5c838252010-02-19 08:53:10 +0000409void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
410 Register receiver,
411 Register scratch1,
412 Register scratch2,
413 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000414 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
415 __ mov(v0, scratch1);
416 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000417}
418
419
lrn@chromium.org7516f052011-03-30 08:52:27 +0000420// Generate StoreField code, value is passed in a0 register.
ager@chromium.org5c838252010-02-19 08:53:10 +0000421// After executing generated code, the receiver_reg and name_reg
422// may be clobbered.
423void StubCompiler::GenerateStoreField(MacroAssembler* masm,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000424 Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +0000425 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000426 Handle<Map> transition,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000427 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +0000428 Register receiver_reg,
429 Register name_reg,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000430 Register scratch1,
431 Register scratch2,
ager@chromium.org5c838252010-02-19 08:53:10 +0000432 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000433 // a0 : value.
434 Label exit;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000435
436 LookupResult lookup(masm->isolate());
437 object->Lookup(*name, &lookup);
438 if (lookup.IsFound() && (lookup.IsReadOnly() || !lookup.IsCacheable())) {
439 // In sloppy mode, we could just return the value and be done. However, we
440 // might be in strict mode, where we have to throw. Since we cannot tell,
441 // go into slow case unconditionally.
442 __ jmp(miss_label);
443 return;
444 }
445
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000446 // Check that the map of the object hasn't changed.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000447 CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
448 : REQUIRE_EXACT_MAP;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000449 __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000450 DO_SMI_CHECK, mode);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000451
452 // Perform global security token check if needed.
453 if (object->IsJSGlobalProxy()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000454 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
455 }
456
457 // Check that we are allowed to write this.
458 if (!transition.is_null() && object->GetPrototype()->IsJSObject()) {
459 JSObject* holder;
460 if (lookup.IsFound()) {
461 holder = lookup.holder();
462 } else {
463 // Find the top object.
464 holder = *object;
465 do {
466 holder = JSObject::cast(holder->GetPrototype());
467 } while (holder->GetPrototype()->IsJSObject());
468 }
469 // We need an extra register, push
470 __ push(name_reg);
471 Label miss_pop, done_check;
472 CheckPrototypes(object, receiver_reg, Handle<JSObject>(holder), name_reg,
473 scratch1, scratch2, name, &miss_pop);
474 __ jmp(&done_check);
475 __ bind(&miss_pop);
476 __ pop(name_reg);
477 __ jmp(miss_label);
478 __ bind(&done_check);
479 __ pop(name_reg);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000480 }
481
482 // Stub never generated for non-global objects that require access
483 // checks.
484 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
485
486 // Perform map transition for the receiver if necessary.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000487 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000488 // The properties must be extended before we can store the value.
489 // We jump to a runtime call that extends the properties array.
490 __ push(receiver_reg);
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000491 __ li(a2, Operand(transition));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000492 __ Push(a2, a0);
493 __ TailCallExternalReference(
494 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
495 masm->isolate()),
496 3, 1);
497 return;
498 }
499
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000500 if (!transition.is_null()) {
verwaest@chromium.org37141392012-05-31 13:27:02 +0000501 // Update the map of the object.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000502 __ li(scratch1, Operand(transition));
503 __ sw(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
verwaest@chromium.org37141392012-05-31 13:27:02 +0000504
505 // Update the write barrier for the map field and pass the now unused
506 // name_reg as scratch register.
507 __ RecordWriteField(receiver_reg,
508 HeapObject::kMapOffset,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000509 scratch1,
verwaest@chromium.org37141392012-05-31 13:27:02 +0000510 name_reg,
511 kRAHasNotBeenSaved,
512 kDontSaveFPRegs,
513 OMIT_REMEMBERED_SET,
514 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000515 }
516
517 // Adjust for the number of properties stored in the object. Even in the
518 // face of a transition we can use the old map here because the size of the
519 // object and the number of in-object properties is not going to change.
520 index -= object->map()->inobject_properties();
521
522 if (index < 0) {
523 // Set the property straight into the object.
524 int offset = object->map()->instance_size() + (index * kPointerSize);
525 __ sw(a0, FieldMemOperand(receiver_reg, offset));
526
527 // Skip updating write barrier if storing a smi.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000528 __ JumpIfSmi(a0, &exit, scratch1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000529
530 // Update the write barrier for the array address.
531 // Pass the now unused name_reg as a scratch register.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000532 __ mov(name_reg, a0);
533 __ RecordWriteField(receiver_reg,
534 offset,
535 name_reg,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000536 scratch1,
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000537 kRAHasNotBeenSaved,
538 kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000539 } else {
540 // Write to the properties array.
541 int offset = index * kPointerSize + FixedArray::kHeaderSize;
542 // Get the properties array.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000543 __ lw(scratch1,
544 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
545 __ sw(a0, FieldMemOperand(scratch1, offset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000546
547 // Skip updating write barrier if storing a smi.
548 __ JumpIfSmi(a0, &exit);
549
550 // Update the write barrier for the array address.
551 // Ok to clobber receiver_reg and name_reg, since we return.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000552 __ mov(name_reg, a0);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000553 __ RecordWriteField(scratch1,
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000554 offset,
555 name_reg,
556 receiver_reg,
557 kRAHasNotBeenSaved,
558 kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000559 }
560
561 // Return the value (register v0).
562 __ bind(&exit);
563 __ mov(v0, a0);
564 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000565}
566
567
568void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000569 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000570 Handle<Code> code = (kind == Code::LOAD_IC)
571 ? masm->isolate()->builtins()->LoadIC_Miss()
572 : masm->isolate()->builtins()->KeyedLoadIC_Miss();
573 __ Jump(code, RelocInfo::CODE_TARGET);
ager@chromium.org5c838252010-02-19 08:53:10 +0000574}
575
576
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000577static void GenerateCallFunction(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000578 Handle<Object> object,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000579 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000580 Label* miss,
581 Code::ExtraICState extra_ic_state) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000582 // ----------- S t a t e -------------
583 // -- a0: receiver
584 // -- a1: function to call
585 // -----------------------------------
586 // Check that the function really is a function.
587 __ JumpIfSmi(a1, miss);
588 __ GetObjectType(a1, a3, a3);
589 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
590
591 // Patch the receiver on the stack with the global proxy if
592 // necessary.
593 if (object->IsGlobalObject()) {
594 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
595 __ sw(a3, MemOperand(sp, arguments.immediate() * kPointerSize));
596 }
597
598 // Invoke the function.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000599 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
600 ? CALL_AS_FUNCTION
601 : CALL_AS_METHOD;
602 __ InvokeFunction(a1, arguments, JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000603}
604
605
606static void PushInterceptorArguments(MacroAssembler* masm,
607 Register receiver,
608 Register holder,
609 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000610 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000611 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000612 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
613 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000614 Register scratch = name;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000615 __ li(scratch, Operand(interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000616 __ Push(scratch, receiver, holder);
617 __ lw(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
618 __ push(scratch);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000619 __ li(scratch, Operand(ExternalReference::isolate_address()));
620 __ push(scratch);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000621}
622
623
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000624static void CompileCallLoadPropertyWithInterceptor(
625 MacroAssembler* masm,
626 Register receiver,
627 Register holder,
628 Register name,
629 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000630 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
631
632 ExternalReference ref =
633 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
634 masm->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000635 __ PrepareCEntryArgs(6);
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000636 __ PrepareCEntryFunction(ref);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000637
638 CEntryStub stub(1);
639 __ CallStub(&stub);
640}
641
642
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000643static const int kFastApiCallArguments = 4;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000644
645
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000646// Reserves space for the extra arguments to API function in the
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000647// caller's frame.
648//
649// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
650static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
651 Register scratch) {
652 ASSERT(Smi::FromInt(0) == 0);
653 for (int i = 0; i < kFastApiCallArguments; i++) {
654 __ push(zero_reg);
655 }
656}
657
658
659// Undoes the effects of ReserveSpaceForFastApiCall.
660static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
661 __ Drop(kFastApiCallArguments);
662}
663
664
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000665static void GenerateFastApiDirectCall(MacroAssembler* masm,
666 const CallOptimization& optimization,
667 int argc) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000668 // ----------- S t a t e -------------
669 // -- sp[0] : holder (set by CheckPrototypes)
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000670 // -- sp[4] : callee JS function
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000671 // -- sp[8] : call data
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000672 // -- sp[12] : isolate
673 // -- sp[16] : last JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000674 // -- ...
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000675 // -- sp[(argc + 3) * 4] : first JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000676 // -- sp[(argc + 4) * 4] : receiver
677 // -----------------------------------
678 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000679 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000680 __ LoadHeapObject(t1, function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000681 __ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset));
682
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000683 // Pass the additional arguments.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000684 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
685 Handle<Object> call_data(api_call_info->data());
686 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
687 __ li(a0, api_call_info);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000688 __ lw(t2, FieldMemOperand(a0, CallHandlerInfo::kDataOffset));
689 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000690 __ li(t2, call_data);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000691 }
692
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000693 __ li(t3, Operand(ExternalReference::isolate_address()));
694 // Store JS function, call data and isolate.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000695 __ sw(t1, MemOperand(sp, 1 * kPointerSize));
696 __ sw(t2, MemOperand(sp, 2 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000697 __ sw(t3, MemOperand(sp, 3 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000698
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000699 // Prepare arguments.
700 __ Addu(a2, sp, Operand(3 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000701
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000702 // Allocate the v8::Arguments structure in the arguments' space since
703 // it's not controlled by GC.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000704 const int kApiStackSpace = 4;
705
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000706 FrameScope frame_scope(masm, StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000707 __ EnterExitFrame(false, kApiStackSpace);
708
709 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
710 // struct from the function (which is currently the case). This means we pass
711 // the first argument in a1 instead of a0. TryCallApiFunctionAndReturn
712 // will handle setting up a0.
713
714 // a1 = v8::Arguments&
715 // Arguments is built at sp + 1 (sp is a reserved spot for ra).
716 __ Addu(a1, sp, kPointerSize);
717
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000718 // v8::Arguments::implicit_args_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000719 __ sw(a2, MemOperand(a1, 0 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000720 // v8::Arguments::values_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000721 __ Addu(t0, a2, Operand(argc * kPointerSize));
722 __ sw(t0, MemOperand(a1, 1 * kPointerSize));
723 // v8::Arguments::length_ = argc
724 __ li(t0, Operand(argc));
725 __ sw(t0, MemOperand(a1, 2 * kPointerSize));
726 // v8::Arguments::is_construct_call = 0
727 __ sw(zero_reg, MemOperand(a1, 3 * kPointerSize));
728
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000729 const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000730 Address function_address = v8::ToCData<Address>(api_call_info->callback());
731 ApiFunction fun(function_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000732 ExternalReference ref =
733 ExternalReference(&fun,
734 ExternalReference::DIRECT_API_CALL,
735 masm->isolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000736 AllowExternalCallThatCantCauseGC scope(masm);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000737 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000738}
739
lrn@chromium.org7516f052011-03-30 08:52:27 +0000740class CallInterceptorCompiler BASE_EMBEDDED {
741 public:
742 CallInterceptorCompiler(StubCompiler* stub_compiler,
743 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000744 Register name,
745 Code::ExtraICState extra_ic_state)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000746 : stub_compiler_(stub_compiler),
747 arguments_(arguments),
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000748 name_(name),
749 extra_ic_state_(extra_ic_state) {}
lrn@chromium.org7516f052011-03-30 08:52:27 +0000750
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000751 void Compile(MacroAssembler* masm,
752 Handle<JSObject> object,
753 Handle<JSObject> holder,
754 Handle<String> name,
755 LookupResult* lookup,
756 Register receiver,
757 Register scratch1,
758 Register scratch2,
759 Register scratch3,
760 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000761 ASSERT(holder->HasNamedInterceptor());
762 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
763
764 // Check that the receiver isn't a smi.
765 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000766 CallOptimization optimization(lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000767 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000768 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
769 holder, lookup, name, optimization, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000770 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000771 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
772 name, holder, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000773 }
774 }
775
776 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000777 void CompileCacheable(MacroAssembler* masm,
778 Handle<JSObject> object,
779 Register receiver,
780 Register scratch1,
781 Register scratch2,
782 Register scratch3,
783 Handle<JSObject> interceptor_holder,
784 LookupResult* lookup,
785 Handle<String> name,
786 const CallOptimization& optimization,
787 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000788 ASSERT(optimization.is_constant_call());
789 ASSERT(!lookup->holder()->IsGlobalObject());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000790 Counters* counters = masm->isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000791 int depth1 = kInvalidProtoDepth;
792 int depth2 = kInvalidProtoDepth;
793 bool can_do_fast_api_call = false;
794 if (optimization.is_simple_api_call() &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000795 !lookup->holder()->IsGlobalObject()) {
796 depth1 = optimization.GetPrototypeDepthOfExpectedType(
797 object, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000798 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000799 depth2 = optimization.GetPrototypeDepthOfExpectedType(
800 interceptor_holder, Handle<JSObject>(lookup->holder()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000801 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000802 can_do_fast_api_call =
803 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000804 }
805
806 __ IncrementCounter(counters->call_const_interceptor(), 1,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000807 scratch1, scratch2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000808
809 if (can_do_fast_api_call) {
810 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
811 scratch1, scratch2);
812 ReserveSpaceForFastApiCall(masm, scratch1);
813 }
814
815 // Check that the maps from receiver to interceptor's holder
816 // haven't changed and thus we can invoke interceptor.
817 Label miss_cleanup;
818 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
819 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000820 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
821 scratch1, scratch2, scratch3,
822 name, depth1, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000823
824 // Invoke an interceptor and if it provides a value,
825 // branch to |regular_invoke|.
826 Label regular_invoke;
827 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
828 &regular_invoke);
829
830 // Interceptor returned nothing for this property. Try to use cached
831 // constant function.
832
833 // Check that the maps from interceptor's holder to constant function's
834 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000835 if (*interceptor_holder != lookup->holder()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000836 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000837 Handle<JSObject>(lookup->holder()),
838 scratch1, scratch2, scratch3,
839 name, depth2, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000840 } else {
841 // CheckPrototypes has a side effect of fetching a 'holder'
842 // for API (object which is instanceof for the signature). It's
843 // safe to omit it here, as if present, it should be fetched
844 // by the previous CheckPrototypes.
845 ASSERT(depth2 == kInvalidProtoDepth);
846 }
847
848 // Invoke function.
849 if (can_do_fast_api_call) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000850 GenerateFastApiDirectCall(masm, optimization, arguments_.immediate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000851 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000852 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
853 ? CALL_AS_FUNCTION
854 : CALL_AS_METHOD;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000855 __ InvokeFunction(optimization.constant_function(), arguments_,
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000856 JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000857 }
858
859 // Deferred code for fast API call case---clean preallocated space.
860 if (can_do_fast_api_call) {
861 __ bind(&miss_cleanup);
862 FreeSpaceForFastApiCall(masm);
863 __ Branch(miss_label);
864 }
865
866 // Invoke a regular function.
867 __ bind(&regular_invoke);
868 if (can_do_fast_api_call) {
869 FreeSpaceForFastApiCall(masm);
870 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000871 }
872
873 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000874 Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000875 Register receiver,
876 Register scratch1,
877 Register scratch2,
878 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000879 Handle<String> name,
880 Handle<JSObject> interceptor_holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000881 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000882 Register holder =
883 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000884 scratch1, scratch2, scratch3,
885 name, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000886
887 // Call a runtime function to load the interceptor property.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000888 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000889 // Save the name_ register across the call.
890 __ push(name_);
891
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000892 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000893
894 __ CallExternalReference(
895 ExternalReference(
896 IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
897 masm->isolate()),
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000898 6);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000899 // Restore the name_ register.
900 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000901 // Leave the internal frame.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000902 }
903
904 void LoadWithInterceptor(MacroAssembler* masm,
905 Register receiver,
906 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000907 Handle<JSObject> holder_obj,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000908 Register scratch,
909 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000910 {
911 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000912
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000913 __ Push(holder, name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000914 CompileCallLoadPropertyWithInterceptor(masm,
915 receiver,
916 holder,
917 name_,
918 holder_obj);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000919 __ pop(name_); // Restore the name.
920 __ pop(receiver); // Restore the holder.
921 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000922 // If interceptor returns no-result sentinel, call the constant function.
923 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
924 __ Branch(interceptor_succeeded, ne, v0, Operand(scratch));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000925 }
926
927 StubCompiler* stub_compiler_;
928 const ParameterCount& arguments_;
929 Register name_;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000930 Code::ExtraICState extra_ic_state_;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000931};
932
933
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000934
935// Generate code to check that a global property cell is empty. Create
936// the property cell at compilation time if no cell exists for the
937// property.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000938static void GenerateCheckPropertyCell(MacroAssembler* masm,
939 Handle<GlobalObject> global,
940 Handle<String> name,
941 Register scratch,
942 Label* miss) {
943 Handle<JSGlobalPropertyCell> cell =
944 GlobalObject::EnsurePropertyCell(global, name);
945 ASSERT(cell->value()->IsTheHole());
946 __ li(scratch, Operand(cell));
947 __ lw(scratch,
948 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
949 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
950 __ Branch(miss, ne, scratch, Operand(at));
951}
952
953
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000954// Calls GenerateCheckPropertyCell for each global object in the prototype chain
955// from object to (but not including) holder.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000956static void GenerateCheckPropertyCells(MacroAssembler* masm,
957 Handle<JSObject> object,
958 Handle<JSObject> holder,
959 Handle<String> name,
960 Register scratch,
961 Label* miss) {
962 Handle<JSObject> current = object;
963 while (!current.is_identical_to(holder)) {
964 if (current->IsGlobalObject()) {
965 GenerateCheckPropertyCell(masm,
966 Handle<GlobalObject>::cast(current),
967 name,
968 scratch,
969 miss);
970 }
971 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
972 }
973}
974
975
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000976// Convert and store int passed in register ival to IEEE 754 single precision
977// floating point value at memory location (dst + 4 * wordoffset)
978// If FPU is available use it for conversion.
979static void StoreIntAsFloat(MacroAssembler* masm,
980 Register dst,
981 Register wordoffset,
982 Register ival,
983 Register fval,
984 Register scratch1,
985 Register scratch2) {
986 if (CpuFeatures::IsSupported(FPU)) {
987 CpuFeatures::Scope scope(FPU);
988 __ mtc1(ival, f0);
989 __ cvt_s_w(f0, f0);
990 __ sll(scratch1, wordoffset, 2);
991 __ addu(scratch1, dst, scratch1);
992 __ swc1(f0, MemOperand(scratch1, 0));
993 } else {
994 // FPU is not available, do manual conversions.
995
996 Label not_special, done;
997 // Move sign bit from source to destination. This works because the sign
998 // bit in the exponent word of the double has the same position and polarity
999 // as the 2's complement sign bit in a Smi.
1000 ASSERT(kBinary32SignMask == 0x80000000u);
1001
1002 __ And(fval, ival, Operand(kBinary32SignMask));
1003 // Negate value if it is negative.
1004 __ subu(scratch1, zero_reg, ival);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001005 __ Movn(ival, scratch1, fval);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001006
1007 // We have -1, 0 or 1, which we treat specially. Register ival contains
1008 // absolute value: it is either equal to 1 (special case of -1 and 1),
1009 // greater than 1 (not a special case) or less than 1 (special case of 0).
1010 __ Branch(&not_special, gt, ival, Operand(1));
1011
1012 // For 1 or -1 we need to or in the 0 exponent (biased).
1013 static const uint32_t exponent_word_for_1 =
1014 kBinary32ExponentBias << kBinary32ExponentShift;
1015
1016 __ Xor(scratch1, ival, Operand(1));
1017 __ li(scratch2, exponent_word_for_1);
1018 __ or_(scratch2, fval, scratch2);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001019 __ Movz(fval, scratch2, scratch1); // Only if ival is equal to 1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001020 __ Branch(&done);
1021
1022 __ bind(&not_special);
1023 // Count leading zeros.
1024 // Gets the wrong answer for 0, but we already checked for that case above.
1025 Register zeros = scratch2;
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001026 __ Clz(zeros, ival);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001027
1028 // Compute exponent and or it into the exponent register.
1029 __ li(scratch1, (kBitsPerInt - 1) + kBinary32ExponentBias);
1030 __ subu(scratch1, scratch1, zeros);
1031
1032 __ sll(scratch1, scratch1, kBinary32ExponentShift);
1033 __ or_(fval, fval, scratch1);
1034
1035 // Shift up the source chopping the top bit off.
1036 __ Addu(zeros, zeros, Operand(1));
1037 // This wouldn't work for 1 and -1 as the shift would be 32 which means 0.
1038 __ sllv(ival, ival, zeros);
1039 // And the top (top 20 bits).
1040 __ srl(scratch1, ival, kBitsPerInt - kBinary32MantissaBits);
1041 __ or_(fval, fval, scratch1);
1042
1043 __ bind(&done);
1044
1045 __ sll(scratch1, wordoffset, 2);
1046 __ addu(scratch1, dst, scratch1);
1047 __ sw(fval, MemOperand(scratch1, 0));
1048 }
1049}
1050
1051
1052// Convert unsigned integer with specified number of leading zeroes in binary
1053// representation to IEEE 754 double.
1054// Integer to convert is passed in register hiword.
1055// Resulting double is returned in registers hiword:loword.
1056// This functions does not work correctly for 0.
1057static void GenerateUInt2Double(MacroAssembler* masm,
1058 Register hiword,
1059 Register loword,
1060 Register scratch,
1061 int leading_zeroes) {
1062 const int meaningful_bits = kBitsPerInt - leading_zeroes - 1;
1063 const int biased_exponent = HeapNumber::kExponentBias + meaningful_bits;
1064
1065 const int mantissa_shift_for_hi_word =
1066 meaningful_bits - HeapNumber::kMantissaBitsInTopWord;
1067
1068 const int mantissa_shift_for_lo_word =
1069 kBitsPerInt - mantissa_shift_for_hi_word;
1070
1071 __ li(scratch, biased_exponent << HeapNumber::kExponentShift);
1072 if (mantissa_shift_for_hi_word > 0) {
1073 __ sll(loword, hiword, mantissa_shift_for_lo_word);
1074 __ srl(hiword, hiword, mantissa_shift_for_hi_word);
1075 __ or_(hiword, scratch, hiword);
1076 } else {
1077 __ mov(loword, zero_reg);
1078 __ sll(hiword, hiword, mantissa_shift_for_hi_word);
1079 __ or_(hiword, scratch, hiword);
1080 }
1081
1082 // If least significant bit of biased exponent was not 1 it was corrupted
1083 // by most significant bit of mantissa so we should fix that.
1084 if (!(biased_exponent & 1)) {
1085 __ li(scratch, 1 << HeapNumber::kExponentShift);
1086 __ nor(scratch, scratch, scratch);
1087 __ and_(hiword, hiword, scratch);
1088 }
1089}
1090
1091
ager@chromium.org5c838252010-02-19 08:53:10 +00001092#undef __
1093#define __ ACCESS_MASM(masm())
1094
1095
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001096Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
1097 Register object_reg,
1098 Handle<JSObject> holder,
1099 Register holder_reg,
1100 Register scratch1,
1101 Register scratch2,
1102 Handle<String> name,
1103 int save_at_depth,
1104 Label* miss) {
1105 // Make sure there's no overlap between holder and object registers.
1106 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1107 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1108 && !scratch2.is(scratch1));
1109
1110 // Keep track of the current object in register reg.
1111 Register reg = object_reg;
1112 int depth = 0;
1113
1114 if (save_at_depth == depth) {
1115 __ sw(reg, MemOperand(sp));
1116 }
1117
1118 // Check the maps in the prototype chain.
1119 // Traverse the prototype chain from the object and do map checks.
1120 Handle<JSObject> current = object;
1121 while (!current.is_identical_to(holder)) {
1122 ++depth;
1123
1124 // Only global objects and objects that do not require access
1125 // checks are allowed in stubs.
1126 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1127
1128 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
1129 if (!current->HasFastProperties() &&
1130 !current->IsJSGlobalObject() &&
1131 !current->IsJSGlobalProxy()) {
1132 if (!name->IsSymbol()) {
1133 name = factory()->LookupSymbol(name);
1134 }
1135 ASSERT(current->property_dictionary()->FindEntry(*name) ==
1136 StringDictionary::kNotFound);
1137
1138 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1139 scratch1, scratch2);
1140
1141 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1142 reg = holder_reg; // From now on the object will be in holder_reg.
1143 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1144 } else {
1145 Handle<Map> current_map(current->map());
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001146 __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK,
1147 ALLOW_ELEMENT_TRANSITION_MAPS);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001148 // Check access rights to the global object. This has to happen after
1149 // the map check so that we know that the object is actually a global
1150 // object.
1151 if (current->IsJSGlobalProxy()) {
1152 __ CheckAccessGlobalProxy(reg, scratch2, miss);
1153 }
1154 reg = holder_reg; // From now on the object will be in holder_reg.
1155
1156 if (heap()->InNewSpace(*prototype)) {
1157 // The prototype is in new space; we cannot store a reference to it
1158 // in the code. Load it from the map.
1159 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1160 } else {
1161 // The prototype is in old space; load it directly.
1162 __ li(reg, Operand(prototype));
1163 }
1164 }
1165
1166 if (save_at_depth == depth) {
1167 __ sw(reg, MemOperand(sp));
1168 }
1169
1170 // Go to the next object in the prototype chain.
1171 current = prototype;
1172 }
1173
1174 // Log the check depth.
1175 LOG(masm()->isolate(), IntEvent("check-maps-depth", depth + 1));
1176
1177 // Check the holder map.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001178 __ CheckMap(reg, scratch1, Handle<Map>(current->map()), miss,
1179 DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001180
1181 // Perform security check for access to the global object.
1182 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1183 if (holder->IsJSGlobalProxy()) {
1184 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1185 }
1186
1187 // If we've skipped any global objects, it's not enough to verify that
1188 // their maps haven't changed. We also need to check that the property
1189 // cell for the property is still empty.
1190 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1191
1192 // Return the register containing the holder.
1193 return reg;
1194}
1195
1196
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001197void StubCompiler::GenerateLoadField(Handle<JSObject> object,
1198 Handle<JSObject> holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001199 Register receiver,
1200 Register scratch1,
1201 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001202 Register scratch3,
ager@chromium.org5c838252010-02-19 08:53:10 +00001203 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001204 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001205 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001206 // Check that the receiver isn't a smi.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001207 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001208
1209 // Check that the maps haven't changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001210 Register reg = CheckPrototypes(
1211 object, receiver, holder, scratch1, scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001212 GenerateFastPropertyLoad(masm(), v0, reg, holder, index);
1213 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001214}
1215
1216
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001217void StubCompiler::GenerateLoadConstant(Handle<JSObject> object,
1218 Handle<JSObject> holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001219 Register receiver,
1220 Register scratch1,
1221 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001222 Register scratch3,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001223 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001224 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001225 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001226 // Check that the receiver isn't a smi.
1227 __ JumpIfSmi(receiver, miss, scratch1);
1228
1229 // Check that the maps haven't changed.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001230 CheckPrototypes(object, receiver, holder,
1231 scratch1, scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001232
1233 // Return the constant value.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001234 __ LoadHeapObject(v0, value);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001235 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001236}
1237
1238
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001239void StubCompiler::GenerateDictionaryLoadCallback(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) {
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001247 ASSERT(!receiver.is(scratch1));
1248 ASSERT(!receiver.is(scratch2));
1249 ASSERT(!receiver.is(scratch3));
1250
1251 // Load the properties dictionary.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001252 Register dictionary = scratch1;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001253 __ lw(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
1254
1255 // Probe the dictionary.
1256 Label probe_done;
1257 StringDictionaryLookupStub::GeneratePositiveLookup(masm(),
1258 miss,
1259 &probe_done,
1260 dictionary,
1261 name_reg,
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001262 scratch2,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001263 scratch3);
1264 __ bind(&probe_done);
1265
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001266 // If probing finds an entry in the dictionary, scratch3 contains the
1267 // pointer into the dictionary. Check that the value is the callback.
1268 Register pointer = scratch3;
1269 const int kElementsStartOffset = StringDictionary::kHeaderSize +
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001270 StringDictionary::kElementsStartIndex * kPointerSize;
1271 const int kValueOffset = kElementsStartOffset + kPointerSize;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001272 __ lw(scratch2, FieldMemOperand(pointer, kValueOffset));
1273 __ Branch(miss, ne, scratch2, Operand(callback));
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001274}
1275
1276
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001277void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
1278 Handle<JSObject> holder,
1279 Register receiver,
1280 Register name_reg,
1281 Register scratch1,
1282 Register scratch2,
1283 Register scratch3,
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001284 Register scratch4,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001285 Handle<AccessorInfo> callback,
1286 Handle<String> name,
1287 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001288 // Check that the receiver isn't a smi.
1289 __ JumpIfSmi(receiver, miss, scratch1);
1290
1291 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001292 Register reg = CheckPrototypes(object, receiver, holder, scratch1,
1293 scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001294
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001295 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
1296 GenerateDictionaryLoadCallback(
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001297 reg, name_reg, scratch2, scratch3, scratch4, callback, name, miss);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001298 }
1299
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001300 // Build AccessorInfo::args_ list on the stack and push property name below
1301 // the exit frame to make GC aware of them and store pointers to them.
1302 __ push(receiver);
1303 __ mov(scratch2, sp); // scratch2 = AccessorInfo::args_
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001304 if (heap()->InNewSpace(callback->data())) {
1305 __ li(scratch3, callback);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001306 __ lw(scratch3, FieldMemOperand(scratch3, AccessorInfo::kDataOffset));
1307 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001308 __ li(scratch3, Handle<Object>(callback->data()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001309 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001310 __ Subu(sp, sp, 4 * kPointerSize);
1311 __ sw(reg, MemOperand(sp, 3 * kPointerSize));
1312 __ sw(scratch3, MemOperand(sp, 2 * kPointerSize));
1313 __ li(scratch3, Operand(ExternalReference::isolate_address()));
1314 __ sw(scratch3, MemOperand(sp, 1 * kPointerSize));
1315 __ sw(name_reg, MemOperand(sp, 0 * kPointerSize));
1316
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001317 __ mov(a2, scratch2); // Saved in case scratch2 == a1.
1318 __ mov(a1, sp); // a1 (first argument - see note below) = Handle<String>
1319
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001320 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
1321 // struct from the function (which is currently the case). This means we pass
1322 // the arguments in a1-a2 instead of a0-a1. TryCallApiFunctionAndReturn
1323 // will handle setting up a0.
1324
1325 const int kApiStackSpace = 1;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001326 FrameScope frame_scope(masm(), StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001327 __ EnterExitFrame(false, kApiStackSpace);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001328
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001329 // Create AccessorInfo instance on the stack above the exit frame with
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001330 // scratch2 (internal::Object** args_) as the data.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001331 __ sw(a2, MemOperand(sp, kPointerSize));
1332 // a2 (second argument - see note above) = AccessorInfo&
1333 __ Addu(a2, sp, kPointerSize);
1334
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001335 const int kStackUnwindSpace = 5;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001336 Address getter_address = v8::ToCData<Address>(callback->getter());
1337 ApiFunction fun(getter_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001338 ExternalReference ref =
1339 ExternalReference(&fun,
1340 ExternalReference::DIRECT_GETTER_CALL,
1341 masm()->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001342 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
ager@chromium.org5c838252010-02-19 08:53:10 +00001343}
1344
1345
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001346void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
1347 Handle<JSObject> interceptor_holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001348 LookupResult* lookup,
1349 Register receiver,
1350 Register name_reg,
1351 Register scratch1,
1352 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001353 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001354 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001355 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001356 ASSERT(interceptor_holder->HasNamedInterceptor());
1357 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1358
1359 // Check that the receiver isn't a smi.
1360 __ JumpIfSmi(receiver, miss);
1361
1362 // So far the most popular follow ups for interceptor loads are FIELD
1363 // and CALLBACKS, so inline only them, other cases may be added
1364 // later.
1365 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001366 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001367 if (lookup->IsField()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001368 compile_followup_inline = true;
1369 } else if (lookup->type() == CALLBACKS &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001370 lookup->GetCallbackObject()->IsAccessorInfo()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001371 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
1372 compile_followup_inline = callback->getter() != NULL &&
1373 callback->IsCompatibleReceiver(*object);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001374 }
1375 }
1376
1377 if (compile_followup_inline) {
1378 // Compile the interceptor call, followed by inline code to load the
1379 // property from further up the prototype chain if the call fails.
1380 // Check that the maps haven't changed.
1381 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1382 scratch1, scratch2, scratch3,
1383 name, miss);
1384 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
1385
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001386 // Preserve the receiver register explicitly whenever it is different from
1387 // the holder and it is needed should the interceptor return without any
1388 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1389 // the FIELD case might cause a miss during the prototype check.
1390 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
1391 bool must_preserve_receiver_reg = !receiver.is(holder_reg) &&
1392 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1393
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001394 // Save necessary data before invoking an interceptor.
1395 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001396 {
1397 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001398 if (must_preserve_receiver_reg) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001399 __ Push(receiver, holder_reg, name_reg);
1400 } else {
1401 __ Push(holder_reg, name_reg);
1402 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001403 // Invoke an interceptor. Note: map checks from receiver to
1404 // interceptor's holder has been compiled before (see a caller
1405 // of this method).
1406 CompileCallLoadPropertyWithInterceptor(masm(),
1407 receiver,
1408 holder_reg,
1409 name_reg,
1410 interceptor_holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001411 // Check if interceptor provided a value for property. If it's
1412 // the case, return immediately.
1413 Label interceptor_failed;
1414 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
1415 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1));
1416 frame_scope.GenerateLeaveFrame();
1417 __ Ret();
1418
1419 __ bind(&interceptor_failed);
1420 __ pop(name_reg);
1421 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001422 if (must_preserve_receiver_reg) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001423 __ pop(receiver);
1424 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001425 // Leave the internal frame.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001426 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001427 // Check that the maps from interceptor's holder to lookup's holder
1428 // haven't changed. And load lookup's holder into |holder| register.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001429 if (must_perfrom_prototype_check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001430 holder_reg = CheckPrototypes(interceptor_holder,
1431 holder_reg,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001432 Handle<JSObject>(lookup->holder()),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001433 scratch1,
1434 scratch2,
1435 scratch3,
1436 name,
1437 miss);
1438 }
1439
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001440 if (lookup->IsField()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001441 // We found FIELD property in prototype chain of interceptor's holder.
1442 // Retrieve a field from field's holder.
1443 GenerateFastPropertyLoad(masm(), v0, holder_reg,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001444 Handle<JSObject>(lookup->holder()),
1445 lookup->GetFieldIndex());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001446 __ Ret();
1447 } else {
1448 // We found CALLBACKS property in prototype chain of interceptor's
1449 // holder.
1450 ASSERT(lookup->type() == CALLBACKS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001451 Handle<AccessorInfo> callback(
1452 AccessorInfo::cast(lookup->GetCallbackObject()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001453 ASSERT(callback->getter() != NULL);
1454
1455 // Tail call to runtime.
1456 // Important invariant in CALLBACKS case: the code above must be
1457 // structured to never clobber |receiver| register.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001458 __ li(scratch2, callback);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001459
1460 __ Push(receiver, holder_reg);
1461 __ lw(scratch3,
1462 FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
1463 __ li(scratch1, Operand(ExternalReference::isolate_address()));
1464 __ Push(scratch3, scratch1, scratch2, name_reg);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001465
1466 ExternalReference ref =
1467 ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
1468 masm()->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001469 __ TailCallExternalReference(ref, 6, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001470 }
1471 } else { // !compile_followup_inline
1472 // Call the runtime system to load the interceptor.
1473 // Check that the maps haven't changed.
1474 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1475 scratch1, scratch2, scratch3,
1476 name, miss);
1477 PushInterceptorArguments(masm(), receiver, holder_reg,
1478 name_reg, interceptor_holder);
1479
1480 ExternalReference ref = ExternalReference(
1481 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), masm()->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001482 __ TailCallExternalReference(ref, 6, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001483 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001484}
1485
1486
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001487void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001488 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001489 __ Branch(miss, ne, a2, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001490 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001491}
1492
1493
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001494void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1495 Handle<JSObject> holder,
1496 Handle<String> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001497 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001498 ASSERT(holder->IsGlobalObject());
1499
1500 // Get the number of arguments.
1501 const int argc = arguments().immediate();
1502
1503 // Get the receiver from the stack.
1504 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1505
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001506 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001507 __ JumpIfSmi(a0, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001508 CheckPrototypes(object, a0, holder, a3, a1, t0, name, miss);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001509}
1510
1511
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001512void CallStubCompiler::GenerateLoadFunctionFromCell(
1513 Handle<JSGlobalPropertyCell> cell,
1514 Handle<JSFunction> function,
1515 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001516 // Get the value from the cell.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001517 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001518 __ lw(a1, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
1519
1520 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001521 if (heap()->InNewSpace(*function)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001522 // We can't embed a pointer to a function in new space so we have
1523 // to verify that the shared function info is unchanged. This has
1524 // the nice side effect that multiple closures based on the same
1525 // function can all use this call IC. Before we load through the
1526 // function, we have to verify that it still is a function.
1527 __ JumpIfSmi(a1, miss);
1528 __ GetObjectType(a1, a3, a3);
1529 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
1530
1531 // Check the shared function info. Make sure it hasn't changed.
1532 __ li(a3, Handle<SharedFunctionInfo>(function->shared()));
1533 __ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
1534 __ Branch(miss, ne, t0, Operand(a3));
1535 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001536 __ Branch(miss, ne, a1, Operand(function));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001537 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001538}
1539
1540
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001541void CallStubCompiler::GenerateMissBranch() {
1542 Handle<Code> code =
danno@chromium.org40cb8782011-05-25 07:58:50 +00001543 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1544 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001545 extra_state_);
1546 __ Jump(code, RelocInfo::CODE_TARGET);
1547}
1548
1549
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001550Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1551 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001552 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001553 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001554 // ----------- S t a t e -------------
1555 // -- a2 : name
1556 // -- ra : return address
1557 // -----------------------------------
1558 Label miss;
1559
1560 GenerateNameCheck(name, &miss);
1561
1562 const int argc = arguments().immediate();
1563
1564 // Get the receiver of the function from the stack into a0.
1565 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1566 // Check that the receiver isn't a smi.
1567 __ JumpIfSmi(a0, &miss, t0);
1568
1569 // Do the right check and compute the holder register.
1570 Register reg = CheckPrototypes(object, a0, holder, a1, a3, t0, name, &miss);
1571 GenerateFastPropertyLoad(masm(), a1, reg, holder, index);
1572
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001573 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001574
1575 // Handle call cache miss.
1576 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001577 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001578
1579 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001580 return GetCode(Code::FIELD, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001581}
1582
1583
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001584Handle<Code> CallStubCompiler::CompileArrayPushCall(
1585 Handle<Object> object,
1586 Handle<JSObject> holder,
1587 Handle<JSGlobalPropertyCell> cell,
1588 Handle<JSFunction> function,
1589 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001590 // ----------- S t a t e -------------
1591 // -- a2 : name
1592 // -- ra : return address
1593 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1594 // -- ...
1595 // -- sp[argc * 4] : receiver
1596 // -----------------------------------
1597
1598 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001599 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001600
1601 Label miss;
1602
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001603 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001604
1605 Register receiver = a1;
1606
1607 // Get the receiver from the stack.
1608 const int argc = arguments().immediate();
1609 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1610
1611 // Check that the receiver isn't a smi.
1612 __ JumpIfSmi(receiver, &miss);
1613
1614 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001615 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, a3, v0, t0,
1616 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001617
1618 if (argc == 0) {
1619 // Nothing to do, just return the length.
1620 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1621 __ Drop(argc + 1);
1622 __ Ret();
1623 } else {
1624 Label call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001625 if (argc == 1) { // Otherwise fall through to call the builtin.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001626 Label attempt_to_grow_elements;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001627
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001628 Register elements = t2;
1629 Register end_elements = t1;
1630 // Get the elements array of the object.
1631 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1632
1633 // Check that the elements are in fast mode and writable.
1634 __ CheckMap(elements,
1635 v0,
1636 Heap::kFixedArrayMapRootIndex,
1637 &call_builtin,
1638 DONT_DO_SMI_CHECK);
1639
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001640 // Get the array's length into v0 and calculate new length.
1641 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1642 STATIC_ASSERT(kSmiTagSize == 1);
1643 STATIC_ASSERT(kSmiTag == 0);
1644 __ Addu(v0, v0, Operand(Smi::FromInt(argc)));
1645
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001646 // Get the elements' length.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001647 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1648
1649 // Check if we could survive without allocation.
1650 __ Branch(&attempt_to_grow_elements, gt, v0, Operand(t0));
1651
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001652 // Check if value is a smi.
1653 Label with_write_barrier;
1654 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1655 __ JumpIfNotSmi(t0, &with_write_barrier);
1656
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001657 // Save new length.
1658 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1659
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001660 // Store the value.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001661 // We may need a register containing the address end_elements below,
1662 // so write back the value in end_elements.
1663 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1664 __ Addu(end_elements, elements, end_elements);
1665 const int kEndElementsOffset =
1666 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001667 __ Addu(end_elements, end_elements, kEndElementsOffset);
1668 __ sw(t0, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001669
1670 // Check for a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001671 __ Drop(argc + 1);
1672 __ Ret();
1673
1674 __ bind(&with_write_barrier);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001675
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001676 __ lw(a3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1677
1678 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
1679 Label fast_object, not_fast_object;
1680 __ CheckFastObjectElements(a3, t3, &not_fast_object);
1681 __ jmp(&fast_object);
1682 // In case of fast smi-only, convert to fast object, otherwise bail out.
1683 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001684 __ CheckFastSmiElements(a3, t3, &call_builtin);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001685 // edx: receiver
1686 // r3: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001687 Label try_holey_map;
1688 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001689 FAST_ELEMENTS,
1690 a3,
1691 t3,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001692 &try_holey_map);
1693 __ mov(a2, receiver);
1694 ElementsTransitionGenerator::
1695 GenerateMapChangeElementsTransition(masm());
1696 __ jmp(&fast_object);
1697
1698 __ bind(&try_holey_map);
1699 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1700 FAST_HOLEY_ELEMENTS,
1701 a3,
1702 t3,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001703 &call_builtin);
1704 __ mov(a2, receiver);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001705 ElementsTransitionGenerator::
1706 GenerateMapChangeElementsTransition(masm());
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001707 __ bind(&fast_object);
1708 } else {
1709 __ CheckFastObjectElements(a3, a3, &call_builtin);
1710 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001711
1712 // Save new length.
1713 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1714
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001715 // Store the value.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001716 // We may need a register containing the address end_elements below,
1717 // so write back the value in end_elements.
1718 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1719 __ Addu(end_elements, elements, end_elements);
1720 __ Addu(end_elements, end_elements, kEndElementsOffset);
1721 __ sw(t0, MemOperand(end_elements));
1722
1723 __ RecordWrite(elements,
1724 end_elements,
1725 t0,
1726 kRAHasNotBeenSaved,
1727 kDontSaveFPRegs,
1728 EMIT_REMEMBERED_SET,
1729 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001730 __ Drop(argc + 1);
1731 __ Ret();
1732
1733 __ bind(&attempt_to_grow_elements);
1734 // v0: array's length + 1.
1735 // t0: elements' length.
1736
1737 if (!FLAG_inline_new) {
1738 __ Branch(&call_builtin);
1739 }
1740
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001741 __ lw(a2, MemOperand(sp, (argc - 1) * kPointerSize));
1742 // Growing elements that are SMI-only requires special handling in case
1743 // the new element is non-Smi. For now, delegate to the builtin.
1744 Label no_fast_elements_check;
1745 __ JumpIfSmi(a2, &no_fast_elements_check);
1746 __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1747 __ CheckFastObjectElements(t3, t3, &call_builtin);
1748 __ bind(&no_fast_elements_check);
1749
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001750 ExternalReference new_space_allocation_top =
1751 ExternalReference::new_space_allocation_top_address(
1752 masm()->isolate());
1753 ExternalReference new_space_allocation_limit =
1754 ExternalReference::new_space_allocation_limit_address(
1755 masm()->isolate());
1756
1757 const int kAllocationDelta = 4;
1758 // Load top and check if it is the end of elements.
1759 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1760 __ Addu(end_elements, elements, end_elements);
1761 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset));
1762 __ li(t3, Operand(new_space_allocation_top));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001763 __ lw(a3, MemOperand(t3));
1764 __ Branch(&call_builtin, ne, end_elements, Operand(a3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001765
1766 __ li(t5, Operand(new_space_allocation_limit));
1767 __ lw(t5, MemOperand(t5));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001768 __ Addu(a3, a3, Operand(kAllocationDelta * kPointerSize));
1769 __ Branch(&call_builtin, hi, a3, Operand(t5));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001770
1771 // We fit and could grow elements.
1772 // Update new_space_allocation_top.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001773 __ sw(a3, MemOperand(t3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001774 // Push the argument.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001775 __ sw(a2, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001776 // Fill the rest with holes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001777 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001778 for (int i = 1; i < kAllocationDelta; i++) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001779 __ sw(a3, MemOperand(end_elements, i * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001780 }
1781
1782 // Update elements' and array's sizes.
1783 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1784 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta)));
1785 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1786
1787 // Elements are in new space, so write barrier is not required.
1788 __ Drop(argc + 1);
1789 __ Ret();
1790 }
1791 __ bind(&call_builtin);
1792 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
1793 masm()->isolate()),
1794 argc + 1,
1795 1);
1796 }
1797
1798 // Handle call cache miss.
1799 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001800 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001801
1802 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001803 return GetCode(function);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001804}
1805
1806
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001807Handle<Code> CallStubCompiler::CompileArrayPopCall(
1808 Handle<Object> object,
1809 Handle<JSObject> holder,
1810 Handle<JSGlobalPropertyCell> cell,
1811 Handle<JSFunction> function,
1812 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001813 // ----------- S t a t e -------------
1814 // -- a2 : name
1815 // -- ra : return address
1816 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1817 // -- ...
1818 // -- sp[argc * 4] : receiver
1819 // -----------------------------------
1820
1821 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001822 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001823
1824 Label miss, return_undefined, call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001825 Register receiver = a1;
1826 Register elements = a3;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001827 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001828
1829 // Get the receiver from the stack.
1830 const int argc = arguments().immediate();
1831 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001832 // Check that the receiver isn't a smi.
1833 __ JumpIfSmi(receiver, &miss);
1834
1835 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001836 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, elements,
1837 t0, v0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001838
1839 // Get the elements array of the object.
1840 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1841
1842 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001843 __ CheckMap(elements,
1844 v0,
1845 Heap::kFixedArrayMapRootIndex,
1846 &call_builtin,
1847 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001848
1849 // Get the array's length into t0 and calculate new length.
1850 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1851 __ Subu(t0, t0, Operand(Smi::FromInt(1)));
1852 __ Branch(&return_undefined, lt, t0, Operand(zero_reg));
1853
1854 // Get the last element.
1855 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1856 STATIC_ASSERT(kSmiTagSize == 1);
1857 STATIC_ASSERT(kSmiTag == 0);
1858 // We can't address the last element in one operation. Compute the more
1859 // expensive shift first, and use an offset later on.
1860 __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize);
1861 __ Addu(elements, elements, t1);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001862 __ lw(v0, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001863 __ Branch(&call_builtin, eq, v0, Operand(t2));
1864
1865 // Set the array's length.
1866 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1867
1868 // Fill with the hole.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001869 __ sw(t2, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001870 __ Drop(argc + 1);
1871 __ Ret();
1872
1873 __ bind(&return_undefined);
1874 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
1875 __ Drop(argc + 1);
1876 __ Ret();
1877
1878 __ bind(&call_builtin);
1879 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop,
1880 masm()->isolate()),
1881 argc + 1,
1882 1);
1883
1884 // Handle call cache miss.
1885 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001886 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001887
1888 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001889 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001890}
1891
1892
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001893Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1894 Handle<Object> object,
1895 Handle<JSObject> holder,
1896 Handle<JSGlobalPropertyCell> cell,
1897 Handle<JSFunction> function,
1898 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001899 // ----------- S t a t e -------------
1900 // -- a2 : function name
1901 // -- ra : return address
1902 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1903 // -- ...
1904 // -- sp[argc * 4] : receiver
1905 // -----------------------------------
1906
1907 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001908 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001909
1910 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001911 Label miss;
1912 Label name_miss;
1913 Label index_out_of_range;
1914
1915 Label* index_out_of_range_label = &index_out_of_range;
1916
danno@chromium.org40cb8782011-05-25 07:58:50 +00001917 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001918 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001919 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001920 index_out_of_range_label = &miss;
1921 }
1922
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001923 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001924
1925 // Check that the maps starting from the prototype haven't changed.
1926 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1927 Context::STRING_FUNCTION_INDEX,
1928 v0,
1929 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001930 ASSERT(!object.is_identical_to(holder));
1931 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1932 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001933
1934 Register receiver = a1;
1935 Register index = t1;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001936 Register result = v0;
1937 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1938 if (argc > 0) {
1939 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1940 } else {
1941 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1942 }
1943
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001944 StringCharCodeAtGenerator generator(receiver,
1945 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001946 result,
1947 &miss, // When not a string.
1948 &miss, // When not a number.
1949 index_out_of_range_label,
1950 STRING_INDEX_IS_NUMBER);
1951 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001952 __ Drop(argc + 1);
1953 __ Ret();
1954
1955 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001956 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001957
1958 if (index_out_of_range.is_linked()) {
1959 __ bind(&index_out_of_range);
1960 __ LoadRoot(v0, Heap::kNanValueRootIndex);
1961 __ Drop(argc + 1);
1962 __ Ret();
1963 }
1964
1965 __ bind(&miss);
1966 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001967 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001968 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001969 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001970
1971 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001972 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001973}
1974
1975
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001976Handle<Code> CallStubCompiler::CompileStringCharAtCall(
1977 Handle<Object> object,
1978 Handle<JSObject> holder,
1979 Handle<JSGlobalPropertyCell> cell,
1980 Handle<JSFunction> function,
1981 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001982 // ----------- S t a t e -------------
1983 // -- a2 : function name
1984 // -- ra : return address
1985 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1986 // -- ...
1987 // -- sp[argc * 4] : receiver
1988 // -----------------------------------
1989
1990 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001991 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001992
1993 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001994 Label miss;
1995 Label name_miss;
1996 Label index_out_of_range;
1997 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00001998 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001999 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002000 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002001 index_out_of_range_label = &miss;
2002 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002003 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002004
2005 // Check that the maps starting from the prototype haven't changed.
2006 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2007 Context::STRING_FUNCTION_INDEX,
2008 v0,
2009 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002010 ASSERT(!object.is_identical_to(holder));
2011 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2012 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002013
2014 Register receiver = v0;
2015 Register index = t1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00002016 Register scratch = a3;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002017 Register result = v0;
2018 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
2019 if (argc > 0) {
2020 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
2021 } else {
2022 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
2023 }
2024
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002025 StringCharAtGenerator generator(receiver,
2026 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00002027 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002028 result,
2029 &miss, // When not a string.
2030 &miss, // When not a number.
2031 index_out_of_range_label,
2032 STRING_INDEX_IS_NUMBER);
2033 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002034 __ Drop(argc + 1);
2035 __ Ret();
2036
2037 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002038 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002039
2040 if (index_out_of_range.is_linked()) {
2041 __ bind(&index_out_of_range);
2042 __ LoadRoot(v0, Heap::kEmptyStringRootIndex);
2043 __ Drop(argc + 1);
2044 __ Ret();
2045 }
2046
2047 __ bind(&miss);
2048 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002049 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002050 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002051 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002052
2053 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002054 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002055}
2056
2057
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002058Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
2059 Handle<Object> object,
2060 Handle<JSObject> holder,
2061 Handle<JSGlobalPropertyCell> cell,
2062 Handle<JSFunction> function,
2063 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002064 // ----------- S t a t e -------------
2065 // -- a2 : function name
2066 // -- ra : return address
2067 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2068 // -- ...
2069 // -- sp[argc * 4] : receiver
2070 // -----------------------------------
2071
2072 const int argc = arguments().immediate();
2073
2074 // If the object is not a JSObject or we got an unexpected number of
2075 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002076 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002077
2078 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002079 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002080
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002081 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002082 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
2083
2084 STATIC_ASSERT(kSmiTag == 0);
2085 __ JumpIfSmi(a1, &miss);
2086
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002087 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2088 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002089 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002090 ASSERT(cell->value() == *function);
2091 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2092 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002093 GenerateLoadFunctionFromCell(cell, function, &miss);
2094 }
2095
2096 // Load the char code argument.
2097 Register code = a1;
2098 __ lw(code, MemOperand(sp, 0 * kPointerSize));
2099
2100 // Check the code is a smi.
2101 Label slow;
2102 STATIC_ASSERT(kSmiTag == 0);
2103 __ JumpIfNotSmi(code, &slow);
2104
2105 // Convert the smi code to uint16.
2106 __ And(code, code, Operand(Smi::FromInt(0xffff)));
2107
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002108 StringCharFromCodeGenerator generator(code, v0);
2109 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002110 __ Drop(argc + 1);
2111 __ Ret();
2112
2113 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002114 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002115
2116 // Tail call the full function. We do not have to patch the receiver
2117 // because the function makes no use of it.
2118 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002119 __ InvokeFunction(
2120 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002121
2122 __ bind(&miss);
2123 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002124 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002125
2126 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002127 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002128}
2129
2130
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002131Handle<Code> CallStubCompiler::CompileMathFloorCall(
2132 Handle<Object> object,
2133 Handle<JSObject> holder,
2134 Handle<JSGlobalPropertyCell> cell,
2135 Handle<JSFunction> function,
2136 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002137 // ----------- S t a t e -------------
2138 // -- a2 : function name
2139 // -- ra : return address
2140 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2141 // -- ...
2142 // -- sp[argc * 4] : receiver
2143 // -----------------------------------
2144
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002145 if (!CpuFeatures::IsSupported(FPU)) {
2146 return Handle<Code>::null();
2147 }
2148
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002149 CpuFeatures::Scope scope_fpu(FPU);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002150 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002151 // If the object is not a JSObject or we got an unexpected number of
2152 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002153 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002154
2155 Label miss, slow;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002156 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002157
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002158 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002159 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002160 STATIC_ASSERT(kSmiTag == 0);
2161 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002162 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2163 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002164 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002165 ASSERT(cell->value() == *function);
2166 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2167 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002168 GenerateLoadFunctionFromCell(cell, function, &miss);
2169 }
2170
2171 // Load the (only) argument into v0.
2172 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2173
2174 // If the argument is a smi, just return.
2175 STATIC_ASSERT(kSmiTag == 0);
2176 __ And(t0, v0, Operand(kSmiTagMask));
2177 __ Drop(argc + 1, eq, t0, Operand(zero_reg));
2178 __ Ret(eq, t0, Operand(zero_reg));
2179
danno@chromium.org40cb8782011-05-25 07:58:50 +00002180 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002181
2182 Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return;
2183
2184 // If fpu is enabled, we use the floor instruction.
2185
2186 // Load the HeapNumber value.
2187 __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2188
2189 // Backup FCSR.
2190 __ cfc1(a3, FCSR);
2191 // Clearing FCSR clears the exception mask with no side-effects.
2192 __ ctc1(zero_reg, FCSR);
2193 // Convert the argument to an integer.
2194 __ floor_w_d(f0, f0);
2195
2196 // Start checking for special cases.
2197 // Get the argument exponent and clear the sign bit.
2198 __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize));
2199 __ And(t2, t1, Operand(~HeapNumber::kSignMask));
2200 __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord);
2201
2202 // Retrieve FCSR and check for fpu errors.
2203 __ cfc1(t5, FCSR);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002204 __ And(t5, t5, Operand(kFCSRExceptionFlagMask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002205 __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));
2206
2207 // Check for NaN, Infinity, and -Infinity.
2208 // They are invariant through a Math.Floor call, so just
2209 // return the original argument.
2210 __ Subu(t3, t2, Operand(HeapNumber::kExponentMask
2211 >> HeapNumber::kMantissaBitsInTopWord));
2212 __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg));
2213 // We had an overflow or underflow in the conversion. Check if we
2214 // have a big exponent.
2215 // If greater or equal, the argument is already round and in v0.
2216 __ Branch(&restore_fcsr_and_return, ge, t3,
2217 Operand(HeapNumber::kMantissaBits));
2218 __ Branch(&wont_fit_smi);
2219
2220 __ bind(&no_fpu_error);
2221 // Move the result back to v0.
2222 __ mfc1(v0, f0);
2223 // Check if the result fits into a smi.
2224 __ Addu(a1, v0, Operand(0x40000000));
2225 __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg));
2226 // Tag the result.
2227 STATIC_ASSERT(kSmiTag == 0);
2228 __ sll(v0, v0, kSmiTagSize);
2229
2230 // Check for -0.
2231 __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg));
2232 // t1 already holds the HeapNumber exponent.
2233 __ And(t0, t1, Operand(HeapNumber::kSignMask));
2234 // If our HeapNumber is negative it was -0, so load its address and return.
2235 // Else v0 is loaded with 0, so we can also just return.
2236 __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg));
2237 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2238
2239 __ bind(&restore_fcsr_and_return);
2240 // Restore FCSR and return.
2241 __ ctc1(a3, FCSR);
2242
2243 __ Drop(argc + 1);
2244 __ Ret();
2245
2246 __ bind(&wont_fit_smi);
2247 // Restore FCSR and fall to slow case.
2248 __ ctc1(a3, FCSR);
2249
2250 __ bind(&slow);
2251 // Tail call the full function. We do not have to patch the receiver
2252 // because the function makes no use of it.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002253 __ InvokeFunction(
2254 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002255
2256 __ bind(&miss);
2257 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002258 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002259
2260 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002261 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002262}
2263
2264
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002265Handle<Code> CallStubCompiler::CompileMathAbsCall(
2266 Handle<Object> object,
2267 Handle<JSObject> holder,
2268 Handle<JSGlobalPropertyCell> cell,
2269 Handle<JSFunction> function,
2270 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002271 // ----------- S t a t e -------------
2272 // -- a2 : function name
2273 // -- ra : return address
2274 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2275 // -- ...
2276 // -- sp[argc * 4] : receiver
2277 // -----------------------------------
2278
2279 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002280 // If the object is not a JSObject or we got an unexpected number of
2281 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002282 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002283
2284 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002285
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002286 GenerateNameCheck(name, &miss);
2287 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002288 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002289 STATIC_ASSERT(kSmiTag == 0);
2290 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002291 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2292 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002293 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002294 ASSERT(cell->value() == *function);
2295 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2296 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002297 GenerateLoadFunctionFromCell(cell, function, &miss);
2298 }
2299
2300 // Load the (only) argument into v0.
2301 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2302
2303 // Check if the argument is a smi.
2304 Label not_smi;
2305 STATIC_ASSERT(kSmiTag == 0);
2306 __ JumpIfNotSmi(v0, &not_smi);
2307
2308 // Do bitwise not or do nothing depending on the sign of the
2309 // argument.
2310 __ sra(t0, v0, kBitsPerInt - 1);
2311 __ Xor(a1, v0, t0);
2312
2313 // Add 1 or do nothing depending on the sign of the argument.
2314 __ Subu(v0, a1, t0);
2315
2316 // If the result is still negative, go to the slow case.
2317 // This only happens for the most negative smi.
2318 Label slow;
2319 __ Branch(&slow, lt, v0, Operand(zero_reg));
2320
2321 // Smi case done.
2322 __ Drop(argc + 1);
2323 __ Ret();
2324
2325 // Check if the argument is a heap number and load its exponent and
2326 // sign.
2327 __ bind(&not_smi);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002328 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002329 __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2330
2331 // Check the sign of the argument. If the argument is positive,
2332 // just return it.
2333 Label negative_sign;
2334 __ And(t0, a1, Operand(HeapNumber::kSignMask));
2335 __ Branch(&negative_sign, ne, t0, Operand(zero_reg));
2336 __ Drop(argc + 1);
2337 __ Ret();
2338
2339 // If the argument is negative, clear the sign, and return a new
2340 // number.
2341 __ bind(&negative_sign);
2342 __ Xor(a1, a1, Operand(HeapNumber::kSignMask));
2343 __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2344 __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
2345 __ AllocateHeapNumber(v0, t0, t1, t2, &slow);
2346 __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2347 __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2348 __ Drop(argc + 1);
2349 __ Ret();
2350
2351 // Tail call the full function. We do not have to patch the receiver
2352 // because the function makes no use of it.
2353 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002354 __ InvokeFunction(
2355 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002356
2357 __ bind(&miss);
2358 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002359 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002360
2361 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002362 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002363}
2364
2365
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002366Handle<Code> CallStubCompiler::CompileFastApiCall(
lrn@chromium.org7516f052011-03-30 08:52:27 +00002367 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002368 Handle<Object> object,
2369 Handle<JSObject> holder,
2370 Handle<JSGlobalPropertyCell> cell,
2371 Handle<JSFunction> function,
2372 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002373
danno@chromium.org40cb8782011-05-25 07:58:50 +00002374 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002375
2376 ASSERT(optimization.is_simple_api_call());
2377 // Bail out if object is a global object as we don't want to
2378 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002379 if (object->IsGlobalObject()) return Handle<Code>::null();
2380 if (!cell.is_null()) return Handle<Code>::null();
2381 if (!object->IsJSObject()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002382 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002383 Handle<JSObject>::cast(object), holder);
2384 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002385
2386 Label miss, miss_before_stack_reserved;
2387
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002388 GenerateNameCheck(name, &miss_before_stack_reserved);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002389
2390 // Get the receiver from the stack.
2391 const int argc = arguments().immediate();
2392 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2393
2394 // Check that the receiver isn't a smi.
2395 __ JumpIfSmi(a1, &miss_before_stack_reserved);
2396
2397 __ IncrementCounter(counters->call_const(), 1, a0, a3);
2398 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2399
2400 ReserveSpaceForFastApiCall(masm(), a0);
2401
2402 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002403 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002404 depth, &miss);
2405
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002406 GenerateFastApiDirectCall(masm(), optimization, argc);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002407
2408 __ bind(&miss);
2409 FreeSpaceForFastApiCall(masm());
2410
2411 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002412 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002413
2414 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002415 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002416}
2417
2418
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002419Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object,
2420 Handle<JSObject> holder,
2421 Handle<JSFunction> function,
2422 Handle<String> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002423 CheckType check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002424 // ----------- S t a t e -------------
2425 // -- a2 : name
2426 // -- ra : return address
2427 // -----------------------------------
2428 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002429 Handle<Code> code = CompileCustomCall(object, holder,
2430 Handle<JSGlobalPropertyCell>::null(),
2431 function, name);
2432 // A null handle means bail out to the regular compiler code below.
2433 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002434 }
2435
2436 Label miss;
2437
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002438 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002439
2440 // Get the receiver from the stack.
2441 const int argc = arguments().immediate();
2442 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2443
2444 // Check that the receiver isn't a smi.
2445 if (check != NUMBER_CHECK) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002446 __ JumpIfSmi(a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002447 }
2448
2449 // Make sure that it's okay not to patch the on stack receiver
2450 // unless we're doing a receiver map check.
2451 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002452 switch (check) {
2453 case RECEIVER_MAP_CHECK:
2454 __ IncrementCounter(masm()->isolate()->counters()->call_const(),
2455 1, a0, a3);
2456
2457 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002458 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2459 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002460
2461 // Patch the receiver on the stack with the global proxy if
2462 // necessary.
2463 if (object->IsGlobalObject()) {
2464 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2465 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2466 }
2467 break;
2468
2469 case STRING_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002470 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002471 // Check that the object is a two-byte string or a symbol.
2472 __ GetObjectType(a1, a3, a3);
2473 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2474 // Check that the maps starting from the prototype haven't changed.
2475 GenerateDirectLoadGlobalFunctionPrototype(
2476 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002477 CheckPrototypes(
2478 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2479 a0, holder, a3, a1, t0, name, &miss);
2480 } else {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002481 // Calling non-strict non-builtins with a value as the receiver
2482 // requires boxing.
2483 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002484 }
2485 break;
2486
2487 case NUMBER_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002488 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002489 Label fast;
2490 // Check that the object is a smi or a heap number.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002491 __ JumpIfSmi(a1, &fast);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002492 __ GetObjectType(a1, a0, a0);
2493 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
2494 __ bind(&fast);
2495 // Check that the maps starting from the prototype haven't changed.
2496 GenerateDirectLoadGlobalFunctionPrototype(
2497 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002498 CheckPrototypes(
2499 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2500 a0, holder, a3, a1, t0, name, &miss);
2501 } else {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002502 // Calling non-strict non-builtins with a value as the receiver
2503 // requires boxing.
2504 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002505 }
2506 break;
2507
2508 case BOOLEAN_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002509 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002510 Label fast;
2511 // Check that the object is a boolean.
2512 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
2513 __ Branch(&fast, eq, a1, Operand(t0));
2514 __ LoadRoot(t0, Heap::kFalseValueRootIndex);
2515 __ Branch(&miss, ne, a1, Operand(t0));
2516 __ bind(&fast);
2517 // Check that the maps starting from the prototype haven't changed.
2518 GenerateDirectLoadGlobalFunctionPrototype(
2519 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002520 CheckPrototypes(
2521 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2522 a0, holder, a3, a1, t0, name, &miss);
2523 } else {
2524 // Calling non-strict non-builtins with a value as the receiver
2525 // requires boxing.
2526 __ jmp(&miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002527 }
2528 break;
2529 }
2530
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002531 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002532 ? CALL_AS_FUNCTION
2533 : CALL_AS_METHOD;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002534 __ InvokeFunction(
2535 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002536
2537 // Handle call cache miss.
2538 __ bind(&miss);
2539
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002540 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002541
2542 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002543 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002544}
2545
2546
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002547Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2548 Handle<JSObject> holder,
2549 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002550 // ----------- S t a t e -------------
2551 // -- a2 : name
2552 // -- ra : return address
2553 // -----------------------------------
2554
2555 Label miss;
2556
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002557 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002558
2559 // Get the number of arguments.
2560 const int argc = arguments().immediate();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002561 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002562 LookupPostInterceptor(holder, name, &lookup);
2563
2564 // Get the receiver from the stack.
2565 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2566
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002567 CallInterceptorCompiler compiler(this, arguments(), a2, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002568 compiler.Compile(masm(), object, holder, name, &lookup, a1, a3, t0, a0,
2569 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002570
2571 // Move returned value, the function to call, to a1.
2572 __ mov(a1, v0);
2573 // Restore receiver.
2574 __ lw(a0, MemOperand(sp, argc * kPointerSize));
2575
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002576 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002577
2578 // Handle call cache miss.
2579 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002580 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002581
2582 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002583 return GetCode(Code::INTERCEPTOR, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002584}
2585
2586
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002587Handle<Code> CallStubCompiler::CompileCallGlobal(
2588 Handle<JSObject> object,
2589 Handle<GlobalObject> holder,
2590 Handle<JSGlobalPropertyCell> cell,
2591 Handle<JSFunction> function,
2592 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002593 // ----------- S t a t e -------------
2594 // -- a2 : name
2595 // -- ra : return address
2596 // -----------------------------------
2597
2598 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002599 Handle<Code> code = CompileCustomCall(object, holder, cell, function, name);
2600 // A null handle means bail out to the regular compiler code below.
2601 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002602 }
2603
2604 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002605 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002606
2607 // Get the number of arguments.
2608 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002609 GenerateGlobalReceiverCheck(object, holder, name, &miss);
2610 GenerateLoadFunctionFromCell(cell, function, &miss);
2611
2612 // Patch the receiver on the stack with the global proxy if
2613 // necessary.
2614 if (object->IsGlobalObject()) {
2615 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
2616 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2617 }
2618
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002619 // Set up the context (function already in r1).
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002620 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
2621
2622 // Jump to the cached code (tail call).
2623 Counters* counters = masm()->isolate()->counters();
2624 __ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002625 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002626 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002627 ? CALL_AS_FUNCTION
2628 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002629 // We call indirectly through the code field in the function to
2630 // allow recompilation to take effect without changing any of the
2631 // call sites.
2632 __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
2633 __ InvokeCode(a3, expected, arguments(), JUMP_FUNCTION,
2634 NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002635
2636 // Handle call cache miss.
2637 __ bind(&miss);
2638 __ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002639 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002640
2641 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002642 return GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002643}
2644
2645
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002646Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +00002647 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002648 Handle<Map> transition,
2649 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002650 // ----------- S t a t e -------------
2651 // -- a0 : value
2652 // -- a1 : receiver
2653 // -- a2 : name
2654 // -- ra : return address
2655 // -----------------------------------
2656 Label miss;
2657
2658 // Name register might be clobbered.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002659 GenerateStoreField(masm(),
2660 object,
2661 index,
2662 transition,
2663 name,
2664 a1, a2, a3, t0,
2665 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002666 __ bind(&miss);
2667 __ li(a2, Operand(Handle<String>(name))); // Restore name.
2668 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2669 __ Jump(ic, RelocInfo::CODE_TARGET);
2670
2671 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002672 return GetCode(transition.is_null()
2673 ? Code::FIELD
2674 : Code::MAP_TRANSITION, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002675}
2676
2677
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002678Handle<Code> StoreStubCompiler::CompileStoreCallback(
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002679 Handle<String> name,
2680 Handle<JSObject> receiver,
2681 Handle<JSObject> holder,
2682 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002683 // ----------- S t a t e -------------
2684 // -- a0 : value
2685 // -- a1 : receiver
2686 // -- a2 : name
2687 // -- ra : return address
2688 // -----------------------------------
2689 Label miss;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002690 // Check that the maps haven't changed.
2691 __ JumpIfSmi(a1, &miss, a3);
2692 CheckPrototypes(receiver, a1, holder, a3, t0, t1, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002693
2694 // Stub never generated for non-global objects that require access
2695 // checks.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002696 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002697
2698 __ push(a1); // Receiver.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002699 __ li(a3, Operand(callback)); // Callback info.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002700 __ Push(a3, a2, a0);
2701
2702 // Do tail-call to the runtime system.
2703 ExternalReference store_callback_property =
2704 ExternalReference(IC_Utility(IC::kStoreCallbackProperty),
2705 masm()->isolate());
2706 __ TailCallExternalReference(store_callback_property, 4, 1);
2707
2708 // Handle store cache miss.
2709 __ bind(&miss);
2710 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2711 __ Jump(ic, RelocInfo::CODE_TARGET);
2712
2713 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002714 return GetCode(Code::CALLBACKS, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002715}
2716
2717
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002718#undef __
2719#define __ ACCESS_MASM(masm)
2720
2721
2722void StoreStubCompiler::GenerateStoreViaSetter(
2723 MacroAssembler* masm,
2724 Handle<JSFunction> setter) {
2725 // ----------- S t a t e -------------
2726 // -- a0 : value
2727 // -- a1 : receiver
2728 // -- a2 : name
2729 // -- ra : return address
2730 // -----------------------------------
2731 {
2732 FrameScope scope(masm, StackFrame::INTERNAL);
2733
2734 // Save value register, so we can restore it later.
2735 __ push(a0);
2736
2737 if (!setter.is_null()) {
2738 // Call the JavaScript setter with receiver and value on the stack.
2739 __ push(a1);
2740 __ push(a0);
2741 ParameterCount actual(1);
2742 __ InvokeFunction(setter, actual, CALL_FUNCTION, NullCallWrapper(),
2743 CALL_AS_METHOD);
2744 } else {
2745 // If we generate a global code snippet for deoptimization only, remember
2746 // the place to continue after deoptimization.
2747 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2748 }
2749
2750 // We have to return the passed value, not the return value of the setter.
2751 __ pop(v0);
2752
2753 // Restore context register.
2754 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2755 }
2756 __ Ret();
2757}
2758
2759
2760#undef __
2761#define __ ACCESS_MASM(masm())
2762
2763
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002764Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002765 Handle<String> name,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002766 Handle<JSObject> receiver,
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002767 Handle<JSObject> holder,
2768 Handle<JSFunction> setter) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002769 // ----------- S t a t e -------------
2770 // -- a0 : value
2771 // -- a1 : receiver
2772 // -- a2 : name
2773 // -- ra : return address
2774 // -----------------------------------
2775 Label miss;
2776
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002777 // Check that the maps haven't changed.
2778 __ JumpIfSmi(a1, &miss);
2779 CheckPrototypes(receiver, a1, holder, a3, t0, t1, name, &miss);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002780
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002781 GenerateStoreViaSetter(masm(), setter);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002782
2783 __ bind(&miss);
2784 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2785 __ Jump(ic, RelocInfo::CODE_TARGET);
2786
2787 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002788 return GetCode(Code::CALLBACKS, name);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002789}
2790
2791
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002792Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
2793 Handle<JSObject> receiver,
2794 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002795 // ----------- S t a t e -------------
2796 // -- a0 : value
2797 // -- a1 : receiver
2798 // -- a2 : name
2799 // -- ra : return address
2800 // -----------------------------------
2801 Label miss;
2802
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002803 // Check that the map of the object hasn't changed.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002804 __ CheckMap(a1, a3, Handle<Map>(receiver->map()), &miss,
2805 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002806
2807 // Perform global security token check if needed.
2808 if (receiver->IsJSGlobalProxy()) {
2809 __ CheckAccessGlobalProxy(a1, a3, &miss);
2810 }
2811
2812 // Stub is never generated for non-global objects that require access
2813 // checks.
2814 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2815
2816 __ Push(a1, a2, a0); // Receiver, name, value.
2817
2818 __ li(a0, Operand(Smi::FromInt(strict_mode_)));
2819 __ push(a0); // Strict mode.
2820
2821 // Do tail-call to the runtime system.
2822 ExternalReference store_ic_property =
2823 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty),
2824 masm()->isolate());
2825 __ TailCallExternalReference(store_ic_property, 4, 1);
2826
2827 // Handle store cache miss.
2828 __ bind(&miss);
2829 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2830 __ Jump(ic, RelocInfo::CODE_TARGET);
2831
2832 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002833 return GetCode(Code::INTERCEPTOR, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002834}
2835
2836
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002837Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2838 Handle<GlobalObject> object,
2839 Handle<JSGlobalPropertyCell> cell,
2840 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002841 // ----------- S t a t e -------------
2842 // -- a0 : value
2843 // -- a1 : receiver
2844 // -- a2 : name
2845 // -- ra : return address
2846 // -----------------------------------
2847 Label miss;
2848
2849 // Check that the map of the global has not changed.
2850 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2851 __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map())));
2852
2853 // Check that the value in the cell is not the hole. If it is, this
2854 // cell could have been deleted and reintroducing the global needs
2855 // to update the property details in the property dictionary of the
2856 // global object. We bail out to the runtime system to do that.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002857 __ li(t0, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002858 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
2859 __ lw(t2, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2860 __ Branch(&miss, eq, t1, Operand(t2));
2861
2862 // Store the value in the cell.
2863 __ sw(a0, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2864 __ mov(v0, a0); // Stored value must be returned in v0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002865 // Cells are always rescanned, so no write barrier here.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002866
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002867 Counters* counters = masm()->isolate()->counters();
2868 __ IncrementCounter(counters->named_store_global_inline(), 1, a1, a3);
2869 __ Ret();
2870
2871 // Handle store cache miss.
2872 __ bind(&miss);
2873 __ IncrementCounter(counters->named_store_global_inline_miss(), 1, a1, a3);
2874 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2875 __ Jump(ic, RelocInfo::CODE_TARGET);
2876
2877 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002878 return GetCode(Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002879}
2880
2881
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002882Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
2883 Handle<JSObject> object,
2884 Handle<JSObject> last) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002885 // ----------- S t a t e -------------
2886 // -- a0 : receiver
2887 // -- ra : return address
2888 // -----------------------------------
2889 Label miss;
2890
2891 // Check that the receiver is not a smi.
2892 __ JumpIfSmi(a0, &miss);
2893
2894 // Check the maps of the full prototype chain.
2895 CheckPrototypes(object, a0, last, a3, a1, t0, name, &miss);
2896
2897 // If the last object in the prototype chain is a global object,
2898 // check that the global property cell is empty.
2899 if (last->IsGlobalObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002900 GenerateCheckPropertyCell(
2901 masm(), Handle<GlobalObject>::cast(last), name, a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002902 }
2903
2904 // Return undefined if maps of the full prototype chain is still the same.
2905 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2906 __ Ret();
2907
2908 __ bind(&miss);
2909 GenerateLoadMiss(masm(), Code::LOAD_IC);
2910
2911 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002912 return GetCode(Code::NONEXISTENT, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00002913}
2914
2915
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002916Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object,
2917 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002918 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002919 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002920 // ----------- S t a t e -------------
2921 // -- a0 : receiver
2922 // -- a2 : name
2923 // -- ra : return address
2924 // -----------------------------------
2925 Label miss;
2926
2927 __ mov(v0, a0);
2928
2929 GenerateLoadField(object, holder, v0, a3, a1, t0, index, name, &miss);
2930 __ bind(&miss);
2931 GenerateLoadMiss(masm(), Code::LOAD_IC);
2932
2933 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002934 return GetCode(Code::FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002935}
2936
2937
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002938Handle<Code> LoadStubCompiler::CompileLoadCallback(
2939 Handle<String> name,
2940 Handle<JSObject> object,
2941 Handle<JSObject> holder,
2942 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002943 // ----------- S t a t e -------------
2944 // -- a0 : receiver
2945 // -- a2 : name
2946 // -- ra : return address
2947 // -----------------------------------
2948 Label miss;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00002949 GenerateLoadCallback(object, holder, a0, a2, a3, a1, t0, t1, callback, name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002950 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002951 __ bind(&miss);
2952 GenerateLoadMiss(masm(), Code::LOAD_IC);
2953
2954 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002955 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002956}
2957
2958
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002959Handle<Code> LoadStubCompiler::CompileLoadViaGetter(
2960 Handle<String> name,
2961 Handle<JSObject> receiver,
2962 Handle<JSObject> holder,
2963 Handle<JSFunction> getter) {
2964 // ----------- S t a t e -------------
2965 // -- a0 : receiver
2966 // -- a2 : name
2967 // -- ra : return address
2968 // -----------------------------------
2969 Label miss;
2970
2971 // Check that the maps haven't changed.
2972 __ JumpIfSmi(a0, &miss);
2973 CheckPrototypes(receiver, a0, holder, a3, t0, a1, name, &miss);
2974
2975 {
2976 FrameScope scope(masm(), StackFrame::INTERNAL);
2977
2978 // Call the JavaScript getter with the receiver on the stack.
2979 __ push(a0);
2980 ParameterCount actual(0);
2981 __ InvokeFunction(getter, actual, CALL_FUNCTION, NullCallWrapper(),
2982 CALL_AS_METHOD);
2983
2984 // Restore context register.
2985 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2986 }
2987 __ Ret();
2988
2989 __ bind(&miss);
2990 GenerateLoadMiss(masm(), Code::LOAD_IC);
2991
2992 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002993 return GetCode(Code::CALLBACKS, name);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002994}
2995
2996
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002997Handle<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object,
2998 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002999 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003000 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003001 // ----------- S t a t e -------------
3002 // -- a0 : receiver
3003 // -- a2 : name
3004 // -- ra : return address
3005 // -----------------------------------
3006 Label miss;
3007
3008 GenerateLoadConstant(object, holder, a0, a3, a1, t0, value, name, &miss);
3009 __ bind(&miss);
3010 GenerateLoadMiss(masm(), Code::LOAD_IC);
3011
3012 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003013 return GetCode(Code::CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003014}
3015
3016
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003017Handle<Code> LoadStubCompiler::CompileLoadInterceptor(Handle<JSObject> object,
3018 Handle<JSObject> holder,
3019 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003020 // ----------- S t a t e -------------
3021 // -- a0 : receiver
3022 // -- a2 : name
3023 // -- ra : return address
3024 // -- [sp] : receiver
3025 // -----------------------------------
3026 Label miss;
3027
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003028 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003029 LookupPostInterceptor(holder, name, &lookup);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003030 GenerateLoadInterceptor(object, holder, &lookup, a0, a2, a3, a1, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003031 &miss);
3032 __ bind(&miss);
3033 GenerateLoadMiss(masm(), Code::LOAD_IC);
3034
3035 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003036 return GetCode(Code::INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003037}
3038
3039
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003040Handle<Code> LoadStubCompiler::CompileLoadGlobal(
3041 Handle<JSObject> object,
3042 Handle<GlobalObject> holder,
3043 Handle<JSGlobalPropertyCell> cell,
3044 Handle<String> name,
3045 bool is_dont_delete) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003046 // ----------- S t a t e -------------
3047 // -- a0 : receiver
3048 // -- a2 : name
3049 // -- ra : return address
3050 // -----------------------------------
3051 Label miss;
3052
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003053 // Check that the map of the global has not changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003054 __ JumpIfSmi(a0, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003055 CheckPrototypes(object, a0, holder, a3, t0, a1, name, &miss);
3056
3057 // Get the value from the cell.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003058 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003059 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
3060
3061 // Check for deleted property if property can actually be deleted.
3062 if (!is_dont_delete) {
3063 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
3064 __ Branch(&miss, eq, t0, Operand(at));
3065 }
3066
3067 __ mov(v0, t0);
3068 Counters* counters = masm()->isolate()->counters();
3069 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
3070 __ Ret();
3071
3072 __ bind(&miss);
3073 __ IncrementCounter(counters->named_load_global_stub_miss(), 1, a1, a3);
3074 GenerateLoadMiss(masm(), Code::LOAD_IC);
3075
3076 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003077 return GetCode(Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003078}
3079
3080
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003081Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
3082 Handle<JSObject> receiver,
3083 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00003084 int index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003085 // ----------- S t a t e -------------
3086 // -- ra : return address
3087 // -- a0 : key
3088 // -- a1 : receiver
3089 // -----------------------------------
3090 Label miss;
3091
3092 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003093 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003094
3095 GenerateLoadField(receiver, holder, a1, a2, a3, t0, index, name, &miss);
3096 __ bind(&miss);
3097 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3098
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003099 return GetCode(Code::FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003100}
3101
3102
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003103Handle<Code> KeyedLoadStubCompiler::CompileLoadCallback(
3104 Handle<String> name,
3105 Handle<JSObject> receiver,
3106 Handle<JSObject> holder,
3107 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003108 // ----------- S t a t e -------------
3109 // -- ra : return address
3110 // -- a0 : key
3111 // -- a1 : receiver
3112 // -----------------------------------
3113 Label miss;
3114
3115 // Check the key is the cached one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003116 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003117
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00003118 GenerateLoadCallback(receiver, holder, a1, a0, a2, a3, t0, t1, callback,
3119 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003120 __ 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::CompileLoadConstant(
3128 Handle<String> name,
3129 Handle<JSObject> receiver,
3130 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003131 Handle<JSFunction> value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003132 // ----------- S t a t e -------------
3133 // -- ra : return address
3134 // -- a0 : key
3135 // -- a1 : receiver
3136 // -----------------------------------
3137 Label miss;
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 GenerateLoadConstant(receiver, holder, a1, a2, a3, t0, value, name, &miss);
3143 __ bind(&miss);
3144 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3145
3146 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003147 return GetCode(Code::CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003148}
3149
3150
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003151Handle<Code> KeyedLoadStubCompiler::CompileLoadInterceptor(
3152 Handle<JSObject> receiver,
3153 Handle<JSObject> holder,
3154 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003155 // ----------- S t a t e -------------
3156 // -- ra : return address
3157 // -- a0 : key
3158 // -- a1 : receiver
3159 // -----------------------------------
3160 Label miss;
3161
3162 // Check the key is the cached one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003163 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003164
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003165 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003166 LookupPostInterceptor(holder, name, &lookup);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003167 GenerateLoadInterceptor(receiver, holder, &lookup, a1, a0, a2, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003168 &miss);
3169 __ bind(&miss);
3170 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3171
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003172 return GetCode(Code::INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003173}
3174
3175
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003176Handle<Code> KeyedLoadStubCompiler::CompileLoadArrayLength(
3177 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003178 // ----------- S t a t e -------------
3179 // -- ra : return address
3180 // -- a0 : key
3181 // -- a1 : receiver
3182 // -----------------------------------
3183 Label miss;
3184
3185 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003186 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003187
3188 GenerateLoadArrayLength(masm(), a1, a2, &miss);
3189 __ bind(&miss);
3190 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3191
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003192 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003193}
3194
3195
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003196Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength(
3197 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003198 // ----------- S t a t e -------------
3199 // -- ra : return address
3200 // -- a0 : key
3201 // -- a1 : receiver
3202 // -----------------------------------
3203 Label miss;
3204
3205 Counters* counters = masm()->isolate()->counters();
3206 __ IncrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
3207
3208 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003209 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003210
3211 GenerateLoadStringLength(masm(), a1, a2, a3, &miss, true);
3212 __ bind(&miss);
3213 __ DecrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
3214
3215 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3216
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003217 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003218}
3219
3220
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003221Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype(
3222 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003223 // ----------- S t a t e -------------
3224 // -- ra : return address
3225 // -- a0 : key
3226 // -- a1 : receiver
3227 // -----------------------------------
3228 Label miss;
3229
3230 Counters* counters = masm()->isolate()->counters();
3231 __ IncrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
3232
3233 // Check the name hasn't changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003234 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003235
3236 GenerateLoadFunctionPrototype(masm(), a1, a2, a3, &miss);
3237 __ bind(&miss);
3238 __ DecrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
3239 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3240
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003241 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003242}
3243
3244
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003245Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
3246 Handle<Map> receiver_map) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003247 // ----------- S t a t e -------------
3248 // -- ra : return address
3249 // -- a0 : key
3250 // -- a1 : receiver
3251 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003252 ElementsKind elements_kind = receiver_map->elements_kind();
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003253 Handle<Code> stub = KeyedLoadElementStub(elements_kind).GetCode();
3254
3255 __ DispatchMap(a1, a2, receiver_map, stub, DO_SMI_CHECK);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003256
3257 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
3258 __ Jump(ic, RelocInfo::CODE_TARGET);
3259
3260 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003261 return GetCode(Code::NORMAL, factory()->empty_string());
danno@chromium.org40cb8782011-05-25 07:58:50 +00003262}
3263
3264
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003265Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
3266 MapHandleList* receiver_maps,
3267 CodeHandleList* handler_ics) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003268 // ----------- S t a t e -------------
3269 // -- ra : return address
3270 // -- a0 : key
3271 // -- a1 : receiver
3272 // -----------------------------------
3273 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003274 __ JumpIfSmi(a1, &miss);
3275
danno@chromium.org40cb8782011-05-25 07:58:50 +00003276 int receiver_count = receiver_maps->length();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003277 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003278 for (int current = 0; current < receiver_count; ++current) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003279 __ Jump(handler_ics->at(current), RelocInfo::CODE_TARGET,
3280 eq, a2, Operand(receiver_maps->at(current)));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003281 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003282
3283 __ bind(&miss);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003284 Handle<Code> miss_ic = isolate()->builtins()->KeyedLoadIC_Miss();
3285 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003286
3287 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003288 return GetCode(Code::NORMAL, factory()->empty_string(), MEGAMORPHIC);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003289}
3290
3291
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003292Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +00003293 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003294 Handle<Map> transition,
3295 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003296 // ----------- S t a t e -------------
3297 // -- a0 : value
3298 // -- a1 : key
3299 // -- a2 : receiver
3300 // -- ra : return address
3301 // -----------------------------------
3302
3303 Label miss;
3304
3305 Counters* counters = masm()->isolate()->counters();
3306 __ IncrementCounter(counters->keyed_store_field(), 1, a3, t0);
3307
3308 // Check that the name has not changed.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003309 __ Branch(&miss, ne, a1, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003310
3311 // a3 is used as scratch register. a1 and a2 keep their values if a jump to
3312 // the miss label is generated.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003313 GenerateStoreField(masm(),
3314 object,
3315 index,
3316 transition,
3317 name,
3318 a2, a1, a3, t0,
3319 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003320 __ bind(&miss);
3321
3322 __ DecrementCounter(counters->keyed_store_field(), 1, a3, t0);
3323 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss();
3324 __ Jump(ic, RelocInfo::CODE_TARGET);
3325
3326 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003327 return GetCode(transition.is_null()
3328 ? Code::FIELD
3329 : Code::MAP_TRANSITION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003330}
3331
3332
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003333Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
3334 Handle<Map> receiver_map) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003335 // ----------- S t a t e -------------
3336 // -- a0 : value
3337 // -- a1 : key
3338 // -- a2 : receiver
3339 // -- ra : return address
3340 // -- a3 : scratch
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003341 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003342 ElementsKind elements_kind = receiver_map->elements_kind();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003343 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003344 Handle<Code> stub =
yangguo@chromium.org56454712012-02-16 15:33:53 +00003345 KeyedStoreElementStub(is_js_array, elements_kind, grow_mode_).GetCode();
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003346
3347 __ DispatchMap(a2, a3, receiver_map, stub, DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003348
danno@chromium.org40cb8782011-05-25 07:58:50 +00003349 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003350 __ Jump(ic, RelocInfo::CODE_TARGET);
3351
3352 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003353 return GetCode(Code::NORMAL, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00003354}
3355
3356
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003357Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
3358 MapHandleList* receiver_maps,
3359 CodeHandleList* handler_stubs,
3360 MapHandleList* transitioned_maps) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003361 // ----------- S t a t e -------------
3362 // -- a0 : value
3363 // -- a1 : key
3364 // -- a2 : receiver
3365 // -- ra : return address
3366 // -- a3 : scratch
3367 // -----------------------------------
3368 Label miss;
3369 __ JumpIfSmi(a2, &miss);
3370
3371 int receiver_count = receiver_maps->length();
3372 __ lw(a3, FieldMemOperand(a2, HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003373 for (int i = 0; i < receiver_count; ++i) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003374 if (transitioned_maps->at(i).is_null()) {
3375 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq,
3376 a3, Operand(receiver_maps->at(i)));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003377 } else {
3378 Label next_map;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003379 __ Branch(&next_map, ne, a3, Operand(receiver_maps->at(i)));
3380 __ li(a3, Operand(transitioned_maps->at(i)));
3381 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003382 __ bind(&next_map);
3383 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003384 }
3385
3386 __ bind(&miss);
3387 Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
3388 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3389
3390 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003391 return GetCode(Code::NORMAL, factory()->empty_string(), MEGAMORPHIC);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003392}
3393
3394
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003395Handle<Code> ConstructStubCompiler::CompileConstructStub(
3396 Handle<JSFunction> function) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003397 // a0 : argc
3398 // a1 : constructor
3399 // ra : return address
3400 // [sp] : last argument
3401 Label generic_stub_call;
3402
3403 // Use t7 for holding undefined which is used in several places below.
3404 __ LoadRoot(t7, Heap::kUndefinedValueRootIndex);
3405
3406#ifdef ENABLE_DEBUGGER_SUPPORT
3407 // Check to see whether there are any break points in the function code. If
3408 // there are jump to the generic constructor stub which calls the actual
3409 // code for the function thereby hitting the break points.
3410 __ lw(t5, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3411 __ lw(a2, FieldMemOperand(t5, SharedFunctionInfo::kDebugInfoOffset));
3412 __ Branch(&generic_stub_call, ne, a2, Operand(t7));
3413#endif
3414
3415 // Load the initial map and verify that it is in fact a map.
3416 // a1: constructor function
3417 // t7: undefined
3418 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003419 __ JumpIfSmi(a2, &generic_stub_call);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003420 __ GetObjectType(a2, a3, t0);
3421 __ Branch(&generic_stub_call, ne, t0, Operand(MAP_TYPE));
3422
3423#ifdef DEBUG
3424 // Cannot construct functions this way.
3425 // a0: argc
3426 // a1: constructor function
3427 // a2: initial map
3428 // t7: undefined
3429 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
3430 __ Check(ne, "Function constructed by construct stub.",
3431 a3, Operand(JS_FUNCTION_TYPE));
3432#endif
3433
3434 // Now allocate the JSObject in new space.
3435 // a0: argc
3436 // a1: constructor function
3437 // a2: initial map
3438 // t7: undefined
3439 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003440 __ AllocateInNewSpace(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003441
3442 // Allocated the JSObject, now initialize the fields. Map is set to initial
3443 // map and properties and elements are set to empty fixed array.
3444 // a0: argc
3445 // a1: constructor function
3446 // a2: initial map
3447 // a3: object size (in words)
3448 // t4: JSObject (not tagged)
3449 // t7: undefined
3450 __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex);
3451 __ mov(t5, t4);
3452 __ sw(a2, MemOperand(t5, JSObject::kMapOffset));
3453 __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset));
3454 __ sw(t6, MemOperand(t5, JSObject::kElementsOffset));
3455 __ Addu(t5, t5, Operand(3 * kPointerSize));
3456 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
3457 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
3458 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
3459
3460
3461 // Calculate the location of the first argument. The stack contains only the
3462 // argc arguments.
3463 __ sll(a1, a0, kPointerSizeLog2);
3464 __ Addu(a1, a1, sp);
3465
3466 // Fill all the in-object properties with undefined.
3467 // a0: argc
3468 // a1: first argument
3469 // a3: object size (in words)
3470 // t4: JSObject (not tagged)
3471 // t5: First in-object property of JSObject (not tagged)
3472 // t7: undefined
3473 // Fill the initialized properties with a constant value or a passed argument
3474 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003475 Handle<SharedFunctionInfo> shared(function->shared());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003476 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3477 if (shared->IsThisPropertyAssignmentArgument(i)) {
3478 Label not_passed, next;
3479 // Check if the argument assigned to the property is actually passed.
3480 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3481 __ Branch(&not_passed, less_equal, a0, Operand(arg_number));
3482 // Argument passed - find it on the stack.
3483 __ lw(a2, MemOperand(a1, (arg_number + 1) * -kPointerSize));
3484 __ sw(a2, MemOperand(t5));
3485 __ Addu(t5, t5, kPointerSize);
3486 __ jmp(&next);
3487 __ bind(&not_passed);
3488 // Set the property to undefined.
3489 __ sw(t7, MemOperand(t5));
3490 __ Addu(t5, t5, Operand(kPointerSize));
3491 __ bind(&next);
3492 } else {
3493 // Set the property to the constant value.
3494 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
3495 __ li(a2, Operand(constant));
3496 __ sw(a2, MemOperand(t5));
3497 __ Addu(t5, t5, kPointerSize);
3498 }
3499 }
3500
3501 // Fill the unused in-object property fields with undefined.
3502 ASSERT(function->has_initial_map());
3503 for (int i = shared->this_property_assignments_count();
3504 i < function->initial_map()->inobject_properties();
3505 i++) {
3506 __ sw(t7, MemOperand(t5));
3507 __ Addu(t5, t5, kPointerSize);
3508 }
3509
3510 // a0: argc
3511 // t4: JSObject (not tagged)
3512 // Move argc to a1 and the JSObject to return to v0 and tag it.
3513 __ mov(a1, a0);
3514 __ mov(v0, t4);
3515 __ Or(v0, v0, Operand(kHeapObjectTag));
3516
3517 // v0: JSObject
3518 // a1: argc
3519 // Remove caller arguments and receiver from the stack and return.
3520 __ sll(t0, a1, kPointerSizeLog2);
3521 __ Addu(sp, sp, t0);
3522 __ Addu(sp, sp, Operand(kPointerSize));
3523 Counters* counters = masm()->isolate()->counters();
3524 __ IncrementCounter(counters->constructed_objects(), 1, a1, a2);
3525 __ IncrementCounter(counters->constructed_objects_stub(), 1, a1, a2);
3526 __ Ret();
3527
3528 // Jump to the generic stub in case the specialized code cannot handle the
3529 // construction.
3530 __ bind(&generic_stub_call);
3531 Handle<Code> generic_construct_stub =
3532 masm()->isolate()->builtins()->JSConstructStubGeneric();
3533 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
3534
3535 // Return the generated code.
3536 return GetCode();
3537}
3538
3539
danno@chromium.org40cb8782011-05-25 07:58:50 +00003540#undef __
3541#define __ ACCESS_MASM(masm)
3542
3543
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003544void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3545 MacroAssembler* masm) {
3546 // ---------- S t a t e --------------
3547 // -- ra : return address
3548 // -- a0 : key
3549 // -- a1 : receiver
3550 // -----------------------------------
3551 Label slow, miss_force_generic;
3552
3553 Register key = a0;
3554 Register receiver = a1;
3555
3556 __ JumpIfNotSmi(key, &miss_force_generic);
3557 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
3558 __ sra(a2, a0, kSmiTagSize);
3559 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
3560 __ Ret();
3561
3562 // Slow case, key and receiver still in a0 and a1.
3563 __ bind(&slow);
3564 __ IncrementCounter(
3565 masm->isolate()->counters()->keyed_load_external_array_slow(),
3566 1, a2, a3);
3567 // Entry registers are intact.
3568 // ---------- S t a t e --------------
3569 // -- ra : return address
3570 // -- a0 : key
3571 // -- a1 : receiver
3572 // -----------------------------------
3573 Handle<Code> slow_ic =
3574 masm->isolate()->builtins()->KeyedLoadIC_Slow();
3575 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
3576
3577 // Miss case, call the runtime.
3578 __ bind(&miss_force_generic);
3579
3580 // ---------- S t a t e --------------
3581 // -- ra : return address
3582 // -- a0 : key
3583 // -- a1 : receiver
3584 // -----------------------------------
3585
3586 Handle<Code> miss_ic =
3587 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3588 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3589}
3590
3591
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003592static bool IsElementTypeSigned(ElementsKind elements_kind) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003593 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003594 case EXTERNAL_BYTE_ELEMENTS:
3595 case EXTERNAL_SHORT_ELEMENTS:
3596 case EXTERNAL_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003597 return true;
3598
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003599 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3600 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3601 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3602 case EXTERNAL_PIXEL_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003603 return false;
3604
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003605 case EXTERNAL_FLOAT_ELEMENTS:
3606 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003607 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003608 case FAST_ELEMENTS:
3609 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003610 case FAST_HOLEY_SMI_ELEMENTS:
3611 case FAST_HOLEY_ELEMENTS:
3612 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003613 case DICTIONARY_ELEMENTS:
3614 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003615 UNREACHABLE();
3616 return false;
3617 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003618 return false;
lrn@chromium.org7516f052011-03-30 08:52:27 +00003619}
3620
3621
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003622static void GenerateSmiKeyCheck(MacroAssembler* masm,
3623 Register key,
3624 Register scratch0,
3625 Register scratch1,
3626 FPURegister double_scratch0,
3627 Label* fail) {
3628 if (CpuFeatures::IsSupported(FPU)) {
3629 CpuFeatures::Scope scope(FPU);
3630 Label key_ok;
3631 // Check for smi or a smi inside a heap number. We convert the heap
3632 // number and check if the conversion is exact and fits into the smi
3633 // range.
3634 __ JumpIfSmi(key, &key_ok);
3635 __ CheckMap(key,
3636 scratch0,
3637 Heap::kHeapNumberMapRootIndex,
3638 fail,
3639 DONT_DO_SMI_CHECK);
3640 __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
3641 __ EmitFPUTruncate(kRoundToZero,
3642 double_scratch0,
3643 double_scratch0,
3644 scratch0,
3645 scratch1,
3646 kCheckForInexactConversion);
3647
3648 __ Branch(fail, ne, scratch1, Operand(zero_reg));
3649
3650 __ mfc1(scratch0, double_scratch0);
3651 __ SmiTagCheckOverflow(key, scratch0, scratch1);
3652 __ BranchOnOverflow(fail, scratch1);
3653 __ bind(&key_ok);
3654 } else {
3655 // Check that the key is a smi.
3656 __ JumpIfNotSmi(key, fail);
3657 }
3658}
3659
3660
danno@chromium.org40cb8782011-05-25 07:58:50 +00003661void KeyedLoadStubCompiler::GenerateLoadExternalArray(
3662 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003663 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003664 // ---------- S t a t e --------------
3665 // -- ra : return address
3666 // -- a0 : key
3667 // -- a1 : receiver
3668 // -----------------------------------
danno@chromium.org40cb8782011-05-25 07:58:50 +00003669 Label miss_force_generic, slow, failed_allocation;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003670
3671 Register key = a0;
3672 Register receiver = a1;
3673
danno@chromium.org40cb8782011-05-25 07:58:50 +00003674 // This stub is meant to be tail-jumped to, the receiver must already
3675 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003676
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003677 // Check that the key is a smi or a heap number convertible to a smi.
3678 GenerateSmiKeyCheck(masm, key, t0, t1, f2, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003679
3680 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3681 // a3: elements array
3682
3683 // Check that the index is in range.
3684 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3685 __ sra(t2, key, kSmiTagSize);
3686 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003687 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003688
3689 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3690 // a3: base pointer of external storage
3691
3692 // We are not untagging smi key and instead work with it
3693 // as if it was premultiplied by 2.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003694 STATIC_ASSERT((kSmiTag == 0) && (kSmiTagSize == 1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003695
3696 Register value = a2;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003697 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003698 case EXTERNAL_BYTE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003699 __ srl(t2, key, 1);
3700 __ addu(t3, a3, t2);
3701 __ lb(value, MemOperand(t3, 0));
3702 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003703 case EXTERNAL_PIXEL_ELEMENTS:
3704 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003705 __ srl(t2, key, 1);
3706 __ addu(t3, a3, t2);
3707 __ lbu(value, MemOperand(t3, 0));
3708 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003709 case EXTERNAL_SHORT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003710 __ addu(t3, a3, key);
3711 __ lh(value, MemOperand(t3, 0));
3712 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003713 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003714 __ addu(t3, a3, key);
3715 __ lhu(value, MemOperand(t3, 0));
3716 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003717 case EXTERNAL_INT_ELEMENTS:
3718 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003719 __ sll(t2, key, 1);
3720 __ addu(t3, a3, t2);
3721 __ lw(value, MemOperand(t3, 0));
3722 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003723 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003724 __ sll(t3, t2, 2);
3725 __ addu(t3, a3, t3);
3726 if (CpuFeatures::IsSupported(FPU)) {
3727 CpuFeatures::Scope scope(FPU);
3728 __ lwc1(f0, MemOperand(t3, 0));
3729 } else {
3730 __ lw(value, MemOperand(t3, 0));
3731 }
3732 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003733 case EXTERNAL_DOUBLE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003734 __ sll(t2, key, 2);
3735 __ addu(t3, a3, t2);
3736 if (CpuFeatures::IsSupported(FPU)) {
3737 CpuFeatures::Scope scope(FPU);
3738 __ ldc1(f0, MemOperand(t3, 0));
3739 } else {
3740 // t3: pointer to the beginning of the double we want to load.
3741 __ lw(a2, MemOperand(t3, 0));
3742 __ lw(a3, MemOperand(t3, Register::kSizeInBytes));
3743 }
3744 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003745 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003746 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003747 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003748 case FAST_HOLEY_ELEMENTS:
3749 case FAST_HOLEY_SMI_ELEMENTS:
3750 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003751 case DICTIONARY_ELEMENTS:
3752 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003753 UNREACHABLE();
3754 break;
3755 }
3756
3757 // For integer array types:
3758 // a2: value
3759 // For float array type:
3760 // f0: value (if FPU is supported)
3761 // a2: value (if FPU is not supported)
3762 // For double array type:
3763 // f0: value (if FPU is supported)
3764 // a2/a3: value (if FPU is not supported)
3765
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003766 if (elements_kind == EXTERNAL_INT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003767 // For the Int and UnsignedInt array types, we need to see whether
3768 // the value can be represented in a Smi. If not, we need to convert
3769 // it to a HeapNumber.
3770 Label box_int;
3771 __ Subu(t3, value, Operand(0xC0000000)); // Non-smi value gives neg result.
3772 __ Branch(&box_int, lt, t3, Operand(zero_reg));
3773 // Tag integer as smi and return it.
3774 __ sll(v0, value, kSmiTagSize);
3775 __ Ret();
3776
3777 __ bind(&box_int);
3778 // Allocate a HeapNumber for the result and perform int-to-double
3779 // conversion.
3780 // The arm version uses a temporary here to save r0, but we don't need to
3781 // (a0 is not modified).
3782 __ LoadRoot(t1, Heap::kHeapNumberMapRootIndex);
3783 __ AllocateHeapNumber(v0, a3, t0, t1, &slow);
3784
3785 if (CpuFeatures::IsSupported(FPU)) {
3786 CpuFeatures::Scope scope(FPU);
3787 __ mtc1(value, f0);
3788 __ cvt_d_w(f0, f0);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00003789 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003790 __ Ret();
3791 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003792 Register dst1 = t2;
3793 Register dst2 = t3;
3794 FloatingPointHelper::Destination dest =
3795 FloatingPointHelper::kCoreRegisters;
3796 FloatingPointHelper::ConvertIntToDouble(masm,
3797 value,
3798 dest,
3799 f0,
3800 dst1,
3801 dst2,
3802 t1,
3803 f2);
3804 __ sw(dst1, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3805 __ sw(dst2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3806 __ Ret();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003807 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003808 } else if (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003809 // The test is different for unsigned int values. Since we need
3810 // the value to be in the range of a positive smi, we can't
3811 // handle either of the top two bits being set in the value.
3812 if (CpuFeatures::IsSupported(FPU)) {
3813 CpuFeatures::Scope scope(FPU);
3814 Label pl_box_int;
3815 __ And(t2, value, Operand(0xC0000000));
3816 __ Branch(&pl_box_int, ne, t2, Operand(zero_reg));
3817
3818 // It can fit in an Smi.
3819 // Tag integer as smi and return it.
3820 __ sll(v0, value, kSmiTagSize);
3821 __ Ret();
3822
3823 __ bind(&pl_box_int);
3824 // Allocate a HeapNumber for the result and perform int-to-double
3825 // conversion. Don't use a0 and a1 as AllocateHeapNumber clobbers all
3826 // registers - also when jumping due to exhausted young space.
3827 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3828 __ AllocateHeapNumber(v0, t2, t3, t6, &slow);
3829
3830 // This is replaced by a macro:
3831 // __ mtc1(value, f0); // LS 32-bits.
3832 // __ mtc1(zero_reg, f1); // MS 32-bits are all zero.
3833 // __ cvt_d_l(f0, f0); // Use 64 bit conv to get correct unsigned 32-bit.
3834
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003835 __ Cvt_d_uw(f0, value, f22);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003836
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00003837 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003838
3839 __ Ret();
3840 } else {
3841 // Check whether unsigned integer fits into smi.
3842 Label box_int_0, box_int_1, done;
3843 __ And(t2, value, Operand(0x80000000));
3844 __ Branch(&box_int_0, ne, t2, Operand(zero_reg));
3845 __ And(t2, value, Operand(0x40000000));
3846 __ Branch(&box_int_1, ne, t2, Operand(zero_reg));
3847
3848 // Tag integer as smi and return it.
3849 __ sll(v0, value, kSmiTagSize);
3850 __ Ret();
3851
3852 Register hiword = value; // a2.
3853 Register loword = a3;
3854
3855 __ bind(&box_int_0);
3856 // Integer does not have leading zeros.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003857 GenerateUInt2Double(masm, hiword, loword, t0, 0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003858 __ Branch(&done);
3859
3860 __ bind(&box_int_1);
3861 // Integer has one leading zero.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003862 GenerateUInt2Double(masm, hiword, loword, t0, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003863
3864
3865 __ bind(&done);
3866 // Integer was converted to double in registers hiword:loword.
3867 // Wrap it into a HeapNumber. Don't use a0 and a1 as AllocateHeapNumber
3868 // clobbers all registers - also when jumping due to exhausted young
3869 // space.
3870 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3871 __ AllocateHeapNumber(t2, t3, t5, t6, &slow);
3872
3873 __ sw(hiword, FieldMemOperand(t2, HeapNumber::kExponentOffset));
3874 __ sw(loword, FieldMemOperand(t2, HeapNumber::kMantissaOffset));
3875
3876 __ mov(v0, t2);
3877 __ Ret();
3878 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003879 } else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003880 // For the floating-point array type, we need to always allocate a
3881 // HeapNumber.
3882 if (CpuFeatures::IsSupported(FPU)) {
3883 CpuFeatures::Scope scope(FPU);
3884 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3885 // AllocateHeapNumber clobbers all registers - also when jumping due to
3886 // exhausted young space.
3887 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3888 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3889 // The float (single) value is already in fpu reg f0 (if we use float).
3890 __ cvt_d_s(f0, f0);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00003891 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003892 __ Ret();
3893 } else {
3894 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3895 // AllocateHeapNumber clobbers all registers - also when jumping due to
3896 // exhausted young space.
3897 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3898 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3899 // FPU is not available, do manual single to double conversion.
3900
3901 // a2: floating point value (binary32).
3902 // v0: heap number for result
3903
3904 // Extract mantissa to t4.
3905 __ And(t4, value, Operand(kBinary32MantissaMask));
3906
3907 // Extract exponent to t5.
3908 __ srl(t5, value, kBinary32MantissaBits);
3909 __ And(t5, t5, Operand(kBinary32ExponentMask >> kBinary32MantissaBits));
3910
3911 Label exponent_rebiased;
3912 __ Branch(&exponent_rebiased, eq, t5, Operand(zero_reg));
3913
3914 __ li(t0, 0x7ff);
3915 __ Xor(t1, t5, Operand(0xFF));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003916 __ Movz(t5, t0, t1); // Set t5 to 0x7ff only if t5 is equal to 0xff.
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003917 __ Branch(&exponent_rebiased, eq, t1, Operand(zero_reg));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003918
3919 // Rebias exponent.
3920 __ Addu(t5,
3921 t5,
3922 Operand(-kBinary32ExponentBias + HeapNumber::kExponentBias));
3923
3924 __ bind(&exponent_rebiased);
3925 __ And(a2, value, Operand(kBinary32SignMask));
3926 value = no_reg;
3927 __ sll(t0, t5, HeapNumber::kMantissaBitsInTopWord);
3928 __ or_(a2, a2, t0);
3929
3930 // Shift mantissa.
3931 static const int kMantissaShiftForHiWord =
3932 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3933
3934 static const int kMantissaShiftForLoWord =
3935 kBitsPerInt - kMantissaShiftForHiWord;
3936
3937 __ srl(t0, t4, kMantissaShiftForHiWord);
3938 __ or_(a2, a2, t0);
3939 __ sll(a0, t4, kMantissaShiftForLoWord);
3940
3941 __ sw(a2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3942 __ sw(a0, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3943 __ Ret();
3944 }
3945
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003946 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003947 if (CpuFeatures::IsSupported(FPU)) {
3948 CpuFeatures::Scope scope(FPU);
3949 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3950 // AllocateHeapNumber clobbers all registers - also when jumping due to
3951 // exhausted young space.
3952 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3953 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3954 // The double value is already in f0
3955 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
3956 __ Ret();
3957 } else {
3958 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3959 // AllocateHeapNumber clobbers all registers - also when jumping due to
3960 // exhausted young space.
3961 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3962 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3963
3964 __ sw(a2, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3965 __ sw(a3, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3966 __ Ret();
3967 }
3968
3969 } else {
3970 // Tag integer as smi and return it.
3971 __ sll(v0, value, kSmiTagSize);
3972 __ Ret();
3973 }
3974
3975 // Slow case, key and receiver still in a0 and a1.
3976 __ bind(&slow);
3977 __ IncrementCounter(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003978 masm->isolate()->counters()->keyed_load_external_array_slow(),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003979 1, a2, a3);
3980
3981 // ---------- S t a t e --------------
3982 // -- ra : return address
3983 // -- a0 : key
3984 // -- a1 : receiver
3985 // -----------------------------------
3986
3987 __ Push(a1, a0);
3988
3989 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
3990
danno@chromium.org40cb8782011-05-25 07:58:50 +00003991 __ bind(&miss_force_generic);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003992 Handle<Code> stub =
3993 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3994 __ Jump(stub, RelocInfo::CODE_TARGET);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003995}
3996
3997
danno@chromium.org40cb8782011-05-25 07:58:50 +00003998void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3999 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004000 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004001 // ---------- S t a t e --------------
4002 // -- a0 : value
4003 // -- a1 : key
4004 // -- a2 : receiver
4005 // -- ra : return address
4006 // -----------------------------------
4007
danno@chromium.org40cb8782011-05-25 07:58:50 +00004008 Label slow, check_heap_number, miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004009
4010 // Register usage.
4011 Register value = a0;
4012 Register key = a1;
4013 Register receiver = a2;
4014 // a3 mostly holds the elements array or the destination external array.
4015
danno@chromium.org40cb8782011-05-25 07:58:50 +00004016 // This stub is meant to be tail-jumped to, the receiver must already
4017 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004018
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004019 // Check that the key is a smi or a heap number convertible to a smi.
4020 GenerateSmiKeyCheck(masm, key, t0, t1, f2, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004021
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004022 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
4023
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004024 // Check that the index is in range.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004025 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
4026 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004027 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004028
4029 // Handle both smis and HeapNumbers in the fast path. Go to the
4030 // runtime for all other kinds of values.
4031 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004032
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004033 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004034 // Double to pixel conversion is only implemented in the runtime for now.
4035 __ JumpIfNotSmi(value, &slow);
4036 } else {
4037 __ JumpIfNotSmi(value, &check_heap_number);
4038 }
4039 __ SmiUntag(t1, value);
4040 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
4041
4042 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004043 // t1: value (integer).
4044
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004045 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004046 case EXTERNAL_PIXEL_ELEMENTS: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004047 // Clamp the value to [0..255].
4048 // v0 is used as a scratch register here.
4049 Label done;
4050 __ li(v0, Operand(255));
4051 // Normal branch: nop in delay slot.
4052 __ Branch(&done, gt, t1, Operand(v0));
4053 // Use delay slot in this branch.
4054 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg));
4055 __ mov(v0, zero_reg); // In delay slot.
4056 __ mov(v0, t1); // Value is in range 0..255.
4057 __ bind(&done);
4058 __ mov(t1, v0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004059
4060 __ srl(t8, key, 1);
4061 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004062 __ sb(t1, MemOperand(t8, 0));
4063 }
4064 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004065 case EXTERNAL_BYTE_ELEMENTS:
4066 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004067 __ srl(t8, key, 1);
4068 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004069 __ sb(t1, MemOperand(t8, 0));
4070 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004071 case EXTERNAL_SHORT_ELEMENTS:
4072 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004073 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004074 __ sh(t1, MemOperand(t8, 0));
4075 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004076 case EXTERNAL_INT_ELEMENTS:
4077 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004078 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004079 __ addu(t8, a3, t8);
4080 __ sw(t1, MemOperand(t8, 0));
4081 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004082 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004083 // Perform int-to-float conversion and store to memory.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004084 __ SmiUntag(t0, key);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004085 StoreIntAsFloat(masm, a3, t0, t1, t2, t3, t4);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004086 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004087 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004088 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004089 __ addu(a3, a3, t8);
4090 // a3: effective address of the double element
4091 FloatingPointHelper::Destination destination;
4092 if (CpuFeatures::IsSupported(FPU)) {
4093 destination = FloatingPointHelper::kFPURegisters;
4094 } else {
4095 destination = FloatingPointHelper::kCoreRegisters;
4096 }
4097 FloatingPointHelper::ConvertIntToDouble(
danno@chromium.org40cb8782011-05-25 07:58:50 +00004098 masm, t1, destination,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004099 f0, t2, t3, // These are: double_dst, dst1, dst2.
4100 t0, f2); // These are: scratch2, single_scratch.
4101 if (destination == FloatingPointHelper::kFPURegisters) {
4102 CpuFeatures::Scope scope(FPU);
4103 __ sdc1(f0, MemOperand(a3, 0));
4104 } else {
4105 __ sw(t2, MemOperand(a3, 0));
4106 __ sw(t3, MemOperand(a3, Register::kSizeInBytes));
4107 }
4108 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004109 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004110 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004111 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004112 case FAST_HOLEY_ELEMENTS:
4113 case FAST_HOLEY_SMI_ELEMENTS:
4114 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004115 case DICTIONARY_ELEMENTS:
4116 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004117 UNREACHABLE();
4118 break;
4119 }
4120
4121 // Entry registers are intact, a0 holds the value which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004122 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004123 __ Ret();
4124
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004125 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004126 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004127 __ bind(&check_heap_number);
4128 __ GetObjectType(value, t1, t2);
4129 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE));
4130
4131 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
4132
4133 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004134
4135 // The WebGL specification leaves the behavior of storing NaN and
4136 // +/-Infinity into integer arrays basically undefined. For more
4137 // reproducible behavior, convert these to zero.
4138
4139 if (CpuFeatures::IsSupported(FPU)) {
4140 CpuFeatures::Scope scope(FPU);
4141
4142 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
4143
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004144 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004145 __ cvt_s_d(f0, f0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004146 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004147 __ addu(t8, a3, t8);
4148 __ swc1(f0, MemOperand(t8, 0));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004149 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004150 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004151 __ addu(t8, a3, t8);
4152 __ sdc1(f0, MemOperand(t8, 0));
4153 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00004154 __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004155
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004156 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004157 case EXTERNAL_BYTE_ELEMENTS:
4158 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004159 __ srl(t8, key, 1);
4160 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004161 __ sb(t3, MemOperand(t8, 0));
4162 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004163 case EXTERNAL_SHORT_ELEMENTS:
4164 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004165 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004166 __ sh(t3, MemOperand(t8, 0));
4167 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004168 case EXTERNAL_INT_ELEMENTS:
4169 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004170 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004171 __ addu(t8, a3, t8);
4172 __ sw(t3, MemOperand(t8, 0));
4173 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004174 case EXTERNAL_PIXEL_ELEMENTS:
4175 case EXTERNAL_FLOAT_ELEMENTS:
4176 case EXTERNAL_DOUBLE_ELEMENTS:
4177 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004178 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004179 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004180 case FAST_HOLEY_ELEMENTS:
4181 case FAST_HOLEY_SMI_ELEMENTS:
4182 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004183 case DICTIONARY_ELEMENTS:
4184 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004185 UNREACHABLE();
4186 break;
4187 }
4188 }
4189
4190 // Entry registers are intact, a0 holds the value
4191 // which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004192 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004193 __ Ret();
4194 } else {
4195 // FPU is not available, do manual conversions.
4196
4197 __ lw(t3, FieldMemOperand(value, HeapNumber::kExponentOffset));
4198 __ lw(t4, FieldMemOperand(value, HeapNumber::kMantissaOffset));
4199
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004200 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004201 Label done, nan_or_infinity_or_zero;
4202 static const int kMantissaInHiWordShift =
4203 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
4204
4205 static const int kMantissaInLoWordShift =
4206 kBitsPerInt - kMantissaInHiWordShift;
4207
4208 // Test for all special exponent values: zeros, subnormal numbers, NaNs
4209 // and infinities. All these should be converted to 0.
4210 __ li(t5, HeapNumber::kExponentMask);
4211 __ and_(t6, t3, t5);
4212 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(zero_reg));
4213
4214 __ xor_(t1, t6, t5);
4215 __ li(t2, kBinary32ExponentMask);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004216 __ Movz(t6, t2, t1); // Only if t6 is equal to t5.
rossberg@chromium.org400388e2012-06-06 09:29:22 +00004217 __ Branch(&nan_or_infinity_or_zero, eq, t1, Operand(zero_reg));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004218
4219 // Rebias exponent.
4220 __ srl(t6, t6, HeapNumber::kExponentShift);
4221 __ Addu(t6,
4222 t6,
4223 Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
4224
4225 __ li(t1, Operand(kBinary32MaxExponent));
4226 __ Slt(t1, t1, t6);
4227 __ And(t2, t3, Operand(HeapNumber::kSignMask));
4228 __ Or(t2, t2, Operand(kBinary32ExponentMask));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004229 __ Movn(t3, t2, t1); // Only if t6 is gt kBinary32MaxExponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004230 __ Branch(&done, gt, t6, Operand(kBinary32MaxExponent));
4231
4232 __ Slt(t1, t6, Operand(kBinary32MinExponent));
4233 __ And(t2, t3, Operand(HeapNumber::kSignMask));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004234 __ Movn(t3, t2, t1); // Only if t6 is lt kBinary32MinExponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004235 __ Branch(&done, lt, t6, Operand(kBinary32MinExponent));
4236
4237 __ And(t7, t3, Operand(HeapNumber::kSignMask));
4238 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4239 __ sll(t3, t3, kMantissaInHiWordShift);
4240 __ or_(t7, t7, t3);
4241 __ srl(t4, t4, kMantissaInLoWordShift);
4242 __ or_(t7, t7, t4);
4243 __ sll(t6, t6, kBinary32ExponentShift);
4244 __ or_(t3, t7, t6);
4245
4246 __ bind(&done);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004247 __ sll(t9, key, 1);
rossberg@chromium.org400388e2012-06-06 09:29:22 +00004248 __ addu(t9, a3, t9);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004249 __ sw(t3, MemOperand(t9, 0));
4250
4251 // Entry registers are intact, a0 holds the value which is the return
4252 // value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004253 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004254 __ Ret();
4255
4256 __ bind(&nan_or_infinity_or_zero);
4257 __ And(t7, t3, Operand(HeapNumber::kSignMask));
4258 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4259 __ or_(t6, t6, t7);
4260 __ sll(t3, t3, kMantissaInHiWordShift);
4261 __ or_(t6, t6, t3);
4262 __ srl(t4, t4, kMantissaInLoWordShift);
4263 __ or_(t3, t6, t4);
4264 __ Branch(&done);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004265 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00004266 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004267 __ addu(t8, a3, t8);
4268 // t8: effective address of destination element.
4269 __ sw(t4, MemOperand(t8, 0));
4270 __ sw(t3, MemOperand(t8, Register::kSizeInBytes));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004271 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004272 __ Ret();
4273 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004274 bool is_signed_type = IsElementTypeSigned(elements_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004275 int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
4276 int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
4277
4278 Label done, sign;
4279
4280 // Test for all special exponent values: zeros, subnormal numbers, NaNs
4281 // and infinities. All these should be converted to 0.
4282 __ li(t5, HeapNumber::kExponentMask);
4283 __ and_(t6, t3, t5);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004284 __ Movz(t3, zero_reg, t6); // Only if t6 is equal to zero.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004285 __ Branch(&done, eq, t6, Operand(zero_reg));
4286
4287 __ xor_(t2, t6, t5);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004288 __ Movz(t3, zero_reg, t2); // Only if t6 is equal to t5.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004289 __ Branch(&done, eq, t6, Operand(t5));
4290
4291 // Unbias exponent.
4292 __ srl(t6, t6, HeapNumber::kExponentShift);
4293 __ Subu(t6, t6, Operand(HeapNumber::kExponentBias));
4294 // If exponent is negative then result is 0.
4295 __ slt(t2, t6, zero_reg);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004296 __ Movn(t3, zero_reg, t2); // Only if exponent is negative.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004297 __ Branch(&done, lt, t6, Operand(zero_reg));
4298
4299 // If exponent is too big then result is minimal value.
4300 __ slti(t1, t6, meaningfull_bits - 1);
4301 __ li(t2, min_value);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004302 __ Movz(t3, t2, t1); // Only if t6 is ge meaningfull_bits - 1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004303 __ Branch(&done, ge, t6, Operand(meaningfull_bits - 1));
4304
4305 __ And(t5, t3, Operand(HeapNumber::kSignMask));
4306 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4307 __ Or(t3, t3, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
4308
4309 __ li(t9, HeapNumber::kMantissaBitsInTopWord);
4310 __ subu(t6, t9, t6);
4311 __ slt(t1, t6, zero_reg);
4312 __ srlv(t2, t3, t6);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004313 __ Movz(t3, t2, t1); // Only if t6 is positive.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004314 __ Branch(&sign, ge, t6, Operand(zero_reg));
4315
4316 __ subu(t6, zero_reg, t6);
4317 __ sllv(t3, t3, t6);
4318 __ li(t9, meaningfull_bits);
4319 __ subu(t6, t9, t6);
4320 __ srlv(t4, t4, t6);
4321 __ or_(t3, t3, t4);
4322
4323 __ bind(&sign);
4324 __ subu(t2, t3, zero_reg);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004325 __ Movz(t3, t2, t5); // Only if t5 is zero.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004326
4327 __ bind(&done);
4328
4329 // Result is in t3.
4330 // This switch block should be exactly the same as above (FPU mode).
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004331 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004332 case EXTERNAL_BYTE_ELEMENTS:
4333 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004334 __ srl(t8, key, 1);
4335 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004336 __ sb(t3, MemOperand(t8, 0));
4337 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004338 case EXTERNAL_SHORT_ELEMENTS:
4339 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004340 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004341 __ sh(t3, MemOperand(t8, 0));
4342 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004343 case EXTERNAL_INT_ELEMENTS:
4344 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004345 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004346 __ addu(t8, a3, t8);
4347 __ sw(t3, MemOperand(t8, 0));
4348 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004349 case EXTERNAL_PIXEL_ELEMENTS:
4350 case EXTERNAL_FLOAT_ELEMENTS:
4351 case EXTERNAL_DOUBLE_ELEMENTS:
4352 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004353 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004354 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004355 case FAST_HOLEY_ELEMENTS:
4356 case FAST_HOLEY_SMI_ELEMENTS:
4357 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004358 case DICTIONARY_ELEMENTS:
4359 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004360 UNREACHABLE();
4361 break;
4362 }
4363 }
4364 }
4365 }
4366
danno@chromium.org40cb8782011-05-25 07:58:50 +00004367 // Slow case, key and receiver still in a0 and a1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004368 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004369 __ IncrementCounter(
4370 masm->isolate()->counters()->keyed_load_external_array_slow(),
4371 1, a2, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004372 // Entry registers are intact.
4373 // ---------- S t a t e --------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004374 // -- ra : return address
danno@chromium.org40cb8782011-05-25 07:58:50 +00004375 // -- a0 : key
4376 // -- a1 : receiver
4377 // -----------------------------------
4378 Handle<Code> slow_ic =
4379 masm->isolate()->builtins()->KeyedStoreIC_Slow();
4380 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4381
4382 // Miss case, call the runtime.
4383 __ bind(&miss_force_generic);
4384
4385 // ---------- S t a t e --------------
4386 // -- ra : return address
4387 // -- a0 : key
4388 // -- a1 : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004389 // -----------------------------------
4390
danno@chromium.org40cb8782011-05-25 07:58:50 +00004391 Handle<Code> miss_ic =
4392 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4393 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
4394}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004395
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004396
danno@chromium.org40cb8782011-05-25 07:58:50 +00004397void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
4398 // ----------- S t a t e -------------
4399 // -- ra : return address
4400 // -- a0 : key
4401 // -- a1 : receiver
4402 // -----------------------------------
4403 Label miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004404
danno@chromium.org40cb8782011-05-25 07:58:50 +00004405 // This stub is meant to be tail-jumped to, the receiver must already
4406 // have been verified by the caller to not be a smi.
4407
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004408 // Check that the key is a smi or a heap number convertible to a smi.
4409 GenerateSmiKeyCheck(masm, a0, t0, t1, f2, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004410
4411 // Get the elements array.
4412 __ lw(a2, FieldMemOperand(a1, JSObject::kElementsOffset));
4413 __ AssertFastElements(a2);
4414
4415 // Check that the key is within bounds.
4416 __ lw(a3, FieldMemOperand(a2, FixedArray::kLengthOffset));
ulan@chromium.org6ff65142012-03-21 09:52:17 +00004417 __ Branch(USE_DELAY_SLOT, &miss_force_generic, hs, a0, Operand(a3));
danno@chromium.org40cb8782011-05-25 07:58:50 +00004418
4419 // Load the result and make sure it's not the hole.
4420 __ Addu(a3, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004421 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004422 __ sll(t0, a0, kPointerSizeLog2 - kSmiTagSize);
4423 __ Addu(t0, t0, a3);
4424 __ lw(t0, MemOperand(t0));
4425 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
4426 __ Branch(&miss_force_generic, eq, t0, Operand(t1));
ulan@chromium.org6ff65142012-03-21 09:52:17 +00004427 __ Ret(USE_DELAY_SLOT);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004428 __ mov(v0, t0);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004429
4430 __ bind(&miss_force_generic);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004431 Handle<Code> stub =
4432 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4433 __ Jump(stub, RelocInfo::CODE_TARGET);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004434}
4435
4436
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004437void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
4438 MacroAssembler* masm) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004439 // ----------- S t a t e -------------
4440 // -- ra : return address
4441 // -- a0 : key
4442 // -- a1 : receiver
4443 // -----------------------------------
4444 Label miss_force_generic, slow_allocate_heapnumber;
4445
4446 Register key_reg = a0;
4447 Register receiver_reg = a1;
4448 Register elements_reg = a2;
4449 Register heap_number_reg = a2;
4450 Register indexed_double_offset = a3;
4451 Register scratch = t0;
4452 Register scratch2 = t1;
4453 Register scratch3 = t2;
4454 Register heap_number_map = t3;
4455
4456 // This stub is meant to be tail-jumped to, the receiver must already
4457 // have been verified by the caller to not be a smi.
4458
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004459 // Check that the key is a smi or a heap number convertible to a smi.
4460 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004461
4462 // Get the elements array.
4463 __ lw(elements_reg,
4464 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4465
4466 // Check that the key is within bounds.
4467 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4468 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4469
4470 // Load the upper word of the double in the fixed array and test for NaN.
4471 __ sll(scratch2, key_reg, kDoubleSizeLog2 - kSmiTagSize);
4472 __ Addu(indexed_double_offset, elements_reg, Operand(scratch2));
4473 uint32_t upper_32_offset = FixedArray::kHeaderSize + sizeof(kHoleNanLower32);
4474 __ lw(scratch, FieldMemOperand(indexed_double_offset, upper_32_offset));
4475 __ Branch(&miss_force_generic, eq, scratch, Operand(kHoleNanUpper32));
4476
4477 // Non-NaN. Allocate a new heap number and copy the double value into it.
4478 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
4479 __ AllocateHeapNumber(heap_number_reg, scratch2, scratch3,
4480 heap_number_map, &slow_allocate_heapnumber);
4481
4482 // Don't need to reload the upper 32 bits of the double, it's already in
4483 // scratch.
4484 __ sw(scratch, FieldMemOperand(heap_number_reg,
4485 HeapNumber::kExponentOffset));
4486 __ lw(scratch, FieldMemOperand(indexed_double_offset,
4487 FixedArray::kHeaderSize));
4488 __ sw(scratch, FieldMemOperand(heap_number_reg,
4489 HeapNumber::kMantissaOffset));
4490
4491 __ mov(v0, heap_number_reg);
4492 __ Ret();
4493
4494 __ bind(&slow_allocate_heapnumber);
4495 Handle<Code> slow_ic =
4496 masm->isolate()->builtins()->KeyedLoadIC_Slow();
4497 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4498
4499 __ bind(&miss_force_generic);
4500 Handle<Code> miss_ic =
4501 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4502 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004503}
4504
4505
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004506void KeyedStoreStubCompiler::GenerateStoreFastElement(
4507 MacroAssembler* masm,
4508 bool is_js_array,
yangguo@chromium.org56454712012-02-16 15:33:53 +00004509 ElementsKind elements_kind,
4510 KeyedAccessGrowMode grow_mode) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00004511 // ----------- S t a t e -------------
4512 // -- a0 : value
4513 // -- a1 : key
4514 // -- a2 : receiver
4515 // -- ra : return address
4516 // -- a3 : scratch
4517 // -- a4 : scratch (elements)
4518 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00004519 Label miss_force_generic, transition_elements_kind, grow, slow;
4520 Label finish_store, check_capacity;
danno@chromium.org40cb8782011-05-25 07:58:50 +00004521
4522 Register value_reg = a0;
4523 Register key_reg = a1;
4524 Register receiver_reg = a2;
yangguo@chromium.org56454712012-02-16 15:33:53 +00004525 Register scratch = t0;
4526 Register elements_reg = a3;
4527 Register length_reg = t1;
4528 Register scratch2 = t2;
danno@chromium.org40cb8782011-05-25 07:58:50 +00004529
4530 // This stub is meant to be tail-jumped to, the receiver must already
4531 // have been verified by the caller to not be a smi.
4532
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004533 // Check that the key is a smi or a heap number convertible to a smi.
4534 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004535
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004536 if (IsFastSmiElementsKind(elements_kind)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00004537 __ JumpIfNotSmi(value_reg, &transition_elements_kind);
4538 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004539
4540 // Check that the key is within bounds.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004541 __ lw(elements_reg,
4542 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00004543 if (is_js_array) {
4544 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4545 } else {
4546 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4547 }
4548 // Compare smis.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004549 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4550 __ Branch(&grow, hs, key_reg, Operand(scratch));
4551 } else {
4552 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4553 }
4554
4555 // Make sure elements is a fast element array, not 'cow'.
4556 __ CheckMap(elements_reg,
4557 scratch,
4558 Heap::kFixedArrayMapRootIndex,
4559 &miss_force_generic,
4560 DONT_DO_SMI_CHECK);
4561
4562 __ bind(&finish_store);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004563
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004564 if (IsFastSmiElementsKind(elements_kind)) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004565 __ Addu(scratch,
4566 elements_reg,
4567 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4568 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4569 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4570 __ Addu(scratch, scratch, scratch2);
4571 __ sw(value_reg, MemOperand(scratch));
4572 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004573 ASSERT(IsFastObjectElementsKind(elements_kind));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004574 __ Addu(scratch,
4575 elements_reg,
4576 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4577 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4578 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4579 __ Addu(scratch, scratch, scratch2);
4580 __ sw(value_reg, MemOperand(scratch));
4581 __ mov(receiver_reg, value_reg);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004582 __ RecordWrite(elements_reg, // Object.
4583 scratch, // Address.
4584 receiver_reg, // Value.
4585 kRAHasNotBeenSaved,
4586 kDontSaveFPRegs);
4587 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004588 // value_reg (a0) is preserved.
4589 // Done.
4590 __ Ret();
4591
4592 __ bind(&miss_force_generic);
4593 Handle<Code> ic =
4594 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4595 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004596
4597 __ bind(&transition_elements_kind);
4598 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4599 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
yangguo@chromium.org56454712012-02-16 15:33:53 +00004600
4601 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4602 // Grow the array by a single element if possible.
4603 __ bind(&grow);
4604
4605 // Make sure the array is only growing by a single element, anything else
4606 // must be handled by the runtime.
4607 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch));
4608
4609 // Check for the empty array, and preallocate a small backing store if
4610 // possible.
4611 __ lw(length_reg,
4612 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4613 __ lw(elements_reg,
4614 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4615 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
4616 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
4617
4618 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
4619 __ AllocateInNewSpace(size, elements_reg, scratch, scratch2, &slow,
4620 TAG_OBJECT);
4621
4622 __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex);
4623 __ sw(scratch, FieldMemOperand(elements_reg, JSObject::kMapOffset));
4624 __ li(scratch, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4625 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4626 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
4627 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
4628 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::SizeFor(i)));
4629 }
4630
4631 // Store the element at index zero.
4632 __ sw(value_reg, FieldMemOperand(elements_reg, FixedArray::SizeFor(0)));
4633
4634 // Install the new backing store in the JSArray.
4635 __ sw(elements_reg,
4636 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4637 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
4638 scratch, kRAHasNotBeenSaved, kDontSaveFPRegs,
4639 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4640
4641 // Increment the length of the array.
4642 __ li(length_reg, Operand(Smi::FromInt(1)));
4643 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4644 __ Ret();
4645
4646 __ bind(&check_capacity);
4647 // Check for cow elements, in general they are not handled by this stub
4648 __ CheckMap(elements_reg,
4649 scratch,
4650 Heap::kFixedCOWArrayMapRootIndex,
4651 &miss_force_generic,
4652 DONT_DO_SMI_CHECK);
4653
4654 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4655 __ Branch(&slow, hs, length_reg, Operand(scratch));
4656
4657 // Grow the array and finish the store.
4658 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
4659 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4660 __ jmp(&finish_store);
4661
4662 __ bind(&slow);
4663 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4664 __ Jump(ic_slow, RelocInfo::CODE_TARGET);
4665 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004666}
4667
4668
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004669void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
4670 MacroAssembler* masm,
yangguo@chromium.org56454712012-02-16 15:33:53 +00004671 bool is_js_array,
4672 KeyedAccessGrowMode grow_mode) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004673 // ----------- S t a t e -------------
4674 // -- a0 : value
4675 // -- a1 : key
4676 // -- a2 : receiver
4677 // -- ra : return address
4678 // -- a3 : scratch
4679 // -- t0 : scratch (elements_reg)
4680 // -- t1 : scratch (mantissa_reg)
4681 // -- t2 : scratch (exponent_reg)
4682 // -- t3 : scratch4
4683 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00004684 Label miss_force_generic, transition_elements_kind, grow, slow;
4685 Label finish_store, check_capacity;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004686
4687 Register value_reg = a0;
4688 Register key_reg = a1;
4689 Register receiver_reg = a2;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004690 Register elements_reg = a3;
4691 Register scratch1 = t0;
4692 Register scratch2 = t1;
4693 Register scratch3 = t2;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004694 Register scratch4 = t3;
yangguo@chromium.org56454712012-02-16 15:33:53 +00004695 Register length_reg = t3;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004696
4697 // This stub is meant to be tail-jumped to, the receiver must already
4698 // have been verified by the caller to not be a smi.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004699
4700 // Check that the key is a smi or a heap number convertible to a smi.
4701 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004702
4703 __ lw(elements_reg,
4704 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4705
4706 // Check that the key is within bounds.
4707 if (is_js_array) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004708 __ lw(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004709 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004710 __ lw(scratch1,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004711 FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4712 }
4713 // Compare smis, unsigned compare catches both negative and out-of-bound
4714 // indexes.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004715 if (grow_mode == ALLOW_JSARRAY_GROWTH) {
4716 __ Branch(&grow, hs, key_reg, Operand(scratch1));
4717 } else {
4718 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch1));
4719 }
4720
4721 __ bind(&finish_store);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004722
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004723 __ StoreNumberToDoubleElements(value_reg,
4724 key_reg,
4725 receiver_reg,
4726 elements_reg,
4727 scratch1,
4728 scratch2,
4729 scratch3,
4730 scratch4,
4731 &transition_elements_kind);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004732
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004733 __ Ret(USE_DELAY_SLOT);
4734 __ mov(v0, value_reg); // In delay slot.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004735
4736 // Handle store cache miss, replacing the ic with the generic stub.
4737 __ bind(&miss_force_generic);
4738 Handle<Code> ic =
4739 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4740 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004741
4742 __ bind(&transition_elements_kind);
4743 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4744 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
yangguo@chromium.org56454712012-02-16 15:33:53 +00004745
4746 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4747 // Grow the array by a single element if possible.
4748 __ bind(&grow);
4749
4750 // Make sure the array is only growing by a single element, anything else
4751 // must be handled by the runtime.
4752 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch1));
4753
4754 // Transition on values that can't be stored in a FixedDoubleArray.
4755 Label value_is_smi;
4756 __ JumpIfSmi(value_reg, &value_is_smi);
4757 __ lw(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
4758 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
4759 __ Branch(&transition_elements_kind, ne, scratch1, Operand(at));
4760 __ bind(&value_is_smi);
4761
4762 // Check for the empty array, and preallocate a small backing store if
4763 // possible.
4764 __ lw(length_reg,
4765 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4766 __ lw(elements_reg,
4767 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4768 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
4769 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
4770
4771 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
4772 __ AllocateInNewSpace(size, elements_reg, scratch1, scratch2, &slow,
4773 TAG_OBJECT);
4774
4775 // Initialize the new FixedDoubleArray. Leave elements unitialized for
4776 // efficiency, they are guaranteed to be initialized before use.
4777 __ LoadRoot(scratch1, Heap::kFixedDoubleArrayMapRootIndex);
4778 __ sw(scratch1, FieldMemOperand(elements_reg, JSObject::kMapOffset));
4779 __ li(scratch1, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4780 __ sw(scratch1,
4781 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
4782
4783 // Install the new backing store in the JSArray.
4784 __ sw(elements_reg,
4785 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4786 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
4787 scratch1, kRAHasNotBeenSaved, kDontSaveFPRegs,
4788 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4789
4790 // Increment the length of the array.
4791 __ li(length_reg, Operand(Smi::FromInt(1)));
4792 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
danno@chromium.org00379b82012-05-04 09:16:29 +00004793 __ lw(elements_reg,
4794 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
yangguo@chromium.org56454712012-02-16 15:33:53 +00004795 __ jmp(&finish_store);
4796
4797 __ bind(&check_capacity);
4798 // Make sure that the backing store can hold additional elements.
4799 __ lw(scratch1,
4800 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
4801 __ Branch(&slow, hs, length_reg, Operand(scratch1));
4802
4803 // Grow the array and finish the store.
4804 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
4805 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4806 __ jmp(&finish_store);
4807
4808 __ bind(&slow);
4809 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4810 __ Jump(ic_slow, RelocInfo::CODE_TARGET);
4811 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004812}
4813
4814
ager@chromium.org5c838252010-02-19 08:53:10 +00004815#undef __
4816
4817} } // namespace v8::internal
4818
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004819#endif // V8_TARGET_ARCH_MIPS