blob: afa2bfdd3763bc3ddd0c32a3e899a4dcb9a3b0c2 [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(
2679 Handle<JSObject> object,
2680 Handle<AccessorInfo> callback,
2681 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002682 // ----------- S t a t e -------------
2683 // -- a0 : value
2684 // -- a1 : receiver
2685 // -- a2 : name
2686 // -- ra : return address
2687 // -----------------------------------
2688 Label miss;
2689
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002690 // Check that the map of the object hasn't changed.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002691 __ CheckMap(a1, a3, Handle<Map>(object->map()), &miss,
2692 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002693
2694 // Perform global security token check if needed.
2695 if (object->IsJSGlobalProxy()) {
2696 __ CheckAccessGlobalProxy(a1, a3, &miss);
2697 }
2698
2699 // Stub never generated for non-global objects that require access
2700 // checks.
2701 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
2702
2703 __ push(a1); // Receiver.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002704 __ li(a3, Operand(callback)); // Callback info.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002705 __ Push(a3, a2, a0);
2706
2707 // Do tail-call to the runtime system.
2708 ExternalReference store_callback_property =
2709 ExternalReference(IC_Utility(IC::kStoreCallbackProperty),
2710 masm()->isolate());
2711 __ TailCallExternalReference(store_callback_property, 4, 1);
2712
2713 // Handle store cache miss.
2714 __ bind(&miss);
2715 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2716 __ Jump(ic, RelocInfo::CODE_TARGET);
2717
2718 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002719 return GetCode(Code::CALLBACKS, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002720}
2721
2722
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002723#undef __
2724#define __ ACCESS_MASM(masm)
2725
2726
2727void StoreStubCompiler::GenerateStoreViaSetter(
2728 MacroAssembler* masm,
2729 Handle<JSFunction> setter) {
2730 // ----------- S t a t e -------------
2731 // -- a0 : value
2732 // -- a1 : receiver
2733 // -- a2 : name
2734 // -- ra : return address
2735 // -----------------------------------
2736 {
2737 FrameScope scope(masm, StackFrame::INTERNAL);
2738
2739 // Save value register, so we can restore it later.
2740 __ push(a0);
2741
2742 if (!setter.is_null()) {
2743 // Call the JavaScript setter with receiver and value on the stack.
2744 __ push(a1);
2745 __ push(a0);
2746 ParameterCount actual(1);
2747 __ InvokeFunction(setter, actual, CALL_FUNCTION, NullCallWrapper(),
2748 CALL_AS_METHOD);
2749 } else {
2750 // If we generate a global code snippet for deoptimization only, remember
2751 // the place to continue after deoptimization.
2752 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2753 }
2754
2755 // We have to return the passed value, not the return value of the setter.
2756 __ pop(v0);
2757
2758 // Restore context register.
2759 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2760 }
2761 __ Ret();
2762}
2763
2764
2765#undef __
2766#define __ ACCESS_MASM(masm())
2767
2768
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002769Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002770 Handle<String> name,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002771 Handle<JSObject> receiver,
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002772 Handle<JSObject> holder,
2773 Handle<JSFunction> setter) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002774 // ----------- S t a t e -------------
2775 // -- a0 : value
2776 // -- a1 : receiver
2777 // -- a2 : name
2778 // -- ra : return address
2779 // -----------------------------------
2780 Label miss;
2781
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002782 // Check that the maps haven't changed.
2783 __ JumpIfSmi(a1, &miss);
2784 CheckPrototypes(receiver, a1, holder, a3, t0, t1, name, &miss);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002785
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002786 GenerateStoreViaSetter(masm(), setter);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002787
2788 __ bind(&miss);
2789 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2790 __ Jump(ic, RelocInfo::CODE_TARGET);
2791
2792 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002793 return GetCode(Code::CALLBACKS, name);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002794}
2795
2796
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002797Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
2798 Handle<JSObject> receiver,
2799 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002800 // ----------- S t a t e -------------
2801 // -- a0 : value
2802 // -- a1 : receiver
2803 // -- a2 : name
2804 // -- ra : return address
2805 // -----------------------------------
2806 Label miss;
2807
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002808 // Check that the map of the object hasn't changed.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002809 __ CheckMap(a1, a3, Handle<Map>(receiver->map()), &miss,
2810 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002811
2812 // Perform global security token check if needed.
2813 if (receiver->IsJSGlobalProxy()) {
2814 __ CheckAccessGlobalProxy(a1, a3, &miss);
2815 }
2816
2817 // Stub is never generated for non-global objects that require access
2818 // checks.
2819 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2820
2821 __ Push(a1, a2, a0); // Receiver, name, value.
2822
2823 __ li(a0, Operand(Smi::FromInt(strict_mode_)));
2824 __ push(a0); // Strict mode.
2825
2826 // Do tail-call to the runtime system.
2827 ExternalReference store_ic_property =
2828 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty),
2829 masm()->isolate());
2830 __ TailCallExternalReference(store_ic_property, 4, 1);
2831
2832 // Handle store cache miss.
2833 __ bind(&miss);
2834 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2835 __ Jump(ic, RelocInfo::CODE_TARGET);
2836
2837 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002838 return GetCode(Code::INTERCEPTOR, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002839}
2840
2841
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002842Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2843 Handle<GlobalObject> object,
2844 Handle<JSGlobalPropertyCell> cell,
2845 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002846 // ----------- S t a t e -------------
2847 // -- a0 : value
2848 // -- a1 : receiver
2849 // -- a2 : name
2850 // -- ra : return address
2851 // -----------------------------------
2852 Label miss;
2853
2854 // Check that the map of the global has not changed.
2855 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2856 __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map())));
2857
2858 // Check that the value in the cell is not the hole. If it is, this
2859 // cell could have been deleted and reintroducing the global needs
2860 // to update the property details in the property dictionary of the
2861 // global object. We bail out to the runtime system to do that.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002862 __ li(t0, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002863 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
2864 __ lw(t2, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2865 __ Branch(&miss, eq, t1, Operand(t2));
2866
2867 // Store the value in the cell.
2868 __ sw(a0, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2869 __ mov(v0, a0); // Stored value must be returned in v0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002870 // Cells are always rescanned, so no write barrier here.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002871
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002872 Counters* counters = masm()->isolate()->counters();
2873 __ IncrementCounter(counters->named_store_global_inline(), 1, a1, a3);
2874 __ Ret();
2875
2876 // Handle store cache miss.
2877 __ bind(&miss);
2878 __ IncrementCounter(counters->named_store_global_inline_miss(), 1, a1, a3);
2879 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2880 __ Jump(ic, RelocInfo::CODE_TARGET);
2881
2882 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002883 return GetCode(Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002884}
2885
2886
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002887Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
2888 Handle<JSObject> object,
2889 Handle<JSObject> last) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002890 // ----------- S t a t e -------------
2891 // -- a0 : receiver
2892 // -- ra : return address
2893 // -----------------------------------
2894 Label miss;
2895
2896 // Check that the receiver is not a smi.
2897 __ JumpIfSmi(a0, &miss);
2898
2899 // Check the maps of the full prototype chain.
2900 CheckPrototypes(object, a0, last, a3, a1, t0, name, &miss);
2901
2902 // If the last object in the prototype chain is a global object,
2903 // check that the global property cell is empty.
2904 if (last->IsGlobalObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002905 GenerateCheckPropertyCell(
2906 masm(), Handle<GlobalObject>::cast(last), name, a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002907 }
2908
2909 // Return undefined if maps of the full prototype chain is still the same.
2910 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2911 __ Ret();
2912
2913 __ bind(&miss);
2914 GenerateLoadMiss(masm(), Code::LOAD_IC);
2915
2916 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002917 return GetCode(Code::NONEXISTENT, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00002918}
2919
2920
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002921Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object,
2922 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002923 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002924 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002925 // ----------- S t a t e -------------
2926 // -- a0 : receiver
2927 // -- a2 : name
2928 // -- ra : return address
2929 // -----------------------------------
2930 Label miss;
2931
2932 __ mov(v0, a0);
2933
2934 GenerateLoadField(object, holder, v0, a3, a1, t0, index, name, &miss);
2935 __ bind(&miss);
2936 GenerateLoadMiss(masm(), Code::LOAD_IC);
2937
2938 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002939 return GetCode(Code::FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002940}
2941
2942
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002943Handle<Code> LoadStubCompiler::CompileLoadCallback(
2944 Handle<String> name,
2945 Handle<JSObject> object,
2946 Handle<JSObject> holder,
2947 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002948 // ----------- S t a t e -------------
2949 // -- a0 : receiver
2950 // -- a2 : name
2951 // -- ra : return address
2952 // -----------------------------------
2953 Label miss;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00002954 GenerateLoadCallback(object, holder, a0, a2, a3, a1, t0, t1, callback, name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002955 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002956 __ bind(&miss);
2957 GenerateLoadMiss(masm(), Code::LOAD_IC);
2958
2959 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002960 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002961}
2962
2963
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002964Handle<Code> LoadStubCompiler::CompileLoadViaGetter(
2965 Handle<String> name,
2966 Handle<JSObject> receiver,
2967 Handle<JSObject> holder,
2968 Handle<JSFunction> getter) {
2969 // ----------- S t a t e -------------
2970 // -- a0 : receiver
2971 // -- a2 : name
2972 // -- ra : return address
2973 // -----------------------------------
2974 Label miss;
2975
2976 // Check that the maps haven't changed.
2977 __ JumpIfSmi(a0, &miss);
2978 CheckPrototypes(receiver, a0, holder, a3, t0, a1, name, &miss);
2979
2980 {
2981 FrameScope scope(masm(), StackFrame::INTERNAL);
2982
2983 // Call the JavaScript getter with the receiver on the stack.
2984 __ push(a0);
2985 ParameterCount actual(0);
2986 __ InvokeFunction(getter, actual, CALL_FUNCTION, NullCallWrapper(),
2987 CALL_AS_METHOD);
2988
2989 // Restore context register.
2990 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2991 }
2992 __ Ret();
2993
2994 __ bind(&miss);
2995 GenerateLoadMiss(masm(), Code::LOAD_IC);
2996
2997 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002998 return GetCode(Code::CALLBACKS, name);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002999}
3000
3001
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003002Handle<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object,
3003 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003004 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003005 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003006 // ----------- S t a t e -------------
3007 // -- a0 : receiver
3008 // -- a2 : name
3009 // -- ra : return address
3010 // -----------------------------------
3011 Label miss;
3012
3013 GenerateLoadConstant(object, holder, a0, a3, a1, t0, value, name, &miss);
3014 __ bind(&miss);
3015 GenerateLoadMiss(masm(), Code::LOAD_IC);
3016
3017 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003018 return GetCode(Code::CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003019}
3020
3021
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003022Handle<Code> LoadStubCompiler::CompileLoadInterceptor(Handle<JSObject> object,
3023 Handle<JSObject> holder,
3024 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003025 // ----------- S t a t e -------------
3026 // -- a0 : receiver
3027 // -- a2 : name
3028 // -- ra : return address
3029 // -- [sp] : receiver
3030 // -----------------------------------
3031 Label miss;
3032
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003033 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003034 LookupPostInterceptor(holder, name, &lookup);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003035 GenerateLoadInterceptor(object, holder, &lookup, a0, a2, a3, a1, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003036 &miss);
3037 __ bind(&miss);
3038 GenerateLoadMiss(masm(), Code::LOAD_IC);
3039
3040 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003041 return GetCode(Code::INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003042}
3043
3044
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003045Handle<Code> LoadStubCompiler::CompileLoadGlobal(
3046 Handle<JSObject> object,
3047 Handle<GlobalObject> holder,
3048 Handle<JSGlobalPropertyCell> cell,
3049 Handle<String> name,
3050 bool is_dont_delete) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003051 // ----------- S t a t e -------------
3052 // -- a0 : receiver
3053 // -- a2 : name
3054 // -- ra : return address
3055 // -----------------------------------
3056 Label miss;
3057
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003058 // Check that the map of the global has not changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003059 __ JumpIfSmi(a0, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003060 CheckPrototypes(object, a0, holder, a3, t0, a1, name, &miss);
3061
3062 // Get the value from the cell.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003063 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003064 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
3065
3066 // Check for deleted property if property can actually be deleted.
3067 if (!is_dont_delete) {
3068 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
3069 __ Branch(&miss, eq, t0, Operand(at));
3070 }
3071
3072 __ mov(v0, t0);
3073 Counters* counters = masm()->isolate()->counters();
3074 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
3075 __ Ret();
3076
3077 __ bind(&miss);
3078 __ IncrementCounter(counters->named_load_global_stub_miss(), 1, a1, a3);
3079 GenerateLoadMiss(masm(), Code::LOAD_IC);
3080
3081 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003082 return GetCode(Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003083}
3084
3085
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003086Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
3087 Handle<JSObject> receiver,
3088 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00003089 int index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003090 // ----------- S t a t e -------------
3091 // -- ra : return address
3092 // -- a0 : key
3093 // -- a1 : receiver
3094 // -----------------------------------
3095 Label miss;
3096
3097 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003098 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003099
3100 GenerateLoadField(receiver, holder, a1, a2, a3, t0, index, name, &miss);
3101 __ bind(&miss);
3102 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3103
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003104 return GetCode(Code::FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003105}
3106
3107
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003108Handle<Code> KeyedLoadStubCompiler::CompileLoadCallback(
3109 Handle<String> name,
3110 Handle<JSObject> receiver,
3111 Handle<JSObject> holder,
3112 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003113 // ----------- S t a t e -------------
3114 // -- ra : return address
3115 // -- a0 : key
3116 // -- a1 : receiver
3117 // -----------------------------------
3118 Label miss;
3119
3120 // Check the key is the cached one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003121 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003122
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00003123 GenerateLoadCallback(receiver, holder, a1, a0, a2, a3, t0, t1, callback,
3124 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003125 __ bind(&miss);
3126 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3127
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003128 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003129}
3130
3131
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003132Handle<Code> KeyedLoadStubCompiler::CompileLoadConstant(
3133 Handle<String> name,
3134 Handle<JSObject> receiver,
3135 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003136 Handle<JSFunction> value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003137 // ----------- S t a t e -------------
3138 // -- ra : return address
3139 // -- a0 : key
3140 // -- a1 : receiver
3141 // -----------------------------------
3142 Label miss;
3143
3144 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003145 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003146
3147 GenerateLoadConstant(receiver, holder, a1, a2, a3, t0, value, name, &miss);
3148 __ bind(&miss);
3149 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3150
3151 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003152 return GetCode(Code::CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003153}
3154
3155
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003156Handle<Code> KeyedLoadStubCompiler::CompileLoadInterceptor(
3157 Handle<JSObject> receiver,
3158 Handle<JSObject> holder,
3159 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003160 // ----------- S t a t e -------------
3161 // -- ra : return address
3162 // -- a0 : key
3163 // -- a1 : receiver
3164 // -----------------------------------
3165 Label miss;
3166
3167 // Check the key is the cached one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003168 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003169
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003170 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003171 LookupPostInterceptor(holder, name, &lookup);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003172 GenerateLoadInterceptor(receiver, holder, &lookup, a1, a0, a2, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003173 &miss);
3174 __ bind(&miss);
3175 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3176
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003177 return GetCode(Code::INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003178}
3179
3180
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003181Handle<Code> KeyedLoadStubCompiler::CompileLoadArrayLength(
3182 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003183 // ----------- S t a t e -------------
3184 // -- ra : return address
3185 // -- a0 : key
3186 // -- a1 : receiver
3187 // -----------------------------------
3188 Label miss;
3189
3190 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003191 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003192
3193 GenerateLoadArrayLength(masm(), a1, a2, &miss);
3194 __ bind(&miss);
3195 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3196
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003197 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003198}
3199
3200
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003201Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength(
3202 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003203 // ----------- S t a t e -------------
3204 // -- ra : return address
3205 // -- a0 : key
3206 // -- a1 : receiver
3207 // -----------------------------------
3208 Label miss;
3209
3210 Counters* counters = masm()->isolate()->counters();
3211 __ IncrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
3212
3213 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003214 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003215
3216 GenerateLoadStringLength(masm(), a1, a2, a3, &miss, true);
3217 __ bind(&miss);
3218 __ DecrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
3219
3220 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3221
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003222 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003223}
3224
3225
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003226Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype(
3227 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003228 // ----------- S t a t e -------------
3229 // -- ra : return address
3230 // -- a0 : key
3231 // -- a1 : receiver
3232 // -----------------------------------
3233 Label miss;
3234
3235 Counters* counters = masm()->isolate()->counters();
3236 __ IncrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
3237
3238 // Check the name hasn't changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003239 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003240
3241 GenerateLoadFunctionPrototype(masm(), a1, a2, a3, &miss);
3242 __ bind(&miss);
3243 __ DecrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
3244 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3245
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003246 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003247}
3248
3249
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003250Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
3251 Handle<Map> receiver_map) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003252 // ----------- S t a t e -------------
3253 // -- ra : return address
3254 // -- a0 : key
3255 // -- a1 : receiver
3256 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003257 ElementsKind elements_kind = receiver_map->elements_kind();
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003258 Handle<Code> stub = KeyedLoadElementStub(elements_kind).GetCode();
3259
3260 __ DispatchMap(a1, a2, receiver_map, stub, DO_SMI_CHECK);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003261
3262 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
3263 __ Jump(ic, RelocInfo::CODE_TARGET);
3264
3265 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003266 return GetCode(Code::NORMAL, factory()->empty_string());
danno@chromium.org40cb8782011-05-25 07:58:50 +00003267}
3268
3269
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003270Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
3271 MapHandleList* receiver_maps,
3272 CodeHandleList* handler_ics) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003273 // ----------- S t a t e -------------
3274 // -- ra : return address
3275 // -- a0 : key
3276 // -- a1 : receiver
3277 // -----------------------------------
3278 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003279 __ JumpIfSmi(a1, &miss);
3280
danno@chromium.org40cb8782011-05-25 07:58:50 +00003281 int receiver_count = receiver_maps->length();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003282 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003283 for (int current = 0; current < receiver_count; ++current) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003284 __ Jump(handler_ics->at(current), RelocInfo::CODE_TARGET,
3285 eq, a2, Operand(receiver_maps->at(current)));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003286 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003287
3288 __ bind(&miss);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003289 Handle<Code> miss_ic = isolate()->builtins()->KeyedLoadIC_Miss();
3290 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003291
3292 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003293 return GetCode(Code::NORMAL, factory()->empty_string(), MEGAMORPHIC);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003294}
3295
3296
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003297Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +00003298 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003299 Handle<Map> transition,
3300 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003301 // ----------- S t a t e -------------
3302 // -- a0 : value
3303 // -- a1 : key
3304 // -- a2 : receiver
3305 // -- ra : return address
3306 // -----------------------------------
3307
3308 Label miss;
3309
3310 Counters* counters = masm()->isolate()->counters();
3311 __ IncrementCounter(counters->keyed_store_field(), 1, a3, t0);
3312
3313 // Check that the name has not changed.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003314 __ Branch(&miss, ne, a1, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003315
3316 // a3 is used as scratch register. a1 and a2 keep their values if a jump to
3317 // the miss label is generated.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003318 GenerateStoreField(masm(),
3319 object,
3320 index,
3321 transition,
3322 name,
3323 a2, a1, a3, t0,
3324 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003325 __ bind(&miss);
3326
3327 __ DecrementCounter(counters->keyed_store_field(), 1, a3, t0);
3328 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss();
3329 __ Jump(ic, RelocInfo::CODE_TARGET);
3330
3331 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003332 return GetCode(transition.is_null()
3333 ? Code::FIELD
3334 : Code::MAP_TRANSITION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003335}
3336
3337
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003338Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
3339 Handle<Map> receiver_map) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003340 // ----------- S t a t e -------------
3341 // -- a0 : value
3342 // -- a1 : key
3343 // -- a2 : receiver
3344 // -- ra : return address
3345 // -- a3 : scratch
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003346 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003347 ElementsKind elements_kind = receiver_map->elements_kind();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003348 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003349 Handle<Code> stub =
yangguo@chromium.org56454712012-02-16 15:33:53 +00003350 KeyedStoreElementStub(is_js_array, elements_kind, grow_mode_).GetCode();
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003351
3352 __ DispatchMap(a2, a3, receiver_map, stub, DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003353
danno@chromium.org40cb8782011-05-25 07:58:50 +00003354 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003355 __ Jump(ic, RelocInfo::CODE_TARGET);
3356
3357 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003358 return GetCode(Code::NORMAL, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00003359}
3360
3361
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003362Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
3363 MapHandleList* receiver_maps,
3364 CodeHandleList* handler_stubs,
3365 MapHandleList* transitioned_maps) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003366 // ----------- S t a t e -------------
3367 // -- a0 : value
3368 // -- a1 : key
3369 // -- a2 : receiver
3370 // -- ra : return address
3371 // -- a3 : scratch
3372 // -----------------------------------
3373 Label miss;
3374 __ JumpIfSmi(a2, &miss);
3375
3376 int receiver_count = receiver_maps->length();
3377 __ lw(a3, FieldMemOperand(a2, HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003378 for (int i = 0; i < receiver_count; ++i) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003379 if (transitioned_maps->at(i).is_null()) {
3380 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq,
3381 a3, Operand(receiver_maps->at(i)));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003382 } else {
3383 Label next_map;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003384 __ Branch(&next_map, ne, a3, Operand(receiver_maps->at(i)));
3385 __ li(a3, Operand(transitioned_maps->at(i)));
3386 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003387 __ bind(&next_map);
3388 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003389 }
3390
3391 __ bind(&miss);
3392 Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
3393 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3394
3395 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003396 return GetCode(Code::NORMAL, factory()->empty_string(), MEGAMORPHIC);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003397}
3398
3399
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003400Handle<Code> ConstructStubCompiler::CompileConstructStub(
3401 Handle<JSFunction> function) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003402 // a0 : argc
3403 // a1 : constructor
3404 // ra : return address
3405 // [sp] : last argument
3406 Label generic_stub_call;
3407
3408 // Use t7 for holding undefined which is used in several places below.
3409 __ LoadRoot(t7, Heap::kUndefinedValueRootIndex);
3410
3411#ifdef ENABLE_DEBUGGER_SUPPORT
3412 // Check to see whether there are any break points in the function code. If
3413 // there are jump to the generic constructor stub which calls the actual
3414 // code for the function thereby hitting the break points.
3415 __ lw(t5, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3416 __ lw(a2, FieldMemOperand(t5, SharedFunctionInfo::kDebugInfoOffset));
3417 __ Branch(&generic_stub_call, ne, a2, Operand(t7));
3418#endif
3419
3420 // Load the initial map and verify that it is in fact a map.
3421 // a1: constructor function
3422 // t7: undefined
3423 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003424 __ JumpIfSmi(a2, &generic_stub_call);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003425 __ GetObjectType(a2, a3, t0);
3426 __ Branch(&generic_stub_call, ne, t0, Operand(MAP_TYPE));
3427
3428#ifdef DEBUG
3429 // Cannot construct functions this way.
3430 // a0: argc
3431 // a1: constructor function
3432 // a2: initial map
3433 // t7: undefined
3434 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
3435 __ Check(ne, "Function constructed by construct stub.",
3436 a3, Operand(JS_FUNCTION_TYPE));
3437#endif
3438
3439 // Now allocate the JSObject in new space.
3440 // a0: argc
3441 // a1: constructor function
3442 // a2: initial map
3443 // t7: undefined
3444 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003445 __ AllocateInNewSpace(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003446
3447 // Allocated the JSObject, now initialize the fields. Map is set to initial
3448 // map and properties and elements are set to empty fixed array.
3449 // a0: argc
3450 // a1: constructor function
3451 // a2: initial map
3452 // a3: object size (in words)
3453 // t4: JSObject (not tagged)
3454 // t7: undefined
3455 __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex);
3456 __ mov(t5, t4);
3457 __ sw(a2, MemOperand(t5, JSObject::kMapOffset));
3458 __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset));
3459 __ sw(t6, MemOperand(t5, JSObject::kElementsOffset));
3460 __ Addu(t5, t5, Operand(3 * kPointerSize));
3461 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
3462 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
3463 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
3464
3465
3466 // Calculate the location of the first argument. The stack contains only the
3467 // argc arguments.
3468 __ sll(a1, a0, kPointerSizeLog2);
3469 __ Addu(a1, a1, sp);
3470
3471 // Fill all the in-object properties with undefined.
3472 // a0: argc
3473 // a1: first argument
3474 // a3: object size (in words)
3475 // t4: JSObject (not tagged)
3476 // t5: First in-object property of JSObject (not tagged)
3477 // t7: undefined
3478 // Fill the initialized properties with a constant value or a passed argument
3479 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003480 Handle<SharedFunctionInfo> shared(function->shared());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003481 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3482 if (shared->IsThisPropertyAssignmentArgument(i)) {
3483 Label not_passed, next;
3484 // Check if the argument assigned to the property is actually passed.
3485 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3486 __ Branch(&not_passed, less_equal, a0, Operand(arg_number));
3487 // Argument passed - find it on the stack.
3488 __ lw(a2, MemOperand(a1, (arg_number + 1) * -kPointerSize));
3489 __ sw(a2, MemOperand(t5));
3490 __ Addu(t5, t5, kPointerSize);
3491 __ jmp(&next);
3492 __ bind(&not_passed);
3493 // Set the property to undefined.
3494 __ sw(t7, MemOperand(t5));
3495 __ Addu(t5, t5, Operand(kPointerSize));
3496 __ bind(&next);
3497 } else {
3498 // Set the property to the constant value.
3499 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
3500 __ li(a2, Operand(constant));
3501 __ sw(a2, MemOperand(t5));
3502 __ Addu(t5, t5, kPointerSize);
3503 }
3504 }
3505
3506 // Fill the unused in-object property fields with undefined.
3507 ASSERT(function->has_initial_map());
3508 for (int i = shared->this_property_assignments_count();
3509 i < function->initial_map()->inobject_properties();
3510 i++) {
3511 __ sw(t7, MemOperand(t5));
3512 __ Addu(t5, t5, kPointerSize);
3513 }
3514
3515 // a0: argc
3516 // t4: JSObject (not tagged)
3517 // Move argc to a1 and the JSObject to return to v0 and tag it.
3518 __ mov(a1, a0);
3519 __ mov(v0, t4);
3520 __ Or(v0, v0, Operand(kHeapObjectTag));
3521
3522 // v0: JSObject
3523 // a1: argc
3524 // Remove caller arguments and receiver from the stack and return.
3525 __ sll(t0, a1, kPointerSizeLog2);
3526 __ Addu(sp, sp, t0);
3527 __ Addu(sp, sp, Operand(kPointerSize));
3528 Counters* counters = masm()->isolate()->counters();
3529 __ IncrementCounter(counters->constructed_objects(), 1, a1, a2);
3530 __ IncrementCounter(counters->constructed_objects_stub(), 1, a1, a2);
3531 __ Ret();
3532
3533 // Jump to the generic stub in case the specialized code cannot handle the
3534 // construction.
3535 __ bind(&generic_stub_call);
3536 Handle<Code> generic_construct_stub =
3537 masm()->isolate()->builtins()->JSConstructStubGeneric();
3538 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
3539
3540 // Return the generated code.
3541 return GetCode();
3542}
3543
3544
danno@chromium.org40cb8782011-05-25 07:58:50 +00003545#undef __
3546#define __ ACCESS_MASM(masm)
3547
3548
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003549void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3550 MacroAssembler* masm) {
3551 // ---------- S t a t e --------------
3552 // -- ra : return address
3553 // -- a0 : key
3554 // -- a1 : receiver
3555 // -----------------------------------
3556 Label slow, miss_force_generic;
3557
3558 Register key = a0;
3559 Register receiver = a1;
3560
3561 __ JumpIfNotSmi(key, &miss_force_generic);
3562 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
3563 __ sra(a2, a0, kSmiTagSize);
3564 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
3565 __ Ret();
3566
3567 // Slow case, key and receiver still in a0 and a1.
3568 __ bind(&slow);
3569 __ IncrementCounter(
3570 masm->isolate()->counters()->keyed_load_external_array_slow(),
3571 1, a2, a3);
3572 // Entry registers are intact.
3573 // ---------- S t a t e --------------
3574 // -- ra : return address
3575 // -- a0 : key
3576 // -- a1 : receiver
3577 // -----------------------------------
3578 Handle<Code> slow_ic =
3579 masm->isolate()->builtins()->KeyedLoadIC_Slow();
3580 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
3581
3582 // Miss case, call the runtime.
3583 __ bind(&miss_force_generic);
3584
3585 // ---------- S t a t e --------------
3586 // -- ra : return address
3587 // -- a0 : key
3588 // -- a1 : receiver
3589 // -----------------------------------
3590
3591 Handle<Code> miss_ic =
3592 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3593 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3594}
3595
3596
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003597static bool IsElementTypeSigned(ElementsKind elements_kind) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003598 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003599 case EXTERNAL_BYTE_ELEMENTS:
3600 case EXTERNAL_SHORT_ELEMENTS:
3601 case EXTERNAL_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003602 return true;
3603
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003604 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3605 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3606 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3607 case EXTERNAL_PIXEL_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003608 return false;
3609
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003610 case EXTERNAL_FLOAT_ELEMENTS:
3611 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003612 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003613 case FAST_ELEMENTS:
3614 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003615 case FAST_HOLEY_SMI_ELEMENTS:
3616 case FAST_HOLEY_ELEMENTS:
3617 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003618 case DICTIONARY_ELEMENTS:
3619 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003620 UNREACHABLE();
3621 return false;
3622 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003623 return false;
lrn@chromium.org7516f052011-03-30 08:52:27 +00003624}
3625
3626
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003627static void GenerateSmiKeyCheck(MacroAssembler* masm,
3628 Register key,
3629 Register scratch0,
3630 Register scratch1,
3631 FPURegister double_scratch0,
3632 Label* fail) {
3633 if (CpuFeatures::IsSupported(FPU)) {
3634 CpuFeatures::Scope scope(FPU);
3635 Label key_ok;
3636 // Check for smi or a smi inside a heap number. We convert the heap
3637 // number and check if the conversion is exact and fits into the smi
3638 // range.
3639 __ JumpIfSmi(key, &key_ok);
3640 __ CheckMap(key,
3641 scratch0,
3642 Heap::kHeapNumberMapRootIndex,
3643 fail,
3644 DONT_DO_SMI_CHECK);
3645 __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
3646 __ EmitFPUTruncate(kRoundToZero,
3647 double_scratch0,
3648 double_scratch0,
3649 scratch0,
3650 scratch1,
3651 kCheckForInexactConversion);
3652
3653 __ Branch(fail, ne, scratch1, Operand(zero_reg));
3654
3655 __ mfc1(scratch0, double_scratch0);
3656 __ SmiTagCheckOverflow(key, scratch0, scratch1);
3657 __ BranchOnOverflow(fail, scratch1);
3658 __ bind(&key_ok);
3659 } else {
3660 // Check that the key is a smi.
3661 __ JumpIfNotSmi(key, fail);
3662 }
3663}
3664
3665
danno@chromium.org40cb8782011-05-25 07:58:50 +00003666void KeyedLoadStubCompiler::GenerateLoadExternalArray(
3667 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003668 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003669 // ---------- S t a t e --------------
3670 // -- ra : return address
3671 // -- a0 : key
3672 // -- a1 : receiver
3673 // -----------------------------------
danno@chromium.org40cb8782011-05-25 07:58:50 +00003674 Label miss_force_generic, slow, failed_allocation;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003675
3676 Register key = a0;
3677 Register receiver = a1;
3678
danno@chromium.org40cb8782011-05-25 07:58:50 +00003679 // This stub is meant to be tail-jumped to, the receiver must already
3680 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003681
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003682 // Check that the key is a smi or a heap number convertible to a smi.
3683 GenerateSmiKeyCheck(masm, key, t0, t1, f2, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003684
3685 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3686 // a3: elements array
3687
3688 // Check that the index is in range.
3689 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3690 __ sra(t2, key, kSmiTagSize);
3691 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003692 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003693
3694 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3695 // a3: base pointer of external storage
3696
3697 // We are not untagging smi key and instead work with it
3698 // as if it was premultiplied by 2.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003699 STATIC_ASSERT((kSmiTag == 0) && (kSmiTagSize == 1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003700
3701 Register value = a2;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003702 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003703 case EXTERNAL_BYTE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003704 __ srl(t2, key, 1);
3705 __ addu(t3, a3, t2);
3706 __ lb(value, MemOperand(t3, 0));
3707 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003708 case EXTERNAL_PIXEL_ELEMENTS:
3709 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003710 __ srl(t2, key, 1);
3711 __ addu(t3, a3, t2);
3712 __ lbu(value, MemOperand(t3, 0));
3713 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003714 case EXTERNAL_SHORT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003715 __ addu(t3, a3, key);
3716 __ lh(value, MemOperand(t3, 0));
3717 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003718 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003719 __ addu(t3, a3, key);
3720 __ lhu(value, MemOperand(t3, 0));
3721 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003722 case EXTERNAL_INT_ELEMENTS:
3723 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003724 __ sll(t2, key, 1);
3725 __ addu(t3, a3, t2);
3726 __ lw(value, MemOperand(t3, 0));
3727 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003728 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003729 __ sll(t3, t2, 2);
3730 __ addu(t3, a3, t3);
3731 if (CpuFeatures::IsSupported(FPU)) {
3732 CpuFeatures::Scope scope(FPU);
3733 __ lwc1(f0, MemOperand(t3, 0));
3734 } else {
3735 __ lw(value, MemOperand(t3, 0));
3736 }
3737 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003738 case EXTERNAL_DOUBLE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003739 __ sll(t2, key, 2);
3740 __ addu(t3, a3, t2);
3741 if (CpuFeatures::IsSupported(FPU)) {
3742 CpuFeatures::Scope scope(FPU);
3743 __ ldc1(f0, MemOperand(t3, 0));
3744 } else {
3745 // t3: pointer to the beginning of the double we want to load.
3746 __ lw(a2, MemOperand(t3, 0));
3747 __ lw(a3, MemOperand(t3, Register::kSizeInBytes));
3748 }
3749 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003750 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003751 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003752 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003753 case FAST_HOLEY_ELEMENTS:
3754 case FAST_HOLEY_SMI_ELEMENTS:
3755 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003756 case DICTIONARY_ELEMENTS:
3757 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003758 UNREACHABLE();
3759 break;
3760 }
3761
3762 // For integer array types:
3763 // a2: value
3764 // For float array type:
3765 // f0: value (if FPU is supported)
3766 // a2: value (if FPU is not supported)
3767 // For double array type:
3768 // f0: value (if FPU is supported)
3769 // a2/a3: value (if FPU is not supported)
3770
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003771 if (elements_kind == EXTERNAL_INT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003772 // For the Int and UnsignedInt array types, we need to see whether
3773 // the value can be represented in a Smi. If not, we need to convert
3774 // it to a HeapNumber.
3775 Label box_int;
3776 __ Subu(t3, value, Operand(0xC0000000)); // Non-smi value gives neg result.
3777 __ Branch(&box_int, lt, t3, Operand(zero_reg));
3778 // Tag integer as smi and return it.
3779 __ sll(v0, value, kSmiTagSize);
3780 __ Ret();
3781
3782 __ bind(&box_int);
3783 // Allocate a HeapNumber for the result and perform int-to-double
3784 // conversion.
3785 // The arm version uses a temporary here to save r0, but we don't need to
3786 // (a0 is not modified).
3787 __ LoadRoot(t1, Heap::kHeapNumberMapRootIndex);
3788 __ AllocateHeapNumber(v0, a3, t0, t1, &slow);
3789
3790 if (CpuFeatures::IsSupported(FPU)) {
3791 CpuFeatures::Scope scope(FPU);
3792 __ mtc1(value, f0);
3793 __ cvt_d_w(f0, f0);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00003794 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003795 __ Ret();
3796 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003797 Register dst1 = t2;
3798 Register dst2 = t3;
3799 FloatingPointHelper::Destination dest =
3800 FloatingPointHelper::kCoreRegisters;
3801 FloatingPointHelper::ConvertIntToDouble(masm,
3802 value,
3803 dest,
3804 f0,
3805 dst1,
3806 dst2,
3807 t1,
3808 f2);
3809 __ sw(dst1, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3810 __ sw(dst2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3811 __ Ret();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003812 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003813 } else if (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003814 // The test is different for unsigned int values. Since we need
3815 // the value to be in the range of a positive smi, we can't
3816 // handle either of the top two bits being set in the value.
3817 if (CpuFeatures::IsSupported(FPU)) {
3818 CpuFeatures::Scope scope(FPU);
3819 Label pl_box_int;
3820 __ And(t2, value, Operand(0xC0000000));
3821 __ Branch(&pl_box_int, ne, t2, Operand(zero_reg));
3822
3823 // It can fit in an Smi.
3824 // Tag integer as smi and return it.
3825 __ sll(v0, value, kSmiTagSize);
3826 __ Ret();
3827
3828 __ bind(&pl_box_int);
3829 // Allocate a HeapNumber for the result and perform int-to-double
3830 // conversion. Don't use a0 and a1 as AllocateHeapNumber clobbers all
3831 // registers - also when jumping due to exhausted young space.
3832 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3833 __ AllocateHeapNumber(v0, t2, t3, t6, &slow);
3834
3835 // This is replaced by a macro:
3836 // __ mtc1(value, f0); // LS 32-bits.
3837 // __ mtc1(zero_reg, f1); // MS 32-bits are all zero.
3838 // __ cvt_d_l(f0, f0); // Use 64 bit conv to get correct unsigned 32-bit.
3839
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003840 __ Cvt_d_uw(f0, value, f22);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003841
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00003842 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003843
3844 __ Ret();
3845 } else {
3846 // Check whether unsigned integer fits into smi.
3847 Label box_int_0, box_int_1, done;
3848 __ And(t2, value, Operand(0x80000000));
3849 __ Branch(&box_int_0, ne, t2, Operand(zero_reg));
3850 __ And(t2, value, Operand(0x40000000));
3851 __ Branch(&box_int_1, ne, t2, Operand(zero_reg));
3852
3853 // Tag integer as smi and return it.
3854 __ sll(v0, value, kSmiTagSize);
3855 __ Ret();
3856
3857 Register hiword = value; // a2.
3858 Register loword = a3;
3859
3860 __ bind(&box_int_0);
3861 // Integer does not have leading zeros.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003862 GenerateUInt2Double(masm, hiword, loword, t0, 0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003863 __ Branch(&done);
3864
3865 __ bind(&box_int_1);
3866 // Integer has one leading zero.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003867 GenerateUInt2Double(masm, hiword, loword, t0, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003868
3869
3870 __ bind(&done);
3871 // Integer was converted to double in registers hiword:loword.
3872 // Wrap it into a HeapNumber. Don't use a0 and a1 as AllocateHeapNumber
3873 // clobbers all registers - also when jumping due to exhausted young
3874 // space.
3875 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3876 __ AllocateHeapNumber(t2, t3, t5, t6, &slow);
3877
3878 __ sw(hiword, FieldMemOperand(t2, HeapNumber::kExponentOffset));
3879 __ sw(loword, FieldMemOperand(t2, HeapNumber::kMantissaOffset));
3880
3881 __ mov(v0, t2);
3882 __ Ret();
3883 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003884 } else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003885 // For the floating-point array type, we need to always allocate a
3886 // HeapNumber.
3887 if (CpuFeatures::IsSupported(FPU)) {
3888 CpuFeatures::Scope scope(FPU);
3889 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3890 // AllocateHeapNumber clobbers all registers - also when jumping due to
3891 // exhausted young space.
3892 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3893 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3894 // The float (single) value is already in fpu reg f0 (if we use float).
3895 __ cvt_d_s(f0, f0);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00003896 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003897 __ Ret();
3898 } else {
3899 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3900 // AllocateHeapNumber clobbers all registers - also when jumping due to
3901 // exhausted young space.
3902 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3903 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3904 // FPU is not available, do manual single to double conversion.
3905
3906 // a2: floating point value (binary32).
3907 // v0: heap number for result
3908
3909 // Extract mantissa to t4.
3910 __ And(t4, value, Operand(kBinary32MantissaMask));
3911
3912 // Extract exponent to t5.
3913 __ srl(t5, value, kBinary32MantissaBits);
3914 __ And(t5, t5, Operand(kBinary32ExponentMask >> kBinary32MantissaBits));
3915
3916 Label exponent_rebiased;
3917 __ Branch(&exponent_rebiased, eq, t5, Operand(zero_reg));
3918
3919 __ li(t0, 0x7ff);
3920 __ Xor(t1, t5, Operand(0xFF));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003921 __ Movz(t5, t0, t1); // Set t5 to 0x7ff only if t5 is equal to 0xff.
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003922 __ Branch(&exponent_rebiased, eq, t1, Operand(zero_reg));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003923
3924 // Rebias exponent.
3925 __ Addu(t5,
3926 t5,
3927 Operand(-kBinary32ExponentBias + HeapNumber::kExponentBias));
3928
3929 __ bind(&exponent_rebiased);
3930 __ And(a2, value, Operand(kBinary32SignMask));
3931 value = no_reg;
3932 __ sll(t0, t5, HeapNumber::kMantissaBitsInTopWord);
3933 __ or_(a2, a2, t0);
3934
3935 // Shift mantissa.
3936 static const int kMantissaShiftForHiWord =
3937 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3938
3939 static const int kMantissaShiftForLoWord =
3940 kBitsPerInt - kMantissaShiftForHiWord;
3941
3942 __ srl(t0, t4, kMantissaShiftForHiWord);
3943 __ or_(a2, a2, t0);
3944 __ sll(a0, t4, kMantissaShiftForLoWord);
3945
3946 __ sw(a2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3947 __ sw(a0, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3948 __ Ret();
3949 }
3950
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003951 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003952 if (CpuFeatures::IsSupported(FPU)) {
3953 CpuFeatures::Scope scope(FPU);
3954 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3955 // AllocateHeapNumber clobbers all registers - also when jumping due to
3956 // exhausted young space.
3957 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3958 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3959 // The double value is already in f0
3960 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
3961 __ Ret();
3962 } else {
3963 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3964 // AllocateHeapNumber clobbers all registers - also when jumping due to
3965 // exhausted young space.
3966 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3967 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3968
3969 __ sw(a2, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3970 __ sw(a3, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3971 __ Ret();
3972 }
3973
3974 } else {
3975 // Tag integer as smi and return it.
3976 __ sll(v0, value, kSmiTagSize);
3977 __ Ret();
3978 }
3979
3980 // Slow case, key and receiver still in a0 and a1.
3981 __ bind(&slow);
3982 __ IncrementCounter(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003983 masm->isolate()->counters()->keyed_load_external_array_slow(),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003984 1, a2, a3);
3985
3986 // ---------- S t a t e --------------
3987 // -- ra : return address
3988 // -- a0 : key
3989 // -- a1 : receiver
3990 // -----------------------------------
3991
3992 __ Push(a1, a0);
3993
3994 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
3995
danno@chromium.org40cb8782011-05-25 07:58:50 +00003996 __ bind(&miss_force_generic);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003997 Handle<Code> stub =
3998 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3999 __ Jump(stub, RelocInfo::CODE_TARGET);
lrn@chromium.org7516f052011-03-30 08:52:27 +00004000}
4001
4002
danno@chromium.org40cb8782011-05-25 07:58:50 +00004003void KeyedStoreStubCompiler::GenerateStoreExternalArray(
4004 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004005 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004006 // ---------- S t a t e --------------
4007 // -- a0 : value
4008 // -- a1 : key
4009 // -- a2 : receiver
4010 // -- ra : return address
4011 // -----------------------------------
4012
danno@chromium.org40cb8782011-05-25 07:58:50 +00004013 Label slow, check_heap_number, miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004014
4015 // Register usage.
4016 Register value = a0;
4017 Register key = a1;
4018 Register receiver = a2;
4019 // a3 mostly holds the elements array or the destination external array.
4020
danno@chromium.org40cb8782011-05-25 07:58:50 +00004021 // This stub is meant to be tail-jumped to, the receiver must already
4022 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004023
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004024 // Check that the key is a smi or a heap number convertible to a smi.
4025 GenerateSmiKeyCheck(masm, key, t0, t1, f2, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004026
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004027 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
4028
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004029 // Check that the index is in range.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004030 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
4031 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004032 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004033
4034 // Handle both smis and HeapNumbers in the fast path. Go to the
4035 // runtime for all other kinds of values.
4036 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004037
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004038 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004039 // Double to pixel conversion is only implemented in the runtime for now.
4040 __ JumpIfNotSmi(value, &slow);
4041 } else {
4042 __ JumpIfNotSmi(value, &check_heap_number);
4043 }
4044 __ SmiUntag(t1, value);
4045 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
4046
4047 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004048 // t1: value (integer).
4049
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004050 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004051 case EXTERNAL_PIXEL_ELEMENTS: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004052 // Clamp the value to [0..255].
4053 // v0 is used as a scratch register here.
4054 Label done;
4055 __ li(v0, Operand(255));
4056 // Normal branch: nop in delay slot.
4057 __ Branch(&done, gt, t1, Operand(v0));
4058 // Use delay slot in this branch.
4059 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg));
4060 __ mov(v0, zero_reg); // In delay slot.
4061 __ mov(v0, t1); // Value is in range 0..255.
4062 __ bind(&done);
4063 __ mov(t1, v0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004064
4065 __ srl(t8, key, 1);
4066 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004067 __ sb(t1, MemOperand(t8, 0));
4068 }
4069 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004070 case EXTERNAL_BYTE_ELEMENTS:
4071 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004072 __ srl(t8, key, 1);
4073 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004074 __ sb(t1, MemOperand(t8, 0));
4075 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004076 case EXTERNAL_SHORT_ELEMENTS:
4077 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004078 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004079 __ sh(t1, MemOperand(t8, 0));
4080 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004081 case EXTERNAL_INT_ELEMENTS:
4082 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004083 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004084 __ addu(t8, a3, t8);
4085 __ sw(t1, MemOperand(t8, 0));
4086 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004087 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004088 // Perform int-to-float conversion and store to memory.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004089 __ SmiUntag(t0, key);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004090 StoreIntAsFloat(masm, a3, t0, t1, t2, t3, t4);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004091 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004092 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004093 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004094 __ addu(a3, a3, t8);
4095 // a3: effective address of the double element
4096 FloatingPointHelper::Destination destination;
4097 if (CpuFeatures::IsSupported(FPU)) {
4098 destination = FloatingPointHelper::kFPURegisters;
4099 } else {
4100 destination = FloatingPointHelper::kCoreRegisters;
4101 }
4102 FloatingPointHelper::ConvertIntToDouble(
danno@chromium.org40cb8782011-05-25 07:58:50 +00004103 masm, t1, destination,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004104 f0, t2, t3, // These are: double_dst, dst1, dst2.
4105 t0, f2); // These are: scratch2, single_scratch.
4106 if (destination == FloatingPointHelper::kFPURegisters) {
4107 CpuFeatures::Scope scope(FPU);
4108 __ sdc1(f0, MemOperand(a3, 0));
4109 } else {
4110 __ sw(t2, MemOperand(a3, 0));
4111 __ sw(t3, MemOperand(a3, Register::kSizeInBytes));
4112 }
4113 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004114 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004115 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004116 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004117 case FAST_HOLEY_ELEMENTS:
4118 case FAST_HOLEY_SMI_ELEMENTS:
4119 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004120 case DICTIONARY_ELEMENTS:
4121 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004122 UNREACHABLE();
4123 break;
4124 }
4125
4126 // Entry registers are intact, a0 holds the value which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004127 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004128 __ Ret();
4129
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004130 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004131 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004132 __ bind(&check_heap_number);
4133 __ GetObjectType(value, t1, t2);
4134 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE));
4135
4136 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
4137
4138 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004139
4140 // The WebGL specification leaves the behavior of storing NaN and
4141 // +/-Infinity into integer arrays basically undefined. For more
4142 // reproducible behavior, convert these to zero.
4143
4144 if (CpuFeatures::IsSupported(FPU)) {
4145 CpuFeatures::Scope scope(FPU);
4146
4147 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
4148
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004149 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004150 __ cvt_s_d(f0, f0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004151 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004152 __ addu(t8, a3, t8);
4153 __ swc1(f0, MemOperand(t8, 0));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004154 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004155 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004156 __ addu(t8, a3, t8);
4157 __ sdc1(f0, MemOperand(t8, 0));
4158 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00004159 __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004160
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004161 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004162 case EXTERNAL_BYTE_ELEMENTS:
4163 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004164 __ srl(t8, key, 1);
4165 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004166 __ sb(t3, MemOperand(t8, 0));
4167 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004168 case EXTERNAL_SHORT_ELEMENTS:
4169 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004170 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004171 __ sh(t3, MemOperand(t8, 0));
4172 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004173 case EXTERNAL_INT_ELEMENTS:
4174 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004175 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004176 __ addu(t8, a3, t8);
4177 __ sw(t3, MemOperand(t8, 0));
4178 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004179 case EXTERNAL_PIXEL_ELEMENTS:
4180 case EXTERNAL_FLOAT_ELEMENTS:
4181 case EXTERNAL_DOUBLE_ELEMENTS:
4182 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004183 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004184 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004185 case FAST_HOLEY_ELEMENTS:
4186 case FAST_HOLEY_SMI_ELEMENTS:
4187 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004188 case DICTIONARY_ELEMENTS:
4189 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004190 UNREACHABLE();
4191 break;
4192 }
4193 }
4194
4195 // Entry registers are intact, a0 holds the value
4196 // which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004197 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004198 __ Ret();
4199 } else {
4200 // FPU is not available, do manual conversions.
4201
4202 __ lw(t3, FieldMemOperand(value, HeapNumber::kExponentOffset));
4203 __ lw(t4, FieldMemOperand(value, HeapNumber::kMantissaOffset));
4204
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004205 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004206 Label done, nan_or_infinity_or_zero;
4207 static const int kMantissaInHiWordShift =
4208 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
4209
4210 static const int kMantissaInLoWordShift =
4211 kBitsPerInt - kMantissaInHiWordShift;
4212
4213 // Test for all special exponent values: zeros, subnormal numbers, NaNs
4214 // and infinities. All these should be converted to 0.
4215 __ li(t5, HeapNumber::kExponentMask);
4216 __ and_(t6, t3, t5);
4217 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(zero_reg));
4218
4219 __ xor_(t1, t6, t5);
4220 __ li(t2, kBinary32ExponentMask);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004221 __ Movz(t6, t2, t1); // Only if t6 is equal to t5.
rossberg@chromium.org400388e2012-06-06 09:29:22 +00004222 __ Branch(&nan_or_infinity_or_zero, eq, t1, Operand(zero_reg));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004223
4224 // Rebias exponent.
4225 __ srl(t6, t6, HeapNumber::kExponentShift);
4226 __ Addu(t6,
4227 t6,
4228 Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
4229
4230 __ li(t1, Operand(kBinary32MaxExponent));
4231 __ Slt(t1, t1, t6);
4232 __ And(t2, t3, Operand(HeapNumber::kSignMask));
4233 __ Or(t2, t2, Operand(kBinary32ExponentMask));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004234 __ Movn(t3, t2, t1); // Only if t6 is gt kBinary32MaxExponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004235 __ Branch(&done, gt, t6, Operand(kBinary32MaxExponent));
4236
4237 __ Slt(t1, t6, Operand(kBinary32MinExponent));
4238 __ And(t2, t3, Operand(HeapNumber::kSignMask));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004239 __ Movn(t3, t2, t1); // Only if t6 is lt kBinary32MinExponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004240 __ Branch(&done, lt, t6, Operand(kBinary32MinExponent));
4241
4242 __ And(t7, t3, Operand(HeapNumber::kSignMask));
4243 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4244 __ sll(t3, t3, kMantissaInHiWordShift);
4245 __ or_(t7, t7, t3);
4246 __ srl(t4, t4, kMantissaInLoWordShift);
4247 __ or_(t7, t7, t4);
4248 __ sll(t6, t6, kBinary32ExponentShift);
4249 __ or_(t3, t7, t6);
4250
4251 __ bind(&done);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004252 __ sll(t9, key, 1);
rossberg@chromium.org400388e2012-06-06 09:29:22 +00004253 __ addu(t9, a3, t9);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004254 __ sw(t3, MemOperand(t9, 0));
4255
4256 // Entry registers are intact, a0 holds the value which is the return
4257 // value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004258 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004259 __ Ret();
4260
4261 __ bind(&nan_or_infinity_or_zero);
4262 __ And(t7, t3, Operand(HeapNumber::kSignMask));
4263 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4264 __ or_(t6, t6, t7);
4265 __ sll(t3, t3, kMantissaInHiWordShift);
4266 __ or_(t6, t6, t3);
4267 __ srl(t4, t4, kMantissaInLoWordShift);
4268 __ or_(t3, t6, t4);
4269 __ Branch(&done);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004270 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00004271 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004272 __ addu(t8, a3, t8);
4273 // t8: effective address of destination element.
4274 __ sw(t4, MemOperand(t8, 0));
4275 __ sw(t3, MemOperand(t8, Register::kSizeInBytes));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004276 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004277 __ Ret();
4278 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004279 bool is_signed_type = IsElementTypeSigned(elements_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004280 int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
4281 int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
4282
4283 Label done, sign;
4284
4285 // Test for all special exponent values: zeros, subnormal numbers, NaNs
4286 // and infinities. All these should be converted to 0.
4287 __ li(t5, HeapNumber::kExponentMask);
4288 __ and_(t6, t3, t5);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004289 __ Movz(t3, zero_reg, t6); // Only if t6 is equal to zero.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004290 __ Branch(&done, eq, t6, Operand(zero_reg));
4291
4292 __ xor_(t2, t6, t5);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004293 __ Movz(t3, zero_reg, t2); // Only if t6 is equal to t5.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004294 __ Branch(&done, eq, t6, Operand(t5));
4295
4296 // Unbias exponent.
4297 __ srl(t6, t6, HeapNumber::kExponentShift);
4298 __ Subu(t6, t6, Operand(HeapNumber::kExponentBias));
4299 // If exponent is negative then result is 0.
4300 __ slt(t2, t6, zero_reg);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004301 __ Movn(t3, zero_reg, t2); // Only if exponent is negative.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004302 __ Branch(&done, lt, t6, Operand(zero_reg));
4303
4304 // If exponent is too big then result is minimal value.
4305 __ slti(t1, t6, meaningfull_bits - 1);
4306 __ li(t2, min_value);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004307 __ Movz(t3, t2, t1); // Only if t6 is ge meaningfull_bits - 1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004308 __ Branch(&done, ge, t6, Operand(meaningfull_bits - 1));
4309
4310 __ And(t5, t3, Operand(HeapNumber::kSignMask));
4311 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4312 __ Or(t3, t3, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
4313
4314 __ li(t9, HeapNumber::kMantissaBitsInTopWord);
4315 __ subu(t6, t9, t6);
4316 __ slt(t1, t6, zero_reg);
4317 __ srlv(t2, t3, t6);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004318 __ Movz(t3, t2, t1); // Only if t6 is positive.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004319 __ Branch(&sign, ge, t6, Operand(zero_reg));
4320
4321 __ subu(t6, zero_reg, t6);
4322 __ sllv(t3, t3, t6);
4323 __ li(t9, meaningfull_bits);
4324 __ subu(t6, t9, t6);
4325 __ srlv(t4, t4, t6);
4326 __ or_(t3, t3, t4);
4327
4328 __ bind(&sign);
4329 __ subu(t2, t3, zero_reg);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004330 __ Movz(t3, t2, t5); // Only if t5 is zero.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004331
4332 __ bind(&done);
4333
4334 // Result is in t3.
4335 // This switch block should be exactly the same as above (FPU mode).
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004336 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004337 case EXTERNAL_BYTE_ELEMENTS:
4338 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004339 __ srl(t8, key, 1);
4340 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004341 __ sb(t3, MemOperand(t8, 0));
4342 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004343 case EXTERNAL_SHORT_ELEMENTS:
4344 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004345 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004346 __ sh(t3, MemOperand(t8, 0));
4347 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004348 case EXTERNAL_INT_ELEMENTS:
4349 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004350 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004351 __ addu(t8, a3, t8);
4352 __ sw(t3, MemOperand(t8, 0));
4353 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004354 case EXTERNAL_PIXEL_ELEMENTS:
4355 case EXTERNAL_FLOAT_ELEMENTS:
4356 case EXTERNAL_DOUBLE_ELEMENTS:
4357 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004358 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004359 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004360 case FAST_HOLEY_ELEMENTS:
4361 case FAST_HOLEY_SMI_ELEMENTS:
4362 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004363 case DICTIONARY_ELEMENTS:
4364 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004365 UNREACHABLE();
4366 break;
4367 }
4368 }
4369 }
4370 }
4371
danno@chromium.org40cb8782011-05-25 07:58:50 +00004372 // Slow case, key and receiver still in a0 and a1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004373 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004374 __ IncrementCounter(
4375 masm->isolate()->counters()->keyed_load_external_array_slow(),
4376 1, a2, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004377 // Entry registers are intact.
4378 // ---------- S t a t e --------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004379 // -- ra : return address
danno@chromium.org40cb8782011-05-25 07:58:50 +00004380 // -- a0 : key
4381 // -- a1 : receiver
4382 // -----------------------------------
4383 Handle<Code> slow_ic =
4384 masm->isolate()->builtins()->KeyedStoreIC_Slow();
4385 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4386
4387 // Miss case, call the runtime.
4388 __ bind(&miss_force_generic);
4389
4390 // ---------- S t a t e --------------
4391 // -- ra : return address
4392 // -- a0 : key
4393 // -- a1 : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004394 // -----------------------------------
4395
danno@chromium.org40cb8782011-05-25 07:58:50 +00004396 Handle<Code> miss_ic =
4397 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4398 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
4399}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004400
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004401
danno@chromium.org40cb8782011-05-25 07:58:50 +00004402void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
4403 // ----------- S t a t e -------------
4404 // -- ra : return address
4405 // -- a0 : key
4406 // -- a1 : receiver
4407 // -----------------------------------
4408 Label miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004409
danno@chromium.org40cb8782011-05-25 07:58:50 +00004410 // This stub is meant to be tail-jumped to, the receiver must already
4411 // have been verified by the caller to not be a smi.
4412
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004413 // Check that the key is a smi or a heap number convertible to a smi.
4414 GenerateSmiKeyCheck(masm, a0, t0, t1, f2, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004415
4416 // Get the elements array.
4417 __ lw(a2, FieldMemOperand(a1, JSObject::kElementsOffset));
4418 __ AssertFastElements(a2);
4419
4420 // Check that the key is within bounds.
4421 __ lw(a3, FieldMemOperand(a2, FixedArray::kLengthOffset));
ulan@chromium.org6ff65142012-03-21 09:52:17 +00004422 __ Branch(USE_DELAY_SLOT, &miss_force_generic, hs, a0, Operand(a3));
danno@chromium.org40cb8782011-05-25 07:58:50 +00004423
4424 // Load the result and make sure it's not the hole.
4425 __ Addu(a3, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004426 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004427 __ sll(t0, a0, kPointerSizeLog2 - kSmiTagSize);
4428 __ Addu(t0, t0, a3);
4429 __ lw(t0, MemOperand(t0));
4430 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
4431 __ Branch(&miss_force_generic, eq, t0, Operand(t1));
ulan@chromium.org6ff65142012-03-21 09:52:17 +00004432 __ Ret(USE_DELAY_SLOT);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004433 __ mov(v0, t0);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004434
4435 __ bind(&miss_force_generic);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004436 Handle<Code> stub =
4437 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4438 __ Jump(stub, RelocInfo::CODE_TARGET);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004439}
4440
4441
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004442void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
4443 MacroAssembler* masm) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004444 // ----------- S t a t e -------------
4445 // -- ra : return address
4446 // -- a0 : key
4447 // -- a1 : receiver
4448 // -----------------------------------
4449 Label miss_force_generic, slow_allocate_heapnumber;
4450
4451 Register key_reg = a0;
4452 Register receiver_reg = a1;
4453 Register elements_reg = a2;
4454 Register heap_number_reg = a2;
4455 Register indexed_double_offset = a3;
4456 Register scratch = t0;
4457 Register scratch2 = t1;
4458 Register scratch3 = t2;
4459 Register heap_number_map = t3;
4460
4461 // This stub is meant to be tail-jumped to, the receiver must already
4462 // have been verified by the caller to not be a smi.
4463
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004464 // Check that the key is a smi or a heap number convertible to a smi.
4465 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004466
4467 // Get the elements array.
4468 __ lw(elements_reg,
4469 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4470
4471 // Check that the key is within bounds.
4472 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4473 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4474
4475 // Load the upper word of the double in the fixed array and test for NaN.
4476 __ sll(scratch2, key_reg, kDoubleSizeLog2 - kSmiTagSize);
4477 __ Addu(indexed_double_offset, elements_reg, Operand(scratch2));
4478 uint32_t upper_32_offset = FixedArray::kHeaderSize + sizeof(kHoleNanLower32);
4479 __ lw(scratch, FieldMemOperand(indexed_double_offset, upper_32_offset));
4480 __ Branch(&miss_force_generic, eq, scratch, Operand(kHoleNanUpper32));
4481
4482 // Non-NaN. Allocate a new heap number and copy the double value into it.
4483 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
4484 __ AllocateHeapNumber(heap_number_reg, scratch2, scratch3,
4485 heap_number_map, &slow_allocate_heapnumber);
4486
4487 // Don't need to reload the upper 32 bits of the double, it's already in
4488 // scratch.
4489 __ sw(scratch, FieldMemOperand(heap_number_reg,
4490 HeapNumber::kExponentOffset));
4491 __ lw(scratch, FieldMemOperand(indexed_double_offset,
4492 FixedArray::kHeaderSize));
4493 __ sw(scratch, FieldMemOperand(heap_number_reg,
4494 HeapNumber::kMantissaOffset));
4495
4496 __ mov(v0, heap_number_reg);
4497 __ Ret();
4498
4499 __ bind(&slow_allocate_heapnumber);
4500 Handle<Code> slow_ic =
4501 masm->isolate()->builtins()->KeyedLoadIC_Slow();
4502 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4503
4504 __ bind(&miss_force_generic);
4505 Handle<Code> miss_ic =
4506 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4507 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004508}
4509
4510
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004511void KeyedStoreStubCompiler::GenerateStoreFastElement(
4512 MacroAssembler* masm,
4513 bool is_js_array,
yangguo@chromium.org56454712012-02-16 15:33:53 +00004514 ElementsKind elements_kind,
4515 KeyedAccessGrowMode grow_mode) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00004516 // ----------- S t a t e -------------
4517 // -- a0 : value
4518 // -- a1 : key
4519 // -- a2 : receiver
4520 // -- ra : return address
4521 // -- a3 : scratch
4522 // -- a4 : scratch (elements)
4523 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00004524 Label miss_force_generic, transition_elements_kind, grow, slow;
4525 Label finish_store, check_capacity;
danno@chromium.org40cb8782011-05-25 07:58:50 +00004526
4527 Register value_reg = a0;
4528 Register key_reg = a1;
4529 Register receiver_reg = a2;
yangguo@chromium.org56454712012-02-16 15:33:53 +00004530 Register scratch = t0;
4531 Register elements_reg = a3;
4532 Register length_reg = t1;
4533 Register scratch2 = t2;
danno@chromium.org40cb8782011-05-25 07:58:50 +00004534
4535 // This stub is meant to be tail-jumped to, the receiver must already
4536 // have been verified by the caller to not be a smi.
4537
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004538 // Check that the key is a smi or a heap number convertible to a smi.
4539 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004540
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004541 if (IsFastSmiElementsKind(elements_kind)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00004542 __ JumpIfNotSmi(value_reg, &transition_elements_kind);
4543 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004544
4545 // Check that the key is within bounds.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004546 __ lw(elements_reg,
4547 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00004548 if (is_js_array) {
4549 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4550 } else {
4551 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4552 }
4553 // Compare smis.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004554 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4555 __ Branch(&grow, hs, key_reg, Operand(scratch));
4556 } else {
4557 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4558 }
4559
4560 // Make sure elements is a fast element array, not 'cow'.
4561 __ CheckMap(elements_reg,
4562 scratch,
4563 Heap::kFixedArrayMapRootIndex,
4564 &miss_force_generic,
4565 DONT_DO_SMI_CHECK);
4566
4567 __ bind(&finish_store);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004568
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004569 if (IsFastSmiElementsKind(elements_kind)) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004570 __ Addu(scratch,
4571 elements_reg,
4572 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4573 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4574 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4575 __ Addu(scratch, scratch, scratch2);
4576 __ sw(value_reg, MemOperand(scratch));
4577 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004578 ASSERT(IsFastObjectElementsKind(elements_kind));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004579 __ Addu(scratch,
4580 elements_reg,
4581 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4582 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4583 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4584 __ Addu(scratch, scratch, scratch2);
4585 __ sw(value_reg, MemOperand(scratch));
4586 __ mov(receiver_reg, value_reg);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004587 __ RecordWrite(elements_reg, // Object.
4588 scratch, // Address.
4589 receiver_reg, // Value.
4590 kRAHasNotBeenSaved,
4591 kDontSaveFPRegs);
4592 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004593 // value_reg (a0) is preserved.
4594 // Done.
4595 __ Ret();
4596
4597 __ bind(&miss_force_generic);
4598 Handle<Code> ic =
4599 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4600 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004601
4602 __ bind(&transition_elements_kind);
4603 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4604 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
yangguo@chromium.org56454712012-02-16 15:33:53 +00004605
4606 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4607 // Grow the array by a single element if possible.
4608 __ bind(&grow);
4609
4610 // Make sure the array is only growing by a single element, anything else
4611 // must be handled by the runtime.
4612 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch));
4613
4614 // Check for the empty array, and preallocate a small backing store if
4615 // possible.
4616 __ lw(length_reg,
4617 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4618 __ lw(elements_reg,
4619 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4620 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
4621 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
4622
4623 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
4624 __ AllocateInNewSpace(size, elements_reg, scratch, scratch2, &slow,
4625 TAG_OBJECT);
4626
4627 __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex);
4628 __ sw(scratch, FieldMemOperand(elements_reg, JSObject::kMapOffset));
4629 __ li(scratch, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4630 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4631 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
4632 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
4633 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::SizeFor(i)));
4634 }
4635
4636 // Store the element at index zero.
4637 __ sw(value_reg, FieldMemOperand(elements_reg, FixedArray::SizeFor(0)));
4638
4639 // Install the new backing store in the JSArray.
4640 __ sw(elements_reg,
4641 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4642 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
4643 scratch, kRAHasNotBeenSaved, kDontSaveFPRegs,
4644 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4645
4646 // Increment the length of the array.
4647 __ li(length_reg, Operand(Smi::FromInt(1)));
4648 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4649 __ Ret();
4650
4651 __ bind(&check_capacity);
4652 // Check for cow elements, in general they are not handled by this stub
4653 __ CheckMap(elements_reg,
4654 scratch,
4655 Heap::kFixedCOWArrayMapRootIndex,
4656 &miss_force_generic,
4657 DONT_DO_SMI_CHECK);
4658
4659 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4660 __ Branch(&slow, hs, length_reg, Operand(scratch));
4661
4662 // Grow the array and finish the store.
4663 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
4664 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4665 __ jmp(&finish_store);
4666
4667 __ bind(&slow);
4668 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4669 __ Jump(ic_slow, RelocInfo::CODE_TARGET);
4670 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004671}
4672
4673
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004674void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
4675 MacroAssembler* masm,
yangguo@chromium.org56454712012-02-16 15:33:53 +00004676 bool is_js_array,
4677 KeyedAccessGrowMode grow_mode) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004678 // ----------- S t a t e -------------
4679 // -- a0 : value
4680 // -- a1 : key
4681 // -- a2 : receiver
4682 // -- ra : return address
4683 // -- a3 : scratch
4684 // -- t0 : scratch (elements_reg)
4685 // -- t1 : scratch (mantissa_reg)
4686 // -- t2 : scratch (exponent_reg)
4687 // -- t3 : scratch4
4688 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00004689 Label miss_force_generic, transition_elements_kind, grow, slow;
4690 Label finish_store, check_capacity;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004691
4692 Register value_reg = a0;
4693 Register key_reg = a1;
4694 Register receiver_reg = a2;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004695 Register elements_reg = a3;
4696 Register scratch1 = t0;
4697 Register scratch2 = t1;
4698 Register scratch3 = t2;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004699 Register scratch4 = t3;
yangguo@chromium.org56454712012-02-16 15:33:53 +00004700 Register length_reg = t3;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004701
4702 // This stub is meant to be tail-jumped to, the receiver must already
4703 // have been verified by the caller to not be a smi.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004704
4705 // Check that the key is a smi or a heap number convertible to a smi.
4706 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004707
4708 __ lw(elements_reg,
4709 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4710
4711 // Check that the key is within bounds.
4712 if (is_js_array) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004713 __ lw(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004714 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004715 __ lw(scratch1,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004716 FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4717 }
4718 // Compare smis, unsigned compare catches both negative and out-of-bound
4719 // indexes.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004720 if (grow_mode == ALLOW_JSARRAY_GROWTH) {
4721 __ Branch(&grow, hs, key_reg, Operand(scratch1));
4722 } else {
4723 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch1));
4724 }
4725
4726 __ bind(&finish_store);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004727
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004728 __ StoreNumberToDoubleElements(value_reg,
4729 key_reg,
4730 receiver_reg,
4731 elements_reg,
4732 scratch1,
4733 scratch2,
4734 scratch3,
4735 scratch4,
4736 &transition_elements_kind);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004737
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004738 __ Ret(USE_DELAY_SLOT);
4739 __ mov(v0, value_reg); // In delay slot.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004740
4741 // Handle store cache miss, replacing the ic with the generic stub.
4742 __ bind(&miss_force_generic);
4743 Handle<Code> ic =
4744 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4745 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004746
4747 __ bind(&transition_elements_kind);
4748 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4749 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
yangguo@chromium.org56454712012-02-16 15:33:53 +00004750
4751 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4752 // Grow the array by a single element if possible.
4753 __ bind(&grow);
4754
4755 // Make sure the array is only growing by a single element, anything else
4756 // must be handled by the runtime.
4757 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch1));
4758
4759 // Transition on values that can't be stored in a FixedDoubleArray.
4760 Label value_is_smi;
4761 __ JumpIfSmi(value_reg, &value_is_smi);
4762 __ lw(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
4763 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
4764 __ Branch(&transition_elements_kind, ne, scratch1, Operand(at));
4765 __ bind(&value_is_smi);
4766
4767 // Check for the empty array, and preallocate a small backing store if
4768 // possible.
4769 __ lw(length_reg,
4770 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4771 __ lw(elements_reg,
4772 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4773 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
4774 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
4775
4776 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
4777 __ AllocateInNewSpace(size, elements_reg, scratch1, scratch2, &slow,
4778 TAG_OBJECT);
4779
4780 // Initialize the new FixedDoubleArray. Leave elements unitialized for
4781 // efficiency, they are guaranteed to be initialized before use.
4782 __ LoadRoot(scratch1, Heap::kFixedDoubleArrayMapRootIndex);
4783 __ sw(scratch1, FieldMemOperand(elements_reg, JSObject::kMapOffset));
4784 __ li(scratch1, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4785 __ sw(scratch1,
4786 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
4787
4788 // Install the new backing store in the JSArray.
4789 __ sw(elements_reg,
4790 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4791 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
4792 scratch1, kRAHasNotBeenSaved, kDontSaveFPRegs,
4793 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4794
4795 // Increment the length of the array.
4796 __ li(length_reg, Operand(Smi::FromInt(1)));
4797 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
danno@chromium.org00379b82012-05-04 09:16:29 +00004798 __ lw(elements_reg,
4799 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
yangguo@chromium.org56454712012-02-16 15:33:53 +00004800 __ jmp(&finish_store);
4801
4802 __ bind(&check_capacity);
4803 // Make sure that the backing store can hold additional elements.
4804 __ lw(scratch1,
4805 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
4806 __ Branch(&slow, hs, length_reg, Operand(scratch1));
4807
4808 // Grow the array and finish the store.
4809 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
4810 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4811 __ jmp(&finish_store);
4812
4813 __ bind(&slow);
4814 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4815 __ Jump(ic_slow, RelocInfo::CODE_TARGET);
4816 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004817}
4818
4819
ager@chromium.org5c838252010-02-19 08:53:10 +00004820#undef __
4821
4822} } // namespace v8::internal
4823
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004824#endif // V8_TARGET_ARCH_MIPS