blob: 6332be495a10f0d7cd5398920dc3110974ed9483 [file] [log] [blame]
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001// Copyright 2012 the V8 project authors. All rights reserved.
ager@chromium.org5c838252010-02-19 08:53:10 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000030#if defined(V8_TARGET_ARCH_MIPS)
31
ager@chromium.org5c838252010-02-19 08:53:10 +000032#include "ic-inl.h"
karlklose@chromium.org83a47282011-05-11 11:54:09 +000033#include "codegen.h"
ager@chromium.org5c838252010-02-19 08:53:10 +000034#include "stub-cache.h"
35
36namespace v8 {
37namespace internal {
38
39#define __ ACCESS_MASM(masm)
40
41
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000042static void ProbeTable(Isolate* isolate,
43 MacroAssembler* masm,
44 Code::Flags flags,
45 StubCache::Table table,
fschneider@chromium.org35814e52012-03-01 15:43:35 +000046 Register receiver,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000047 Register name,
fschneider@chromium.org35814e52012-03-01 15:43:35 +000048 // Number of the cache entry, not scaled.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000049 Register offset,
50 Register scratch,
fschneider@chromium.org35814e52012-03-01 15:43:35 +000051 Register scratch2,
52 Register offset_scratch) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000053 ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
54 ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
fschneider@chromium.org35814e52012-03-01 15:43:35 +000055 ExternalReference map_offset(isolate->stub_cache()->map_reference(table));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000056
57 uint32_t key_off_addr = reinterpret_cast<uint32_t>(key_offset.address());
58 uint32_t value_off_addr = reinterpret_cast<uint32_t>(value_offset.address());
fschneider@chromium.org35814e52012-03-01 15:43:35 +000059 uint32_t map_off_addr = reinterpret_cast<uint32_t>(map_offset.address());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000060
61 // Check the relative positions of the address fields.
62 ASSERT(value_off_addr > key_off_addr);
63 ASSERT((value_off_addr - key_off_addr) % 4 == 0);
64 ASSERT((value_off_addr - key_off_addr) < (256 * 4));
fschneider@chromium.org35814e52012-03-01 15:43:35 +000065 ASSERT(map_off_addr > key_off_addr);
66 ASSERT((map_off_addr - key_off_addr) % 4 == 0);
67 ASSERT((map_off_addr - key_off_addr) < (256 * 4));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000068
69 Label miss;
fschneider@chromium.org35814e52012-03-01 15:43:35 +000070 Register base_addr = scratch;
71 scratch = no_reg;
72
73 // Multiply by 3 because there are 3 fields per entry (name, code, map).
74 __ sll(offset_scratch, offset, 1);
75 __ Addu(offset_scratch, offset_scratch, offset);
76
77 // Calculate the base address of the entry.
78 __ li(base_addr, Operand(key_offset));
79 __ sll(at, offset_scratch, kPointerSizeLog2);
80 __ Addu(base_addr, base_addr, at);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000081
82 // Check that the key in the entry matches the name.
fschneider@chromium.org35814e52012-03-01 15:43:35 +000083 __ lw(at, MemOperand(base_addr, 0));
84 __ Branch(&miss, ne, name, Operand(at));
85
86 // Check the map matches.
87 __ lw(at, MemOperand(base_addr, map_off_addr - key_off_addr));
88 __ lw(scratch2, FieldMemOperand(receiver, HeapObject::kMapOffset));
89 __ Branch(&miss, ne, at, Operand(scratch2));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000090
91 // Get the code entry from the cache.
fschneider@chromium.org35814e52012-03-01 15:43:35 +000092 Register code = scratch2;
93 scratch2 = no_reg;
94 __ lw(code, MemOperand(base_addr, value_off_addr - key_off_addr));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000095
96 // Check that the flags match what we're looking for.
fschneider@chromium.org35814e52012-03-01 15:43:35 +000097 Register flags_reg = base_addr;
98 base_addr = no_reg;
99 __ lw(flags_reg, FieldMemOperand(code, Code::kFlagsOffset));
100 __ And(flags_reg, flags_reg, Operand(~Code::kFlagsNotUsedInLookup));
101 __ Branch(&miss, ne, flags_reg, Operand(flags));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000102
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000103#ifdef DEBUG
104 if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
105 __ jmp(&miss);
106 } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
107 __ jmp(&miss);
108 }
109#endif
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000110
111 // Jump to the first instruction in the code stub.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000112 __ Addu(at, code, Operand(Code::kHeaderSize - kHeapObjectTag));
113 __ Jump(at);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000114
115 // Miss: fall through.
116 __ bind(&miss);
117}
118
119
120// Helper function used to check that the dictionary doesn't contain
121// the property. This function may return false negatives, so miss_label
122// must always call a backup property check that is complete.
123// This function is safe to call if the receiver has fast properties.
124// Name must be a symbol and receiver must be a heap object.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000125static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
126 Label* miss_label,
127 Register receiver,
128 Handle<String> name,
129 Register scratch0,
130 Register scratch1) {
131 ASSERT(name->IsSymbol());
132 Counters* counters = masm->isolate()->counters();
133 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
134 __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
135
136 Label done;
137
138 const int kInterceptorOrAccessCheckNeededMask =
139 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
140
141 // Bail out if the receiver has a named interceptor or requires access checks.
142 Register map = scratch1;
143 __ lw(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
144 __ lbu(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
145 __ And(scratch0, scratch0, Operand(kInterceptorOrAccessCheckNeededMask));
146 __ Branch(miss_label, ne, scratch0, Operand(zero_reg));
147
148 // Check that receiver is a JSObject.
149 __ lbu(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
150 __ Branch(miss_label, lt, scratch0, Operand(FIRST_SPEC_OBJECT_TYPE));
151
152 // Load properties array.
153 Register properties = scratch0;
154 __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
155 // Check that the properties array is a dictionary.
156 __ lw(map, FieldMemOperand(properties, HeapObject::kMapOffset));
157 Register tmp = properties;
158 __ LoadRoot(tmp, Heap::kHashTableMapRootIndex);
159 __ Branch(miss_label, ne, map, Operand(tmp));
160
161 // Restore the temporarily used register.
162 __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
163
164
165 StringDictionaryLookupStub::GenerateNegativeLookup(masm,
166 miss_label,
167 &done,
168 receiver,
169 properties,
170 name,
171 scratch1);
172 __ bind(&done);
173 __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
174}
175
176
ager@chromium.org5c838252010-02-19 08:53:10 +0000177void StubCache::GenerateProbe(MacroAssembler* masm,
178 Code::Flags flags,
179 Register receiver,
180 Register name,
181 Register scratch,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000182 Register extra,
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000183 Register extra2,
184 Register extra3) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000185 Isolate* isolate = masm->isolate();
186 Label miss;
187
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000188 // Make sure that code is valid. The multiplying code relies on the
189 // entry size being 12.
190 ASSERT(sizeof(Entry) == 12);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000191
192 // Make sure the flags does not name a specific type.
193 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
194
195 // Make sure that there are no register conflicts.
196 ASSERT(!scratch.is(receiver));
197 ASSERT(!scratch.is(name));
198 ASSERT(!extra.is(receiver));
199 ASSERT(!extra.is(name));
200 ASSERT(!extra.is(scratch));
201 ASSERT(!extra2.is(receiver));
202 ASSERT(!extra2.is(name));
203 ASSERT(!extra2.is(scratch));
204 ASSERT(!extra2.is(extra));
205
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000206 // Check register validity.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000207 ASSERT(!scratch.is(no_reg));
208 ASSERT(!extra.is(no_reg));
209 ASSERT(!extra2.is(no_reg));
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000210 ASSERT(!extra3.is(no_reg));
211
212 Counters* counters = masm->isolate()->counters();
213 __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1,
214 extra2, extra3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000215
216 // Check that the receiver isn't a smi.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000217 __ JumpIfSmi(receiver, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000218
219 // Get the map of the receiver and compute the hash.
220 __ lw(scratch, FieldMemOperand(name, String::kHashFieldOffset));
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000221 __ lw(at, FieldMemOperand(receiver, HeapObject::kMapOffset));
222 __ Addu(scratch, scratch, at);
223 uint32_t mask = kPrimaryTableSize - 1;
224 // We shift out the last two bits because they are not part of the hash and
225 // they are always 01 for maps.
226 __ srl(scratch, scratch, kHeapObjectTagSize);
227 __ Xor(scratch, scratch, Operand((flags >> kHeapObjectTagSize) & mask));
228 __ And(scratch, scratch, Operand(mask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000229
230 // Probe the primary table.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000231 ProbeTable(isolate,
232 masm,
233 flags,
234 kPrimary,
235 receiver,
236 name,
237 scratch,
238 extra,
239 extra2,
240 extra3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000241
242 // Primary miss: Compute hash for secondary probe.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000243 __ srl(at, name, kHeapObjectTagSize);
244 __ Subu(scratch, scratch, at);
245 uint32_t mask2 = kSecondaryTableSize - 1;
246 __ Addu(scratch, scratch, Operand((flags >> kHeapObjectTagSize) & mask2));
247 __ And(scratch, scratch, Operand(mask2));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000248
249 // Probe the secondary table.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000250 ProbeTable(isolate,
251 masm,
252 flags,
253 kSecondary,
254 receiver,
255 name,
256 scratch,
257 extra,
258 extra2,
259 extra3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000260
261 // Cache miss: Fall-through and let caller handle the miss by
262 // entering the runtime system.
263 __ bind(&miss);
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000264 __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1,
265 extra2, extra3);
ager@chromium.org5c838252010-02-19 08:53:10 +0000266}
267
268
269void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
270 int index,
271 Register prototype) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000272 // Load the global or builtins object from the current context.
273 __ lw(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
274 // Load the global context from the global or builtins object.
275 __ lw(prototype,
276 FieldMemOperand(prototype, GlobalObject::kGlobalContextOffset));
277 // Load the function from the global context.
278 __ lw(prototype, MemOperand(prototype, Context::SlotOffset(index)));
279 // Load the initial map. The global functions all have initial maps.
280 __ lw(prototype,
281 FieldMemOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
282 // Load the prototype from the initial map.
283 __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000284}
285
286
lrn@chromium.org7516f052011-03-30 08:52:27 +0000287void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000288 MacroAssembler* masm,
289 int index,
290 Register prototype,
291 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000292 Isolate* isolate = masm->isolate();
293 // Check we're still in the same context.
294 __ lw(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
295 ASSERT(!prototype.is(at));
296 __ li(at, isolate->global());
297 __ Branch(miss, ne, prototype, Operand(at));
298 // Get the global function with the given index.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000299 Handle<JSFunction> function(
300 JSFunction::cast(isolate->global_context()->get(index)));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000301 // Load its initial map. The global functions all have initial maps.
302 __ li(prototype, Handle<Map>(function->initial_map()));
303 // Load the prototype from the initial map.
304 __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000305}
306
307
ager@chromium.org5c838252010-02-19 08:53:10 +0000308// Load a fast property out of a holder object (src). In-object properties
309// are loaded directly otherwise the property is loaded from the properties
310// fixed array.
311void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000312 Register dst,
313 Register src,
314 Handle<JSObject> holder,
315 int index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000316 // Adjust for the number of properties stored in the holder.
317 index -= holder->map()->inobject_properties();
318 if (index < 0) {
319 // Get the property straight out of the holder.
320 int offset = holder->map()->instance_size() + (index * kPointerSize);
321 __ lw(dst, FieldMemOperand(src, offset));
322 } else {
323 // Calculate the offset into the properties array.
324 int offset = index * kPointerSize + FixedArray::kHeaderSize;
325 __ lw(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
326 __ lw(dst, FieldMemOperand(dst, offset));
327 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000328}
329
330
331void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
332 Register receiver,
333 Register scratch,
334 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000335 // Check that the receiver isn't a smi.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000336 __ JumpIfSmi(receiver, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000337
338 // Check that the object is a JS array.
339 __ GetObjectType(receiver, scratch, scratch);
340 __ Branch(miss_label, ne, scratch, Operand(JS_ARRAY_TYPE));
341
342 // Load length directly from the JS array.
343 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
344 __ Ret();
345}
346
347
348// Generate code to check if an object is a string. If the object is a
349// heap object, its map's instance type is left in the scratch1 register.
350// If this is not needed, scratch1 and scratch2 may be the same register.
351static void GenerateStringCheck(MacroAssembler* masm,
352 Register receiver,
353 Register scratch1,
354 Register scratch2,
355 Label* smi,
356 Label* non_string_object) {
357 // Check that the receiver isn't a smi.
358 __ JumpIfSmi(receiver, smi, t0);
359
360 // Check that the object is a string.
361 __ lw(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
362 __ lbu(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
363 __ And(scratch2, scratch1, Operand(kIsNotStringMask));
364 // The cast is to resolve the overload for the argument of 0x0.
365 __ Branch(non_string_object,
366 ne,
367 scratch2,
368 Operand(static_cast<int32_t>(kStringTag)));
ager@chromium.org5c838252010-02-19 08:53:10 +0000369}
370
371
lrn@chromium.org7516f052011-03-30 08:52:27 +0000372// Generate code to load the length from a string object and return the length.
373// If the receiver object is not a string or a wrapped string object the
374// execution continues at the miss label. The register containing the
375// receiver is potentially clobbered.
376void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
377 Register receiver,
378 Register scratch1,
379 Register scratch2,
380 Label* miss,
381 bool support_wrappers) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000382 Label check_wrapper;
383
384 // Check if the object is a string leaving the instance type in the
385 // scratch1 register.
386 GenerateStringCheck(masm, receiver, scratch1, scratch2, miss,
387 support_wrappers ? &check_wrapper : miss);
388
389 // Load length directly from the string.
390 __ lw(v0, FieldMemOperand(receiver, String::kLengthOffset));
391 __ Ret();
392
393 if (support_wrappers) {
394 // Check if the object is a JSValue wrapper.
395 __ bind(&check_wrapper);
396 __ Branch(miss, ne, scratch1, Operand(JS_VALUE_TYPE));
397
398 // Unwrap the value and check if the wrapped value is a string.
399 __ lw(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
400 GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
401 __ lw(v0, FieldMemOperand(scratch1, String::kLengthOffset));
402 __ Ret();
403 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000404}
405
406
ager@chromium.org5c838252010-02-19 08:53:10 +0000407void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
408 Register receiver,
409 Register scratch1,
410 Register scratch2,
411 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000412 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
413 __ mov(v0, scratch1);
414 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000415}
416
417
lrn@chromium.org7516f052011-03-30 08:52:27 +0000418// Generate StoreField code, value is passed in a0 register.
ager@chromium.org5c838252010-02-19 08:53:10 +0000419// After executing generated code, the receiver_reg and name_reg
420// may be clobbered.
421void StubCompiler::GenerateStoreField(MacroAssembler* masm,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000422 Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +0000423 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000424 Handle<Map> transition,
ager@chromium.org5c838252010-02-19 08:53:10 +0000425 Register receiver_reg,
426 Register name_reg,
427 Register scratch,
428 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000429 // a0 : value.
430 Label exit;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000431 // Check that the map of the object hasn't changed.
432 __ CheckMap(receiver_reg, scratch, Handle<Map>(object->map()), miss_label,
433 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000434
435 // Perform global security token check if needed.
436 if (object->IsJSGlobalProxy()) {
437 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
438 }
439
440 // Stub never generated for non-global objects that require access
441 // checks.
442 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
443
444 // Perform map transition for the receiver if necessary.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000445 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000446 // The properties must be extended before we can store the value.
447 // We jump to a runtime call that extends the properties array.
448 __ push(receiver_reg);
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000449 __ li(a2, Operand(transition));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000450 __ Push(a2, a0);
451 __ TailCallExternalReference(
452 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
453 masm->isolate()),
454 3, 1);
455 return;
456 }
457
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000458 if (!transition.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000459 // Update the map of the object; no write barrier updating is
460 // needed because the map is never in new space.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000461 __ li(t0, Operand(transition));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000462 __ sw(t0, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
463 }
464
465 // Adjust for the number of properties stored in the object. Even in the
466 // face of a transition we can use the old map here because the size of the
467 // object and the number of in-object properties is not going to change.
468 index -= object->map()->inobject_properties();
469
470 if (index < 0) {
471 // Set the property straight into the object.
472 int offset = object->map()->instance_size() + (index * kPointerSize);
473 __ sw(a0, FieldMemOperand(receiver_reg, offset));
474
475 // Skip updating write barrier if storing a smi.
476 __ JumpIfSmi(a0, &exit, scratch);
477
478 // Update the write barrier for the array address.
479 // Pass the now unused name_reg as a scratch register.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000480 __ mov(name_reg, a0);
481 __ RecordWriteField(receiver_reg,
482 offset,
483 name_reg,
484 scratch,
485 kRAHasNotBeenSaved,
486 kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000487 } else {
488 // Write to the properties array.
489 int offset = index * kPointerSize + FixedArray::kHeaderSize;
490 // Get the properties array.
491 __ lw(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
492 __ sw(a0, FieldMemOperand(scratch, offset));
493
494 // Skip updating write barrier if storing a smi.
495 __ JumpIfSmi(a0, &exit);
496
497 // Update the write barrier for the array address.
498 // Ok to clobber receiver_reg and name_reg, since we return.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000499 __ mov(name_reg, a0);
500 __ RecordWriteField(scratch,
501 offset,
502 name_reg,
503 receiver_reg,
504 kRAHasNotBeenSaved,
505 kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000506 }
507
508 // Return the value (register v0).
509 __ bind(&exit);
510 __ mov(v0, a0);
511 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000512}
513
514
515void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000516 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000517 Handle<Code> code = (kind == Code::LOAD_IC)
518 ? masm->isolate()->builtins()->LoadIC_Miss()
519 : masm->isolate()->builtins()->KeyedLoadIC_Miss();
520 __ Jump(code, RelocInfo::CODE_TARGET);
ager@chromium.org5c838252010-02-19 08:53:10 +0000521}
522
523
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000524static void GenerateCallFunction(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000525 Handle<Object> object,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000526 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000527 Label* miss,
528 Code::ExtraICState extra_ic_state) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000529 // ----------- S t a t e -------------
530 // -- a0: receiver
531 // -- a1: function to call
532 // -----------------------------------
533 // Check that the function really is a function.
534 __ JumpIfSmi(a1, miss);
535 __ GetObjectType(a1, a3, a3);
536 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
537
538 // Patch the receiver on the stack with the global proxy if
539 // necessary.
540 if (object->IsGlobalObject()) {
541 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
542 __ sw(a3, MemOperand(sp, arguments.immediate() * kPointerSize));
543 }
544
545 // Invoke the function.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000546 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
547 ? CALL_AS_FUNCTION
548 : CALL_AS_METHOD;
549 __ InvokeFunction(a1, arguments, JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000550}
551
552
553static void PushInterceptorArguments(MacroAssembler* masm,
554 Register receiver,
555 Register holder,
556 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000557 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000558 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000559 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
560 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000561 Register scratch = name;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000562 __ li(scratch, Operand(interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000563 __ Push(scratch, receiver, holder);
564 __ lw(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
565 __ push(scratch);
566}
567
568
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000569static void CompileCallLoadPropertyWithInterceptor(
570 MacroAssembler* masm,
571 Register receiver,
572 Register holder,
573 Register name,
574 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000575 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
576
577 ExternalReference ref =
578 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
579 masm->isolate());
580 __ li(a0, Operand(5));
581 __ li(a1, Operand(ref));
582
583 CEntryStub stub(1);
584 __ CallStub(&stub);
585}
586
587
588static const int kFastApiCallArguments = 3;
589
590
591// Reserves space for the extra arguments to FastHandleApiCall in the
592// caller's frame.
593//
594// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
595static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
596 Register scratch) {
597 ASSERT(Smi::FromInt(0) == 0);
598 for (int i = 0; i < kFastApiCallArguments; i++) {
599 __ push(zero_reg);
600 }
601}
602
603
604// Undoes the effects of ReserveSpaceForFastApiCall.
605static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
606 __ Drop(kFastApiCallArguments);
607}
608
609
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000610static void GenerateFastApiDirectCall(MacroAssembler* masm,
611 const CallOptimization& optimization,
612 int argc) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000613 // ----------- S t a t e -------------
614 // -- sp[0] : holder (set by CheckPrototypes)
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000615 // -- sp[4] : callee JS function
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000616 // -- sp[8] : call data
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000617 // -- sp[12] : last JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000618 // -- ...
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000619 // -- sp[(argc + 3) * 4] : first JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000620 // -- sp[(argc + 4) * 4] : receiver
621 // -----------------------------------
622 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000623 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000624 __ LoadHeapObject(t1, function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000625 __ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset));
626
627 // Pass the additional arguments FastHandleApiCall expects.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000628 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
629 Handle<Object> call_data(api_call_info->data());
630 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
631 __ li(a0, api_call_info);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000632 __ lw(t2, FieldMemOperand(a0, CallHandlerInfo::kDataOffset));
633 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000634 __ li(t2, call_data);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000635 }
636
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000637 // Store JS function and call data.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000638 __ sw(t1, MemOperand(sp, 1 * kPointerSize));
639 __ sw(t2, MemOperand(sp, 2 * kPointerSize));
640
641 // a2 points to call data as expected by Arguments
642 // (refer to layout above).
643 __ Addu(a2, sp, Operand(2 * kPointerSize));
644
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000645 const int kApiStackSpace = 4;
646
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000647 FrameScope frame_scope(masm, StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000648 __ EnterExitFrame(false, kApiStackSpace);
649
650 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
651 // struct from the function (which is currently the case). This means we pass
652 // the first argument in a1 instead of a0. TryCallApiFunctionAndReturn
653 // will handle setting up a0.
654
655 // a1 = v8::Arguments&
656 // Arguments is built at sp + 1 (sp is a reserved spot for ra).
657 __ Addu(a1, sp, kPointerSize);
658
659 // v8::Arguments::implicit_args = data
660 __ sw(a2, MemOperand(a1, 0 * kPointerSize));
661 // v8::Arguments::values = last argument
662 __ Addu(t0, a2, Operand(argc * kPointerSize));
663 __ sw(t0, MemOperand(a1, 1 * kPointerSize));
664 // v8::Arguments::length_ = argc
665 __ li(t0, Operand(argc));
666 __ sw(t0, MemOperand(a1, 2 * kPointerSize));
667 // v8::Arguments::is_construct_call = 0
668 __ sw(zero_reg, MemOperand(a1, 3 * kPointerSize));
669
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000670 const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000671 Address function_address = v8::ToCData<Address>(api_call_info->callback());
672 ApiFunction fun(function_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000673 ExternalReference ref =
674 ExternalReference(&fun,
675 ExternalReference::DIRECT_API_CALL,
676 masm->isolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000677 AllowExternalCallThatCantCauseGC scope(masm);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000678 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000679}
680
lrn@chromium.org7516f052011-03-30 08:52:27 +0000681class CallInterceptorCompiler BASE_EMBEDDED {
682 public:
683 CallInterceptorCompiler(StubCompiler* stub_compiler,
684 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000685 Register name,
686 Code::ExtraICState extra_ic_state)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000687 : stub_compiler_(stub_compiler),
688 arguments_(arguments),
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000689 name_(name),
690 extra_ic_state_(extra_ic_state) {}
lrn@chromium.org7516f052011-03-30 08:52:27 +0000691
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000692 void Compile(MacroAssembler* masm,
693 Handle<JSObject> object,
694 Handle<JSObject> holder,
695 Handle<String> name,
696 LookupResult* lookup,
697 Register receiver,
698 Register scratch1,
699 Register scratch2,
700 Register scratch3,
701 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000702 ASSERT(holder->HasNamedInterceptor());
703 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
704
705 // Check that the receiver isn't a smi.
706 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000707 CallOptimization optimization(lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000708 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000709 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
710 holder, lookup, name, optimization, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000711 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000712 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
713 name, holder, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000714 }
715 }
716
717 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000718 void CompileCacheable(MacroAssembler* masm,
719 Handle<JSObject> object,
720 Register receiver,
721 Register scratch1,
722 Register scratch2,
723 Register scratch3,
724 Handle<JSObject> interceptor_holder,
725 LookupResult* lookup,
726 Handle<String> name,
727 const CallOptimization& optimization,
728 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000729 ASSERT(optimization.is_constant_call());
730 ASSERT(!lookup->holder()->IsGlobalObject());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000731 Counters* counters = masm->isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000732 int depth1 = kInvalidProtoDepth;
733 int depth2 = kInvalidProtoDepth;
734 bool can_do_fast_api_call = false;
735 if (optimization.is_simple_api_call() &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000736 !lookup->holder()->IsGlobalObject()) {
737 depth1 = optimization.GetPrototypeDepthOfExpectedType(
738 object, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000739 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000740 depth2 = optimization.GetPrototypeDepthOfExpectedType(
741 interceptor_holder, Handle<JSObject>(lookup->holder()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000742 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000743 can_do_fast_api_call =
744 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000745 }
746
747 __ IncrementCounter(counters->call_const_interceptor(), 1,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000748 scratch1, scratch2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000749
750 if (can_do_fast_api_call) {
751 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
752 scratch1, scratch2);
753 ReserveSpaceForFastApiCall(masm, scratch1);
754 }
755
756 // Check that the maps from receiver to interceptor's holder
757 // haven't changed and thus we can invoke interceptor.
758 Label miss_cleanup;
759 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
760 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000761 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
762 scratch1, scratch2, scratch3,
763 name, depth1, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000764
765 // Invoke an interceptor and if it provides a value,
766 // branch to |regular_invoke|.
767 Label regular_invoke;
768 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
769 &regular_invoke);
770
771 // Interceptor returned nothing for this property. Try to use cached
772 // constant function.
773
774 // Check that the maps from interceptor's holder to constant function's
775 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000776 if (*interceptor_holder != lookup->holder()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000777 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000778 Handle<JSObject>(lookup->holder()),
779 scratch1, scratch2, scratch3,
780 name, depth2, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000781 } else {
782 // CheckPrototypes has a side effect of fetching a 'holder'
783 // for API (object which is instanceof for the signature). It's
784 // safe to omit it here, as if present, it should be fetched
785 // by the previous CheckPrototypes.
786 ASSERT(depth2 == kInvalidProtoDepth);
787 }
788
789 // Invoke function.
790 if (can_do_fast_api_call) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000791 GenerateFastApiDirectCall(masm, optimization, arguments_.immediate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000792 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000793 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
794 ? CALL_AS_FUNCTION
795 : CALL_AS_METHOD;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000796 __ InvokeFunction(optimization.constant_function(), arguments_,
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000797 JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000798 }
799
800 // Deferred code for fast API call case---clean preallocated space.
801 if (can_do_fast_api_call) {
802 __ bind(&miss_cleanup);
803 FreeSpaceForFastApiCall(masm);
804 __ Branch(miss_label);
805 }
806
807 // Invoke a regular function.
808 __ bind(&regular_invoke);
809 if (can_do_fast_api_call) {
810 FreeSpaceForFastApiCall(masm);
811 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000812 }
813
814 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000815 Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000816 Register receiver,
817 Register scratch1,
818 Register scratch2,
819 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000820 Handle<String> name,
821 Handle<JSObject> interceptor_holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000822 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000823 Register holder =
824 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000825 scratch1, scratch2, scratch3,
826 name, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000827
828 // Call a runtime function to load the interceptor property.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000829 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000830 // Save the name_ register across the call.
831 __ push(name_);
832
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000833 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000834
835 __ CallExternalReference(
836 ExternalReference(
837 IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
838 masm->isolate()),
839 5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000840 // Restore the name_ register.
841 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000842 // Leave the internal frame.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000843 }
844
845 void LoadWithInterceptor(MacroAssembler* masm,
846 Register receiver,
847 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000848 Handle<JSObject> holder_obj,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000849 Register scratch,
850 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000851 {
852 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000853
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000854 __ Push(holder, name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000855 CompileCallLoadPropertyWithInterceptor(masm,
856 receiver,
857 holder,
858 name_,
859 holder_obj);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000860 __ pop(name_); // Restore the name.
861 __ pop(receiver); // Restore the holder.
862 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000863 // If interceptor returns no-result sentinel, call the constant function.
864 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
865 __ Branch(interceptor_succeeded, ne, v0, Operand(scratch));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000866 }
867
868 StubCompiler* stub_compiler_;
869 const ParameterCount& arguments_;
870 Register name_;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000871 Code::ExtraICState extra_ic_state_;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000872};
873
874
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000875
876// Generate code to check that a global property cell is empty. Create
877// the property cell at compilation time if no cell exists for the
878// property.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000879static void GenerateCheckPropertyCell(MacroAssembler* masm,
880 Handle<GlobalObject> global,
881 Handle<String> name,
882 Register scratch,
883 Label* miss) {
884 Handle<JSGlobalPropertyCell> cell =
885 GlobalObject::EnsurePropertyCell(global, name);
886 ASSERT(cell->value()->IsTheHole());
887 __ li(scratch, Operand(cell));
888 __ lw(scratch,
889 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
890 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
891 __ Branch(miss, ne, scratch, Operand(at));
892}
893
894
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000895// Calls GenerateCheckPropertyCell for each global object in the prototype chain
896// from object to (but not including) holder.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000897static void GenerateCheckPropertyCells(MacroAssembler* masm,
898 Handle<JSObject> object,
899 Handle<JSObject> holder,
900 Handle<String> name,
901 Register scratch,
902 Label* miss) {
903 Handle<JSObject> current = object;
904 while (!current.is_identical_to(holder)) {
905 if (current->IsGlobalObject()) {
906 GenerateCheckPropertyCell(masm,
907 Handle<GlobalObject>::cast(current),
908 name,
909 scratch,
910 miss);
911 }
912 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
913 }
914}
915
916
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000917// Convert and store int passed in register ival to IEEE 754 single precision
918// floating point value at memory location (dst + 4 * wordoffset)
919// If FPU is available use it for conversion.
920static void StoreIntAsFloat(MacroAssembler* masm,
921 Register dst,
922 Register wordoffset,
923 Register ival,
924 Register fval,
925 Register scratch1,
926 Register scratch2) {
927 if (CpuFeatures::IsSupported(FPU)) {
928 CpuFeatures::Scope scope(FPU);
929 __ mtc1(ival, f0);
930 __ cvt_s_w(f0, f0);
931 __ sll(scratch1, wordoffset, 2);
932 __ addu(scratch1, dst, scratch1);
933 __ swc1(f0, MemOperand(scratch1, 0));
934 } else {
935 // FPU is not available, do manual conversions.
936
937 Label not_special, done;
938 // Move sign bit from source to destination. This works because the sign
939 // bit in the exponent word of the double has the same position and polarity
940 // as the 2's complement sign bit in a Smi.
941 ASSERT(kBinary32SignMask == 0x80000000u);
942
943 __ And(fval, ival, Operand(kBinary32SignMask));
944 // Negate value if it is negative.
945 __ subu(scratch1, zero_reg, ival);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +0000946 __ Movn(ival, scratch1, fval);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000947
948 // We have -1, 0 or 1, which we treat specially. Register ival contains
949 // absolute value: it is either equal to 1 (special case of -1 and 1),
950 // greater than 1 (not a special case) or less than 1 (special case of 0).
951 __ Branch(&not_special, gt, ival, Operand(1));
952
953 // For 1 or -1 we need to or in the 0 exponent (biased).
954 static const uint32_t exponent_word_for_1 =
955 kBinary32ExponentBias << kBinary32ExponentShift;
956
957 __ Xor(scratch1, ival, Operand(1));
958 __ li(scratch2, exponent_word_for_1);
959 __ or_(scratch2, fval, scratch2);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +0000960 __ Movz(fval, scratch2, scratch1); // Only if ival is equal to 1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000961 __ Branch(&done);
962
963 __ bind(&not_special);
964 // Count leading zeros.
965 // Gets the wrong answer for 0, but we already checked for that case above.
966 Register zeros = scratch2;
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +0000967 __ Clz(zeros, ival);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000968
969 // Compute exponent and or it into the exponent register.
970 __ li(scratch1, (kBitsPerInt - 1) + kBinary32ExponentBias);
971 __ subu(scratch1, scratch1, zeros);
972
973 __ sll(scratch1, scratch1, kBinary32ExponentShift);
974 __ or_(fval, fval, scratch1);
975
976 // Shift up the source chopping the top bit off.
977 __ Addu(zeros, zeros, Operand(1));
978 // This wouldn't work for 1 and -1 as the shift would be 32 which means 0.
979 __ sllv(ival, ival, zeros);
980 // And the top (top 20 bits).
981 __ srl(scratch1, ival, kBitsPerInt - kBinary32MantissaBits);
982 __ or_(fval, fval, scratch1);
983
984 __ bind(&done);
985
986 __ sll(scratch1, wordoffset, 2);
987 __ addu(scratch1, dst, scratch1);
988 __ sw(fval, MemOperand(scratch1, 0));
989 }
990}
991
992
993// Convert unsigned integer with specified number of leading zeroes in binary
994// representation to IEEE 754 double.
995// Integer to convert is passed in register hiword.
996// Resulting double is returned in registers hiword:loword.
997// This functions does not work correctly for 0.
998static void GenerateUInt2Double(MacroAssembler* masm,
999 Register hiword,
1000 Register loword,
1001 Register scratch,
1002 int leading_zeroes) {
1003 const int meaningful_bits = kBitsPerInt - leading_zeroes - 1;
1004 const int biased_exponent = HeapNumber::kExponentBias + meaningful_bits;
1005
1006 const int mantissa_shift_for_hi_word =
1007 meaningful_bits - HeapNumber::kMantissaBitsInTopWord;
1008
1009 const int mantissa_shift_for_lo_word =
1010 kBitsPerInt - mantissa_shift_for_hi_word;
1011
1012 __ li(scratch, biased_exponent << HeapNumber::kExponentShift);
1013 if (mantissa_shift_for_hi_word > 0) {
1014 __ sll(loword, hiword, mantissa_shift_for_lo_word);
1015 __ srl(hiword, hiword, mantissa_shift_for_hi_word);
1016 __ or_(hiword, scratch, hiword);
1017 } else {
1018 __ mov(loword, zero_reg);
1019 __ sll(hiword, hiword, mantissa_shift_for_hi_word);
1020 __ or_(hiword, scratch, hiword);
1021 }
1022
1023 // If least significant bit of biased exponent was not 1 it was corrupted
1024 // by most significant bit of mantissa so we should fix that.
1025 if (!(biased_exponent & 1)) {
1026 __ li(scratch, 1 << HeapNumber::kExponentShift);
1027 __ nor(scratch, scratch, scratch);
1028 __ and_(hiword, hiword, scratch);
1029 }
1030}
1031
1032
ager@chromium.org5c838252010-02-19 08:53:10 +00001033#undef __
1034#define __ ACCESS_MASM(masm())
1035
1036
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001037Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
1038 Register object_reg,
1039 Handle<JSObject> holder,
1040 Register holder_reg,
1041 Register scratch1,
1042 Register scratch2,
1043 Handle<String> name,
1044 int save_at_depth,
1045 Label* miss) {
1046 // Make sure there's no overlap between holder and object registers.
1047 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1048 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1049 && !scratch2.is(scratch1));
1050
1051 // Keep track of the current object in register reg.
1052 Register reg = object_reg;
1053 int depth = 0;
1054
1055 if (save_at_depth == depth) {
1056 __ sw(reg, MemOperand(sp));
1057 }
1058
1059 // Check the maps in the prototype chain.
1060 // Traverse the prototype chain from the object and do map checks.
1061 Handle<JSObject> current = object;
1062 while (!current.is_identical_to(holder)) {
1063 ++depth;
1064
1065 // Only global objects and objects that do not require access
1066 // checks are allowed in stubs.
1067 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1068
1069 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
1070 if (!current->HasFastProperties() &&
1071 !current->IsJSGlobalObject() &&
1072 !current->IsJSGlobalProxy()) {
1073 if (!name->IsSymbol()) {
1074 name = factory()->LookupSymbol(name);
1075 }
1076 ASSERT(current->property_dictionary()->FindEntry(*name) ==
1077 StringDictionary::kNotFound);
1078
1079 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1080 scratch1, scratch2);
1081
1082 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1083 reg = holder_reg; // From now on the object will be in holder_reg.
1084 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1085 } else {
1086 Handle<Map> current_map(current->map());
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001087 __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK,
1088 ALLOW_ELEMENT_TRANSITION_MAPS);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001089 // Check access rights to the global object. This has to happen after
1090 // the map check so that we know that the object is actually a global
1091 // object.
1092 if (current->IsJSGlobalProxy()) {
1093 __ CheckAccessGlobalProxy(reg, scratch2, miss);
1094 }
1095 reg = holder_reg; // From now on the object will be in holder_reg.
1096
1097 if (heap()->InNewSpace(*prototype)) {
1098 // The prototype is in new space; we cannot store a reference to it
1099 // in the code. Load it from the map.
1100 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1101 } else {
1102 // The prototype is in old space; load it directly.
1103 __ li(reg, Operand(prototype));
1104 }
1105 }
1106
1107 if (save_at_depth == depth) {
1108 __ sw(reg, MemOperand(sp));
1109 }
1110
1111 // Go to the next object in the prototype chain.
1112 current = prototype;
1113 }
1114
1115 // Log the check depth.
1116 LOG(masm()->isolate(), IntEvent("check-maps-depth", depth + 1));
1117
1118 // Check the holder map.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001119 __ CheckMap(reg, scratch1, Handle<Map>(current->map()), miss,
1120 DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001121
1122 // Perform security check for access to the global object.
1123 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1124 if (holder->IsJSGlobalProxy()) {
1125 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1126 }
1127
1128 // If we've skipped any global objects, it's not enough to verify that
1129 // their maps haven't changed. We also need to check that the property
1130 // cell for the property is still empty.
1131 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1132
1133 // Return the register containing the holder.
1134 return reg;
1135}
1136
1137
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001138void StubCompiler::GenerateLoadField(Handle<JSObject> object,
1139 Handle<JSObject> holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001140 Register receiver,
1141 Register scratch1,
1142 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001143 Register scratch3,
ager@chromium.org5c838252010-02-19 08:53:10 +00001144 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001145 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001146 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001147 // Check that the receiver isn't a smi.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001148 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001149
1150 // Check that the maps haven't changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001151 Register reg = CheckPrototypes(
1152 object, receiver, holder, scratch1, scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001153 GenerateFastPropertyLoad(masm(), v0, reg, holder, index);
1154 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001155}
1156
1157
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001158void StubCompiler::GenerateLoadConstant(Handle<JSObject> object,
1159 Handle<JSObject> holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001160 Register receiver,
1161 Register scratch1,
1162 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001163 Register scratch3,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001164 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001165 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001166 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001167 // Check that the receiver isn't a smi.
1168 __ JumpIfSmi(receiver, miss, scratch1);
1169
1170 // Check that the maps haven't changed.
1171 Register reg =
1172 CheckPrototypes(object, receiver, holder,
1173 scratch1, scratch2, scratch3, name, miss);
1174
1175 // Return the constant value.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001176 __ LoadHeapObject(v0, value);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001177 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001178}
1179
1180
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001181void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
1182 Handle<JSObject> holder,
1183 Register receiver,
1184 Register name_reg,
1185 Register scratch1,
1186 Register scratch2,
1187 Register scratch3,
1188 Handle<AccessorInfo> callback,
1189 Handle<String> name,
1190 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001191 // Check that the receiver isn't a smi.
1192 __ JumpIfSmi(receiver, miss, scratch1);
1193
1194 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001195 Register reg = CheckPrototypes(object, receiver, holder, scratch1,
1196 scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001197
1198 // Build AccessorInfo::args_ list on the stack and push property name below
1199 // the exit frame to make GC aware of them and store pointers to them.
1200 __ push(receiver);
1201 __ mov(scratch2, sp); // scratch2 = AccessorInfo::args_
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001202 if (heap()->InNewSpace(callback->data())) {
1203 __ li(scratch3, callback);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001204 __ lw(scratch3, FieldMemOperand(scratch3, AccessorInfo::kDataOffset));
1205 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001206 __ li(scratch3, Handle<Object>(callback->data()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001207 }
1208 __ Push(reg, scratch3, name_reg);
1209 __ mov(a2, scratch2); // Saved in case scratch2 == a1.
1210 __ mov(a1, sp); // a1 (first argument - see note below) = Handle<String>
1211
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001212 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
1213 // struct from the function (which is currently the case). This means we pass
1214 // the arguments in a1-a2 instead of a0-a1. TryCallApiFunctionAndReturn
1215 // will handle setting up a0.
1216
1217 const int kApiStackSpace = 1;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001218 FrameScope frame_scope(masm(), StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001219 __ EnterExitFrame(false, kApiStackSpace);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001220
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001221 // Create AccessorInfo instance on the stack above the exit frame with
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001222 // scratch2 (internal::Object** args_) as the data.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001223 __ sw(a2, MemOperand(sp, kPointerSize));
1224 // a2 (second argument - see note above) = AccessorInfo&
1225 __ Addu(a2, sp, kPointerSize);
1226
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001227 const int kStackUnwindSpace = 4;
1228 Address getter_address = v8::ToCData<Address>(callback->getter());
1229 ApiFunction fun(getter_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001230 ExternalReference ref =
1231 ExternalReference(&fun,
1232 ExternalReference::DIRECT_GETTER_CALL,
1233 masm()->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001234 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
ager@chromium.org5c838252010-02-19 08:53:10 +00001235}
1236
1237
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001238void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
1239 Handle<JSObject> interceptor_holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001240 LookupResult* lookup,
1241 Register receiver,
1242 Register name_reg,
1243 Register scratch1,
1244 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001245 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001246 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001247 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001248 ASSERT(interceptor_holder->HasNamedInterceptor());
1249 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1250
1251 // Check that the receiver isn't a smi.
1252 __ JumpIfSmi(receiver, miss);
1253
1254 // So far the most popular follow ups for interceptor loads are FIELD
1255 // and CALLBACKS, so inline only them, other cases may be added
1256 // later.
1257 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001258 if (lookup->IsFound() && lookup->IsCacheable()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001259 if (lookup->type() == FIELD) {
1260 compile_followup_inline = true;
1261 } else if (lookup->type() == CALLBACKS &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001262 lookup->GetCallbackObject()->IsAccessorInfo()) {
1263 compile_followup_inline =
1264 AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001265 }
1266 }
1267
1268 if (compile_followup_inline) {
1269 // Compile the interceptor call, followed by inline code to load the
1270 // property from further up the prototype chain if the call fails.
1271 // Check that the maps haven't changed.
1272 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1273 scratch1, scratch2, scratch3,
1274 name, miss);
1275 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
1276
1277 // Save necessary data before invoking an interceptor.
1278 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001279 {
1280 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001281 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
1282 // CALLBACKS case needs a receiver to be passed into C++ callback.
1283 __ Push(receiver, holder_reg, name_reg);
1284 } else {
1285 __ Push(holder_reg, name_reg);
1286 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001287 // Invoke an interceptor. Note: map checks from receiver to
1288 // interceptor's holder has been compiled before (see a caller
1289 // of this method).
1290 CompileCallLoadPropertyWithInterceptor(masm(),
1291 receiver,
1292 holder_reg,
1293 name_reg,
1294 interceptor_holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001295 // Check if interceptor provided a value for property. If it's
1296 // the case, return immediately.
1297 Label interceptor_failed;
1298 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
1299 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1));
1300 frame_scope.GenerateLeaveFrame();
1301 __ Ret();
1302
1303 __ bind(&interceptor_failed);
1304 __ pop(name_reg);
1305 __ pop(holder_reg);
1306 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
1307 __ pop(receiver);
1308 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001309 // Leave the internal frame.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001310 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001311 // Check that the maps from interceptor's holder to lookup's holder
1312 // haven't changed. And load lookup's holder into |holder| register.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001313 if (*interceptor_holder != lookup->holder()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001314 holder_reg = CheckPrototypes(interceptor_holder,
1315 holder_reg,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001316 Handle<JSObject>(lookup->holder()),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001317 scratch1,
1318 scratch2,
1319 scratch3,
1320 name,
1321 miss);
1322 }
1323
1324 if (lookup->type() == FIELD) {
1325 // We found FIELD property in prototype chain of interceptor's holder.
1326 // Retrieve a field from field's holder.
1327 GenerateFastPropertyLoad(masm(), v0, holder_reg,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001328 Handle<JSObject>(lookup->holder()),
1329 lookup->GetFieldIndex());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001330 __ Ret();
1331 } else {
1332 // We found CALLBACKS property in prototype chain of interceptor's
1333 // holder.
1334 ASSERT(lookup->type() == CALLBACKS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001335 Handle<AccessorInfo> callback(
1336 AccessorInfo::cast(lookup->GetCallbackObject()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001337 ASSERT(callback->getter() != NULL);
1338
1339 // Tail call to runtime.
1340 // Important invariant in CALLBACKS case: the code above must be
1341 // structured to never clobber |receiver| register.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001342 __ li(scratch2, callback);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001343 // holder_reg is either receiver or scratch1.
1344 if (!receiver.is(holder_reg)) {
1345 ASSERT(scratch1.is(holder_reg));
1346 __ Push(receiver, holder_reg);
1347 __ lw(scratch3,
1348 FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
1349 __ Push(scratch3, scratch2, name_reg);
1350 } else {
1351 __ push(receiver);
1352 __ lw(scratch3,
1353 FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
1354 __ Push(holder_reg, scratch3, scratch2, name_reg);
1355 }
1356
1357 ExternalReference ref =
1358 ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
1359 masm()->isolate());
1360 __ TailCallExternalReference(ref, 5, 1);
1361 }
1362 } else { // !compile_followup_inline
1363 // Call the runtime system to load the interceptor.
1364 // Check that the maps haven't changed.
1365 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1366 scratch1, scratch2, scratch3,
1367 name, miss);
1368 PushInterceptorArguments(masm(), receiver, holder_reg,
1369 name_reg, interceptor_holder);
1370
1371 ExternalReference ref = ExternalReference(
1372 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), masm()->isolate());
1373 __ TailCallExternalReference(ref, 5, 1);
1374 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001375}
1376
1377
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001378void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001379 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001380 __ Branch(miss, ne, a2, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001381 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001382}
1383
1384
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001385void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1386 Handle<JSObject> holder,
1387 Handle<String> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001388 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001389 ASSERT(holder->IsGlobalObject());
1390
1391 // Get the number of arguments.
1392 const int argc = arguments().immediate();
1393
1394 // Get the receiver from the stack.
1395 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1396
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001397 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001398 __ JumpIfSmi(a0, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001399 CheckPrototypes(object, a0, holder, a3, a1, t0, name, miss);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001400}
1401
1402
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001403void CallStubCompiler::GenerateLoadFunctionFromCell(
1404 Handle<JSGlobalPropertyCell> cell,
1405 Handle<JSFunction> function,
1406 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001407 // Get the value from the cell.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001408 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001409 __ lw(a1, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
1410
1411 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001412 if (heap()->InNewSpace(*function)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001413 // We can't embed a pointer to a function in new space so we have
1414 // to verify that the shared function info is unchanged. This has
1415 // the nice side effect that multiple closures based on the same
1416 // function can all use this call IC. Before we load through the
1417 // function, we have to verify that it still is a function.
1418 __ JumpIfSmi(a1, miss);
1419 __ GetObjectType(a1, a3, a3);
1420 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
1421
1422 // Check the shared function info. Make sure it hasn't changed.
1423 __ li(a3, Handle<SharedFunctionInfo>(function->shared()));
1424 __ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
1425 __ Branch(miss, ne, t0, Operand(a3));
1426 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001427 __ Branch(miss, ne, a1, Operand(function));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001428 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001429}
1430
1431
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001432void CallStubCompiler::GenerateMissBranch() {
1433 Handle<Code> code =
danno@chromium.org40cb8782011-05-25 07:58:50 +00001434 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1435 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001436 extra_state_);
1437 __ Jump(code, RelocInfo::CODE_TARGET);
1438}
1439
1440
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001441Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1442 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001443 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001444 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001445 // ----------- S t a t e -------------
1446 // -- a2 : name
1447 // -- ra : return address
1448 // -----------------------------------
1449 Label miss;
1450
1451 GenerateNameCheck(name, &miss);
1452
1453 const int argc = arguments().immediate();
1454
1455 // Get the receiver of the function from the stack into a0.
1456 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1457 // Check that the receiver isn't a smi.
1458 __ JumpIfSmi(a0, &miss, t0);
1459
1460 // Do the right check and compute the holder register.
1461 Register reg = CheckPrototypes(object, a0, holder, a1, a3, t0, name, &miss);
1462 GenerateFastPropertyLoad(masm(), a1, reg, holder, index);
1463
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001464 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001465
1466 // Handle call cache miss.
1467 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001468 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001469
1470 // Return the generated code.
1471 return GetCode(FIELD, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001472}
1473
1474
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001475Handle<Code> CallStubCompiler::CompileArrayPushCall(
1476 Handle<Object> object,
1477 Handle<JSObject> holder,
1478 Handle<JSGlobalPropertyCell> cell,
1479 Handle<JSFunction> function,
1480 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001481 // ----------- S t a t e -------------
1482 // -- a2 : name
1483 // -- ra : return address
1484 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1485 // -- ...
1486 // -- sp[argc * 4] : receiver
1487 // -----------------------------------
1488
1489 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001490 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001491
1492 Label miss;
1493
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001494 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001495
1496 Register receiver = a1;
1497
1498 // Get the receiver from the stack.
1499 const int argc = arguments().immediate();
1500 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1501
1502 // Check that the receiver isn't a smi.
1503 __ JumpIfSmi(receiver, &miss);
1504
1505 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001506 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, a3, v0, t0,
1507 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001508
1509 if (argc == 0) {
1510 // Nothing to do, just return the length.
1511 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1512 __ Drop(argc + 1);
1513 __ Ret();
1514 } else {
1515 Label call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001516 if (argc == 1) { // Otherwise fall through to call the builtin.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001517 Label attempt_to_grow_elements;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001518
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001519 Register elements = t2;
1520 Register end_elements = t1;
1521 // Get the elements array of the object.
1522 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1523
1524 // Check that the elements are in fast mode and writable.
1525 __ CheckMap(elements,
1526 v0,
1527 Heap::kFixedArrayMapRootIndex,
1528 &call_builtin,
1529 DONT_DO_SMI_CHECK);
1530
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001531 // Get the array's length into v0 and calculate new length.
1532 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1533 STATIC_ASSERT(kSmiTagSize == 1);
1534 STATIC_ASSERT(kSmiTag == 0);
1535 __ Addu(v0, v0, Operand(Smi::FromInt(argc)));
1536
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001537 // Get the elements' length.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001538 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1539
1540 // Check if we could survive without allocation.
1541 __ Branch(&attempt_to_grow_elements, gt, v0, Operand(t0));
1542
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001543 // Check if value is a smi.
1544 Label with_write_barrier;
1545 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1546 __ JumpIfNotSmi(t0, &with_write_barrier);
1547
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001548 // Save new length.
1549 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1550
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001551 // Store the value.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001552 // We may need a register containing the address end_elements below,
1553 // so write back the value in end_elements.
1554 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1555 __ Addu(end_elements, elements, end_elements);
1556 const int kEndElementsOffset =
1557 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001558 __ Addu(end_elements, end_elements, kEndElementsOffset);
1559 __ sw(t0, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001560
1561 // Check for a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001562 __ Drop(argc + 1);
1563 __ Ret();
1564
1565 __ bind(&with_write_barrier);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001566
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001567 __ lw(a3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1568
1569 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
1570 Label fast_object, not_fast_object;
1571 __ CheckFastObjectElements(a3, t3, &not_fast_object);
1572 __ jmp(&fast_object);
1573 // In case of fast smi-only, convert to fast object, otherwise bail out.
1574 __ bind(&not_fast_object);
1575 __ CheckFastSmiOnlyElements(a3, t3, &call_builtin);
1576 // edx: receiver
1577 // r3: map
1578 __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
1579 FAST_ELEMENTS,
1580 a3,
1581 t3,
1582 &call_builtin);
1583 __ mov(a2, receiver);
1584 ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm());
1585 __ bind(&fast_object);
1586 } else {
1587 __ CheckFastObjectElements(a3, a3, &call_builtin);
1588 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001589
1590 // Save new length.
1591 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1592
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001593 // Store the value.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001594 // We may need a register containing the address end_elements below,
1595 // so write back the value in end_elements.
1596 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1597 __ Addu(end_elements, elements, end_elements);
1598 __ Addu(end_elements, end_elements, kEndElementsOffset);
1599 __ sw(t0, MemOperand(end_elements));
1600
1601 __ RecordWrite(elements,
1602 end_elements,
1603 t0,
1604 kRAHasNotBeenSaved,
1605 kDontSaveFPRegs,
1606 EMIT_REMEMBERED_SET,
1607 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001608 __ Drop(argc + 1);
1609 __ Ret();
1610
1611 __ bind(&attempt_to_grow_elements);
1612 // v0: array's length + 1.
1613 // t0: elements' length.
1614
1615 if (!FLAG_inline_new) {
1616 __ Branch(&call_builtin);
1617 }
1618
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001619 __ lw(a2, MemOperand(sp, (argc - 1) * kPointerSize));
1620 // Growing elements that are SMI-only requires special handling in case
1621 // the new element is non-Smi. For now, delegate to the builtin.
1622 Label no_fast_elements_check;
1623 __ JumpIfSmi(a2, &no_fast_elements_check);
1624 __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1625 __ CheckFastObjectElements(t3, t3, &call_builtin);
1626 __ bind(&no_fast_elements_check);
1627
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001628 ExternalReference new_space_allocation_top =
1629 ExternalReference::new_space_allocation_top_address(
1630 masm()->isolate());
1631 ExternalReference new_space_allocation_limit =
1632 ExternalReference::new_space_allocation_limit_address(
1633 masm()->isolate());
1634
1635 const int kAllocationDelta = 4;
1636 // Load top and check if it is the end of elements.
1637 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1638 __ Addu(end_elements, elements, end_elements);
1639 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset));
1640 __ li(t3, Operand(new_space_allocation_top));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001641 __ lw(a3, MemOperand(t3));
1642 __ Branch(&call_builtin, ne, end_elements, Operand(a3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001643
1644 __ li(t5, Operand(new_space_allocation_limit));
1645 __ lw(t5, MemOperand(t5));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001646 __ Addu(a3, a3, Operand(kAllocationDelta * kPointerSize));
1647 __ Branch(&call_builtin, hi, a3, Operand(t5));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001648
1649 // We fit and could grow elements.
1650 // Update new_space_allocation_top.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001651 __ sw(a3, MemOperand(t3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001652 // Push the argument.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001653 __ sw(a2, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001654 // Fill the rest with holes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001655 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001656 for (int i = 1; i < kAllocationDelta; i++) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001657 __ sw(a3, MemOperand(end_elements, i * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001658 }
1659
1660 // Update elements' and array's sizes.
1661 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1662 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta)));
1663 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1664
1665 // Elements are in new space, so write barrier is not required.
1666 __ Drop(argc + 1);
1667 __ Ret();
1668 }
1669 __ bind(&call_builtin);
1670 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
1671 masm()->isolate()),
1672 argc + 1,
1673 1);
1674 }
1675
1676 // Handle call cache miss.
1677 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001678 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001679
1680 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001681 return GetCode(function);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001682}
1683
1684
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001685Handle<Code> CallStubCompiler::CompileArrayPopCall(
1686 Handle<Object> object,
1687 Handle<JSObject> holder,
1688 Handle<JSGlobalPropertyCell> cell,
1689 Handle<JSFunction> function,
1690 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001691 // ----------- S t a t e -------------
1692 // -- a2 : name
1693 // -- ra : return address
1694 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1695 // -- ...
1696 // -- sp[argc * 4] : receiver
1697 // -----------------------------------
1698
1699 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001700 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001701
1702 Label miss, return_undefined, call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001703 Register receiver = a1;
1704 Register elements = a3;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001705 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001706
1707 // Get the receiver from the stack.
1708 const int argc = arguments().immediate();
1709 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001710 // Check that the receiver isn't a smi.
1711 __ JumpIfSmi(receiver, &miss);
1712
1713 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001714 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, elements,
1715 t0, v0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001716
1717 // Get the elements array of the object.
1718 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1719
1720 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001721 __ CheckMap(elements,
1722 v0,
1723 Heap::kFixedArrayMapRootIndex,
1724 &call_builtin,
1725 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001726
1727 // Get the array's length into t0 and calculate new length.
1728 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1729 __ Subu(t0, t0, Operand(Smi::FromInt(1)));
1730 __ Branch(&return_undefined, lt, t0, Operand(zero_reg));
1731
1732 // Get the last element.
1733 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1734 STATIC_ASSERT(kSmiTagSize == 1);
1735 STATIC_ASSERT(kSmiTag == 0);
1736 // We can't address the last element in one operation. Compute the more
1737 // expensive shift first, and use an offset later on.
1738 __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize);
1739 __ Addu(elements, elements, t1);
1740 __ lw(v0, MemOperand(elements, FixedArray::kHeaderSize - kHeapObjectTag));
1741 __ Branch(&call_builtin, eq, v0, Operand(t2));
1742
1743 // Set the array's length.
1744 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1745
1746 // Fill with the hole.
1747 __ sw(t2, MemOperand(elements, FixedArray::kHeaderSize - kHeapObjectTag));
1748 __ Drop(argc + 1);
1749 __ Ret();
1750
1751 __ bind(&return_undefined);
1752 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
1753 __ Drop(argc + 1);
1754 __ Ret();
1755
1756 __ bind(&call_builtin);
1757 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop,
1758 masm()->isolate()),
1759 argc + 1,
1760 1);
1761
1762 // Handle call cache miss.
1763 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001764 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001765
1766 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001767 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001768}
1769
1770
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001771Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1772 Handle<Object> object,
1773 Handle<JSObject> holder,
1774 Handle<JSGlobalPropertyCell> cell,
1775 Handle<JSFunction> function,
1776 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001777 // ----------- S t a t e -------------
1778 // -- a2 : function name
1779 // -- ra : return address
1780 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1781 // -- ...
1782 // -- sp[argc * 4] : receiver
1783 // -----------------------------------
1784
1785 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001786 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001787
1788 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001789 Label miss;
1790 Label name_miss;
1791 Label index_out_of_range;
1792
1793 Label* index_out_of_range_label = &index_out_of_range;
1794
danno@chromium.org40cb8782011-05-25 07:58:50 +00001795 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001796 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001797 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001798 index_out_of_range_label = &miss;
1799 }
1800
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001801 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001802
1803 // Check that the maps starting from the prototype haven't changed.
1804 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1805 Context::STRING_FUNCTION_INDEX,
1806 v0,
1807 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001808 ASSERT(!object.is_identical_to(holder));
1809 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1810 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001811
1812 Register receiver = a1;
1813 Register index = t1;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001814 Register result = v0;
1815 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1816 if (argc > 0) {
1817 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1818 } else {
1819 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1820 }
1821
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001822 StringCharCodeAtGenerator generator(receiver,
1823 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001824 result,
1825 &miss, // When not a string.
1826 &miss, // When not a number.
1827 index_out_of_range_label,
1828 STRING_INDEX_IS_NUMBER);
1829 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001830 __ Drop(argc + 1);
1831 __ Ret();
1832
1833 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001834 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001835
1836 if (index_out_of_range.is_linked()) {
1837 __ bind(&index_out_of_range);
1838 __ LoadRoot(v0, Heap::kNanValueRootIndex);
1839 __ Drop(argc + 1);
1840 __ Ret();
1841 }
1842
1843 __ bind(&miss);
1844 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001845 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001846 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001847 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001848
1849 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001850 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001851}
1852
1853
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001854Handle<Code> CallStubCompiler::CompileStringCharAtCall(
1855 Handle<Object> object,
1856 Handle<JSObject> holder,
1857 Handle<JSGlobalPropertyCell> cell,
1858 Handle<JSFunction> function,
1859 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001860 // ----------- S t a t e -------------
1861 // -- a2 : function name
1862 // -- ra : return address
1863 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1864 // -- ...
1865 // -- sp[argc * 4] : receiver
1866 // -----------------------------------
1867
1868 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001869 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001870
1871 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001872 Label miss;
1873 Label name_miss;
1874 Label index_out_of_range;
1875 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00001876 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001877 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001878 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001879 index_out_of_range_label = &miss;
1880 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001881 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001882
1883 // Check that the maps starting from the prototype haven't changed.
1884 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1885 Context::STRING_FUNCTION_INDEX,
1886 v0,
1887 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001888 ASSERT(!object.is_identical_to(holder));
1889 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1890 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001891
1892 Register receiver = v0;
1893 Register index = t1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001894 Register scratch = a3;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001895 Register result = v0;
1896 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1897 if (argc > 0) {
1898 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1899 } else {
1900 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1901 }
1902
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001903 StringCharAtGenerator generator(receiver,
1904 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00001905 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001906 result,
1907 &miss, // When not a string.
1908 &miss, // When not a number.
1909 index_out_of_range_label,
1910 STRING_INDEX_IS_NUMBER);
1911 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001912 __ Drop(argc + 1);
1913 __ Ret();
1914
1915 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001916 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001917
1918 if (index_out_of_range.is_linked()) {
1919 __ bind(&index_out_of_range);
1920 __ LoadRoot(v0, Heap::kEmptyStringRootIndex);
1921 __ Drop(argc + 1);
1922 __ Ret();
1923 }
1924
1925 __ bind(&miss);
1926 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001927 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001928 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001929 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001930
1931 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001932 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001933}
1934
1935
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001936Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
1937 Handle<Object> object,
1938 Handle<JSObject> holder,
1939 Handle<JSGlobalPropertyCell> cell,
1940 Handle<JSFunction> function,
1941 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001942 // ----------- S t a t e -------------
1943 // -- a2 : function name
1944 // -- ra : return address
1945 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1946 // -- ...
1947 // -- sp[argc * 4] : receiver
1948 // -----------------------------------
1949
1950 const int argc = arguments().immediate();
1951
1952 // If the object is not a JSObject or we got an unexpected number of
1953 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001954 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001955
1956 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001957 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001958
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001959 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001960 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
1961
1962 STATIC_ASSERT(kSmiTag == 0);
1963 __ JumpIfSmi(a1, &miss);
1964
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001965 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
1966 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001967 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001968 ASSERT(cell->value() == *function);
1969 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
1970 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001971 GenerateLoadFunctionFromCell(cell, function, &miss);
1972 }
1973
1974 // Load the char code argument.
1975 Register code = a1;
1976 __ lw(code, MemOperand(sp, 0 * kPointerSize));
1977
1978 // Check the code is a smi.
1979 Label slow;
1980 STATIC_ASSERT(kSmiTag == 0);
1981 __ JumpIfNotSmi(code, &slow);
1982
1983 // Convert the smi code to uint16.
1984 __ And(code, code, Operand(Smi::FromInt(0xffff)));
1985
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001986 StringCharFromCodeGenerator generator(code, v0);
1987 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001988 __ Drop(argc + 1);
1989 __ Ret();
1990
1991 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001992 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001993
1994 // Tail call the full function. We do not have to patch the receiver
1995 // because the function makes no use of it.
1996 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001997 __ InvokeFunction(
1998 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001999
2000 __ bind(&miss);
2001 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002002 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002003
2004 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002005 return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002006}
2007
2008
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002009Handle<Code> CallStubCompiler::CompileMathFloorCall(
2010 Handle<Object> object,
2011 Handle<JSObject> holder,
2012 Handle<JSGlobalPropertyCell> cell,
2013 Handle<JSFunction> function,
2014 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002015 // ----------- S t a t e -------------
2016 // -- a2 : function name
2017 // -- ra : return address
2018 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2019 // -- ...
2020 // -- sp[argc * 4] : receiver
2021 // -----------------------------------
2022
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002023 if (!CpuFeatures::IsSupported(FPU)) {
2024 return Handle<Code>::null();
2025 }
2026
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002027 CpuFeatures::Scope scope_fpu(FPU);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002028 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002029 // If the object is not a JSObject or we got an unexpected number of
2030 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002031 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002032
2033 Label miss, slow;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002034 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002035
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002036 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002037 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002038 STATIC_ASSERT(kSmiTag == 0);
2039 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002040 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2041 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002042 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002043 ASSERT(cell->value() == *function);
2044 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2045 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002046 GenerateLoadFunctionFromCell(cell, function, &miss);
2047 }
2048
2049 // Load the (only) argument into v0.
2050 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2051
2052 // If the argument is a smi, just return.
2053 STATIC_ASSERT(kSmiTag == 0);
2054 __ And(t0, v0, Operand(kSmiTagMask));
2055 __ Drop(argc + 1, eq, t0, Operand(zero_reg));
2056 __ Ret(eq, t0, Operand(zero_reg));
2057
danno@chromium.org40cb8782011-05-25 07:58:50 +00002058 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002059
2060 Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return;
2061
2062 // If fpu is enabled, we use the floor instruction.
2063
2064 // Load the HeapNumber value.
2065 __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2066
2067 // Backup FCSR.
2068 __ cfc1(a3, FCSR);
2069 // Clearing FCSR clears the exception mask with no side-effects.
2070 __ ctc1(zero_reg, FCSR);
2071 // Convert the argument to an integer.
2072 __ floor_w_d(f0, f0);
2073
2074 // Start checking for special cases.
2075 // Get the argument exponent and clear the sign bit.
2076 __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize));
2077 __ And(t2, t1, Operand(~HeapNumber::kSignMask));
2078 __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord);
2079
2080 // Retrieve FCSR and check for fpu errors.
2081 __ cfc1(t5, FCSR);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002082 __ And(t5, t5, Operand(kFCSRExceptionFlagMask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002083 __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));
2084
2085 // Check for NaN, Infinity, and -Infinity.
2086 // They are invariant through a Math.Floor call, so just
2087 // return the original argument.
2088 __ Subu(t3, t2, Operand(HeapNumber::kExponentMask
2089 >> HeapNumber::kMantissaBitsInTopWord));
2090 __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg));
2091 // We had an overflow or underflow in the conversion. Check if we
2092 // have a big exponent.
2093 // If greater or equal, the argument is already round and in v0.
2094 __ Branch(&restore_fcsr_and_return, ge, t3,
2095 Operand(HeapNumber::kMantissaBits));
2096 __ Branch(&wont_fit_smi);
2097
2098 __ bind(&no_fpu_error);
2099 // Move the result back to v0.
2100 __ mfc1(v0, f0);
2101 // Check if the result fits into a smi.
2102 __ Addu(a1, v0, Operand(0x40000000));
2103 __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg));
2104 // Tag the result.
2105 STATIC_ASSERT(kSmiTag == 0);
2106 __ sll(v0, v0, kSmiTagSize);
2107
2108 // Check for -0.
2109 __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg));
2110 // t1 already holds the HeapNumber exponent.
2111 __ And(t0, t1, Operand(HeapNumber::kSignMask));
2112 // If our HeapNumber is negative it was -0, so load its address and return.
2113 // Else v0 is loaded with 0, so we can also just return.
2114 __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg));
2115 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2116
2117 __ bind(&restore_fcsr_and_return);
2118 // Restore FCSR and return.
2119 __ ctc1(a3, FCSR);
2120
2121 __ Drop(argc + 1);
2122 __ Ret();
2123
2124 __ bind(&wont_fit_smi);
2125 // Restore FCSR and fall to slow case.
2126 __ ctc1(a3, FCSR);
2127
2128 __ bind(&slow);
2129 // Tail call the full function. We do not have to patch the receiver
2130 // because the function makes no use of it.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002131 __ InvokeFunction(
2132 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002133
2134 __ bind(&miss);
2135 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002136 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002137
2138 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002139 return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002140}
2141
2142
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002143Handle<Code> CallStubCompiler::CompileMathAbsCall(
2144 Handle<Object> object,
2145 Handle<JSObject> holder,
2146 Handle<JSGlobalPropertyCell> cell,
2147 Handle<JSFunction> function,
2148 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002149 // ----------- S t a t e -------------
2150 // -- a2 : function name
2151 // -- ra : return address
2152 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2153 // -- ...
2154 // -- sp[argc * 4] : receiver
2155 // -----------------------------------
2156
2157 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002158 // If the object is not a JSObject or we got an unexpected number of
2159 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002160 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002161
2162 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002163
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002164 GenerateNameCheck(name, &miss);
2165 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002166 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002167 STATIC_ASSERT(kSmiTag == 0);
2168 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002169 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2170 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002171 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002172 ASSERT(cell->value() == *function);
2173 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2174 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002175 GenerateLoadFunctionFromCell(cell, function, &miss);
2176 }
2177
2178 // Load the (only) argument into v0.
2179 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2180
2181 // Check if the argument is a smi.
2182 Label not_smi;
2183 STATIC_ASSERT(kSmiTag == 0);
2184 __ JumpIfNotSmi(v0, &not_smi);
2185
2186 // Do bitwise not or do nothing depending on the sign of the
2187 // argument.
2188 __ sra(t0, v0, kBitsPerInt - 1);
2189 __ Xor(a1, v0, t0);
2190
2191 // Add 1 or do nothing depending on the sign of the argument.
2192 __ Subu(v0, a1, t0);
2193
2194 // If the result is still negative, go to the slow case.
2195 // This only happens for the most negative smi.
2196 Label slow;
2197 __ Branch(&slow, lt, v0, Operand(zero_reg));
2198
2199 // Smi case done.
2200 __ Drop(argc + 1);
2201 __ Ret();
2202
2203 // Check if the argument is a heap number and load its exponent and
2204 // sign.
2205 __ bind(&not_smi);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002206 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002207 __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2208
2209 // Check the sign of the argument. If the argument is positive,
2210 // just return it.
2211 Label negative_sign;
2212 __ And(t0, a1, Operand(HeapNumber::kSignMask));
2213 __ Branch(&negative_sign, ne, t0, Operand(zero_reg));
2214 __ Drop(argc + 1);
2215 __ Ret();
2216
2217 // If the argument is negative, clear the sign, and return a new
2218 // number.
2219 __ bind(&negative_sign);
2220 __ Xor(a1, a1, Operand(HeapNumber::kSignMask));
2221 __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2222 __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
2223 __ AllocateHeapNumber(v0, t0, t1, t2, &slow);
2224 __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2225 __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2226 __ Drop(argc + 1);
2227 __ Ret();
2228
2229 // Tail call the full function. We do not have to patch the receiver
2230 // because the function makes no use of it.
2231 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002232 __ InvokeFunction(
2233 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002234
2235 __ bind(&miss);
2236 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002237 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002238
2239 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002240 return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002241}
2242
2243
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002244Handle<Code> CallStubCompiler::CompileFastApiCall(
lrn@chromium.org7516f052011-03-30 08:52:27 +00002245 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002246 Handle<Object> object,
2247 Handle<JSObject> holder,
2248 Handle<JSGlobalPropertyCell> cell,
2249 Handle<JSFunction> function,
2250 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002251
danno@chromium.org40cb8782011-05-25 07:58:50 +00002252 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002253
2254 ASSERT(optimization.is_simple_api_call());
2255 // Bail out if object is a global object as we don't want to
2256 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002257 if (object->IsGlobalObject()) return Handle<Code>::null();
2258 if (!cell.is_null()) return Handle<Code>::null();
2259 if (!object->IsJSObject()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002260 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002261 Handle<JSObject>::cast(object), holder);
2262 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002263
2264 Label miss, miss_before_stack_reserved;
2265
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002266 GenerateNameCheck(name, &miss_before_stack_reserved);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002267
2268 // Get the receiver from the stack.
2269 const int argc = arguments().immediate();
2270 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2271
2272 // Check that the receiver isn't a smi.
2273 __ JumpIfSmi(a1, &miss_before_stack_reserved);
2274
2275 __ IncrementCounter(counters->call_const(), 1, a0, a3);
2276 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2277
2278 ReserveSpaceForFastApiCall(masm(), a0);
2279
2280 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002281 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002282 depth, &miss);
2283
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002284 GenerateFastApiDirectCall(masm(), optimization, argc);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002285
2286 __ bind(&miss);
2287 FreeSpaceForFastApiCall(masm());
2288
2289 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002290 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002291
2292 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002293 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002294}
2295
2296
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002297Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object,
2298 Handle<JSObject> holder,
2299 Handle<JSFunction> function,
2300 Handle<String> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002301 CheckType check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002302 // ----------- S t a t e -------------
2303 // -- a2 : name
2304 // -- ra : return address
2305 // -----------------------------------
2306 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002307 Handle<Code> code = CompileCustomCall(object, holder,
2308 Handle<JSGlobalPropertyCell>::null(),
2309 function, name);
2310 // A null handle means bail out to the regular compiler code below.
2311 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002312 }
2313
2314 Label miss;
2315
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002316 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002317
2318 // Get the receiver from the stack.
2319 const int argc = arguments().immediate();
2320 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2321
2322 // Check that the receiver isn't a smi.
2323 if (check != NUMBER_CHECK) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002324 __ JumpIfSmi(a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002325 }
2326
2327 // Make sure that it's okay not to patch the on stack receiver
2328 // unless we're doing a receiver map check.
2329 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002330 switch (check) {
2331 case RECEIVER_MAP_CHECK:
2332 __ IncrementCounter(masm()->isolate()->counters()->call_const(),
2333 1, a0, a3);
2334
2335 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002336 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2337 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002338
2339 // Patch the receiver on the stack with the global proxy if
2340 // necessary.
2341 if (object->IsGlobalObject()) {
2342 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2343 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2344 }
2345 break;
2346
2347 case STRING_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002348 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002349 // Check that the object is a two-byte string or a symbol.
2350 __ GetObjectType(a1, a3, a3);
2351 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2352 // Check that the maps starting from the prototype haven't changed.
2353 GenerateDirectLoadGlobalFunctionPrototype(
2354 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002355 CheckPrototypes(
2356 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2357 a0, holder, a3, a1, t0, name, &miss);
2358 } else {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002359 // Calling non-strict non-builtins with a value as the receiver
2360 // requires boxing.
2361 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002362 }
2363 break;
2364
2365 case NUMBER_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002366 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002367 Label fast;
2368 // Check that the object is a smi or a heap number.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002369 __ JumpIfSmi(a1, &fast);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002370 __ GetObjectType(a1, a0, a0);
2371 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
2372 __ bind(&fast);
2373 // Check that the maps starting from the prototype haven't changed.
2374 GenerateDirectLoadGlobalFunctionPrototype(
2375 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002376 CheckPrototypes(
2377 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2378 a0, holder, a3, a1, t0, name, &miss);
2379 } else {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002380 // Calling non-strict non-builtins with a value as the receiver
2381 // requires boxing.
2382 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002383 }
2384 break;
2385
2386 case BOOLEAN_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002387 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002388 Label fast;
2389 // Check that the object is a boolean.
2390 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
2391 __ Branch(&fast, eq, a1, Operand(t0));
2392 __ LoadRoot(t0, Heap::kFalseValueRootIndex);
2393 __ Branch(&miss, ne, a1, Operand(t0));
2394 __ bind(&fast);
2395 // Check that the maps starting from the prototype haven't changed.
2396 GenerateDirectLoadGlobalFunctionPrototype(
2397 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002398 CheckPrototypes(
2399 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2400 a0, holder, a3, a1, t0, name, &miss);
2401 } else {
2402 // Calling non-strict non-builtins with a value as the receiver
2403 // requires boxing.
2404 __ jmp(&miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002405 }
2406 break;
2407 }
2408
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002409 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002410 ? CALL_AS_FUNCTION
2411 : CALL_AS_METHOD;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002412 __ InvokeFunction(
2413 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002414
2415 // Handle call cache miss.
2416 __ bind(&miss);
2417
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002418 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002419
2420 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002421 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002422}
2423
2424
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002425Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2426 Handle<JSObject> holder,
2427 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002428 // ----------- S t a t e -------------
2429 // -- a2 : name
2430 // -- ra : return address
2431 // -----------------------------------
2432
2433 Label miss;
2434
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002435 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002436
2437 // Get the number of arguments.
2438 const int argc = arguments().immediate();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002439 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002440 LookupPostInterceptor(holder, name, &lookup);
2441
2442 // Get the receiver from the stack.
2443 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2444
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002445 CallInterceptorCompiler compiler(this, arguments(), a2, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002446 compiler.Compile(masm(), object, holder, name, &lookup, a1, a3, t0, a0,
2447 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002448
2449 // Move returned value, the function to call, to a1.
2450 __ mov(a1, v0);
2451 // Restore receiver.
2452 __ lw(a0, MemOperand(sp, argc * kPointerSize));
2453
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002454 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002455
2456 // Handle call cache miss.
2457 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002458 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002459
2460 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002461 return GetCode(INTERCEPTOR, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002462}
2463
2464
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002465Handle<Code> CallStubCompiler::CompileCallGlobal(
2466 Handle<JSObject> object,
2467 Handle<GlobalObject> holder,
2468 Handle<JSGlobalPropertyCell> cell,
2469 Handle<JSFunction> function,
2470 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002471 // ----------- S t a t e -------------
2472 // -- a2 : name
2473 // -- ra : return address
2474 // -----------------------------------
2475
2476 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002477 Handle<Code> code = CompileCustomCall(object, holder, cell, function, name);
2478 // A null handle means bail out to the regular compiler code below.
2479 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002480 }
2481
2482 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002483 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002484
2485 // Get the number of arguments.
2486 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002487 GenerateGlobalReceiverCheck(object, holder, name, &miss);
2488 GenerateLoadFunctionFromCell(cell, function, &miss);
2489
2490 // Patch the receiver on the stack with the global proxy if
2491 // necessary.
2492 if (object->IsGlobalObject()) {
2493 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
2494 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2495 }
2496
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002497 // Set up the context (function already in r1).
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002498 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
2499
2500 // Jump to the cached code (tail call).
2501 Counters* counters = masm()->isolate()->counters();
2502 __ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002503 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002504 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002505 ? CALL_AS_FUNCTION
2506 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002507 // We call indirectly through the code field in the function to
2508 // allow recompilation to take effect without changing any of the
2509 // call sites.
2510 __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
2511 __ InvokeCode(a3, expected, arguments(), JUMP_FUNCTION,
2512 NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002513
2514 // Handle call cache miss.
2515 __ bind(&miss);
2516 __ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002517 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002518
2519 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002520 return GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002521}
2522
2523
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002524Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +00002525 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002526 Handle<Map> transition,
2527 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002528 // ----------- S t a t e -------------
2529 // -- a0 : value
2530 // -- a1 : receiver
2531 // -- a2 : name
2532 // -- ra : return address
2533 // -----------------------------------
2534 Label miss;
2535
2536 // Name register might be clobbered.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002537 GenerateStoreField(masm(), object, index, transition, a1, a2, a3, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002538 __ bind(&miss);
2539 __ li(a2, Operand(Handle<String>(name))); // Restore name.
2540 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2541 __ Jump(ic, RelocInfo::CODE_TARGET);
2542
2543 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002544 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002545}
2546
2547
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002548Handle<Code> StoreStubCompiler::CompileStoreCallback(
2549 Handle<JSObject> object,
2550 Handle<AccessorInfo> callback,
2551 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002552 // ----------- S t a t e -------------
2553 // -- a0 : value
2554 // -- a1 : receiver
2555 // -- a2 : name
2556 // -- ra : return address
2557 // -----------------------------------
2558 Label miss;
2559
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002560 // Check that the map of the object hasn't changed.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002561 __ CheckMap(a1, a3, Handle<Map>(object->map()), &miss,
2562 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002563
2564 // Perform global security token check if needed.
2565 if (object->IsJSGlobalProxy()) {
2566 __ CheckAccessGlobalProxy(a1, a3, &miss);
2567 }
2568
2569 // Stub never generated for non-global objects that require access
2570 // checks.
2571 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
2572
2573 __ push(a1); // Receiver.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002574 __ li(a3, Operand(callback)); // Callback info.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002575 __ Push(a3, a2, a0);
2576
2577 // Do tail-call to the runtime system.
2578 ExternalReference store_callback_property =
2579 ExternalReference(IC_Utility(IC::kStoreCallbackProperty),
2580 masm()->isolate());
2581 __ TailCallExternalReference(store_callback_property, 4, 1);
2582
2583 // Handle store cache miss.
2584 __ bind(&miss);
2585 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2586 __ Jump(ic, RelocInfo::CODE_TARGET);
2587
2588 // Return the generated code.
2589 return GetCode(CALLBACKS, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002590}
2591
2592
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002593Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
2594 Handle<JSObject> receiver,
2595 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002596 // ----------- S t a t e -------------
2597 // -- a0 : value
2598 // -- a1 : receiver
2599 // -- a2 : name
2600 // -- ra : return address
2601 // -----------------------------------
2602 Label miss;
2603
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002604 // Check that the map of the object hasn't changed.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002605 __ CheckMap(a1, a3, Handle<Map>(receiver->map()), &miss,
2606 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002607
2608 // Perform global security token check if needed.
2609 if (receiver->IsJSGlobalProxy()) {
2610 __ CheckAccessGlobalProxy(a1, a3, &miss);
2611 }
2612
2613 // Stub is never generated for non-global objects that require access
2614 // checks.
2615 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2616
2617 __ Push(a1, a2, a0); // Receiver, name, value.
2618
2619 __ li(a0, Operand(Smi::FromInt(strict_mode_)));
2620 __ push(a0); // Strict mode.
2621
2622 // Do tail-call to the runtime system.
2623 ExternalReference store_ic_property =
2624 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty),
2625 masm()->isolate());
2626 __ TailCallExternalReference(store_ic_property, 4, 1);
2627
2628 // Handle store cache miss.
2629 __ bind(&miss);
2630 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2631 __ Jump(ic, RelocInfo::CODE_TARGET);
2632
2633 // Return the generated code.
2634 return GetCode(INTERCEPTOR, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002635}
2636
2637
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002638Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2639 Handle<GlobalObject> object,
2640 Handle<JSGlobalPropertyCell> cell,
2641 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002642 // ----------- S t a t e -------------
2643 // -- a0 : value
2644 // -- a1 : receiver
2645 // -- a2 : name
2646 // -- ra : return address
2647 // -----------------------------------
2648 Label miss;
2649
2650 // Check that the map of the global has not changed.
2651 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2652 __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map())));
2653
2654 // Check that the value in the cell is not the hole. If it is, this
2655 // cell could have been deleted and reintroducing the global needs
2656 // to update the property details in the property dictionary of the
2657 // global object. We bail out to the runtime system to do that.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002658 __ li(t0, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002659 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
2660 __ lw(t2, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2661 __ Branch(&miss, eq, t1, Operand(t2));
2662
2663 // Store the value in the cell.
2664 __ sw(a0, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2665 __ mov(v0, a0); // Stored value must be returned in v0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002666 // Cells are always rescanned, so no write barrier here.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002667
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002668 Counters* counters = masm()->isolate()->counters();
2669 __ IncrementCounter(counters->named_store_global_inline(), 1, a1, a3);
2670 __ Ret();
2671
2672 // Handle store cache miss.
2673 __ bind(&miss);
2674 __ IncrementCounter(counters->named_store_global_inline_miss(), 1, a1, a3);
2675 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2676 __ Jump(ic, RelocInfo::CODE_TARGET);
2677
2678 // Return the generated code.
2679 return GetCode(NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002680}
2681
2682
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002683Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
2684 Handle<JSObject> object,
2685 Handle<JSObject> last) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002686 // ----------- S t a t e -------------
2687 // -- a0 : receiver
2688 // -- ra : return address
2689 // -----------------------------------
2690 Label miss;
2691
2692 // Check that the receiver is not a smi.
2693 __ JumpIfSmi(a0, &miss);
2694
2695 // Check the maps of the full prototype chain.
2696 CheckPrototypes(object, a0, last, a3, a1, t0, name, &miss);
2697
2698 // If the last object in the prototype chain is a global object,
2699 // check that the global property cell is empty.
2700 if (last->IsGlobalObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002701 GenerateCheckPropertyCell(
2702 masm(), Handle<GlobalObject>::cast(last), name, a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002703 }
2704
2705 // Return undefined if maps of the full prototype chain is still the same.
2706 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2707 __ Ret();
2708
2709 __ bind(&miss);
2710 GenerateLoadMiss(masm(), Code::LOAD_IC);
2711
2712 // Return the generated code.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002713 return GetCode(NONEXISTENT, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00002714}
2715
2716
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002717Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object,
2718 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002719 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002720 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002721 // ----------- S t a t e -------------
2722 // -- a0 : receiver
2723 // -- a2 : name
2724 // -- ra : return address
2725 // -----------------------------------
2726 Label miss;
2727
2728 __ mov(v0, a0);
2729
2730 GenerateLoadField(object, holder, v0, a3, a1, t0, index, name, &miss);
2731 __ bind(&miss);
2732 GenerateLoadMiss(masm(), Code::LOAD_IC);
2733
2734 // Return the generated code.
2735 return GetCode(FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002736}
2737
2738
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002739Handle<Code> LoadStubCompiler::CompileLoadCallback(
2740 Handle<String> name,
2741 Handle<JSObject> object,
2742 Handle<JSObject> holder,
2743 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002744 // ----------- S t a t e -------------
2745 // -- a0 : receiver
2746 // -- a2 : name
2747 // -- ra : return address
2748 // -----------------------------------
2749 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002750 GenerateLoadCallback(object, holder, a0, a2, a3, a1, t0, callback, name,
2751 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002752 __ bind(&miss);
2753 GenerateLoadMiss(masm(), Code::LOAD_IC);
2754
2755 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002756 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002757}
2758
2759
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002760Handle<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object,
2761 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002762 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002763 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002764 // ----------- S t a t e -------------
2765 // -- a0 : receiver
2766 // -- a2 : name
2767 // -- ra : return address
2768 // -----------------------------------
2769 Label miss;
2770
2771 GenerateLoadConstant(object, holder, a0, a3, a1, t0, value, name, &miss);
2772 __ bind(&miss);
2773 GenerateLoadMiss(masm(), Code::LOAD_IC);
2774
2775 // Return the generated code.
2776 return GetCode(CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002777}
2778
2779
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002780Handle<Code> LoadStubCompiler::CompileLoadInterceptor(Handle<JSObject> object,
2781 Handle<JSObject> holder,
2782 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002783 // ----------- S t a t e -------------
2784 // -- a0 : receiver
2785 // -- a2 : name
2786 // -- ra : return address
2787 // -- [sp] : receiver
2788 // -----------------------------------
2789 Label miss;
2790
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002791 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002792 LookupPostInterceptor(holder, name, &lookup);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002793 GenerateLoadInterceptor(object, holder, &lookup, a0, a2, a3, a1, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002794 &miss);
2795 __ bind(&miss);
2796 GenerateLoadMiss(masm(), Code::LOAD_IC);
2797
2798 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002799 return GetCode(INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002800}
2801
2802
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002803Handle<Code> LoadStubCompiler::CompileLoadGlobal(
2804 Handle<JSObject> object,
2805 Handle<GlobalObject> holder,
2806 Handle<JSGlobalPropertyCell> cell,
2807 Handle<String> name,
2808 bool is_dont_delete) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002809 // ----------- S t a t e -------------
2810 // -- a0 : receiver
2811 // -- a2 : name
2812 // -- ra : return address
2813 // -----------------------------------
2814 Label miss;
2815
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002816 // Check that the map of the global has not changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00002817 __ JumpIfSmi(a0, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002818 CheckPrototypes(object, a0, holder, a3, t0, a1, name, &miss);
2819
2820 // Get the value from the cell.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002821 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002822 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
2823
2824 // Check for deleted property if property can actually be deleted.
2825 if (!is_dont_delete) {
2826 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
2827 __ Branch(&miss, eq, t0, Operand(at));
2828 }
2829
2830 __ mov(v0, t0);
2831 Counters* counters = masm()->isolate()->counters();
2832 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
2833 __ Ret();
2834
2835 __ bind(&miss);
2836 __ IncrementCounter(counters->named_load_global_stub_miss(), 1, a1, a3);
2837 GenerateLoadMiss(masm(), Code::LOAD_IC);
2838
2839 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002840 return GetCode(NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002841}
2842
2843
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002844Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
2845 Handle<JSObject> receiver,
2846 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002847 int index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002848 // ----------- S t a t e -------------
2849 // -- ra : return address
2850 // -- a0 : key
2851 // -- a1 : receiver
2852 // -----------------------------------
2853 Label miss;
2854
2855 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002856 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002857
2858 GenerateLoadField(receiver, holder, a1, a2, a3, t0, index, name, &miss);
2859 __ bind(&miss);
2860 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2861
2862 return GetCode(FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002863}
2864
2865
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002866Handle<Code> KeyedLoadStubCompiler::CompileLoadCallback(
2867 Handle<String> name,
2868 Handle<JSObject> receiver,
2869 Handle<JSObject> holder,
2870 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002871 // ----------- S t a t e -------------
2872 // -- ra : return address
2873 // -- a0 : key
2874 // -- a1 : receiver
2875 // -----------------------------------
2876 Label miss;
2877
2878 // Check the key is the cached one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002879 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002880
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002881 GenerateLoadCallback(receiver, holder, a1, a0, a2, a3, t0, callback, name,
2882 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002883 __ bind(&miss);
2884 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2885
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002886 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002887}
2888
2889
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002890Handle<Code> KeyedLoadStubCompiler::CompileLoadConstant(
2891 Handle<String> name,
2892 Handle<JSObject> receiver,
2893 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002894 Handle<JSFunction> value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002895 // ----------- S t a t e -------------
2896 // -- ra : return address
2897 // -- a0 : key
2898 // -- a1 : receiver
2899 // -----------------------------------
2900 Label miss;
2901
2902 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002903 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002904
2905 GenerateLoadConstant(receiver, holder, a1, a2, a3, t0, value, name, &miss);
2906 __ bind(&miss);
2907 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2908
2909 // Return the generated code.
2910 return GetCode(CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002911}
2912
2913
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002914Handle<Code> KeyedLoadStubCompiler::CompileLoadInterceptor(
2915 Handle<JSObject> receiver,
2916 Handle<JSObject> holder,
2917 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002918 // ----------- S t a t e -------------
2919 // -- ra : return address
2920 // -- a0 : key
2921 // -- a1 : receiver
2922 // -----------------------------------
2923 Label miss;
2924
2925 // Check the key is the cached one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002926 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002927
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002928 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002929 LookupPostInterceptor(holder, name, &lookup);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002930 GenerateLoadInterceptor(receiver, holder, &lookup, a1, a0, a2, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002931 &miss);
2932 __ bind(&miss);
2933 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2934
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002935 return GetCode(INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002936}
2937
2938
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002939Handle<Code> KeyedLoadStubCompiler::CompileLoadArrayLength(
2940 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002941 // ----------- S t a t e -------------
2942 // -- ra : return address
2943 // -- a0 : key
2944 // -- a1 : receiver
2945 // -----------------------------------
2946 Label miss;
2947
2948 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002949 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002950
2951 GenerateLoadArrayLength(masm(), a1, a2, &miss);
2952 __ bind(&miss);
2953 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2954
2955 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002956}
2957
2958
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002959Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength(
2960 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002961 // ----------- S t a t e -------------
2962 // -- ra : return address
2963 // -- a0 : key
2964 // -- a1 : receiver
2965 // -----------------------------------
2966 Label miss;
2967
2968 Counters* counters = masm()->isolate()->counters();
2969 __ IncrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
2970
2971 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002972 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002973
2974 GenerateLoadStringLength(masm(), a1, a2, a3, &miss, true);
2975 __ bind(&miss);
2976 __ DecrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
2977
2978 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2979
2980 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002981}
2982
2983
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002984Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype(
2985 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002986 // ----------- S t a t e -------------
2987 // -- ra : return address
2988 // -- a0 : key
2989 // -- a1 : receiver
2990 // -----------------------------------
2991 Label miss;
2992
2993 Counters* counters = masm()->isolate()->counters();
2994 __ IncrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
2995
2996 // Check the name hasn't changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002997 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002998
2999 GenerateLoadFunctionPrototype(masm(), a1, a2, a3, &miss);
3000 __ bind(&miss);
3001 __ DecrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
3002 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3003
3004 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003005}
3006
3007
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003008Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
3009 Handle<Map> receiver_map) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003010 // ----------- S t a t e -------------
3011 // -- ra : return address
3012 // -- a0 : key
3013 // -- a1 : receiver
3014 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003015 ElementsKind elements_kind = receiver_map->elements_kind();
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003016 Handle<Code> stub = KeyedLoadElementStub(elements_kind).GetCode();
3017
3018 __ DispatchMap(a1, a2, receiver_map, stub, DO_SMI_CHECK);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003019
3020 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
3021 __ Jump(ic, RelocInfo::CODE_TARGET);
3022
3023 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003024 return GetCode(NORMAL, factory()->empty_string());
danno@chromium.org40cb8782011-05-25 07:58:50 +00003025}
3026
3027
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003028Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
3029 MapHandleList* receiver_maps,
3030 CodeHandleList* handler_ics) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003031 // ----------- S t a t e -------------
3032 // -- ra : return address
3033 // -- a0 : key
3034 // -- a1 : receiver
3035 // -----------------------------------
3036 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003037 __ JumpIfSmi(a1, &miss);
3038
danno@chromium.org40cb8782011-05-25 07:58:50 +00003039 int receiver_count = receiver_maps->length();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003040 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003041 for (int current = 0; current < receiver_count; ++current) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003042 __ Jump(handler_ics->at(current), RelocInfo::CODE_TARGET,
3043 eq, a2, Operand(receiver_maps->at(current)));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003044 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003045
3046 __ bind(&miss);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003047 Handle<Code> miss_ic = isolate()->builtins()->KeyedLoadIC_Miss();
3048 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003049
3050 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003051 return GetCode(NORMAL, factory()->empty_string(), MEGAMORPHIC);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003052}
3053
3054
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003055Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +00003056 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003057 Handle<Map> transition,
3058 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003059 // ----------- S t a t e -------------
3060 // -- a0 : value
3061 // -- a1 : key
3062 // -- a2 : receiver
3063 // -- ra : return address
3064 // -----------------------------------
3065
3066 Label miss;
3067
3068 Counters* counters = masm()->isolate()->counters();
3069 __ IncrementCounter(counters->keyed_store_field(), 1, a3, t0);
3070
3071 // Check that the name has not changed.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003072 __ Branch(&miss, ne, a1, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003073
3074 // a3 is used as scratch register. a1 and a2 keep their values if a jump to
3075 // the miss label is generated.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003076 GenerateStoreField(masm(), object, index, transition, a2, a1, a3, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003077 __ bind(&miss);
3078
3079 __ DecrementCounter(counters->keyed_store_field(), 1, a3, t0);
3080 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss();
3081 __ Jump(ic, RelocInfo::CODE_TARGET);
3082
3083 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003084 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003085}
3086
3087
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003088Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
3089 Handle<Map> receiver_map) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003090 // ----------- S t a t e -------------
3091 // -- a0 : value
3092 // -- a1 : key
3093 // -- a2 : receiver
3094 // -- ra : return address
3095 // -- a3 : scratch
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003096 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003097 ElementsKind elements_kind = receiver_map->elements_kind();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003098 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003099 Handle<Code> stub =
yangguo@chromium.org56454712012-02-16 15:33:53 +00003100 KeyedStoreElementStub(is_js_array, elements_kind, grow_mode_).GetCode();
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003101
3102 __ DispatchMap(a2, a3, receiver_map, stub, DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003103
danno@chromium.org40cb8782011-05-25 07:58:50 +00003104 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003105 __ Jump(ic, RelocInfo::CODE_TARGET);
3106
3107 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003108 return GetCode(NORMAL, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00003109}
3110
3111
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003112Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
3113 MapHandleList* receiver_maps,
3114 CodeHandleList* handler_stubs,
3115 MapHandleList* transitioned_maps) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003116 // ----------- S t a t e -------------
3117 // -- a0 : value
3118 // -- a1 : key
3119 // -- a2 : receiver
3120 // -- ra : return address
3121 // -- a3 : scratch
3122 // -----------------------------------
3123 Label miss;
3124 __ JumpIfSmi(a2, &miss);
3125
3126 int receiver_count = receiver_maps->length();
3127 __ lw(a3, FieldMemOperand(a2, HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003128 for (int i = 0; i < receiver_count; ++i) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003129 if (transitioned_maps->at(i).is_null()) {
3130 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq,
3131 a3, Operand(receiver_maps->at(i)));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003132 } else {
3133 Label next_map;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003134 __ Branch(&next_map, ne, a3, Operand(receiver_maps->at(i)));
3135 __ li(a3, Operand(transitioned_maps->at(i)));
3136 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003137 __ bind(&next_map);
3138 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003139 }
3140
3141 __ bind(&miss);
3142 Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
3143 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3144
3145 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003146 return GetCode(NORMAL, factory()->empty_string(), MEGAMORPHIC);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003147}
3148
3149
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003150Handle<Code> ConstructStubCompiler::CompileConstructStub(
3151 Handle<JSFunction> function) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003152 // a0 : argc
3153 // a1 : constructor
3154 // ra : return address
3155 // [sp] : last argument
3156 Label generic_stub_call;
3157
3158 // Use t7 for holding undefined which is used in several places below.
3159 __ LoadRoot(t7, Heap::kUndefinedValueRootIndex);
3160
3161#ifdef ENABLE_DEBUGGER_SUPPORT
3162 // Check to see whether there are any break points in the function code. If
3163 // there are jump to the generic constructor stub which calls the actual
3164 // code for the function thereby hitting the break points.
3165 __ lw(t5, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3166 __ lw(a2, FieldMemOperand(t5, SharedFunctionInfo::kDebugInfoOffset));
3167 __ Branch(&generic_stub_call, ne, a2, Operand(t7));
3168#endif
3169
3170 // Load the initial map and verify that it is in fact a map.
3171 // a1: constructor function
3172 // t7: undefined
3173 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003174 __ JumpIfSmi(a2, &generic_stub_call);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003175 __ GetObjectType(a2, a3, t0);
3176 __ Branch(&generic_stub_call, ne, t0, Operand(MAP_TYPE));
3177
3178#ifdef DEBUG
3179 // Cannot construct functions this way.
3180 // a0: argc
3181 // a1: constructor function
3182 // a2: initial map
3183 // t7: undefined
3184 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
3185 __ Check(ne, "Function constructed by construct stub.",
3186 a3, Operand(JS_FUNCTION_TYPE));
3187#endif
3188
3189 // Now allocate the JSObject in new space.
3190 // a0: argc
3191 // a1: constructor function
3192 // a2: initial map
3193 // t7: undefined
3194 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003195 __ AllocateInNewSpace(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003196
3197 // Allocated the JSObject, now initialize the fields. Map is set to initial
3198 // map and properties and elements are set to empty fixed array.
3199 // a0: argc
3200 // a1: constructor function
3201 // a2: initial map
3202 // a3: object size (in words)
3203 // t4: JSObject (not tagged)
3204 // t7: undefined
3205 __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex);
3206 __ mov(t5, t4);
3207 __ sw(a2, MemOperand(t5, JSObject::kMapOffset));
3208 __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset));
3209 __ sw(t6, MemOperand(t5, JSObject::kElementsOffset));
3210 __ Addu(t5, t5, Operand(3 * kPointerSize));
3211 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
3212 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
3213 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
3214
3215
3216 // Calculate the location of the first argument. The stack contains only the
3217 // argc arguments.
3218 __ sll(a1, a0, kPointerSizeLog2);
3219 __ Addu(a1, a1, sp);
3220
3221 // Fill all the in-object properties with undefined.
3222 // a0: argc
3223 // a1: first argument
3224 // a3: object size (in words)
3225 // t4: JSObject (not tagged)
3226 // t5: First in-object property of JSObject (not tagged)
3227 // t7: undefined
3228 // Fill the initialized properties with a constant value or a passed argument
3229 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003230 Handle<SharedFunctionInfo> shared(function->shared());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003231 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3232 if (shared->IsThisPropertyAssignmentArgument(i)) {
3233 Label not_passed, next;
3234 // Check if the argument assigned to the property is actually passed.
3235 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3236 __ Branch(&not_passed, less_equal, a0, Operand(arg_number));
3237 // Argument passed - find it on the stack.
3238 __ lw(a2, MemOperand(a1, (arg_number + 1) * -kPointerSize));
3239 __ sw(a2, MemOperand(t5));
3240 __ Addu(t5, t5, kPointerSize);
3241 __ jmp(&next);
3242 __ bind(&not_passed);
3243 // Set the property to undefined.
3244 __ sw(t7, MemOperand(t5));
3245 __ Addu(t5, t5, Operand(kPointerSize));
3246 __ bind(&next);
3247 } else {
3248 // Set the property to the constant value.
3249 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
3250 __ li(a2, Operand(constant));
3251 __ sw(a2, MemOperand(t5));
3252 __ Addu(t5, t5, kPointerSize);
3253 }
3254 }
3255
3256 // Fill the unused in-object property fields with undefined.
3257 ASSERT(function->has_initial_map());
3258 for (int i = shared->this_property_assignments_count();
3259 i < function->initial_map()->inobject_properties();
3260 i++) {
3261 __ sw(t7, MemOperand(t5));
3262 __ Addu(t5, t5, kPointerSize);
3263 }
3264
3265 // a0: argc
3266 // t4: JSObject (not tagged)
3267 // Move argc to a1 and the JSObject to return to v0 and tag it.
3268 __ mov(a1, a0);
3269 __ mov(v0, t4);
3270 __ Or(v0, v0, Operand(kHeapObjectTag));
3271
3272 // v0: JSObject
3273 // a1: argc
3274 // Remove caller arguments and receiver from the stack and return.
3275 __ sll(t0, a1, kPointerSizeLog2);
3276 __ Addu(sp, sp, t0);
3277 __ Addu(sp, sp, Operand(kPointerSize));
3278 Counters* counters = masm()->isolate()->counters();
3279 __ IncrementCounter(counters->constructed_objects(), 1, a1, a2);
3280 __ IncrementCounter(counters->constructed_objects_stub(), 1, a1, a2);
3281 __ Ret();
3282
3283 // Jump to the generic stub in case the specialized code cannot handle the
3284 // construction.
3285 __ bind(&generic_stub_call);
3286 Handle<Code> generic_construct_stub =
3287 masm()->isolate()->builtins()->JSConstructStubGeneric();
3288 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
3289
3290 // Return the generated code.
3291 return GetCode();
3292}
3293
3294
danno@chromium.org40cb8782011-05-25 07:58:50 +00003295#undef __
3296#define __ ACCESS_MASM(masm)
3297
3298
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003299void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3300 MacroAssembler* masm) {
3301 // ---------- S t a t e --------------
3302 // -- ra : return address
3303 // -- a0 : key
3304 // -- a1 : receiver
3305 // -----------------------------------
3306 Label slow, miss_force_generic;
3307
3308 Register key = a0;
3309 Register receiver = a1;
3310
3311 __ JumpIfNotSmi(key, &miss_force_generic);
3312 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
3313 __ sra(a2, a0, kSmiTagSize);
3314 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
3315 __ Ret();
3316
3317 // Slow case, key and receiver still in a0 and a1.
3318 __ bind(&slow);
3319 __ IncrementCounter(
3320 masm->isolate()->counters()->keyed_load_external_array_slow(),
3321 1, a2, a3);
3322 // Entry registers are intact.
3323 // ---------- S t a t e --------------
3324 // -- ra : return address
3325 // -- a0 : key
3326 // -- a1 : receiver
3327 // -----------------------------------
3328 Handle<Code> slow_ic =
3329 masm->isolate()->builtins()->KeyedLoadIC_Slow();
3330 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
3331
3332 // Miss case, call the runtime.
3333 __ bind(&miss_force_generic);
3334
3335 // ---------- S t a t e --------------
3336 // -- ra : return address
3337 // -- a0 : key
3338 // -- a1 : receiver
3339 // -----------------------------------
3340
3341 Handle<Code> miss_ic =
3342 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3343 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3344}
3345
3346
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003347static bool IsElementTypeSigned(ElementsKind elements_kind) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003348 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003349 case EXTERNAL_BYTE_ELEMENTS:
3350 case EXTERNAL_SHORT_ELEMENTS:
3351 case EXTERNAL_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003352 return true;
3353
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003354 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3355 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3356 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3357 case EXTERNAL_PIXEL_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003358 return false;
3359
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003360 case EXTERNAL_FLOAT_ELEMENTS:
3361 case EXTERNAL_DOUBLE_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003362 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003363 case FAST_ELEMENTS:
3364 case FAST_DOUBLE_ELEMENTS:
3365 case DICTIONARY_ELEMENTS:
3366 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003367 UNREACHABLE();
3368 return false;
3369 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003370 return false;
lrn@chromium.org7516f052011-03-30 08:52:27 +00003371}
3372
3373
danno@chromium.org40cb8782011-05-25 07:58:50 +00003374void KeyedLoadStubCompiler::GenerateLoadExternalArray(
3375 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003376 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003377 // ---------- S t a t e --------------
3378 // -- ra : return address
3379 // -- a0 : key
3380 // -- a1 : receiver
3381 // -----------------------------------
danno@chromium.org40cb8782011-05-25 07:58:50 +00003382 Label miss_force_generic, slow, failed_allocation;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003383
3384 Register key = a0;
3385 Register receiver = a1;
3386
danno@chromium.org40cb8782011-05-25 07:58:50 +00003387 // This stub is meant to be tail-jumped to, the receiver must already
3388 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003389
3390 // Check that the key is a smi.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003391 __ JumpIfNotSmi(key, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003392
3393 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3394 // a3: elements array
3395
3396 // Check that the index is in range.
3397 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3398 __ sra(t2, key, kSmiTagSize);
3399 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003400 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003401
3402 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3403 // a3: base pointer of external storage
3404
3405 // We are not untagging smi key and instead work with it
3406 // as if it was premultiplied by 2.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003407 STATIC_ASSERT((kSmiTag == 0) && (kSmiTagSize == 1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003408
3409 Register value = a2;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003410 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003411 case EXTERNAL_BYTE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003412 __ srl(t2, key, 1);
3413 __ addu(t3, a3, t2);
3414 __ lb(value, MemOperand(t3, 0));
3415 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003416 case EXTERNAL_PIXEL_ELEMENTS:
3417 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003418 __ srl(t2, key, 1);
3419 __ addu(t3, a3, t2);
3420 __ lbu(value, MemOperand(t3, 0));
3421 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003422 case EXTERNAL_SHORT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003423 __ addu(t3, a3, key);
3424 __ lh(value, MemOperand(t3, 0));
3425 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003426 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003427 __ addu(t3, a3, key);
3428 __ lhu(value, MemOperand(t3, 0));
3429 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003430 case EXTERNAL_INT_ELEMENTS:
3431 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003432 __ sll(t2, key, 1);
3433 __ addu(t3, a3, t2);
3434 __ lw(value, MemOperand(t3, 0));
3435 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003436 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003437 __ sll(t3, t2, 2);
3438 __ addu(t3, a3, t3);
3439 if (CpuFeatures::IsSupported(FPU)) {
3440 CpuFeatures::Scope scope(FPU);
3441 __ lwc1(f0, MemOperand(t3, 0));
3442 } else {
3443 __ lw(value, MemOperand(t3, 0));
3444 }
3445 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003446 case EXTERNAL_DOUBLE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003447 __ sll(t2, key, 2);
3448 __ addu(t3, a3, t2);
3449 if (CpuFeatures::IsSupported(FPU)) {
3450 CpuFeatures::Scope scope(FPU);
3451 __ ldc1(f0, MemOperand(t3, 0));
3452 } else {
3453 // t3: pointer to the beginning of the double we want to load.
3454 __ lw(a2, MemOperand(t3, 0));
3455 __ lw(a3, MemOperand(t3, Register::kSizeInBytes));
3456 }
3457 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003458 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003459 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003460 case FAST_DOUBLE_ELEMENTS:
3461 case DICTIONARY_ELEMENTS:
3462 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003463 UNREACHABLE();
3464 break;
3465 }
3466
3467 // For integer array types:
3468 // a2: value
3469 // For float array type:
3470 // f0: value (if FPU is supported)
3471 // a2: value (if FPU is not supported)
3472 // For double array type:
3473 // f0: value (if FPU is supported)
3474 // a2/a3: value (if FPU is not supported)
3475
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003476 if (elements_kind == EXTERNAL_INT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003477 // For the Int and UnsignedInt array types, we need to see whether
3478 // the value can be represented in a Smi. If not, we need to convert
3479 // it to a HeapNumber.
3480 Label box_int;
3481 __ Subu(t3, value, Operand(0xC0000000)); // Non-smi value gives neg result.
3482 __ Branch(&box_int, lt, t3, Operand(zero_reg));
3483 // Tag integer as smi and return it.
3484 __ sll(v0, value, kSmiTagSize);
3485 __ Ret();
3486
3487 __ bind(&box_int);
3488 // Allocate a HeapNumber for the result and perform int-to-double
3489 // conversion.
3490 // The arm version uses a temporary here to save r0, but we don't need to
3491 // (a0 is not modified).
3492 __ LoadRoot(t1, Heap::kHeapNumberMapRootIndex);
3493 __ AllocateHeapNumber(v0, a3, t0, t1, &slow);
3494
3495 if (CpuFeatures::IsSupported(FPU)) {
3496 CpuFeatures::Scope scope(FPU);
3497 __ mtc1(value, f0);
3498 __ cvt_d_w(f0, f0);
3499 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag));
3500 __ Ret();
3501 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003502 Register dst1 = t2;
3503 Register dst2 = t3;
3504 FloatingPointHelper::Destination dest =
3505 FloatingPointHelper::kCoreRegisters;
3506 FloatingPointHelper::ConvertIntToDouble(masm,
3507 value,
3508 dest,
3509 f0,
3510 dst1,
3511 dst2,
3512 t1,
3513 f2);
3514 __ sw(dst1, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3515 __ sw(dst2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3516 __ Ret();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003517 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003518 } else if (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003519 // The test is different for unsigned int values. Since we need
3520 // the value to be in the range of a positive smi, we can't
3521 // handle either of the top two bits being set in the value.
3522 if (CpuFeatures::IsSupported(FPU)) {
3523 CpuFeatures::Scope scope(FPU);
3524 Label pl_box_int;
3525 __ And(t2, value, Operand(0xC0000000));
3526 __ Branch(&pl_box_int, ne, t2, Operand(zero_reg));
3527
3528 // It can fit in an Smi.
3529 // Tag integer as smi and return it.
3530 __ sll(v0, value, kSmiTagSize);
3531 __ Ret();
3532
3533 __ bind(&pl_box_int);
3534 // Allocate a HeapNumber for the result and perform int-to-double
3535 // conversion. Don't use a0 and a1 as AllocateHeapNumber clobbers all
3536 // registers - also when jumping due to exhausted young space.
3537 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3538 __ AllocateHeapNumber(v0, t2, t3, t6, &slow);
3539
3540 // This is replaced by a macro:
3541 // __ mtc1(value, f0); // LS 32-bits.
3542 // __ mtc1(zero_reg, f1); // MS 32-bits are all zero.
3543 // __ cvt_d_l(f0, f0); // Use 64 bit conv to get correct unsigned 32-bit.
3544
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003545 __ Cvt_d_uw(f0, value, f22);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003546
3547 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag));
3548
3549 __ Ret();
3550 } else {
3551 // Check whether unsigned integer fits into smi.
3552 Label box_int_0, box_int_1, done;
3553 __ And(t2, value, Operand(0x80000000));
3554 __ Branch(&box_int_0, ne, t2, Operand(zero_reg));
3555 __ And(t2, value, Operand(0x40000000));
3556 __ Branch(&box_int_1, ne, t2, Operand(zero_reg));
3557
3558 // Tag integer as smi and return it.
3559 __ sll(v0, value, kSmiTagSize);
3560 __ Ret();
3561
3562 Register hiword = value; // a2.
3563 Register loword = a3;
3564
3565 __ bind(&box_int_0);
3566 // Integer does not have leading zeros.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003567 GenerateUInt2Double(masm, hiword, loword, t0, 0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003568 __ Branch(&done);
3569
3570 __ bind(&box_int_1);
3571 // Integer has one leading zero.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003572 GenerateUInt2Double(masm, hiword, loword, t0, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003573
3574
3575 __ bind(&done);
3576 // Integer was converted to double in registers hiword:loword.
3577 // Wrap it into a HeapNumber. Don't use a0 and a1 as AllocateHeapNumber
3578 // clobbers all registers - also when jumping due to exhausted young
3579 // space.
3580 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3581 __ AllocateHeapNumber(t2, t3, t5, t6, &slow);
3582
3583 __ sw(hiword, FieldMemOperand(t2, HeapNumber::kExponentOffset));
3584 __ sw(loword, FieldMemOperand(t2, HeapNumber::kMantissaOffset));
3585
3586 __ mov(v0, t2);
3587 __ Ret();
3588 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003589 } else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003590 // For the floating-point array type, we need to always allocate a
3591 // HeapNumber.
3592 if (CpuFeatures::IsSupported(FPU)) {
3593 CpuFeatures::Scope scope(FPU);
3594 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3595 // AllocateHeapNumber clobbers all registers - also when jumping due to
3596 // exhausted young space.
3597 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3598 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3599 // The float (single) value is already in fpu reg f0 (if we use float).
3600 __ cvt_d_s(f0, f0);
3601 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag));
3602 __ Ret();
3603 } else {
3604 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3605 // AllocateHeapNumber clobbers all registers - also when jumping due to
3606 // exhausted young space.
3607 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3608 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3609 // FPU is not available, do manual single to double conversion.
3610
3611 // a2: floating point value (binary32).
3612 // v0: heap number for result
3613
3614 // Extract mantissa to t4.
3615 __ And(t4, value, Operand(kBinary32MantissaMask));
3616
3617 // Extract exponent to t5.
3618 __ srl(t5, value, kBinary32MantissaBits);
3619 __ And(t5, t5, Operand(kBinary32ExponentMask >> kBinary32MantissaBits));
3620
3621 Label exponent_rebiased;
3622 __ Branch(&exponent_rebiased, eq, t5, Operand(zero_reg));
3623
3624 __ li(t0, 0x7ff);
3625 __ Xor(t1, t5, Operand(0xFF));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003626 __ Movz(t5, t0, t1); // Set t5 to 0x7ff only if t5 is equal to 0xff.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003627 __ Branch(&exponent_rebiased, eq, t0, Operand(0xff));
3628
3629 // Rebias exponent.
3630 __ Addu(t5,
3631 t5,
3632 Operand(-kBinary32ExponentBias + HeapNumber::kExponentBias));
3633
3634 __ bind(&exponent_rebiased);
3635 __ And(a2, value, Operand(kBinary32SignMask));
3636 value = no_reg;
3637 __ sll(t0, t5, HeapNumber::kMantissaBitsInTopWord);
3638 __ or_(a2, a2, t0);
3639
3640 // Shift mantissa.
3641 static const int kMantissaShiftForHiWord =
3642 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3643
3644 static const int kMantissaShiftForLoWord =
3645 kBitsPerInt - kMantissaShiftForHiWord;
3646
3647 __ srl(t0, t4, kMantissaShiftForHiWord);
3648 __ or_(a2, a2, t0);
3649 __ sll(a0, t4, kMantissaShiftForLoWord);
3650
3651 __ sw(a2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3652 __ sw(a0, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3653 __ Ret();
3654 }
3655
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003656 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003657 if (CpuFeatures::IsSupported(FPU)) {
3658 CpuFeatures::Scope scope(FPU);
3659 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3660 // AllocateHeapNumber clobbers all registers - also when jumping due to
3661 // exhausted young space.
3662 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3663 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3664 // The double value is already in f0
3665 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
3666 __ Ret();
3667 } else {
3668 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3669 // AllocateHeapNumber clobbers all registers - also when jumping due to
3670 // exhausted young space.
3671 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3672 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3673
3674 __ sw(a2, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3675 __ sw(a3, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3676 __ Ret();
3677 }
3678
3679 } else {
3680 // Tag integer as smi and return it.
3681 __ sll(v0, value, kSmiTagSize);
3682 __ Ret();
3683 }
3684
3685 // Slow case, key and receiver still in a0 and a1.
3686 __ bind(&slow);
3687 __ IncrementCounter(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003688 masm->isolate()->counters()->keyed_load_external_array_slow(),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003689 1, a2, a3);
3690
3691 // ---------- S t a t e --------------
3692 // -- ra : return address
3693 // -- a0 : key
3694 // -- a1 : receiver
3695 // -----------------------------------
3696
3697 __ Push(a1, a0);
3698
3699 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
3700
danno@chromium.org40cb8782011-05-25 07:58:50 +00003701 __ bind(&miss_force_generic);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003702 Handle<Code> stub =
3703 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3704 __ Jump(stub, RelocInfo::CODE_TARGET);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003705}
3706
3707
danno@chromium.org40cb8782011-05-25 07:58:50 +00003708void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3709 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003710 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003711 // ---------- S t a t e --------------
3712 // -- a0 : value
3713 // -- a1 : key
3714 // -- a2 : receiver
3715 // -- ra : return address
3716 // -----------------------------------
3717
danno@chromium.org40cb8782011-05-25 07:58:50 +00003718 Label slow, check_heap_number, miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003719
3720 // Register usage.
3721 Register value = a0;
3722 Register key = a1;
3723 Register receiver = a2;
3724 // a3 mostly holds the elements array or the destination external array.
3725
danno@chromium.org40cb8782011-05-25 07:58:50 +00003726 // This stub is meant to be tail-jumped to, the receiver must already
3727 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003728
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003729 // Check that the key is a smi.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003730 __ JumpIfNotSmi(key, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003731
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003732 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3733
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003734 // Check that the index is in range.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003735 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3736 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003737 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003738
3739 // Handle both smis and HeapNumbers in the fast path. Go to the
3740 // runtime for all other kinds of values.
3741 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003742
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003743 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003744 // Double to pixel conversion is only implemented in the runtime for now.
3745 __ JumpIfNotSmi(value, &slow);
3746 } else {
3747 __ JumpIfNotSmi(value, &check_heap_number);
3748 }
3749 __ SmiUntag(t1, value);
3750 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3751
3752 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003753 // t1: value (integer).
3754
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003755 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003756 case EXTERNAL_PIXEL_ELEMENTS: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003757 // Clamp the value to [0..255].
3758 // v0 is used as a scratch register here.
3759 Label done;
3760 __ li(v0, Operand(255));
3761 // Normal branch: nop in delay slot.
3762 __ Branch(&done, gt, t1, Operand(v0));
3763 // Use delay slot in this branch.
3764 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg));
3765 __ mov(v0, zero_reg); // In delay slot.
3766 __ mov(v0, t1); // Value is in range 0..255.
3767 __ bind(&done);
3768 __ mov(t1, v0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003769
3770 __ srl(t8, key, 1);
3771 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003772 __ sb(t1, MemOperand(t8, 0));
3773 }
3774 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003775 case EXTERNAL_BYTE_ELEMENTS:
3776 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003777 __ srl(t8, key, 1);
3778 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003779 __ sb(t1, MemOperand(t8, 0));
3780 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003781 case EXTERNAL_SHORT_ELEMENTS:
3782 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003783 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003784 __ sh(t1, MemOperand(t8, 0));
3785 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003786 case EXTERNAL_INT_ELEMENTS:
3787 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003788 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003789 __ addu(t8, a3, t8);
3790 __ sw(t1, MemOperand(t8, 0));
3791 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003792 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003793 // Perform int-to-float conversion and store to memory.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003794 __ SmiUntag(t0, key);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003795 StoreIntAsFloat(masm, a3, t0, t1, t2, t3, t4);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003796 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003797 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003798 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003799 __ addu(a3, a3, t8);
3800 // a3: effective address of the double element
3801 FloatingPointHelper::Destination destination;
3802 if (CpuFeatures::IsSupported(FPU)) {
3803 destination = FloatingPointHelper::kFPURegisters;
3804 } else {
3805 destination = FloatingPointHelper::kCoreRegisters;
3806 }
3807 FloatingPointHelper::ConvertIntToDouble(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003808 masm, t1, destination,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003809 f0, t2, t3, // These are: double_dst, dst1, dst2.
3810 t0, f2); // These are: scratch2, single_scratch.
3811 if (destination == FloatingPointHelper::kFPURegisters) {
3812 CpuFeatures::Scope scope(FPU);
3813 __ sdc1(f0, MemOperand(a3, 0));
3814 } else {
3815 __ sw(t2, MemOperand(a3, 0));
3816 __ sw(t3, MemOperand(a3, Register::kSizeInBytes));
3817 }
3818 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003819 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003820 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003821 case FAST_DOUBLE_ELEMENTS:
3822 case DICTIONARY_ELEMENTS:
3823 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003824 UNREACHABLE();
3825 break;
3826 }
3827
3828 // Entry registers are intact, a0 holds the value which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003829 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003830 __ Ret();
3831
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003832 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003833 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003834 __ bind(&check_heap_number);
3835 __ GetObjectType(value, t1, t2);
3836 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE));
3837
3838 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3839
3840 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003841
3842 // The WebGL specification leaves the behavior of storing NaN and
3843 // +/-Infinity into integer arrays basically undefined. For more
3844 // reproducible behavior, convert these to zero.
3845
3846 if (CpuFeatures::IsSupported(FPU)) {
3847 CpuFeatures::Scope scope(FPU);
3848
3849 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
3850
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003851 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003852 __ cvt_s_d(f0, f0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003853 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003854 __ addu(t8, a3, t8);
3855 __ swc1(f0, MemOperand(t8, 0));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003856 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003857 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003858 __ addu(t8, a3, t8);
3859 __ sdc1(f0, MemOperand(t8, 0));
3860 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003861 __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003862
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003863 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003864 case EXTERNAL_BYTE_ELEMENTS:
3865 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003866 __ srl(t8, key, 1);
3867 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003868 __ sb(t3, MemOperand(t8, 0));
3869 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003870 case EXTERNAL_SHORT_ELEMENTS:
3871 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003872 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003873 __ sh(t3, MemOperand(t8, 0));
3874 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003875 case EXTERNAL_INT_ELEMENTS:
3876 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003877 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003878 __ addu(t8, a3, t8);
3879 __ sw(t3, MemOperand(t8, 0));
3880 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003881 case EXTERNAL_PIXEL_ELEMENTS:
3882 case EXTERNAL_FLOAT_ELEMENTS:
3883 case EXTERNAL_DOUBLE_ELEMENTS:
3884 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003885 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003886 case FAST_DOUBLE_ELEMENTS:
3887 case DICTIONARY_ELEMENTS:
3888 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003889 UNREACHABLE();
3890 break;
3891 }
3892 }
3893
3894 // Entry registers are intact, a0 holds the value
3895 // which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003896 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003897 __ Ret();
3898 } else {
3899 // FPU is not available, do manual conversions.
3900
3901 __ lw(t3, FieldMemOperand(value, HeapNumber::kExponentOffset));
3902 __ lw(t4, FieldMemOperand(value, HeapNumber::kMantissaOffset));
3903
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003904 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003905 Label done, nan_or_infinity_or_zero;
3906 static const int kMantissaInHiWordShift =
3907 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3908
3909 static const int kMantissaInLoWordShift =
3910 kBitsPerInt - kMantissaInHiWordShift;
3911
3912 // Test for all special exponent values: zeros, subnormal numbers, NaNs
3913 // and infinities. All these should be converted to 0.
3914 __ li(t5, HeapNumber::kExponentMask);
3915 __ and_(t6, t3, t5);
3916 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(zero_reg));
3917
3918 __ xor_(t1, t6, t5);
3919 __ li(t2, kBinary32ExponentMask);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003920 __ Movz(t6, t2, t1); // Only if t6 is equal to t5.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003921 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(t5));
3922
3923 // Rebias exponent.
3924 __ srl(t6, t6, HeapNumber::kExponentShift);
3925 __ Addu(t6,
3926 t6,
3927 Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
3928
3929 __ li(t1, Operand(kBinary32MaxExponent));
3930 __ Slt(t1, t1, t6);
3931 __ And(t2, t3, Operand(HeapNumber::kSignMask));
3932 __ Or(t2, t2, Operand(kBinary32ExponentMask));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003933 __ Movn(t3, t2, t1); // Only if t6 is gt kBinary32MaxExponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003934 __ Branch(&done, gt, t6, Operand(kBinary32MaxExponent));
3935
3936 __ Slt(t1, t6, Operand(kBinary32MinExponent));
3937 __ And(t2, t3, Operand(HeapNumber::kSignMask));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003938 __ Movn(t3, t2, t1); // Only if t6 is lt kBinary32MinExponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003939 __ Branch(&done, lt, t6, Operand(kBinary32MinExponent));
3940
3941 __ And(t7, t3, Operand(HeapNumber::kSignMask));
3942 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3943 __ sll(t3, t3, kMantissaInHiWordShift);
3944 __ or_(t7, t7, t3);
3945 __ srl(t4, t4, kMantissaInLoWordShift);
3946 __ or_(t7, t7, t4);
3947 __ sll(t6, t6, kBinary32ExponentShift);
3948 __ or_(t3, t7, t6);
3949
3950 __ bind(&done);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003951 __ sll(t9, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003952 __ addu(t9, a2, t9);
3953 __ sw(t3, MemOperand(t9, 0));
3954
3955 // Entry registers are intact, a0 holds the value which is the return
3956 // value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003957 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003958 __ Ret();
3959
3960 __ bind(&nan_or_infinity_or_zero);
3961 __ And(t7, t3, Operand(HeapNumber::kSignMask));
3962 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3963 __ or_(t6, t6, t7);
3964 __ sll(t3, t3, kMantissaInHiWordShift);
3965 __ or_(t6, t6, t3);
3966 __ srl(t4, t4, kMantissaInLoWordShift);
3967 __ or_(t3, t6, t4);
3968 __ Branch(&done);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003969 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003970 __ sll(t8, t0, 3);
3971 __ addu(t8, a3, t8);
3972 // t8: effective address of destination element.
3973 __ sw(t4, MemOperand(t8, 0));
3974 __ sw(t3, MemOperand(t8, Register::kSizeInBytes));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003975 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003976 __ Ret();
3977 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003978 bool is_signed_type = IsElementTypeSigned(elements_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003979 int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
3980 int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
3981
3982 Label done, sign;
3983
3984 // Test for all special exponent values: zeros, subnormal numbers, NaNs
3985 // and infinities. All these should be converted to 0.
3986 __ li(t5, HeapNumber::kExponentMask);
3987 __ and_(t6, t3, t5);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003988 __ Movz(t3, zero_reg, t6); // Only if t6 is equal to zero.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003989 __ Branch(&done, eq, t6, Operand(zero_reg));
3990
3991 __ xor_(t2, t6, t5);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003992 __ Movz(t3, zero_reg, t2); // Only if t6 is equal to t5.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003993 __ Branch(&done, eq, t6, Operand(t5));
3994
3995 // Unbias exponent.
3996 __ srl(t6, t6, HeapNumber::kExponentShift);
3997 __ Subu(t6, t6, Operand(HeapNumber::kExponentBias));
3998 // If exponent is negative then result is 0.
3999 __ slt(t2, t6, zero_reg);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004000 __ Movn(t3, zero_reg, t2); // Only if exponent is negative.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004001 __ Branch(&done, lt, t6, Operand(zero_reg));
4002
4003 // If exponent is too big then result is minimal value.
4004 __ slti(t1, t6, meaningfull_bits - 1);
4005 __ li(t2, min_value);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004006 __ Movz(t3, t2, t1); // Only if t6 is ge meaningfull_bits - 1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004007 __ Branch(&done, ge, t6, Operand(meaningfull_bits - 1));
4008
4009 __ And(t5, t3, Operand(HeapNumber::kSignMask));
4010 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4011 __ Or(t3, t3, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
4012
4013 __ li(t9, HeapNumber::kMantissaBitsInTopWord);
4014 __ subu(t6, t9, t6);
4015 __ slt(t1, t6, zero_reg);
4016 __ srlv(t2, t3, t6);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004017 __ Movz(t3, t2, t1); // Only if t6 is positive.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004018 __ Branch(&sign, ge, t6, Operand(zero_reg));
4019
4020 __ subu(t6, zero_reg, t6);
4021 __ sllv(t3, t3, t6);
4022 __ li(t9, meaningfull_bits);
4023 __ subu(t6, t9, t6);
4024 __ srlv(t4, t4, t6);
4025 __ or_(t3, t3, t4);
4026
4027 __ bind(&sign);
4028 __ subu(t2, t3, zero_reg);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004029 __ Movz(t3, t2, t5); // Only if t5 is zero.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004030
4031 __ bind(&done);
4032
4033 // Result is in t3.
4034 // This switch block should be exactly the same as above (FPU mode).
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004035 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004036 case EXTERNAL_BYTE_ELEMENTS:
4037 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004038 __ srl(t8, key, 1);
4039 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004040 __ sb(t3, MemOperand(t8, 0));
4041 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004042 case EXTERNAL_SHORT_ELEMENTS:
4043 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004044 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004045 __ sh(t3, MemOperand(t8, 0));
4046 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004047 case EXTERNAL_INT_ELEMENTS:
4048 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004049 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004050 __ addu(t8, a3, t8);
4051 __ sw(t3, MemOperand(t8, 0));
4052 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004053 case EXTERNAL_PIXEL_ELEMENTS:
4054 case EXTERNAL_FLOAT_ELEMENTS:
4055 case EXTERNAL_DOUBLE_ELEMENTS:
4056 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004057 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004058 case FAST_DOUBLE_ELEMENTS:
4059 case DICTIONARY_ELEMENTS:
4060 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004061 UNREACHABLE();
4062 break;
4063 }
4064 }
4065 }
4066 }
4067
danno@chromium.org40cb8782011-05-25 07:58:50 +00004068 // Slow case, key and receiver still in a0 and a1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004069 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004070 __ IncrementCounter(
4071 masm->isolate()->counters()->keyed_load_external_array_slow(),
4072 1, a2, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004073 // Entry registers are intact.
4074 // ---------- S t a t e --------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004075 // -- ra : return address
danno@chromium.org40cb8782011-05-25 07:58:50 +00004076 // -- a0 : key
4077 // -- a1 : receiver
4078 // -----------------------------------
4079 Handle<Code> slow_ic =
4080 masm->isolate()->builtins()->KeyedStoreIC_Slow();
4081 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4082
4083 // Miss case, call the runtime.
4084 __ bind(&miss_force_generic);
4085
4086 // ---------- S t a t e --------------
4087 // -- ra : return address
4088 // -- a0 : key
4089 // -- a1 : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004090 // -----------------------------------
4091
danno@chromium.org40cb8782011-05-25 07:58:50 +00004092 Handle<Code> miss_ic =
4093 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4094 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
4095}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004096
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004097
danno@chromium.org40cb8782011-05-25 07:58:50 +00004098void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
4099 // ----------- S t a t e -------------
4100 // -- ra : return address
4101 // -- a0 : key
4102 // -- a1 : receiver
4103 // -----------------------------------
4104 Label miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004105
danno@chromium.org40cb8782011-05-25 07:58:50 +00004106 // This stub is meant to be tail-jumped to, the receiver must already
4107 // have been verified by the caller to not be a smi.
4108
4109 // Check that the key is a smi.
4110 __ JumpIfNotSmi(a0, &miss_force_generic);
4111
4112 // Get the elements array.
4113 __ lw(a2, FieldMemOperand(a1, JSObject::kElementsOffset));
4114 __ AssertFastElements(a2);
4115
4116 // Check that the key is within bounds.
4117 __ lw(a3, FieldMemOperand(a2, FixedArray::kLengthOffset));
4118 __ Branch(&miss_force_generic, hs, a0, Operand(a3));
4119
4120 // Load the result and make sure it's not the hole.
4121 __ Addu(a3, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004122 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004123 __ sll(t0, a0, kPointerSizeLog2 - kSmiTagSize);
4124 __ Addu(t0, t0, a3);
4125 __ lw(t0, MemOperand(t0));
4126 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
4127 __ Branch(&miss_force_generic, eq, t0, Operand(t1));
4128 __ mov(v0, t0);
4129 __ Ret();
4130
4131 __ bind(&miss_force_generic);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004132 Handle<Code> stub =
4133 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4134 __ Jump(stub, RelocInfo::CODE_TARGET);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004135}
4136
4137
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004138void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
4139 MacroAssembler* masm) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004140 // ----------- S t a t e -------------
4141 // -- ra : return address
4142 // -- a0 : key
4143 // -- a1 : receiver
4144 // -----------------------------------
4145 Label miss_force_generic, slow_allocate_heapnumber;
4146
4147 Register key_reg = a0;
4148 Register receiver_reg = a1;
4149 Register elements_reg = a2;
4150 Register heap_number_reg = a2;
4151 Register indexed_double_offset = a3;
4152 Register scratch = t0;
4153 Register scratch2 = t1;
4154 Register scratch3 = t2;
4155 Register heap_number_map = t3;
4156
4157 // This stub is meant to be tail-jumped to, the receiver must already
4158 // have been verified by the caller to not be a smi.
4159
4160 // Check that the key is a smi.
4161 __ JumpIfNotSmi(key_reg, &miss_force_generic);
4162
4163 // Get the elements array.
4164 __ lw(elements_reg,
4165 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4166
4167 // Check that the key is within bounds.
4168 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4169 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4170
4171 // Load the upper word of the double in the fixed array and test for NaN.
4172 __ sll(scratch2, key_reg, kDoubleSizeLog2 - kSmiTagSize);
4173 __ Addu(indexed_double_offset, elements_reg, Operand(scratch2));
4174 uint32_t upper_32_offset = FixedArray::kHeaderSize + sizeof(kHoleNanLower32);
4175 __ lw(scratch, FieldMemOperand(indexed_double_offset, upper_32_offset));
4176 __ Branch(&miss_force_generic, eq, scratch, Operand(kHoleNanUpper32));
4177
4178 // Non-NaN. Allocate a new heap number and copy the double value into it.
4179 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
4180 __ AllocateHeapNumber(heap_number_reg, scratch2, scratch3,
4181 heap_number_map, &slow_allocate_heapnumber);
4182
4183 // Don't need to reload the upper 32 bits of the double, it's already in
4184 // scratch.
4185 __ sw(scratch, FieldMemOperand(heap_number_reg,
4186 HeapNumber::kExponentOffset));
4187 __ lw(scratch, FieldMemOperand(indexed_double_offset,
4188 FixedArray::kHeaderSize));
4189 __ sw(scratch, FieldMemOperand(heap_number_reg,
4190 HeapNumber::kMantissaOffset));
4191
4192 __ mov(v0, heap_number_reg);
4193 __ Ret();
4194
4195 __ bind(&slow_allocate_heapnumber);
4196 Handle<Code> slow_ic =
4197 masm->isolate()->builtins()->KeyedLoadIC_Slow();
4198 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4199
4200 __ bind(&miss_force_generic);
4201 Handle<Code> miss_ic =
4202 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4203 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004204}
4205
4206
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004207void KeyedStoreStubCompiler::GenerateStoreFastElement(
4208 MacroAssembler* masm,
4209 bool is_js_array,
yangguo@chromium.org56454712012-02-16 15:33:53 +00004210 ElementsKind elements_kind,
4211 KeyedAccessGrowMode grow_mode) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00004212 // ----------- S t a t e -------------
4213 // -- a0 : value
4214 // -- a1 : key
4215 // -- a2 : receiver
4216 // -- ra : return address
4217 // -- a3 : scratch
4218 // -- a4 : scratch (elements)
4219 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00004220 Label miss_force_generic, transition_elements_kind, grow, slow;
4221 Label finish_store, check_capacity;
danno@chromium.org40cb8782011-05-25 07:58:50 +00004222
4223 Register value_reg = a0;
4224 Register key_reg = a1;
4225 Register receiver_reg = a2;
yangguo@chromium.org56454712012-02-16 15:33:53 +00004226 Register scratch = t0;
4227 Register elements_reg = a3;
4228 Register length_reg = t1;
4229 Register scratch2 = t2;
4230 Register scratch3 = t3;
danno@chromium.org40cb8782011-05-25 07:58:50 +00004231
4232 // This stub is meant to be tail-jumped to, the receiver must already
4233 // have been verified by the caller to not be a smi.
4234
4235 // Check that the key is a smi.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00004236 __ JumpIfNotSmi(key_reg, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004237
yangguo@chromium.org56454712012-02-16 15:33:53 +00004238 if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
4239 __ JumpIfNotSmi(value_reg, &transition_elements_kind);
4240 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004241
4242 // Check that the key is within bounds.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004243 __ lw(elements_reg,
4244 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00004245 if (is_js_array) {
4246 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4247 } else {
4248 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4249 }
4250 // Compare smis.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004251 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4252 __ Branch(&grow, hs, key_reg, Operand(scratch));
4253 } else {
4254 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4255 }
4256
4257 // Make sure elements is a fast element array, not 'cow'.
4258 __ CheckMap(elements_reg,
4259 scratch,
4260 Heap::kFixedArrayMapRootIndex,
4261 &miss_force_generic,
4262 DONT_DO_SMI_CHECK);
4263
4264 __ bind(&finish_store);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004265
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004266 if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004267 __ Addu(scratch,
4268 elements_reg,
4269 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4270 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4271 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4272 __ Addu(scratch, scratch, scratch2);
4273 __ sw(value_reg, MemOperand(scratch));
4274 } else {
4275 ASSERT(elements_kind == FAST_ELEMENTS);
4276 __ Addu(scratch,
4277 elements_reg,
4278 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4279 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4280 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4281 __ Addu(scratch, scratch, scratch2);
4282 __ sw(value_reg, MemOperand(scratch));
4283 __ mov(receiver_reg, value_reg);
4284 ASSERT(elements_kind == FAST_ELEMENTS);
4285 __ RecordWrite(elements_reg, // Object.
4286 scratch, // Address.
4287 receiver_reg, // Value.
4288 kRAHasNotBeenSaved,
4289 kDontSaveFPRegs);
4290 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004291 // value_reg (a0) is preserved.
4292 // Done.
4293 __ Ret();
4294
4295 __ bind(&miss_force_generic);
4296 Handle<Code> ic =
4297 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4298 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004299
4300 __ bind(&transition_elements_kind);
4301 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4302 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
yangguo@chromium.org56454712012-02-16 15:33:53 +00004303
4304 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4305 // Grow the array by a single element if possible.
4306 __ bind(&grow);
4307
4308 // Make sure the array is only growing by a single element, anything else
4309 // must be handled by the runtime.
4310 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch));
4311
4312 // Check for the empty array, and preallocate a small backing store if
4313 // possible.
4314 __ lw(length_reg,
4315 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4316 __ lw(elements_reg,
4317 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4318 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
4319 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
4320
4321 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
4322 __ AllocateInNewSpace(size, elements_reg, scratch, scratch2, &slow,
4323 TAG_OBJECT);
4324
4325 __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex);
4326 __ sw(scratch, FieldMemOperand(elements_reg, JSObject::kMapOffset));
4327 __ li(scratch, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4328 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4329 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
4330 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
4331 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::SizeFor(i)));
4332 }
4333
4334 // Store the element at index zero.
4335 __ sw(value_reg, FieldMemOperand(elements_reg, FixedArray::SizeFor(0)));
4336
4337 // Install the new backing store in the JSArray.
4338 __ sw(elements_reg,
4339 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4340 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
4341 scratch, kRAHasNotBeenSaved, kDontSaveFPRegs,
4342 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4343
4344 // Increment the length of the array.
4345 __ li(length_reg, Operand(Smi::FromInt(1)));
4346 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4347 __ Ret();
4348
4349 __ bind(&check_capacity);
4350 // Check for cow elements, in general they are not handled by this stub
4351 __ CheckMap(elements_reg,
4352 scratch,
4353 Heap::kFixedCOWArrayMapRootIndex,
4354 &miss_force_generic,
4355 DONT_DO_SMI_CHECK);
4356
4357 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4358 __ Branch(&slow, hs, length_reg, Operand(scratch));
4359
4360 // Grow the array and finish the store.
4361 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
4362 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4363 __ jmp(&finish_store);
4364
4365 __ bind(&slow);
4366 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4367 __ Jump(ic_slow, RelocInfo::CODE_TARGET);
4368 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004369}
4370
4371
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004372void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
4373 MacroAssembler* masm,
yangguo@chromium.org56454712012-02-16 15:33:53 +00004374 bool is_js_array,
4375 KeyedAccessGrowMode grow_mode) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004376 // ----------- S t a t e -------------
4377 // -- a0 : value
4378 // -- a1 : key
4379 // -- a2 : receiver
4380 // -- ra : return address
4381 // -- a3 : scratch
4382 // -- t0 : scratch (elements_reg)
4383 // -- t1 : scratch (mantissa_reg)
4384 // -- t2 : scratch (exponent_reg)
4385 // -- t3 : scratch4
4386 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00004387 Label miss_force_generic, transition_elements_kind, grow, slow;
4388 Label finish_store, check_capacity;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004389
4390 Register value_reg = a0;
4391 Register key_reg = a1;
4392 Register receiver_reg = a2;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004393 Register elements_reg = a3;
4394 Register scratch1 = t0;
4395 Register scratch2 = t1;
4396 Register scratch3 = t2;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004397 Register scratch4 = t3;
yangguo@chromium.org56454712012-02-16 15:33:53 +00004398 Register length_reg = t3;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004399
4400 // This stub is meant to be tail-jumped to, the receiver must already
4401 // have been verified by the caller to not be a smi.
4402 __ JumpIfNotSmi(key_reg, &miss_force_generic);
4403
4404 __ lw(elements_reg,
4405 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4406
4407 // Check that the key is within bounds.
4408 if (is_js_array) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004409 __ lw(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004410 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004411 __ lw(scratch1,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004412 FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4413 }
4414 // Compare smis, unsigned compare catches both negative and out-of-bound
4415 // indexes.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004416 if (grow_mode == ALLOW_JSARRAY_GROWTH) {
4417 __ Branch(&grow, hs, key_reg, Operand(scratch1));
4418 } else {
4419 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch1));
4420 }
4421
4422 __ bind(&finish_store);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004423
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004424 __ StoreNumberToDoubleElements(value_reg,
4425 key_reg,
4426 receiver_reg,
4427 elements_reg,
4428 scratch1,
4429 scratch2,
4430 scratch3,
4431 scratch4,
4432 &transition_elements_kind);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004433
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004434 __ Ret(USE_DELAY_SLOT);
4435 __ mov(v0, value_reg); // In delay slot.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004436
4437 // Handle store cache miss, replacing the ic with the generic stub.
4438 __ bind(&miss_force_generic);
4439 Handle<Code> ic =
4440 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4441 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004442
4443 __ bind(&transition_elements_kind);
4444 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4445 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
yangguo@chromium.org56454712012-02-16 15:33:53 +00004446
4447 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4448 // Grow the array by a single element if possible.
4449 __ bind(&grow);
4450
4451 // Make sure the array is only growing by a single element, anything else
4452 // must be handled by the runtime.
4453 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch1));
4454
4455 // Transition on values that can't be stored in a FixedDoubleArray.
4456 Label value_is_smi;
4457 __ JumpIfSmi(value_reg, &value_is_smi);
4458 __ lw(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
4459 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
4460 __ Branch(&transition_elements_kind, ne, scratch1, Operand(at));
4461 __ bind(&value_is_smi);
4462
4463 // Check for the empty array, and preallocate a small backing store if
4464 // possible.
4465 __ lw(length_reg,
4466 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4467 __ lw(elements_reg,
4468 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4469 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
4470 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
4471
4472 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
4473 __ AllocateInNewSpace(size, elements_reg, scratch1, scratch2, &slow,
4474 TAG_OBJECT);
4475
4476 // Initialize the new FixedDoubleArray. Leave elements unitialized for
4477 // efficiency, they are guaranteed to be initialized before use.
4478 __ LoadRoot(scratch1, Heap::kFixedDoubleArrayMapRootIndex);
4479 __ sw(scratch1, FieldMemOperand(elements_reg, JSObject::kMapOffset));
4480 __ li(scratch1, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4481 __ sw(scratch1,
4482 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
4483
4484 // Install the new backing store in the JSArray.
4485 __ sw(elements_reg,
4486 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4487 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
4488 scratch1, kRAHasNotBeenSaved, kDontSaveFPRegs,
4489 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4490
4491 // Increment the length of the array.
4492 __ li(length_reg, Operand(Smi::FromInt(1)));
4493 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4494 __ jmp(&finish_store);
4495
4496 __ bind(&check_capacity);
4497 // Make sure that the backing store can hold additional elements.
4498 __ lw(scratch1,
4499 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
4500 __ Branch(&slow, hs, length_reg, Operand(scratch1));
4501
4502 // Grow the array and finish the store.
4503 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
4504 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4505 __ jmp(&finish_store);
4506
4507 __ bind(&slow);
4508 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4509 __ Jump(ic_slow, RelocInfo::CODE_TARGET);
4510 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004511}
4512
4513
ager@chromium.org5c838252010-02-19 08:53:10 +00004514#undef __
4515
4516} } // namespace v8::internal
4517
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004518#endif // V8_TARGET_ARCH_MIPS