blob: ae563069f800104338c9a98acfc3fb66d7f1756d [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,
46 Register name,
47 Register offset,
48 Register scratch,
49 Register scratch2) {
50 ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
51 ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
52
53 uint32_t key_off_addr = reinterpret_cast<uint32_t>(key_offset.address());
54 uint32_t value_off_addr = reinterpret_cast<uint32_t>(value_offset.address());
55
56 // Check the relative positions of the address fields.
57 ASSERT(value_off_addr > key_off_addr);
58 ASSERT((value_off_addr - key_off_addr) % 4 == 0);
59 ASSERT((value_off_addr - key_off_addr) < (256 * 4));
60
61 Label miss;
62 Register offsets_base_addr = scratch;
63
64 // Check that the key in the entry matches the name.
65 __ li(offsets_base_addr, Operand(key_offset));
66 __ sll(scratch2, offset, 1);
67 __ addu(scratch2, offsets_base_addr, scratch2);
68 __ lw(scratch2, MemOperand(scratch2));
69 __ Branch(&miss, ne, name, Operand(scratch2));
70
71 // Get the code entry from the cache.
72 __ Addu(offsets_base_addr, offsets_base_addr,
73 Operand(value_off_addr - key_off_addr));
74 __ sll(scratch2, offset, 1);
75 __ addu(scratch2, offsets_base_addr, scratch2);
76 __ lw(scratch2, MemOperand(scratch2));
77
78 // Check that the flags match what we're looking for.
79 __ lw(scratch2, FieldMemOperand(scratch2, Code::kFlagsOffset));
80 __ And(scratch2, scratch2, Operand(~Code::kFlagsNotUsedInLookup));
81 __ Branch(&miss, ne, scratch2, Operand(flags));
82
83 // Re-load code entry from cache.
84 __ sll(offset, offset, 1);
85 __ addu(offset, offset, offsets_base_addr);
86 __ lw(offset, MemOperand(offset));
87
88 // Jump to the first instruction in the code stub.
89 __ Addu(offset, offset, Operand(Code::kHeaderSize - kHeapObjectTag));
90 __ Jump(offset);
91
92 // Miss: fall through.
93 __ bind(&miss);
94}
95
96
97// Helper function used to check that the dictionary doesn't contain
98// the property. This function may return false negatives, so miss_label
99// must always call a backup property check that is complete.
100// This function is safe to call if the receiver has fast properties.
101// Name must be a symbol and receiver must be a heap object.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000102static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
103 Label* miss_label,
104 Register receiver,
105 Handle<String> name,
106 Register scratch0,
107 Register scratch1) {
108 ASSERT(name->IsSymbol());
109 Counters* counters = masm->isolate()->counters();
110 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
111 __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
112
113 Label done;
114
115 const int kInterceptorOrAccessCheckNeededMask =
116 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
117
118 // Bail out if the receiver has a named interceptor or requires access checks.
119 Register map = scratch1;
120 __ lw(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
121 __ lbu(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
122 __ And(scratch0, scratch0, Operand(kInterceptorOrAccessCheckNeededMask));
123 __ Branch(miss_label, ne, scratch0, Operand(zero_reg));
124
125 // Check that receiver is a JSObject.
126 __ lbu(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
127 __ Branch(miss_label, lt, scratch0, Operand(FIRST_SPEC_OBJECT_TYPE));
128
129 // Load properties array.
130 Register properties = scratch0;
131 __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
132 // Check that the properties array is a dictionary.
133 __ lw(map, FieldMemOperand(properties, HeapObject::kMapOffset));
134 Register tmp = properties;
135 __ LoadRoot(tmp, Heap::kHashTableMapRootIndex);
136 __ Branch(miss_label, ne, map, Operand(tmp));
137
138 // Restore the temporarily used register.
139 __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
140
141
142 StringDictionaryLookupStub::GenerateNegativeLookup(masm,
143 miss_label,
144 &done,
145 receiver,
146 properties,
147 name,
148 scratch1);
149 __ bind(&done);
150 __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
151}
152
153
ager@chromium.org5c838252010-02-19 08:53:10 +0000154void StubCache::GenerateProbe(MacroAssembler* masm,
155 Code::Flags flags,
156 Register receiver,
157 Register name,
158 Register scratch,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000159 Register extra,
160 Register extra2) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000161 Isolate* isolate = masm->isolate();
162 Label miss;
163
164 // Make sure that code is valid. The shifting code relies on the
165 // entry size being 8.
166 ASSERT(sizeof(Entry) == 8);
167
168 // Make sure the flags does not name a specific type.
169 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
170
171 // Make sure that there are no register conflicts.
172 ASSERT(!scratch.is(receiver));
173 ASSERT(!scratch.is(name));
174 ASSERT(!extra.is(receiver));
175 ASSERT(!extra.is(name));
176 ASSERT(!extra.is(scratch));
177 ASSERT(!extra2.is(receiver));
178 ASSERT(!extra2.is(name));
179 ASSERT(!extra2.is(scratch));
180 ASSERT(!extra2.is(extra));
181
182 // Check scratch, extra and extra2 registers are valid.
183 ASSERT(!scratch.is(no_reg));
184 ASSERT(!extra.is(no_reg));
185 ASSERT(!extra2.is(no_reg));
186
187 // Check that the receiver isn't a smi.
188 __ JumpIfSmi(receiver, &miss, t0);
189
190 // Get the map of the receiver and compute the hash.
191 __ lw(scratch, FieldMemOperand(name, String::kHashFieldOffset));
192 __ lw(t8, FieldMemOperand(receiver, HeapObject::kMapOffset));
193 __ Addu(scratch, scratch, Operand(t8));
194 __ Xor(scratch, scratch, Operand(flags));
195 __ And(scratch,
196 scratch,
197 Operand((kPrimaryTableSize - 1) << kHeapObjectTagSize));
198
199 // Probe the primary table.
200 ProbeTable(isolate, masm, flags, kPrimary, name, scratch, extra, extra2);
201
202 // Primary miss: Compute hash for secondary probe.
203 __ Subu(scratch, scratch, Operand(name));
204 __ Addu(scratch, scratch, Operand(flags));
205 __ And(scratch,
206 scratch,
207 Operand((kSecondaryTableSize - 1) << kHeapObjectTagSize));
208
209 // Probe the secondary table.
210 ProbeTable(isolate, masm, flags, kSecondary, name, scratch, extra, extra2);
211
212 // Cache miss: Fall-through and let caller handle the miss by
213 // entering the runtime system.
214 __ bind(&miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000215}
216
217
218void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
219 int index,
220 Register prototype) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000221 // Load the global or builtins object from the current context.
222 __ lw(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
223 // Load the global context from the global or builtins object.
224 __ lw(prototype,
225 FieldMemOperand(prototype, GlobalObject::kGlobalContextOffset));
226 // Load the function from the global context.
227 __ lw(prototype, MemOperand(prototype, Context::SlotOffset(index)));
228 // Load the initial map. The global functions all have initial maps.
229 __ lw(prototype,
230 FieldMemOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
231 // Load the prototype from the initial map.
232 __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000233}
234
235
lrn@chromium.org7516f052011-03-30 08:52:27 +0000236void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000237 MacroAssembler* masm,
238 int index,
239 Register prototype,
240 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000241 Isolate* isolate = masm->isolate();
242 // Check we're still in the same context.
243 __ lw(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
244 ASSERT(!prototype.is(at));
245 __ li(at, isolate->global());
246 __ Branch(miss, ne, prototype, Operand(at));
247 // Get the global function with the given index.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000248 Handle<JSFunction> function(
249 JSFunction::cast(isolate->global_context()->get(index)));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000250 // Load its initial map. The global functions all have initial maps.
251 __ li(prototype, Handle<Map>(function->initial_map()));
252 // Load the prototype from the initial map.
253 __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000254}
255
256
ager@chromium.org5c838252010-02-19 08:53:10 +0000257// Load a fast property out of a holder object (src). In-object properties
258// are loaded directly otherwise the property is loaded from the properties
259// fixed array.
260void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000261 Register dst,
262 Register src,
263 Handle<JSObject> holder,
264 int index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000265 // Adjust for the number of properties stored in the holder.
266 index -= holder->map()->inobject_properties();
267 if (index < 0) {
268 // Get the property straight out of the holder.
269 int offset = holder->map()->instance_size() + (index * kPointerSize);
270 __ lw(dst, FieldMemOperand(src, offset));
271 } else {
272 // Calculate the offset into the properties array.
273 int offset = index * kPointerSize + FixedArray::kHeaderSize;
274 __ lw(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
275 __ lw(dst, FieldMemOperand(dst, offset));
276 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000277}
278
279
280void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
281 Register receiver,
282 Register scratch,
283 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000284 // Check that the receiver isn't a smi.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000285 __ JumpIfSmi(receiver, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000286
287 // Check that the object is a JS array.
288 __ GetObjectType(receiver, scratch, scratch);
289 __ Branch(miss_label, ne, scratch, Operand(JS_ARRAY_TYPE));
290
291 // Load length directly from the JS array.
292 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
293 __ Ret();
294}
295
296
297// Generate code to check if an object is a string. If the object is a
298// heap object, its map's instance type is left in the scratch1 register.
299// If this is not needed, scratch1 and scratch2 may be the same register.
300static void GenerateStringCheck(MacroAssembler* masm,
301 Register receiver,
302 Register scratch1,
303 Register scratch2,
304 Label* smi,
305 Label* non_string_object) {
306 // Check that the receiver isn't a smi.
307 __ JumpIfSmi(receiver, smi, t0);
308
309 // Check that the object is a string.
310 __ lw(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
311 __ lbu(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
312 __ And(scratch2, scratch1, Operand(kIsNotStringMask));
313 // The cast is to resolve the overload for the argument of 0x0.
314 __ Branch(non_string_object,
315 ne,
316 scratch2,
317 Operand(static_cast<int32_t>(kStringTag)));
ager@chromium.org5c838252010-02-19 08:53:10 +0000318}
319
320
lrn@chromium.org7516f052011-03-30 08:52:27 +0000321// Generate code to load the length from a string object and return the length.
322// If the receiver object is not a string or a wrapped string object the
323// execution continues at the miss label. The register containing the
324// receiver is potentially clobbered.
325void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
326 Register receiver,
327 Register scratch1,
328 Register scratch2,
329 Label* miss,
330 bool support_wrappers) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000331 Label check_wrapper;
332
333 // Check if the object is a string leaving the instance type in the
334 // scratch1 register.
335 GenerateStringCheck(masm, receiver, scratch1, scratch2, miss,
336 support_wrappers ? &check_wrapper : miss);
337
338 // Load length directly from the string.
339 __ lw(v0, FieldMemOperand(receiver, String::kLengthOffset));
340 __ Ret();
341
342 if (support_wrappers) {
343 // Check if the object is a JSValue wrapper.
344 __ bind(&check_wrapper);
345 __ Branch(miss, ne, scratch1, Operand(JS_VALUE_TYPE));
346
347 // Unwrap the value and check if the wrapped value is a string.
348 __ lw(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
349 GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
350 __ lw(v0, FieldMemOperand(scratch1, String::kLengthOffset));
351 __ Ret();
352 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000353}
354
355
ager@chromium.org5c838252010-02-19 08:53:10 +0000356void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
357 Register receiver,
358 Register scratch1,
359 Register scratch2,
360 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000361 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
362 __ mov(v0, scratch1);
363 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000364}
365
366
lrn@chromium.org7516f052011-03-30 08:52:27 +0000367// Generate StoreField code, value is passed in a0 register.
ager@chromium.org5c838252010-02-19 08:53:10 +0000368// After executing generated code, the receiver_reg and name_reg
369// may be clobbered.
370void StubCompiler::GenerateStoreField(MacroAssembler* masm,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000371 Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +0000372 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000373 Handle<Map> transition,
ager@chromium.org5c838252010-02-19 08:53:10 +0000374 Register receiver_reg,
375 Register name_reg,
376 Register scratch,
377 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000378 // a0 : value.
379 Label exit;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000380 // Check that the map of the object hasn't changed.
381 __ CheckMap(receiver_reg, scratch, Handle<Map>(object->map()), miss_label,
382 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000383
384 // Perform global security token check if needed.
385 if (object->IsJSGlobalProxy()) {
386 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
387 }
388
389 // Stub never generated for non-global objects that require access
390 // checks.
391 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
392
393 // Perform map transition for the receiver if necessary.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000394 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000395 // The properties must be extended before we can store the value.
396 // We jump to a runtime call that extends the properties array.
397 __ push(receiver_reg);
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000398 __ li(a2, Operand(transition));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000399 __ Push(a2, a0);
400 __ TailCallExternalReference(
401 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
402 masm->isolate()),
403 3, 1);
404 return;
405 }
406
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000407 if (!transition.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000408 // Update the map of the object; no write barrier updating is
409 // needed because the map is never in new space.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000410 __ li(t0, Operand(transition));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000411 __ sw(t0, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
412 }
413
414 // Adjust for the number of properties stored in the object. Even in the
415 // face of a transition we can use the old map here because the size of the
416 // object and the number of in-object properties is not going to change.
417 index -= object->map()->inobject_properties();
418
419 if (index < 0) {
420 // Set the property straight into the object.
421 int offset = object->map()->instance_size() + (index * kPointerSize);
422 __ sw(a0, FieldMemOperand(receiver_reg, offset));
423
424 // Skip updating write barrier if storing a smi.
425 __ JumpIfSmi(a0, &exit, scratch);
426
427 // Update the write barrier for the array address.
428 // Pass the now unused name_reg as a scratch register.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000429 __ mov(name_reg, a0);
430 __ RecordWriteField(receiver_reg,
431 offset,
432 name_reg,
433 scratch,
434 kRAHasNotBeenSaved,
435 kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000436 } else {
437 // Write to the properties array.
438 int offset = index * kPointerSize + FixedArray::kHeaderSize;
439 // Get the properties array.
440 __ lw(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
441 __ sw(a0, FieldMemOperand(scratch, offset));
442
443 // Skip updating write barrier if storing a smi.
444 __ JumpIfSmi(a0, &exit);
445
446 // Update the write barrier for the array address.
447 // Ok to clobber receiver_reg and name_reg, since we return.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000448 __ mov(name_reg, a0);
449 __ RecordWriteField(scratch,
450 offset,
451 name_reg,
452 receiver_reg,
453 kRAHasNotBeenSaved,
454 kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000455 }
456
457 // Return the value (register v0).
458 __ bind(&exit);
459 __ mov(v0, a0);
460 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000461}
462
463
464void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000465 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000466 Handle<Code> code = (kind == Code::LOAD_IC)
467 ? masm->isolate()->builtins()->LoadIC_Miss()
468 : masm->isolate()->builtins()->KeyedLoadIC_Miss();
469 __ Jump(code, RelocInfo::CODE_TARGET);
ager@chromium.org5c838252010-02-19 08:53:10 +0000470}
471
472
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000473static void GenerateCallFunction(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000474 Handle<Object> object,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000475 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000476 Label* miss,
477 Code::ExtraICState extra_ic_state) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000478 // ----------- S t a t e -------------
479 // -- a0: receiver
480 // -- a1: function to call
481 // -----------------------------------
482 // Check that the function really is a function.
483 __ JumpIfSmi(a1, miss);
484 __ GetObjectType(a1, a3, a3);
485 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
486
487 // Patch the receiver on the stack with the global proxy if
488 // necessary.
489 if (object->IsGlobalObject()) {
490 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
491 __ sw(a3, MemOperand(sp, arguments.immediate() * kPointerSize));
492 }
493
494 // Invoke the function.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000495 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
496 ? CALL_AS_FUNCTION
497 : CALL_AS_METHOD;
498 __ InvokeFunction(a1, arguments, JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000499}
500
501
502static void PushInterceptorArguments(MacroAssembler* masm,
503 Register receiver,
504 Register holder,
505 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000506 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000507 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000508 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
509 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000510 Register scratch = name;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000511 __ li(scratch, Operand(interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000512 __ Push(scratch, receiver, holder);
513 __ lw(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
514 __ push(scratch);
515}
516
517
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000518static void CompileCallLoadPropertyWithInterceptor(
519 MacroAssembler* masm,
520 Register receiver,
521 Register holder,
522 Register name,
523 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000524 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
525
526 ExternalReference ref =
527 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
528 masm->isolate());
529 __ li(a0, Operand(5));
530 __ li(a1, Operand(ref));
531
532 CEntryStub stub(1);
533 __ CallStub(&stub);
534}
535
536
537static const int kFastApiCallArguments = 3;
538
539
540// Reserves space for the extra arguments to FastHandleApiCall in the
541// caller's frame.
542//
543// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
544static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
545 Register scratch) {
546 ASSERT(Smi::FromInt(0) == 0);
547 for (int i = 0; i < kFastApiCallArguments; i++) {
548 __ push(zero_reg);
549 }
550}
551
552
553// Undoes the effects of ReserveSpaceForFastApiCall.
554static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
555 __ Drop(kFastApiCallArguments);
556}
557
558
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000559static void GenerateFastApiDirectCall(MacroAssembler* masm,
560 const CallOptimization& optimization,
561 int argc) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000562 // ----------- S t a t e -------------
563 // -- sp[0] : holder (set by CheckPrototypes)
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000564 // -- sp[4] : callee JS function
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000565 // -- sp[8] : call data
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000566 // -- sp[12] : last JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000567 // -- ...
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000568 // -- sp[(argc + 3) * 4] : first JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000569 // -- sp[(argc + 4) * 4] : receiver
570 // -----------------------------------
571 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000572 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000573 __ LoadHeapObject(t1, function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000574 __ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset));
575
576 // Pass the additional arguments FastHandleApiCall expects.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000577 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
578 Handle<Object> call_data(api_call_info->data());
579 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
580 __ li(a0, api_call_info);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000581 __ lw(t2, FieldMemOperand(a0, CallHandlerInfo::kDataOffset));
582 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000583 __ li(t2, call_data);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000584 }
585
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000586 // Store JS function and call data.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000587 __ sw(t1, MemOperand(sp, 1 * kPointerSize));
588 __ sw(t2, MemOperand(sp, 2 * kPointerSize));
589
590 // a2 points to call data as expected by Arguments
591 // (refer to layout above).
592 __ Addu(a2, sp, Operand(2 * kPointerSize));
593
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000594 const int kApiStackSpace = 4;
595
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000596 FrameScope frame_scope(masm, StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000597 __ EnterExitFrame(false, kApiStackSpace);
598
599 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
600 // struct from the function (which is currently the case). This means we pass
601 // the first argument in a1 instead of a0. TryCallApiFunctionAndReturn
602 // will handle setting up a0.
603
604 // a1 = v8::Arguments&
605 // Arguments is built at sp + 1 (sp is a reserved spot for ra).
606 __ Addu(a1, sp, kPointerSize);
607
608 // v8::Arguments::implicit_args = data
609 __ sw(a2, MemOperand(a1, 0 * kPointerSize));
610 // v8::Arguments::values = last argument
611 __ Addu(t0, a2, Operand(argc * kPointerSize));
612 __ sw(t0, MemOperand(a1, 1 * kPointerSize));
613 // v8::Arguments::length_ = argc
614 __ li(t0, Operand(argc));
615 __ sw(t0, MemOperand(a1, 2 * kPointerSize));
616 // v8::Arguments::is_construct_call = 0
617 __ sw(zero_reg, MemOperand(a1, 3 * kPointerSize));
618
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000619 const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000620 Address function_address = v8::ToCData<Address>(api_call_info->callback());
621 ApiFunction fun(function_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000622 ExternalReference ref =
623 ExternalReference(&fun,
624 ExternalReference::DIRECT_API_CALL,
625 masm->isolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000626 AllowExternalCallThatCantCauseGC scope(masm);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000627 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000628}
629
lrn@chromium.org7516f052011-03-30 08:52:27 +0000630class CallInterceptorCompiler BASE_EMBEDDED {
631 public:
632 CallInterceptorCompiler(StubCompiler* stub_compiler,
633 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000634 Register name,
635 Code::ExtraICState extra_ic_state)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000636 : stub_compiler_(stub_compiler),
637 arguments_(arguments),
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000638 name_(name),
639 extra_ic_state_(extra_ic_state) {}
lrn@chromium.org7516f052011-03-30 08:52:27 +0000640
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000641 void Compile(MacroAssembler* masm,
642 Handle<JSObject> object,
643 Handle<JSObject> holder,
644 Handle<String> name,
645 LookupResult* lookup,
646 Register receiver,
647 Register scratch1,
648 Register scratch2,
649 Register scratch3,
650 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000651 ASSERT(holder->HasNamedInterceptor());
652 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
653
654 // Check that the receiver isn't a smi.
655 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000656 CallOptimization optimization(lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000657 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000658 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
659 holder, lookup, name, optimization, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000660 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000661 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
662 name, holder, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000663 }
664 }
665
666 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000667 void CompileCacheable(MacroAssembler* masm,
668 Handle<JSObject> object,
669 Register receiver,
670 Register scratch1,
671 Register scratch2,
672 Register scratch3,
673 Handle<JSObject> interceptor_holder,
674 LookupResult* lookup,
675 Handle<String> name,
676 const CallOptimization& optimization,
677 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000678 ASSERT(optimization.is_constant_call());
679 ASSERT(!lookup->holder()->IsGlobalObject());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000680 Counters* counters = masm->isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000681 int depth1 = kInvalidProtoDepth;
682 int depth2 = kInvalidProtoDepth;
683 bool can_do_fast_api_call = false;
684 if (optimization.is_simple_api_call() &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000685 !lookup->holder()->IsGlobalObject()) {
686 depth1 = optimization.GetPrototypeDepthOfExpectedType(
687 object, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000688 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000689 depth2 = optimization.GetPrototypeDepthOfExpectedType(
690 interceptor_holder, Handle<JSObject>(lookup->holder()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000691 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000692 can_do_fast_api_call =
693 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000694 }
695
696 __ IncrementCounter(counters->call_const_interceptor(), 1,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000697 scratch1, scratch2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000698
699 if (can_do_fast_api_call) {
700 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
701 scratch1, scratch2);
702 ReserveSpaceForFastApiCall(masm, scratch1);
703 }
704
705 // Check that the maps from receiver to interceptor's holder
706 // haven't changed and thus we can invoke interceptor.
707 Label miss_cleanup;
708 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
709 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000710 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
711 scratch1, scratch2, scratch3,
712 name, depth1, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000713
714 // Invoke an interceptor and if it provides a value,
715 // branch to |regular_invoke|.
716 Label regular_invoke;
717 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
718 &regular_invoke);
719
720 // Interceptor returned nothing for this property. Try to use cached
721 // constant function.
722
723 // Check that the maps from interceptor's holder to constant function's
724 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000725 if (*interceptor_holder != lookup->holder()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000726 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000727 Handle<JSObject>(lookup->holder()),
728 scratch1, scratch2, scratch3,
729 name, depth2, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000730 } else {
731 // CheckPrototypes has a side effect of fetching a 'holder'
732 // for API (object which is instanceof for the signature). It's
733 // safe to omit it here, as if present, it should be fetched
734 // by the previous CheckPrototypes.
735 ASSERT(depth2 == kInvalidProtoDepth);
736 }
737
738 // Invoke function.
739 if (can_do_fast_api_call) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000740 GenerateFastApiDirectCall(masm, optimization, arguments_.immediate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000741 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000742 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
743 ? CALL_AS_FUNCTION
744 : CALL_AS_METHOD;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000745 __ InvokeFunction(optimization.constant_function(), arguments_,
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000746 JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000747 }
748
749 // Deferred code for fast API call case---clean preallocated space.
750 if (can_do_fast_api_call) {
751 __ bind(&miss_cleanup);
752 FreeSpaceForFastApiCall(masm);
753 __ Branch(miss_label);
754 }
755
756 // Invoke a regular function.
757 __ bind(&regular_invoke);
758 if (can_do_fast_api_call) {
759 FreeSpaceForFastApiCall(masm);
760 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000761 }
762
763 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000764 Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000765 Register receiver,
766 Register scratch1,
767 Register scratch2,
768 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000769 Handle<String> name,
770 Handle<JSObject> interceptor_holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000771 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000772 Register holder =
773 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000774 scratch1, scratch2, scratch3,
775 name, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000776
777 // Call a runtime function to load the interceptor property.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000778 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000779 // Save the name_ register across the call.
780 __ push(name_);
781
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000782 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000783
784 __ CallExternalReference(
785 ExternalReference(
786 IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
787 masm->isolate()),
788 5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000789 // Restore the name_ register.
790 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000791 // Leave the internal frame.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000792 }
793
794 void LoadWithInterceptor(MacroAssembler* masm,
795 Register receiver,
796 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000797 Handle<JSObject> holder_obj,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000798 Register scratch,
799 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000800 {
801 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000802
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000803 __ Push(holder, name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000804 CompileCallLoadPropertyWithInterceptor(masm,
805 receiver,
806 holder,
807 name_,
808 holder_obj);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000809 __ pop(name_); // Restore the name.
810 __ pop(receiver); // Restore the holder.
811 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000812 // If interceptor returns no-result sentinel, call the constant function.
813 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
814 __ Branch(interceptor_succeeded, ne, v0, Operand(scratch));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000815 }
816
817 StubCompiler* stub_compiler_;
818 const ParameterCount& arguments_;
819 Register name_;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000820 Code::ExtraICState extra_ic_state_;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000821};
822
823
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000824
825// Generate code to check that a global property cell is empty. Create
826// the property cell at compilation time if no cell exists for the
827// property.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000828static void GenerateCheckPropertyCell(MacroAssembler* masm,
829 Handle<GlobalObject> global,
830 Handle<String> name,
831 Register scratch,
832 Label* miss) {
833 Handle<JSGlobalPropertyCell> cell =
834 GlobalObject::EnsurePropertyCell(global, name);
835 ASSERT(cell->value()->IsTheHole());
836 __ li(scratch, Operand(cell));
837 __ lw(scratch,
838 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
839 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
840 __ Branch(miss, ne, scratch, Operand(at));
841}
842
843
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000844// Calls GenerateCheckPropertyCell for each global object in the prototype chain
845// from object to (but not including) holder.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000846static void GenerateCheckPropertyCells(MacroAssembler* masm,
847 Handle<JSObject> object,
848 Handle<JSObject> holder,
849 Handle<String> name,
850 Register scratch,
851 Label* miss) {
852 Handle<JSObject> current = object;
853 while (!current.is_identical_to(holder)) {
854 if (current->IsGlobalObject()) {
855 GenerateCheckPropertyCell(masm,
856 Handle<GlobalObject>::cast(current),
857 name,
858 scratch,
859 miss);
860 }
861 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
862 }
863}
864
865
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000866// Convert and store int passed in register ival to IEEE 754 single precision
867// floating point value at memory location (dst + 4 * wordoffset)
868// If FPU is available use it for conversion.
869static void StoreIntAsFloat(MacroAssembler* masm,
870 Register dst,
871 Register wordoffset,
872 Register ival,
873 Register fval,
874 Register scratch1,
875 Register scratch2) {
876 if (CpuFeatures::IsSupported(FPU)) {
877 CpuFeatures::Scope scope(FPU);
878 __ mtc1(ival, f0);
879 __ cvt_s_w(f0, f0);
880 __ sll(scratch1, wordoffset, 2);
881 __ addu(scratch1, dst, scratch1);
882 __ swc1(f0, MemOperand(scratch1, 0));
883 } else {
884 // FPU is not available, do manual conversions.
885
886 Label not_special, done;
887 // Move sign bit from source to destination. This works because the sign
888 // bit in the exponent word of the double has the same position and polarity
889 // as the 2's complement sign bit in a Smi.
890 ASSERT(kBinary32SignMask == 0x80000000u);
891
892 __ And(fval, ival, Operand(kBinary32SignMask));
893 // Negate value if it is negative.
894 __ subu(scratch1, zero_reg, ival);
895 __ movn(ival, scratch1, fval);
896
897 // We have -1, 0 or 1, which we treat specially. Register ival contains
898 // absolute value: it is either equal to 1 (special case of -1 and 1),
899 // greater than 1 (not a special case) or less than 1 (special case of 0).
900 __ Branch(&not_special, gt, ival, Operand(1));
901
902 // For 1 or -1 we need to or in the 0 exponent (biased).
903 static const uint32_t exponent_word_for_1 =
904 kBinary32ExponentBias << kBinary32ExponentShift;
905
906 __ Xor(scratch1, ival, Operand(1));
907 __ li(scratch2, exponent_word_for_1);
908 __ or_(scratch2, fval, scratch2);
909 __ movz(fval, scratch2, scratch1); // Only if ival is equal to 1.
910 __ Branch(&done);
911
912 __ bind(&not_special);
913 // Count leading zeros.
914 // Gets the wrong answer for 0, but we already checked for that case above.
915 Register zeros = scratch2;
916 __ clz(zeros, ival);
917
918 // Compute exponent and or it into the exponent register.
919 __ li(scratch1, (kBitsPerInt - 1) + kBinary32ExponentBias);
920 __ subu(scratch1, scratch1, zeros);
921
922 __ sll(scratch1, scratch1, kBinary32ExponentShift);
923 __ or_(fval, fval, scratch1);
924
925 // Shift up the source chopping the top bit off.
926 __ Addu(zeros, zeros, Operand(1));
927 // This wouldn't work for 1 and -1 as the shift would be 32 which means 0.
928 __ sllv(ival, ival, zeros);
929 // And the top (top 20 bits).
930 __ srl(scratch1, ival, kBitsPerInt - kBinary32MantissaBits);
931 __ or_(fval, fval, scratch1);
932
933 __ bind(&done);
934
935 __ sll(scratch1, wordoffset, 2);
936 __ addu(scratch1, dst, scratch1);
937 __ sw(fval, MemOperand(scratch1, 0));
938 }
939}
940
941
942// Convert unsigned integer with specified number of leading zeroes in binary
943// representation to IEEE 754 double.
944// Integer to convert is passed in register hiword.
945// Resulting double is returned in registers hiword:loword.
946// This functions does not work correctly for 0.
947static void GenerateUInt2Double(MacroAssembler* masm,
948 Register hiword,
949 Register loword,
950 Register scratch,
951 int leading_zeroes) {
952 const int meaningful_bits = kBitsPerInt - leading_zeroes - 1;
953 const int biased_exponent = HeapNumber::kExponentBias + meaningful_bits;
954
955 const int mantissa_shift_for_hi_word =
956 meaningful_bits - HeapNumber::kMantissaBitsInTopWord;
957
958 const int mantissa_shift_for_lo_word =
959 kBitsPerInt - mantissa_shift_for_hi_word;
960
961 __ li(scratch, biased_exponent << HeapNumber::kExponentShift);
962 if (mantissa_shift_for_hi_word > 0) {
963 __ sll(loword, hiword, mantissa_shift_for_lo_word);
964 __ srl(hiword, hiword, mantissa_shift_for_hi_word);
965 __ or_(hiword, scratch, hiword);
966 } else {
967 __ mov(loword, zero_reg);
968 __ sll(hiword, hiword, mantissa_shift_for_hi_word);
969 __ or_(hiword, scratch, hiword);
970 }
971
972 // If least significant bit of biased exponent was not 1 it was corrupted
973 // by most significant bit of mantissa so we should fix that.
974 if (!(biased_exponent & 1)) {
975 __ li(scratch, 1 << HeapNumber::kExponentShift);
976 __ nor(scratch, scratch, scratch);
977 __ and_(hiword, hiword, scratch);
978 }
979}
980
981
ager@chromium.org5c838252010-02-19 08:53:10 +0000982#undef __
983#define __ ACCESS_MASM(masm())
984
985
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000986Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
987 Register object_reg,
988 Handle<JSObject> holder,
989 Register holder_reg,
990 Register scratch1,
991 Register scratch2,
992 Handle<String> name,
993 int save_at_depth,
994 Label* miss) {
995 // Make sure there's no overlap between holder and object registers.
996 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
997 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
998 && !scratch2.is(scratch1));
999
1000 // Keep track of the current object in register reg.
1001 Register reg = object_reg;
1002 int depth = 0;
1003
1004 if (save_at_depth == depth) {
1005 __ sw(reg, MemOperand(sp));
1006 }
1007
1008 // Check the maps in the prototype chain.
1009 // Traverse the prototype chain from the object and do map checks.
1010 Handle<JSObject> current = object;
1011 while (!current.is_identical_to(holder)) {
1012 ++depth;
1013
1014 // Only global objects and objects that do not require access
1015 // checks are allowed in stubs.
1016 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1017
1018 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
1019 if (!current->HasFastProperties() &&
1020 !current->IsJSGlobalObject() &&
1021 !current->IsJSGlobalProxy()) {
1022 if (!name->IsSymbol()) {
1023 name = factory()->LookupSymbol(name);
1024 }
1025 ASSERT(current->property_dictionary()->FindEntry(*name) ==
1026 StringDictionary::kNotFound);
1027
1028 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1029 scratch1, scratch2);
1030
1031 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1032 reg = holder_reg; // From now on the object will be in holder_reg.
1033 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1034 } else {
1035 Handle<Map> current_map(current->map());
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001036 __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK,
1037 ALLOW_ELEMENT_TRANSITION_MAPS);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001038 // Check access rights to the global object. This has to happen after
1039 // the map check so that we know that the object is actually a global
1040 // object.
1041 if (current->IsJSGlobalProxy()) {
1042 __ CheckAccessGlobalProxy(reg, scratch2, miss);
1043 }
1044 reg = holder_reg; // From now on the object will be in holder_reg.
1045
1046 if (heap()->InNewSpace(*prototype)) {
1047 // The prototype is in new space; we cannot store a reference to it
1048 // in the code. Load it from the map.
1049 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1050 } else {
1051 // The prototype is in old space; load it directly.
1052 __ li(reg, Operand(prototype));
1053 }
1054 }
1055
1056 if (save_at_depth == depth) {
1057 __ sw(reg, MemOperand(sp));
1058 }
1059
1060 // Go to the next object in the prototype chain.
1061 current = prototype;
1062 }
1063
1064 // Log the check depth.
1065 LOG(masm()->isolate(), IntEvent("check-maps-depth", depth + 1));
1066
1067 // Check the holder map.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001068 __ CheckMap(reg, scratch1, Handle<Map>(current->map()), miss,
1069 DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001070
1071 // Perform security check for access to the global object.
1072 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1073 if (holder->IsJSGlobalProxy()) {
1074 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1075 }
1076
1077 // If we've skipped any global objects, it's not enough to verify that
1078 // their maps haven't changed. We also need to check that the property
1079 // cell for the property is still empty.
1080 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1081
1082 // Return the register containing the holder.
1083 return reg;
1084}
1085
1086
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001087void StubCompiler::GenerateLoadField(Handle<JSObject> object,
1088 Handle<JSObject> holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001089 Register receiver,
1090 Register scratch1,
1091 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001092 Register scratch3,
ager@chromium.org5c838252010-02-19 08:53:10 +00001093 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001094 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001095 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001096 // Check that the receiver isn't a smi.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001097 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001098
1099 // Check that the maps haven't changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001100 Register reg = CheckPrototypes(
1101 object, receiver, holder, scratch1, scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001102 GenerateFastPropertyLoad(masm(), v0, reg, holder, index);
1103 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001104}
1105
1106
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001107void StubCompiler::GenerateLoadConstant(Handle<JSObject> object,
1108 Handle<JSObject> holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001109 Register receiver,
1110 Register scratch1,
1111 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001112 Register scratch3,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001113 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001114 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001115 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001116 // Check that the receiver isn't a smi.
1117 __ JumpIfSmi(receiver, miss, scratch1);
1118
1119 // Check that the maps haven't changed.
1120 Register reg =
1121 CheckPrototypes(object, receiver, holder,
1122 scratch1, scratch2, scratch3, name, miss);
1123
1124 // Return the constant value.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001125 __ LoadHeapObject(v0, value);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001126 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001127}
1128
1129
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001130void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
1131 Handle<JSObject> holder,
1132 Register receiver,
1133 Register name_reg,
1134 Register scratch1,
1135 Register scratch2,
1136 Register scratch3,
1137 Handle<AccessorInfo> callback,
1138 Handle<String> name,
1139 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001140 // Check that the receiver isn't a smi.
1141 __ JumpIfSmi(receiver, miss, scratch1);
1142
1143 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001144 Register reg = CheckPrototypes(object, receiver, holder, scratch1,
1145 scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001146
1147 // Build AccessorInfo::args_ list on the stack and push property name below
1148 // the exit frame to make GC aware of them and store pointers to them.
1149 __ push(receiver);
1150 __ mov(scratch2, sp); // scratch2 = AccessorInfo::args_
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001151 if (heap()->InNewSpace(callback->data())) {
1152 __ li(scratch3, callback);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001153 __ lw(scratch3, FieldMemOperand(scratch3, AccessorInfo::kDataOffset));
1154 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001155 __ li(scratch3, Handle<Object>(callback->data()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001156 }
1157 __ Push(reg, scratch3, name_reg);
1158 __ mov(a2, scratch2); // Saved in case scratch2 == a1.
1159 __ mov(a1, sp); // a1 (first argument - see note below) = Handle<String>
1160
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001161 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
1162 // struct from the function (which is currently the case). This means we pass
1163 // the arguments in a1-a2 instead of a0-a1. TryCallApiFunctionAndReturn
1164 // will handle setting up a0.
1165
1166 const int kApiStackSpace = 1;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001167 FrameScope frame_scope(masm(), StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001168 __ EnterExitFrame(false, kApiStackSpace);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001169
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001170 // Create AccessorInfo instance on the stack above the exit frame with
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001171 // scratch2 (internal::Object** args_) as the data.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001172 __ sw(a2, MemOperand(sp, kPointerSize));
1173 // a2 (second argument - see note above) = AccessorInfo&
1174 __ Addu(a2, sp, kPointerSize);
1175
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001176 const int kStackUnwindSpace = 4;
1177 Address getter_address = v8::ToCData<Address>(callback->getter());
1178 ApiFunction fun(getter_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001179 ExternalReference ref =
1180 ExternalReference(&fun,
1181 ExternalReference::DIRECT_GETTER_CALL,
1182 masm()->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001183 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
ager@chromium.org5c838252010-02-19 08:53:10 +00001184}
1185
1186
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001187void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
1188 Handle<JSObject> interceptor_holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001189 LookupResult* lookup,
1190 Register receiver,
1191 Register name_reg,
1192 Register scratch1,
1193 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001194 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001195 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001196 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001197 ASSERT(interceptor_holder->HasNamedInterceptor());
1198 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1199
1200 // Check that the receiver isn't a smi.
1201 __ JumpIfSmi(receiver, miss);
1202
1203 // So far the most popular follow ups for interceptor loads are FIELD
1204 // and CALLBACKS, so inline only them, other cases may be added
1205 // later.
1206 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001207 if (lookup->IsFound() && lookup->IsCacheable()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001208 if (lookup->type() == FIELD) {
1209 compile_followup_inline = true;
1210 } else if (lookup->type() == CALLBACKS &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001211 lookup->GetCallbackObject()->IsAccessorInfo()) {
1212 compile_followup_inline =
1213 AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001214 }
1215 }
1216
1217 if (compile_followup_inline) {
1218 // Compile the interceptor call, followed by inline code to load the
1219 // property from further up the prototype chain if the call fails.
1220 // Check that the maps haven't changed.
1221 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1222 scratch1, scratch2, scratch3,
1223 name, miss);
1224 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
1225
1226 // Save necessary data before invoking an interceptor.
1227 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001228 {
1229 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001230 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
1231 // CALLBACKS case needs a receiver to be passed into C++ callback.
1232 __ Push(receiver, holder_reg, name_reg);
1233 } else {
1234 __ Push(holder_reg, name_reg);
1235 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001236 // Invoke an interceptor. Note: map checks from receiver to
1237 // interceptor's holder has been compiled before (see a caller
1238 // of this method).
1239 CompileCallLoadPropertyWithInterceptor(masm(),
1240 receiver,
1241 holder_reg,
1242 name_reg,
1243 interceptor_holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001244 // Check if interceptor provided a value for property. If it's
1245 // the case, return immediately.
1246 Label interceptor_failed;
1247 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
1248 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1));
1249 frame_scope.GenerateLeaveFrame();
1250 __ Ret();
1251
1252 __ bind(&interceptor_failed);
1253 __ pop(name_reg);
1254 __ pop(holder_reg);
1255 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
1256 __ pop(receiver);
1257 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001258 // Leave the internal frame.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001259 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001260 // Check that the maps from interceptor's holder to lookup's holder
1261 // haven't changed. And load lookup's holder into |holder| register.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001262 if (*interceptor_holder != lookup->holder()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001263 holder_reg = CheckPrototypes(interceptor_holder,
1264 holder_reg,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001265 Handle<JSObject>(lookup->holder()),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001266 scratch1,
1267 scratch2,
1268 scratch3,
1269 name,
1270 miss);
1271 }
1272
1273 if (lookup->type() == FIELD) {
1274 // We found FIELD property in prototype chain of interceptor's holder.
1275 // Retrieve a field from field's holder.
1276 GenerateFastPropertyLoad(masm(), v0, holder_reg,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001277 Handle<JSObject>(lookup->holder()),
1278 lookup->GetFieldIndex());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001279 __ Ret();
1280 } else {
1281 // We found CALLBACKS property in prototype chain of interceptor's
1282 // holder.
1283 ASSERT(lookup->type() == CALLBACKS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001284 Handle<AccessorInfo> callback(
1285 AccessorInfo::cast(lookup->GetCallbackObject()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001286 ASSERT(callback->getter() != NULL);
1287
1288 // Tail call to runtime.
1289 // Important invariant in CALLBACKS case: the code above must be
1290 // structured to never clobber |receiver| register.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001291 __ li(scratch2, callback);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001292 // holder_reg is either receiver or scratch1.
1293 if (!receiver.is(holder_reg)) {
1294 ASSERT(scratch1.is(holder_reg));
1295 __ Push(receiver, holder_reg);
1296 __ lw(scratch3,
1297 FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
1298 __ Push(scratch3, scratch2, name_reg);
1299 } else {
1300 __ push(receiver);
1301 __ lw(scratch3,
1302 FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
1303 __ Push(holder_reg, scratch3, scratch2, name_reg);
1304 }
1305
1306 ExternalReference ref =
1307 ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
1308 masm()->isolate());
1309 __ TailCallExternalReference(ref, 5, 1);
1310 }
1311 } else { // !compile_followup_inline
1312 // Call the runtime system to load the interceptor.
1313 // Check that the maps haven't changed.
1314 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1315 scratch1, scratch2, scratch3,
1316 name, miss);
1317 PushInterceptorArguments(masm(), receiver, holder_reg,
1318 name_reg, interceptor_holder);
1319
1320 ExternalReference ref = ExternalReference(
1321 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), masm()->isolate());
1322 __ TailCallExternalReference(ref, 5, 1);
1323 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001324}
1325
1326
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001327void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001328 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001329 __ Branch(miss, ne, a2, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001330 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001331}
1332
1333
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001334void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1335 Handle<JSObject> holder,
1336 Handle<String> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001337 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001338 ASSERT(holder->IsGlobalObject());
1339
1340 // Get the number of arguments.
1341 const int argc = arguments().immediate();
1342
1343 // Get the receiver from the stack.
1344 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1345
1346 // If the object is the holder then we know that it's a global
1347 // object which can only happen for contextual calls. In this case,
1348 // the receiver cannot be a smi.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001349 if (!object.is_identical_to(holder)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001350 __ JumpIfSmi(a0, miss);
1351 }
1352
1353 // Check that the maps haven't changed.
1354 CheckPrototypes(object, a0, holder, a3, a1, t0, name, miss);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001355}
1356
1357
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001358void CallStubCompiler::GenerateLoadFunctionFromCell(
1359 Handle<JSGlobalPropertyCell> cell,
1360 Handle<JSFunction> function,
1361 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001362 // Get the value from the cell.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001363 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001364 __ lw(a1, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
1365
1366 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001367 if (heap()->InNewSpace(*function)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001368 // We can't embed a pointer to a function in new space so we have
1369 // to verify that the shared function info is unchanged. This has
1370 // the nice side effect that multiple closures based on the same
1371 // function can all use this call IC. Before we load through the
1372 // function, we have to verify that it still is a function.
1373 __ JumpIfSmi(a1, miss);
1374 __ GetObjectType(a1, a3, a3);
1375 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
1376
1377 // Check the shared function info. Make sure it hasn't changed.
1378 __ li(a3, Handle<SharedFunctionInfo>(function->shared()));
1379 __ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
1380 __ Branch(miss, ne, t0, Operand(a3));
1381 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001382 __ Branch(miss, ne, a1, Operand(function));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001383 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001384}
1385
1386
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001387void CallStubCompiler::GenerateMissBranch() {
1388 Handle<Code> code =
danno@chromium.org40cb8782011-05-25 07:58:50 +00001389 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1390 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001391 extra_state_);
1392 __ Jump(code, RelocInfo::CODE_TARGET);
1393}
1394
1395
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001396Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1397 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001398 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001399 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001400 // ----------- S t a t e -------------
1401 // -- a2 : name
1402 // -- ra : return address
1403 // -----------------------------------
1404 Label miss;
1405
1406 GenerateNameCheck(name, &miss);
1407
1408 const int argc = arguments().immediate();
1409
1410 // Get the receiver of the function from the stack into a0.
1411 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1412 // Check that the receiver isn't a smi.
1413 __ JumpIfSmi(a0, &miss, t0);
1414
1415 // Do the right check and compute the holder register.
1416 Register reg = CheckPrototypes(object, a0, holder, a1, a3, t0, name, &miss);
1417 GenerateFastPropertyLoad(masm(), a1, reg, holder, index);
1418
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001419 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001420
1421 // Handle call cache miss.
1422 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001423 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001424
1425 // Return the generated code.
1426 return GetCode(FIELD, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001427}
1428
1429
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001430Handle<Code> CallStubCompiler::CompileArrayPushCall(
1431 Handle<Object> object,
1432 Handle<JSObject> holder,
1433 Handle<JSGlobalPropertyCell> cell,
1434 Handle<JSFunction> function,
1435 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001436 // ----------- S t a t e -------------
1437 // -- a2 : name
1438 // -- ra : return address
1439 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1440 // -- ...
1441 // -- sp[argc * 4] : receiver
1442 // -----------------------------------
1443
1444 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001445 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001446
1447 Label miss;
1448
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001449 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001450
1451 Register receiver = a1;
1452
1453 // Get the receiver from the stack.
1454 const int argc = arguments().immediate();
1455 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1456
1457 // Check that the receiver isn't a smi.
1458 __ JumpIfSmi(receiver, &miss);
1459
1460 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001461 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, a3, v0, t0,
1462 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001463
1464 if (argc == 0) {
1465 // Nothing to do, just return the length.
1466 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1467 __ Drop(argc + 1);
1468 __ Ret();
1469 } else {
1470 Label call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001471 if (argc == 1) { // Otherwise fall through to call the builtin.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001472 Label attempt_to_grow_elements;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001473
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001474 Register elements = t2;
1475 Register end_elements = t1;
1476 // Get the elements array of the object.
1477 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1478
1479 // Check that the elements are in fast mode and writable.
1480 __ CheckMap(elements,
1481 v0,
1482 Heap::kFixedArrayMapRootIndex,
1483 &call_builtin,
1484 DONT_DO_SMI_CHECK);
1485
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001486 // Get the array's length into v0 and calculate new length.
1487 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1488 STATIC_ASSERT(kSmiTagSize == 1);
1489 STATIC_ASSERT(kSmiTag == 0);
1490 __ Addu(v0, v0, Operand(Smi::FromInt(argc)));
1491
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001492 // Get the elements' length.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001493 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1494
1495 // Check if we could survive without allocation.
1496 __ Branch(&attempt_to_grow_elements, gt, v0, Operand(t0));
1497
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001498 // Check if value is a smi.
1499 Label with_write_barrier;
1500 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1501 __ JumpIfNotSmi(t0, &with_write_barrier);
1502
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001503 // Save new length.
1504 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1505
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001506 // Store the value.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001507 // We may need a register containing the address end_elements below,
1508 // so write back the value in end_elements.
1509 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1510 __ Addu(end_elements, elements, end_elements);
1511 const int kEndElementsOffset =
1512 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001513 __ Addu(end_elements, end_elements, kEndElementsOffset);
1514 __ sw(t0, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001515
1516 // Check for a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001517 __ Drop(argc + 1);
1518 __ Ret();
1519
1520 __ bind(&with_write_barrier);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001521
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001522 __ lw(a3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1523
1524 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
1525 Label fast_object, not_fast_object;
1526 __ CheckFastObjectElements(a3, t3, &not_fast_object);
1527 __ jmp(&fast_object);
1528 // In case of fast smi-only, convert to fast object, otherwise bail out.
1529 __ bind(&not_fast_object);
1530 __ CheckFastSmiOnlyElements(a3, t3, &call_builtin);
1531 // edx: receiver
1532 // r3: map
1533 __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
1534 FAST_ELEMENTS,
1535 a3,
1536 t3,
1537 &call_builtin);
1538 __ mov(a2, receiver);
1539 ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm());
1540 __ bind(&fast_object);
1541 } else {
1542 __ CheckFastObjectElements(a3, a3, &call_builtin);
1543 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001544
1545 // Save new length.
1546 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1547
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001548 // Store the value.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001549 // We may need a register containing the address end_elements below,
1550 // so write back the value in end_elements.
1551 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1552 __ Addu(end_elements, elements, end_elements);
1553 __ Addu(end_elements, end_elements, kEndElementsOffset);
1554 __ sw(t0, MemOperand(end_elements));
1555
1556 __ RecordWrite(elements,
1557 end_elements,
1558 t0,
1559 kRAHasNotBeenSaved,
1560 kDontSaveFPRegs,
1561 EMIT_REMEMBERED_SET,
1562 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001563 __ Drop(argc + 1);
1564 __ Ret();
1565
1566 __ bind(&attempt_to_grow_elements);
1567 // v0: array's length + 1.
1568 // t0: elements' length.
1569
1570 if (!FLAG_inline_new) {
1571 __ Branch(&call_builtin);
1572 }
1573
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001574 __ lw(a2, MemOperand(sp, (argc - 1) * kPointerSize));
1575 // Growing elements that are SMI-only requires special handling in case
1576 // the new element is non-Smi. For now, delegate to the builtin.
1577 Label no_fast_elements_check;
1578 __ JumpIfSmi(a2, &no_fast_elements_check);
1579 __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1580 __ CheckFastObjectElements(t3, t3, &call_builtin);
1581 __ bind(&no_fast_elements_check);
1582
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001583 ExternalReference new_space_allocation_top =
1584 ExternalReference::new_space_allocation_top_address(
1585 masm()->isolate());
1586 ExternalReference new_space_allocation_limit =
1587 ExternalReference::new_space_allocation_limit_address(
1588 masm()->isolate());
1589
1590 const int kAllocationDelta = 4;
1591 // Load top and check if it is the end of elements.
1592 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1593 __ Addu(end_elements, elements, end_elements);
1594 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset));
1595 __ li(t3, Operand(new_space_allocation_top));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001596 __ lw(a3, MemOperand(t3));
1597 __ Branch(&call_builtin, ne, end_elements, Operand(a3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001598
1599 __ li(t5, Operand(new_space_allocation_limit));
1600 __ lw(t5, MemOperand(t5));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001601 __ Addu(a3, a3, Operand(kAllocationDelta * kPointerSize));
1602 __ Branch(&call_builtin, hi, a3, Operand(t5));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001603
1604 // We fit and could grow elements.
1605 // Update new_space_allocation_top.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001606 __ sw(a3, MemOperand(t3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001607 // Push the argument.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001608 __ sw(a2, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001609 // Fill the rest with holes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001610 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001611 for (int i = 1; i < kAllocationDelta; i++) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001612 __ sw(a3, MemOperand(end_elements, i * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001613 }
1614
1615 // Update elements' and array's sizes.
1616 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1617 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta)));
1618 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1619
1620 // Elements are in new space, so write barrier is not required.
1621 __ Drop(argc + 1);
1622 __ Ret();
1623 }
1624 __ bind(&call_builtin);
1625 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
1626 masm()->isolate()),
1627 argc + 1,
1628 1);
1629 }
1630
1631 // Handle call cache miss.
1632 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001633 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001634
1635 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001636 return GetCode(function);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001637}
1638
1639
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001640Handle<Code> CallStubCompiler::CompileArrayPopCall(
1641 Handle<Object> object,
1642 Handle<JSObject> holder,
1643 Handle<JSGlobalPropertyCell> cell,
1644 Handle<JSFunction> function,
1645 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001646 // ----------- S t a t e -------------
1647 // -- a2 : name
1648 // -- ra : return address
1649 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1650 // -- ...
1651 // -- sp[argc * 4] : receiver
1652 // -----------------------------------
1653
1654 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001655 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001656
1657 Label miss, return_undefined, call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001658 Register receiver = a1;
1659 Register elements = a3;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001660 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001661
1662 // Get the receiver from the stack.
1663 const int argc = arguments().immediate();
1664 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001665 // Check that the receiver isn't a smi.
1666 __ JumpIfSmi(receiver, &miss);
1667
1668 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001669 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, elements,
1670 t0, v0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001671
1672 // Get the elements array of the object.
1673 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1674
1675 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001676 __ CheckMap(elements,
1677 v0,
1678 Heap::kFixedArrayMapRootIndex,
1679 &call_builtin,
1680 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001681
1682 // Get the array's length into t0 and calculate new length.
1683 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1684 __ Subu(t0, t0, Operand(Smi::FromInt(1)));
1685 __ Branch(&return_undefined, lt, t0, Operand(zero_reg));
1686
1687 // Get the last element.
1688 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1689 STATIC_ASSERT(kSmiTagSize == 1);
1690 STATIC_ASSERT(kSmiTag == 0);
1691 // We can't address the last element in one operation. Compute the more
1692 // expensive shift first, and use an offset later on.
1693 __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize);
1694 __ Addu(elements, elements, t1);
1695 __ lw(v0, MemOperand(elements, FixedArray::kHeaderSize - kHeapObjectTag));
1696 __ Branch(&call_builtin, eq, v0, Operand(t2));
1697
1698 // Set the array's length.
1699 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1700
1701 // Fill with the hole.
1702 __ sw(t2, MemOperand(elements, FixedArray::kHeaderSize - kHeapObjectTag));
1703 __ Drop(argc + 1);
1704 __ Ret();
1705
1706 __ bind(&return_undefined);
1707 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
1708 __ Drop(argc + 1);
1709 __ Ret();
1710
1711 __ bind(&call_builtin);
1712 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop,
1713 masm()->isolate()),
1714 argc + 1,
1715 1);
1716
1717 // Handle call cache miss.
1718 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001719 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001720
1721 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001722 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001723}
1724
1725
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001726Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1727 Handle<Object> object,
1728 Handle<JSObject> holder,
1729 Handle<JSGlobalPropertyCell> cell,
1730 Handle<JSFunction> function,
1731 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001732 // ----------- S t a t e -------------
1733 // -- a2 : function name
1734 // -- ra : return address
1735 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1736 // -- ...
1737 // -- sp[argc * 4] : receiver
1738 // -----------------------------------
1739
1740 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001741 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001742
1743 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001744 Label miss;
1745 Label name_miss;
1746 Label index_out_of_range;
1747
1748 Label* index_out_of_range_label = &index_out_of_range;
1749
danno@chromium.org40cb8782011-05-25 07:58:50 +00001750 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001751 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001752 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001753 index_out_of_range_label = &miss;
1754 }
1755
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001756 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001757
1758 // Check that the maps starting from the prototype haven't changed.
1759 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1760 Context::STRING_FUNCTION_INDEX,
1761 v0,
1762 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001763 ASSERT(!object.is_identical_to(holder));
1764 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1765 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001766
1767 Register receiver = a1;
1768 Register index = t1;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001769 Register result = v0;
1770 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1771 if (argc > 0) {
1772 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1773 } else {
1774 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1775 }
1776
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001777 StringCharCodeAtGenerator generator(receiver,
1778 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001779 result,
1780 &miss, // When not a string.
1781 &miss, // When not a number.
1782 index_out_of_range_label,
1783 STRING_INDEX_IS_NUMBER);
1784 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001785 __ Drop(argc + 1);
1786 __ Ret();
1787
1788 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001789 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001790
1791 if (index_out_of_range.is_linked()) {
1792 __ bind(&index_out_of_range);
1793 __ LoadRoot(v0, Heap::kNanValueRootIndex);
1794 __ Drop(argc + 1);
1795 __ Ret();
1796 }
1797
1798 __ bind(&miss);
1799 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001800 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001801 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001802 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001803
1804 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001805 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001806}
1807
1808
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001809Handle<Code> CallStubCompiler::CompileStringCharAtCall(
1810 Handle<Object> object,
1811 Handle<JSObject> holder,
1812 Handle<JSGlobalPropertyCell> cell,
1813 Handle<JSFunction> function,
1814 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001815 // ----------- S t a t e -------------
1816 // -- a2 : function name
1817 // -- ra : return address
1818 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1819 // -- ...
1820 // -- sp[argc * 4] : receiver
1821 // -----------------------------------
1822
1823 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001824 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001825
1826 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001827 Label miss;
1828 Label name_miss;
1829 Label index_out_of_range;
1830 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00001831 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001832 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001833 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001834 index_out_of_range_label = &miss;
1835 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001836 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001837
1838 // Check that the maps starting from the prototype haven't changed.
1839 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1840 Context::STRING_FUNCTION_INDEX,
1841 v0,
1842 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001843 ASSERT(!object.is_identical_to(holder));
1844 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1845 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001846
1847 Register receiver = v0;
1848 Register index = t1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001849 Register scratch = a3;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001850 Register result = v0;
1851 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1852 if (argc > 0) {
1853 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1854 } else {
1855 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1856 }
1857
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001858 StringCharAtGenerator generator(receiver,
1859 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00001860 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001861 result,
1862 &miss, // When not a string.
1863 &miss, // When not a number.
1864 index_out_of_range_label,
1865 STRING_INDEX_IS_NUMBER);
1866 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001867 __ Drop(argc + 1);
1868 __ Ret();
1869
1870 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001871 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001872
1873 if (index_out_of_range.is_linked()) {
1874 __ bind(&index_out_of_range);
1875 __ LoadRoot(v0, Heap::kEmptyStringRootIndex);
1876 __ Drop(argc + 1);
1877 __ Ret();
1878 }
1879
1880 __ bind(&miss);
1881 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001882 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001883 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001884 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001885
1886 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001887 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001888}
1889
1890
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001891Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
1892 Handle<Object> object,
1893 Handle<JSObject> holder,
1894 Handle<JSGlobalPropertyCell> cell,
1895 Handle<JSFunction> function,
1896 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001897 // ----------- S t a t e -------------
1898 // -- a2 : function name
1899 // -- ra : return address
1900 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1901 // -- ...
1902 // -- sp[argc * 4] : receiver
1903 // -----------------------------------
1904
1905 const int argc = arguments().immediate();
1906
1907 // If the object is not a JSObject or we got an unexpected number of
1908 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001909 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001910
1911 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001912 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001913
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001914 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001915 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
1916
1917 STATIC_ASSERT(kSmiTag == 0);
1918 __ JumpIfSmi(a1, &miss);
1919
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001920 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
1921 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001922 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001923 ASSERT(cell->value() == *function);
1924 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
1925 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001926 GenerateLoadFunctionFromCell(cell, function, &miss);
1927 }
1928
1929 // Load the char code argument.
1930 Register code = a1;
1931 __ lw(code, MemOperand(sp, 0 * kPointerSize));
1932
1933 // Check the code is a smi.
1934 Label slow;
1935 STATIC_ASSERT(kSmiTag == 0);
1936 __ JumpIfNotSmi(code, &slow);
1937
1938 // Convert the smi code to uint16.
1939 __ And(code, code, Operand(Smi::FromInt(0xffff)));
1940
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001941 StringCharFromCodeGenerator generator(code, v0);
1942 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001943 __ Drop(argc + 1);
1944 __ Ret();
1945
1946 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001947 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001948
1949 // Tail call the full function. We do not have to patch the receiver
1950 // because the function makes no use of it.
1951 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001952 __ InvokeFunction(
1953 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001954
1955 __ bind(&miss);
1956 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001957 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001958
1959 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001960 return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001961}
1962
1963
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001964Handle<Code> CallStubCompiler::CompileMathFloorCall(
1965 Handle<Object> object,
1966 Handle<JSObject> holder,
1967 Handle<JSGlobalPropertyCell> cell,
1968 Handle<JSFunction> function,
1969 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001970 // ----------- S t a t e -------------
1971 // -- a2 : function name
1972 // -- ra : return address
1973 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1974 // -- ...
1975 // -- sp[argc * 4] : receiver
1976 // -----------------------------------
1977
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001978 if (!CpuFeatures::IsSupported(FPU)) {
1979 return Handle<Code>::null();
1980 }
1981
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001982 CpuFeatures::Scope scope_fpu(FPU);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001983 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001984 // If the object is not a JSObject or we got an unexpected number of
1985 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001986 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001987
1988 Label miss, slow;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001989 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001990
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001991 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001992 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001993 STATIC_ASSERT(kSmiTag == 0);
1994 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001995 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
1996 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001997 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001998 ASSERT(cell->value() == *function);
1999 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2000 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002001 GenerateLoadFunctionFromCell(cell, function, &miss);
2002 }
2003
2004 // Load the (only) argument into v0.
2005 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2006
2007 // If the argument is a smi, just return.
2008 STATIC_ASSERT(kSmiTag == 0);
2009 __ And(t0, v0, Operand(kSmiTagMask));
2010 __ Drop(argc + 1, eq, t0, Operand(zero_reg));
2011 __ Ret(eq, t0, Operand(zero_reg));
2012
danno@chromium.org40cb8782011-05-25 07:58:50 +00002013 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002014
2015 Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return;
2016
2017 // If fpu is enabled, we use the floor instruction.
2018
2019 // Load the HeapNumber value.
2020 __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2021
2022 // Backup FCSR.
2023 __ cfc1(a3, FCSR);
2024 // Clearing FCSR clears the exception mask with no side-effects.
2025 __ ctc1(zero_reg, FCSR);
2026 // Convert the argument to an integer.
2027 __ floor_w_d(f0, f0);
2028
2029 // Start checking for special cases.
2030 // Get the argument exponent and clear the sign bit.
2031 __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize));
2032 __ And(t2, t1, Operand(~HeapNumber::kSignMask));
2033 __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord);
2034
2035 // Retrieve FCSR and check for fpu errors.
2036 __ cfc1(t5, FCSR);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002037 __ And(t5, t5, Operand(kFCSRExceptionFlagMask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002038 __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));
2039
2040 // Check for NaN, Infinity, and -Infinity.
2041 // They are invariant through a Math.Floor call, so just
2042 // return the original argument.
2043 __ Subu(t3, t2, Operand(HeapNumber::kExponentMask
2044 >> HeapNumber::kMantissaBitsInTopWord));
2045 __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg));
2046 // We had an overflow or underflow in the conversion. Check if we
2047 // have a big exponent.
2048 // If greater or equal, the argument is already round and in v0.
2049 __ Branch(&restore_fcsr_and_return, ge, t3,
2050 Operand(HeapNumber::kMantissaBits));
2051 __ Branch(&wont_fit_smi);
2052
2053 __ bind(&no_fpu_error);
2054 // Move the result back to v0.
2055 __ mfc1(v0, f0);
2056 // Check if the result fits into a smi.
2057 __ Addu(a1, v0, Operand(0x40000000));
2058 __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg));
2059 // Tag the result.
2060 STATIC_ASSERT(kSmiTag == 0);
2061 __ sll(v0, v0, kSmiTagSize);
2062
2063 // Check for -0.
2064 __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg));
2065 // t1 already holds the HeapNumber exponent.
2066 __ And(t0, t1, Operand(HeapNumber::kSignMask));
2067 // If our HeapNumber is negative it was -0, so load its address and return.
2068 // Else v0 is loaded with 0, so we can also just return.
2069 __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg));
2070 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2071
2072 __ bind(&restore_fcsr_and_return);
2073 // Restore FCSR and return.
2074 __ ctc1(a3, FCSR);
2075
2076 __ Drop(argc + 1);
2077 __ Ret();
2078
2079 __ bind(&wont_fit_smi);
2080 // Restore FCSR and fall to slow case.
2081 __ ctc1(a3, FCSR);
2082
2083 __ bind(&slow);
2084 // Tail call the full function. We do not have to patch the receiver
2085 // because the function makes no use of it.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002086 __ InvokeFunction(
2087 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002088
2089 __ bind(&miss);
2090 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002091 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002092
2093 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002094 return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002095}
2096
2097
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002098Handle<Code> CallStubCompiler::CompileMathAbsCall(
2099 Handle<Object> object,
2100 Handle<JSObject> holder,
2101 Handle<JSGlobalPropertyCell> cell,
2102 Handle<JSFunction> function,
2103 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002104 // ----------- S t a t e -------------
2105 // -- a2 : function name
2106 // -- ra : return address
2107 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2108 // -- ...
2109 // -- sp[argc * 4] : receiver
2110 // -----------------------------------
2111
2112 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002113 // If the object is not a JSObject or we got an unexpected number of
2114 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002115 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002116
2117 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002118
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002119 GenerateNameCheck(name, &miss);
2120 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002121 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002122 STATIC_ASSERT(kSmiTag == 0);
2123 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002124 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2125 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002126 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002127 ASSERT(cell->value() == *function);
2128 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2129 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002130 GenerateLoadFunctionFromCell(cell, function, &miss);
2131 }
2132
2133 // Load the (only) argument into v0.
2134 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2135
2136 // Check if the argument is a smi.
2137 Label not_smi;
2138 STATIC_ASSERT(kSmiTag == 0);
2139 __ JumpIfNotSmi(v0, &not_smi);
2140
2141 // Do bitwise not or do nothing depending on the sign of the
2142 // argument.
2143 __ sra(t0, v0, kBitsPerInt - 1);
2144 __ Xor(a1, v0, t0);
2145
2146 // Add 1 or do nothing depending on the sign of the argument.
2147 __ Subu(v0, a1, t0);
2148
2149 // If the result is still negative, go to the slow case.
2150 // This only happens for the most negative smi.
2151 Label slow;
2152 __ Branch(&slow, lt, v0, Operand(zero_reg));
2153
2154 // Smi case done.
2155 __ Drop(argc + 1);
2156 __ Ret();
2157
2158 // Check if the argument is a heap number and load its exponent and
2159 // sign.
2160 __ bind(&not_smi);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002161 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002162 __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2163
2164 // Check the sign of the argument. If the argument is positive,
2165 // just return it.
2166 Label negative_sign;
2167 __ And(t0, a1, Operand(HeapNumber::kSignMask));
2168 __ Branch(&negative_sign, ne, t0, Operand(zero_reg));
2169 __ Drop(argc + 1);
2170 __ Ret();
2171
2172 // If the argument is negative, clear the sign, and return a new
2173 // number.
2174 __ bind(&negative_sign);
2175 __ Xor(a1, a1, Operand(HeapNumber::kSignMask));
2176 __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2177 __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
2178 __ AllocateHeapNumber(v0, t0, t1, t2, &slow);
2179 __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2180 __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2181 __ Drop(argc + 1);
2182 __ Ret();
2183
2184 // Tail call the full function. We do not have to patch the receiver
2185 // because the function makes no use of it.
2186 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002187 __ InvokeFunction(
2188 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002189
2190 __ bind(&miss);
2191 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002192 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002193
2194 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002195 return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002196}
2197
2198
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002199Handle<Code> CallStubCompiler::CompileFastApiCall(
lrn@chromium.org7516f052011-03-30 08:52:27 +00002200 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002201 Handle<Object> object,
2202 Handle<JSObject> holder,
2203 Handle<JSGlobalPropertyCell> cell,
2204 Handle<JSFunction> function,
2205 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002206
danno@chromium.org40cb8782011-05-25 07:58:50 +00002207 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002208
2209 ASSERT(optimization.is_simple_api_call());
2210 // Bail out if object is a global object as we don't want to
2211 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002212 if (object->IsGlobalObject()) return Handle<Code>::null();
2213 if (!cell.is_null()) return Handle<Code>::null();
2214 if (!object->IsJSObject()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002215 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002216 Handle<JSObject>::cast(object), holder);
2217 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002218
2219 Label miss, miss_before_stack_reserved;
2220
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002221 GenerateNameCheck(name, &miss_before_stack_reserved);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002222
2223 // Get the receiver from the stack.
2224 const int argc = arguments().immediate();
2225 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2226
2227 // Check that the receiver isn't a smi.
2228 __ JumpIfSmi(a1, &miss_before_stack_reserved);
2229
2230 __ IncrementCounter(counters->call_const(), 1, a0, a3);
2231 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2232
2233 ReserveSpaceForFastApiCall(masm(), a0);
2234
2235 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002236 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002237 depth, &miss);
2238
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002239 GenerateFastApiDirectCall(masm(), optimization, argc);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002240
2241 __ bind(&miss);
2242 FreeSpaceForFastApiCall(masm());
2243
2244 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002245 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002246
2247 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002248 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002249}
2250
2251
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002252Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object,
2253 Handle<JSObject> holder,
2254 Handle<JSFunction> function,
2255 Handle<String> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002256 CheckType check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002257 // ----------- S t a t e -------------
2258 // -- a2 : name
2259 // -- ra : return address
2260 // -----------------------------------
2261 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002262 Handle<Code> code = CompileCustomCall(object, holder,
2263 Handle<JSGlobalPropertyCell>::null(),
2264 function, name);
2265 // A null handle means bail out to the regular compiler code below.
2266 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002267 }
2268
2269 Label miss;
2270
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002271 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002272
2273 // Get the receiver from the stack.
2274 const int argc = arguments().immediate();
2275 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2276
2277 // Check that the receiver isn't a smi.
2278 if (check != NUMBER_CHECK) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002279 __ JumpIfSmi(a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002280 }
2281
2282 // Make sure that it's okay not to patch the on stack receiver
2283 // unless we're doing a receiver map check.
2284 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002285 switch (check) {
2286 case RECEIVER_MAP_CHECK:
2287 __ IncrementCounter(masm()->isolate()->counters()->call_const(),
2288 1, a0, a3);
2289
2290 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002291 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2292 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002293
2294 // Patch the receiver on the stack with the global proxy if
2295 // necessary.
2296 if (object->IsGlobalObject()) {
2297 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2298 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2299 }
2300 break;
2301
2302 case STRING_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002303 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002304 // Check that the object is a two-byte string or a symbol.
2305 __ GetObjectType(a1, a3, a3);
2306 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2307 // Check that the maps starting from the prototype haven't changed.
2308 GenerateDirectLoadGlobalFunctionPrototype(
2309 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002310 CheckPrototypes(
2311 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2312 a0, holder, a3, a1, t0, name, &miss);
2313 } else {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002314 // Calling non-strict non-builtins with a value as the receiver
2315 // requires boxing.
2316 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002317 }
2318 break;
2319
2320 case NUMBER_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002321 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002322 Label fast;
2323 // Check that the object is a smi or a heap number.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002324 __ JumpIfSmi(a1, &fast);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002325 __ GetObjectType(a1, a0, a0);
2326 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
2327 __ bind(&fast);
2328 // Check that the maps starting from the prototype haven't changed.
2329 GenerateDirectLoadGlobalFunctionPrototype(
2330 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002331 CheckPrototypes(
2332 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2333 a0, holder, a3, a1, t0, name, &miss);
2334 } else {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002335 // Calling non-strict non-builtins with a value as the receiver
2336 // requires boxing.
2337 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002338 }
2339 break;
2340
2341 case BOOLEAN_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002342 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002343 Label fast;
2344 // Check that the object is a boolean.
2345 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
2346 __ Branch(&fast, eq, a1, Operand(t0));
2347 __ LoadRoot(t0, Heap::kFalseValueRootIndex);
2348 __ Branch(&miss, ne, a1, Operand(t0));
2349 __ bind(&fast);
2350 // Check that the maps starting from the prototype haven't changed.
2351 GenerateDirectLoadGlobalFunctionPrototype(
2352 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002353 CheckPrototypes(
2354 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2355 a0, holder, a3, a1, t0, name, &miss);
2356 } else {
2357 // Calling non-strict non-builtins with a value as the receiver
2358 // requires boxing.
2359 __ jmp(&miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002360 }
2361 break;
2362 }
2363
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002364 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002365 ? CALL_AS_FUNCTION
2366 : CALL_AS_METHOD;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002367 __ InvokeFunction(
2368 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002369
2370 // Handle call cache miss.
2371 __ bind(&miss);
2372
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002373 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002374
2375 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002376 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002377}
2378
2379
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002380Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2381 Handle<JSObject> holder,
2382 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002383 // ----------- S t a t e -------------
2384 // -- a2 : name
2385 // -- ra : return address
2386 // -----------------------------------
2387
2388 Label miss;
2389
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002390 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002391
2392 // Get the number of arguments.
2393 const int argc = arguments().immediate();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002394 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002395 LookupPostInterceptor(holder, name, &lookup);
2396
2397 // Get the receiver from the stack.
2398 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2399
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002400 CallInterceptorCompiler compiler(this, arguments(), a2, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002401 compiler.Compile(masm(), object, holder, name, &lookup, a1, a3, t0, a0,
2402 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002403
2404 // Move returned value, the function to call, to a1.
2405 __ mov(a1, v0);
2406 // Restore receiver.
2407 __ lw(a0, MemOperand(sp, argc * kPointerSize));
2408
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002409 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002410
2411 // Handle call cache miss.
2412 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002413 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002414
2415 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002416 return GetCode(INTERCEPTOR, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002417}
2418
2419
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002420Handle<Code> CallStubCompiler::CompileCallGlobal(
2421 Handle<JSObject> object,
2422 Handle<GlobalObject> holder,
2423 Handle<JSGlobalPropertyCell> cell,
2424 Handle<JSFunction> function,
2425 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002426 // ----------- S t a t e -------------
2427 // -- a2 : name
2428 // -- ra : return address
2429 // -----------------------------------
2430
2431 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002432 Handle<Code> code = CompileCustomCall(object, holder, cell, function, name);
2433 // A null handle means bail out to the regular compiler code below.
2434 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002435 }
2436
2437 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002438 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002439
2440 // Get the number of arguments.
2441 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002442 GenerateGlobalReceiverCheck(object, holder, name, &miss);
2443 GenerateLoadFunctionFromCell(cell, function, &miss);
2444
2445 // Patch the receiver on the stack with the global proxy if
2446 // necessary.
2447 if (object->IsGlobalObject()) {
2448 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
2449 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2450 }
2451
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002452 // Set up the context (function already in r1).
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002453 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
2454
2455 // Jump to the cached code (tail call).
2456 Counters* counters = masm()->isolate()->counters();
2457 __ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002458 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002459 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002460 ? CALL_AS_FUNCTION
2461 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002462 // We call indirectly through the code field in the function to
2463 // allow recompilation to take effect without changing any of the
2464 // call sites.
2465 __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
2466 __ InvokeCode(a3, expected, arguments(), JUMP_FUNCTION,
2467 NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002468
2469 // Handle call cache miss.
2470 __ bind(&miss);
2471 __ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002472 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002473
2474 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002475 return GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002476}
2477
2478
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002479Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +00002480 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002481 Handle<Map> transition,
2482 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002483 // ----------- S t a t e -------------
2484 // -- a0 : value
2485 // -- a1 : receiver
2486 // -- a2 : name
2487 // -- ra : return address
2488 // -----------------------------------
2489 Label miss;
2490
2491 // Name register might be clobbered.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002492 GenerateStoreField(masm(), object, index, transition, a1, a2, a3, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002493 __ bind(&miss);
2494 __ li(a2, Operand(Handle<String>(name))); // Restore name.
2495 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2496 __ Jump(ic, RelocInfo::CODE_TARGET);
2497
2498 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002499 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002500}
2501
2502
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002503Handle<Code> StoreStubCompiler::CompileStoreCallback(
2504 Handle<JSObject> object,
2505 Handle<AccessorInfo> callback,
2506 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002507 // ----------- S t a t e -------------
2508 // -- a0 : value
2509 // -- a1 : receiver
2510 // -- a2 : name
2511 // -- ra : return address
2512 // -----------------------------------
2513 Label miss;
2514
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002515 // Check that the map of the object hasn't changed.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002516 __ CheckMap(a1, a3, Handle<Map>(object->map()), &miss,
2517 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002518
2519 // Perform global security token check if needed.
2520 if (object->IsJSGlobalProxy()) {
2521 __ CheckAccessGlobalProxy(a1, a3, &miss);
2522 }
2523
2524 // Stub never generated for non-global objects that require access
2525 // checks.
2526 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
2527
2528 __ push(a1); // Receiver.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002529 __ li(a3, Operand(callback)); // Callback info.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002530 __ Push(a3, a2, a0);
2531
2532 // Do tail-call to the runtime system.
2533 ExternalReference store_callback_property =
2534 ExternalReference(IC_Utility(IC::kStoreCallbackProperty),
2535 masm()->isolate());
2536 __ TailCallExternalReference(store_callback_property, 4, 1);
2537
2538 // Handle store cache miss.
2539 __ bind(&miss);
2540 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2541 __ Jump(ic, RelocInfo::CODE_TARGET);
2542
2543 // Return the generated code.
2544 return GetCode(CALLBACKS, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002545}
2546
2547
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002548Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
2549 Handle<JSObject> receiver,
2550 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002551 // ----------- S t a t e -------------
2552 // -- a0 : value
2553 // -- a1 : receiver
2554 // -- a2 : name
2555 // -- ra : return address
2556 // -----------------------------------
2557 Label miss;
2558
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002559 // Check that the map of the object hasn't changed.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002560 __ CheckMap(a1, a3, Handle<Map>(receiver->map()), &miss,
2561 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002562
2563 // Perform global security token check if needed.
2564 if (receiver->IsJSGlobalProxy()) {
2565 __ CheckAccessGlobalProxy(a1, a3, &miss);
2566 }
2567
2568 // Stub is never generated for non-global objects that require access
2569 // checks.
2570 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2571
2572 __ Push(a1, a2, a0); // Receiver, name, value.
2573
2574 __ li(a0, Operand(Smi::FromInt(strict_mode_)));
2575 __ push(a0); // Strict mode.
2576
2577 // Do tail-call to the runtime system.
2578 ExternalReference store_ic_property =
2579 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty),
2580 masm()->isolate());
2581 __ TailCallExternalReference(store_ic_property, 4, 1);
2582
2583 // Handle store cache miss.
2584 __ bind(&miss);
2585 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2586 __ Jump(ic, RelocInfo::CODE_TARGET);
2587
2588 // Return the generated code.
2589 return GetCode(INTERCEPTOR, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002590}
2591
2592
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002593Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2594 Handle<GlobalObject> object,
2595 Handle<JSGlobalPropertyCell> cell,
2596 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002597 // ----------- S t a t e -------------
2598 // -- a0 : value
2599 // -- a1 : receiver
2600 // -- a2 : name
2601 // -- ra : return address
2602 // -----------------------------------
2603 Label miss;
2604
2605 // Check that the map of the global has not changed.
2606 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2607 __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map())));
2608
2609 // Check that the value in the cell is not the hole. If it is, this
2610 // cell could have been deleted and reintroducing the global needs
2611 // to update the property details in the property dictionary of the
2612 // global object. We bail out to the runtime system to do that.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002613 __ li(t0, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002614 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
2615 __ lw(t2, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2616 __ Branch(&miss, eq, t1, Operand(t2));
2617
2618 // Store the value in the cell.
2619 __ sw(a0, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2620 __ mov(v0, a0); // Stored value must be returned in v0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002621 // Cells are always rescanned, so no write barrier here.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002622
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002623 Counters* counters = masm()->isolate()->counters();
2624 __ IncrementCounter(counters->named_store_global_inline(), 1, a1, a3);
2625 __ Ret();
2626
2627 // Handle store cache miss.
2628 __ bind(&miss);
2629 __ IncrementCounter(counters->named_store_global_inline_miss(), 1, a1, a3);
2630 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2631 __ Jump(ic, RelocInfo::CODE_TARGET);
2632
2633 // Return the generated code.
2634 return GetCode(NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002635}
2636
2637
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002638Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
2639 Handle<JSObject> object,
2640 Handle<JSObject> last) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002641 // ----------- S t a t e -------------
2642 // -- a0 : receiver
2643 // -- ra : return address
2644 // -----------------------------------
2645 Label miss;
2646
2647 // Check that the receiver is not a smi.
2648 __ JumpIfSmi(a0, &miss);
2649
2650 // Check the maps of the full prototype chain.
2651 CheckPrototypes(object, a0, last, a3, a1, t0, name, &miss);
2652
2653 // If the last object in the prototype chain is a global object,
2654 // check that the global property cell is empty.
2655 if (last->IsGlobalObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002656 GenerateCheckPropertyCell(
2657 masm(), Handle<GlobalObject>::cast(last), name, a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002658 }
2659
2660 // Return undefined if maps of the full prototype chain is still the same.
2661 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2662 __ Ret();
2663
2664 __ bind(&miss);
2665 GenerateLoadMiss(masm(), Code::LOAD_IC);
2666
2667 // Return the generated code.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002668 return GetCode(NONEXISTENT, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00002669}
2670
2671
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002672Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object,
2673 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002674 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002675 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002676 // ----------- S t a t e -------------
2677 // -- a0 : receiver
2678 // -- a2 : name
2679 // -- ra : return address
2680 // -----------------------------------
2681 Label miss;
2682
2683 __ mov(v0, a0);
2684
2685 GenerateLoadField(object, holder, v0, a3, a1, t0, index, name, &miss);
2686 __ bind(&miss);
2687 GenerateLoadMiss(masm(), Code::LOAD_IC);
2688
2689 // Return the generated code.
2690 return GetCode(FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002691}
2692
2693
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002694Handle<Code> LoadStubCompiler::CompileLoadCallback(
2695 Handle<String> name,
2696 Handle<JSObject> object,
2697 Handle<JSObject> holder,
2698 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002699 // ----------- S t a t e -------------
2700 // -- a0 : receiver
2701 // -- a2 : name
2702 // -- ra : return address
2703 // -----------------------------------
2704 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002705 GenerateLoadCallback(object, holder, a0, a2, a3, a1, t0, callback, name,
2706 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002707 __ bind(&miss);
2708 GenerateLoadMiss(masm(), Code::LOAD_IC);
2709
2710 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002711 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002712}
2713
2714
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002715Handle<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object,
2716 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002717 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002718 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002719 // ----------- S t a t e -------------
2720 // -- a0 : receiver
2721 // -- a2 : name
2722 // -- ra : return address
2723 // -----------------------------------
2724 Label miss;
2725
2726 GenerateLoadConstant(object, holder, a0, a3, a1, t0, value, name, &miss);
2727 __ bind(&miss);
2728 GenerateLoadMiss(masm(), Code::LOAD_IC);
2729
2730 // Return the generated code.
2731 return GetCode(CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002732}
2733
2734
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002735Handle<Code> LoadStubCompiler::CompileLoadInterceptor(Handle<JSObject> object,
2736 Handle<JSObject> holder,
2737 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002738 // ----------- S t a t e -------------
2739 // -- a0 : receiver
2740 // -- a2 : name
2741 // -- ra : return address
2742 // -- [sp] : receiver
2743 // -----------------------------------
2744 Label miss;
2745
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002746 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002747 LookupPostInterceptor(holder, name, &lookup);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002748 GenerateLoadInterceptor(object, holder, &lookup, a0, a2, a3, a1, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002749 &miss);
2750 __ bind(&miss);
2751 GenerateLoadMiss(masm(), Code::LOAD_IC);
2752
2753 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002754 return GetCode(INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002755}
2756
2757
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002758Handle<Code> LoadStubCompiler::CompileLoadGlobal(
2759 Handle<JSObject> object,
2760 Handle<GlobalObject> holder,
2761 Handle<JSGlobalPropertyCell> cell,
2762 Handle<String> name,
2763 bool is_dont_delete) {
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 // If the object is the holder then we know that it's a global
2772 // object which can only happen for contextual calls. In this case,
2773 // the receiver cannot be a smi.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002774 if (!object.is_identical_to(holder)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002775 __ JumpIfSmi(a0, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002776 }
2777
2778 // Check that the map of the global has not changed.
2779 CheckPrototypes(object, a0, holder, a3, t0, a1, name, &miss);
2780
2781 // Get the value from the cell.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002782 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002783 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
2784
2785 // Check for deleted property if property can actually be deleted.
2786 if (!is_dont_delete) {
2787 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
2788 __ Branch(&miss, eq, t0, Operand(at));
2789 }
2790
2791 __ mov(v0, t0);
2792 Counters* counters = masm()->isolate()->counters();
2793 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
2794 __ Ret();
2795
2796 __ bind(&miss);
2797 __ IncrementCounter(counters->named_load_global_stub_miss(), 1, a1, a3);
2798 GenerateLoadMiss(masm(), Code::LOAD_IC);
2799
2800 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002801 return GetCode(NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002802}
2803
2804
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002805Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
2806 Handle<JSObject> receiver,
2807 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002808 int index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002809 // ----------- S t a t e -------------
2810 // -- ra : return address
2811 // -- a0 : key
2812 // -- a1 : receiver
2813 // -----------------------------------
2814 Label miss;
2815
2816 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002817 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002818
2819 GenerateLoadField(receiver, holder, a1, a2, a3, t0, index, name, &miss);
2820 __ bind(&miss);
2821 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2822
2823 return GetCode(FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002824}
2825
2826
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002827Handle<Code> KeyedLoadStubCompiler::CompileLoadCallback(
2828 Handle<String> name,
2829 Handle<JSObject> receiver,
2830 Handle<JSObject> holder,
2831 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002832 // ----------- S t a t e -------------
2833 // -- ra : return address
2834 // -- a0 : key
2835 // -- a1 : receiver
2836 // -----------------------------------
2837 Label miss;
2838
2839 // Check the key is the cached one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002840 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002841
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002842 GenerateLoadCallback(receiver, holder, a1, a0, a2, a3, t0, callback, name,
2843 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002844 __ bind(&miss);
2845 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2846
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002847 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002848}
2849
2850
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002851Handle<Code> KeyedLoadStubCompiler::CompileLoadConstant(
2852 Handle<String> name,
2853 Handle<JSObject> receiver,
2854 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002855 Handle<JSFunction> value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002856 // ----------- S t a t e -------------
2857 // -- ra : return address
2858 // -- a0 : key
2859 // -- a1 : receiver
2860 // -----------------------------------
2861 Label miss;
2862
2863 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002864 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002865
2866 GenerateLoadConstant(receiver, holder, a1, a2, a3, t0, value, name, &miss);
2867 __ bind(&miss);
2868 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2869
2870 // Return the generated code.
2871 return GetCode(CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002872}
2873
2874
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002875Handle<Code> KeyedLoadStubCompiler::CompileLoadInterceptor(
2876 Handle<JSObject> receiver,
2877 Handle<JSObject> holder,
2878 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002879 // ----------- S t a t e -------------
2880 // -- ra : return address
2881 // -- a0 : key
2882 // -- a1 : receiver
2883 // -----------------------------------
2884 Label miss;
2885
2886 // Check the key is the cached one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002887 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002888
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002889 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002890 LookupPostInterceptor(holder, name, &lookup);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002891 GenerateLoadInterceptor(receiver, holder, &lookup, a1, a0, a2, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002892 &miss);
2893 __ bind(&miss);
2894 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2895
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002896 return GetCode(INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002897}
2898
2899
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002900Handle<Code> KeyedLoadStubCompiler::CompileLoadArrayLength(
2901 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002902 // ----------- S t a t e -------------
2903 // -- ra : return address
2904 // -- a0 : key
2905 // -- a1 : receiver
2906 // -----------------------------------
2907 Label miss;
2908
2909 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002910 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002911
2912 GenerateLoadArrayLength(masm(), a1, a2, &miss);
2913 __ bind(&miss);
2914 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2915
2916 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002917}
2918
2919
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002920Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength(
2921 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002922 // ----------- S t a t e -------------
2923 // -- ra : return address
2924 // -- a0 : key
2925 // -- a1 : receiver
2926 // -----------------------------------
2927 Label miss;
2928
2929 Counters* counters = masm()->isolate()->counters();
2930 __ IncrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
2931
2932 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002933 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002934
2935 GenerateLoadStringLength(masm(), a1, a2, a3, &miss, true);
2936 __ bind(&miss);
2937 __ DecrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
2938
2939 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2940
2941 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002942}
2943
2944
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002945Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype(
2946 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002947 // ----------- S t a t e -------------
2948 // -- ra : return address
2949 // -- a0 : key
2950 // -- a1 : receiver
2951 // -----------------------------------
2952 Label miss;
2953
2954 Counters* counters = masm()->isolate()->counters();
2955 __ IncrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
2956
2957 // Check the name hasn't changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002958 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002959
2960 GenerateLoadFunctionPrototype(masm(), a1, a2, a3, &miss);
2961 __ bind(&miss);
2962 __ DecrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
2963 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2964
2965 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002966}
2967
2968
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002969Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
2970 Handle<Map> receiver_map) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00002971 // ----------- S t a t e -------------
2972 // -- ra : return address
2973 // -- a0 : key
2974 // -- a1 : receiver
2975 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002976 ElementsKind elements_kind = receiver_map->elements_kind();
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002977 Handle<Code> stub = KeyedLoadElementStub(elements_kind).GetCode();
2978
2979 __ DispatchMap(a1, a2, receiver_map, stub, DO_SMI_CHECK);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002980
2981 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
2982 __ Jump(ic, RelocInfo::CODE_TARGET);
2983
2984 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002985 return GetCode(NORMAL, factory()->empty_string());
danno@chromium.org40cb8782011-05-25 07:58:50 +00002986}
2987
2988
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002989Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
2990 MapHandleList* receiver_maps,
2991 CodeHandleList* handler_ics) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002992 // ----------- S t a t e -------------
2993 // -- ra : return address
2994 // -- a0 : key
2995 // -- a1 : receiver
2996 // -----------------------------------
2997 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002998 __ JumpIfSmi(a1, &miss);
2999
danno@chromium.org40cb8782011-05-25 07:58:50 +00003000 int receiver_count = receiver_maps->length();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003001 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003002 for (int current = 0; current < receiver_count; ++current) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003003 __ Jump(handler_ics->at(current), RelocInfo::CODE_TARGET,
3004 eq, a2, Operand(receiver_maps->at(current)));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003005 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003006
3007 __ bind(&miss);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003008 Handle<Code> miss_ic = isolate()->builtins()->KeyedLoadIC_Miss();
3009 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003010
3011 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003012 return GetCode(NORMAL, factory()->empty_string(), MEGAMORPHIC);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003013}
3014
3015
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003016Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +00003017 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003018 Handle<Map> transition,
3019 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003020 // ----------- S t a t e -------------
3021 // -- a0 : value
3022 // -- a1 : key
3023 // -- a2 : receiver
3024 // -- ra : return address
3025 // -----------------------------------
3026
3027 Label miss;
3028
3029 Counters* counters = masm()->isolate()->counters();
3030 __ IncrementCounter(counters->keyed_store_field(), 1, a3, t0);
3031
3032 // Check that the name has not changed.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003033 __ Branch(&miss, ne, a1, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003034
3035 // a3 is used as scratch register. a1 and a2 keep their values if a jump to
3036 // the miss label is generated.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003037 GenerateStoreField(masm(), object, index, transition, a2, a1, a3, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003038 __ bind(&miss);
3039
3040 __ DecrementCounter(counters->keyed_store_field(), 1, a3, t0);
3041 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss();
3042 __ Jump(ic, RelocInfo::CODE_TARGET);
3043
3044 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003045 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003046}
3047
3048
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003049Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
3050 Handle<Map> receiver_map) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003051 // ----------- S t a t e -------------
3052 // -- a0 : value
3053 // -- a1 : key
3054 // -- a2 : receiver
3055 // -- ra : return address
3056 // -- a3 : scratch
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003057 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003058 ElementsKind elements_kind = receiver_map->elements_kind();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003059 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003060 Handle<Code> stub =
3061 KeyedStoreElementStub(is_js_array, elements_kind).GetCode();
3062
3063 __ DispatchMap(a2, a3, receiver_map, stub, DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003064
danno@chromium.org40cb8782011-05-25 07:58:50 +00003065 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003066 __ Jump(ic, RelocInfo::CODE_TARGET);
3067
3068 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003069 return GetCode(NORMAL, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00003070}
3071
3072
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003073Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
3074 MapHandleList* receiver_maps,
3075 CodeHandleList* handler_stubs,
3076 MapHandleList* transitioned_maps) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003077 // ----------- S t a t e -------------
3078 // -- a0 : value
3079 // -- a1 : key
3080 // -- a2 : receiver
3081 // -- ra : return address
3082 // -- a3 : scratch
3083 // -----------------------------------
3084 Label miss;
3085 __ JumpIfSmi(a2, &miss);
3086
3087 int receiver_count = receiver_maps->length();
3088 __ lw(a3, FieldMemOperand(a2, HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003089 for (int i = 0; i < receiver_count; ++i) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003090 if (transitioned_maps->at(i).is_null()) {
3091 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq,
3092 a3, Operand(receiver_maps->at(i)));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003093 } else {
3094 Label next_map;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003095 __ Branch(&next_map, ne, a3, Operand(receiver_maps->at(i)));
3096 __ li(a3, Operand(transitioned_maps->at(i)));
3097 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003098 __ bind(&next_map);
3099 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003100 }
3101
3102 __ bind(&miss);
3103 Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
3104 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3105
3106 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003107 return GetCode(NORMAL, factory()->empty_string(), MEGAMORPHIC);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003108}
3109
3110
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003111Handle<Code> ConstructStubCompiler::CompileConstructStub(
3112 Handle<JSFunction> function) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003113 // a0 : argc
3114 // a1 : constructor
3115 // ra : return address
3116 // [sp] : last argument
3117 Label generic_stub_call;
3118
3119 // Use t7 for holding undefined which is used in several places below.
3120 __ LoadRoot(t7, Heap::kUndefinedValueRootIndex);
3121
3122#ifdef ENABLE_DEBUGGER_SUPPORT
3123 // Check to see whether there are any break points in the function code. If
3124 // there are jump to the generic constructor stub which calls the actual
3125 // code for the function thereby hitting the break points.
3126 __ lw(t5, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3127 __ lw(a2, FieldMemOperand(t5, SharedFunctionInfo::kDebugInfoOffset));
3128 __ Branch(&generic_stub_call, ne, a2, Operand(t7));
3129#endif
3130
3131 // Load the initial map and verify that it is in fact a map.
3132 // a1: constructor function
3133 // t7: undefined
3134 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003135 __ JumpIfSmi(a2, &generic_stub_call);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003136 __ GetObjectType(a2, a3, t0);
3137 __ Branch(&generic_stub_call, ne, t0, Operand(MAP_TYPE));
3138
3139#ifdef DEBUG
3140 // Cannot construct functions this way.
3141 // a0: argc
3142 // a1: constructor function
3143 // a2: initial map
3144 // t7: undefined
3145 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
3146 __ Check(ne, "Function constructed by construct stub.",
3147 a3, Operand(JS_FUNCTION_TYPE));
3148#endif
3149
3150 // Now allocate the JSObject in new space.
3151 // a0: argc
3152 // a1: constructor function
3153 // a2: initial map
3154 // t7: undefined
3155 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003156 __ AllocateInNewSpace(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003157
3158 // Allocated the JSObject, now initialize the fields. Map is set to initial
3159 // map and properties and elements are set to empty fixed array.
3160 // a0: argc
3161 // a1: constructor function
3162 // a2: initial map
3163 // a3: object size (in words)
3164 // t4: JSObject (not tagged)
3165 // t7: undefined
3166 __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex);
3167 __ mov(t5, t4);
3168 __ sw(a2, MemOperand(t5, JSObject::kMapOffset));
3169 __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset));
3170 __ sw(t6, MemOperand(t5, JSObject::kElementsOffset));
3171 __ Addu(t5, t5, Operand(3 * kPointerSize));
3172 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
3173 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
3174 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
3175
3176
3177 // Calculate the location of the first argument. The stack contains only the
3178 // argc arguments.
3179 __ sll(a1, a0, kPointerSizeLog2);
3180 __ Addu(a1, a1, sp);
3181
3182 // Fill all the in-object properties with undefined.
3183 // a0: argc
3184 // a1: first argument
3185 // a3: object size (in words)
3186 // t4: JSObject (not tagged)
3187 // t5: First in-object property of JSObject (not tagged)
3188 // t7: undefined
3189 // Fill the initialized properties with a constant value or a passed argument
3190 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003191 Handle<SharedFunctionInfo> shared(function->shared());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003192 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3193 if (shared->IsThisPropertyAssignmentArgument(i)) {
3194 Label not_passed, next;
3195 // Check if the argument assigned to the property is actually passed.
3196 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3197 __ Branch(&not_passed, less_equal, a0, Operand(arg_number));
3198 // Argument passed - find it on the stack.
3199 __ lw(a2, MemOperand(a1, (arg_number + 1) * -kPointerSize));
3200 __ sw(a2, MemOperand(t5));
3201 __ Addu(t5, t5, kPointerSize);
3202 __ jmp(&next);
3203 __ bind(&not_passed);
3204 // Set the property to undefined.
3205 __ sw(t7, MemOperand(t5));
3206 __ Addu(t5, t5, Operand(kPointerSize));
3207 __ bind(&next);
3208 } else {
3209 // Set the property to the constant value.
3210 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
3211 __ li(a2, Operand(constant));
3212 __ sw(a2, MemOperand(t5));
3213 __ Addu(t5, t5, kPointerSize);
3214 }
3215 }
3216
3217 // Fill the unused in-object property fields with undefined.
3218 ASSERT(function->has_initial_map());
3219 for (int i = shared->this_property_assignments_count();
3220 i < function->initial_map()->inobject_properties();
3221 i++) {
3222 __ sw(t7, MemOperand(t5));
3223 __ Addu(t5, t5, kPointerSize);
3224 }
3225
3226 // a0: argc
3227 // t4: JSObject (not tagged)
3228 // Move argc to a1 and the JSObject to return to v0 and tag it.
3229 __ mov(a1, a0);
3230 __ mov(v0, t4);
3231 __ Or(v0, v0, Operand(kHeapObjectTag));
3232
3233 // v0: JSObject
3234 // a1: argc
3235 // Remove caller arguments and receiver from the stack and return.
3236 __ sll(t0, a1, kPointerSizeLog2);
3237 __ Addu(sp, sp, t0);
3238 __ Addu(sp, sp, Operand(kPointerSize));
3239 Counters* counters = masm()->isolate()->counters();
3240 __ IncrementCounter(counters->constructed_objects(), 1, a1, a2);
3241 __ IncrementCounter(counters->constructed_objects_stub(), 1, a1, a2);
3242 __ Ret();
3243
3244 // Jump to the generic stub in case the specialized code cannot handle the
3245 // construction.
3246 __ bind(&generic_stub_call);
3247 Handle<Code> generic_construct_stub =
3248 masm()->isolate()->builtins()->JSConstructStubGeneric();
3249 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
3250
3251 // Return the generated code.
3252 return GetCode();
3253}
3254
3255
danno@chromium.org40cb8782011-05-25 07:58:50 +00003256#undef __
3257#define __ ACCESS_MASM(masm)
3258
3259
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003260void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3261 MacroAssembler* masm) {
3262 // ---------- S t a t e --------------
3263 // -- ra : return address
3264 // -- a0 : key
3265 // -- a1 : receiver
3266 // -----------------------------------
3267 Label slow, miss_force_generic;
3268
3269 Register key = a0;
3270 Register receiver = a1;
3271
3272 __ JumpIfNotSmi(key, &miss_force_generic);
3273 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
3274 __ sra(a2, a0, kSmiTagSize);
3275 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
3276 __ Ret();
3277
3278 // Slow case, key and receiver still in a0 and a1.
3279 __ bind(&slow);
3280 __ IncrementCounter(
3281 masm->isolate()->counters()->keyed_load_external_array_slow(),
3282 1, a2, a3);
3283 // Entry registers are intact.
3284 // ---------- S t a t e --------------
3285 // -- ra : return address
3286 // -- a0 : key
3287 // -- a1 : receiver
3288 // -----------------------------------
3289 Handle<Code> slow_ic =
3290 masm->isolate()->builtins()->KeyedLoadIC_Slow();
3291 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
3292
3293 // Miss case, call the runtime.
3294 __ bind(&miss_force_generic);
3295
3296 // ---------- S t a t e --------------
3297 // -- ra : return address
3298 // -- a0 : key
3299 // -- a1 : receiver
3300 // -----------------------------------
3301
3302 Handle<Code> miss_ic =
3303 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3304 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3305}
3306
3307
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003308static bool IsElementTypeSigned(ElementsKind elements_kind) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003309 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003310 case EXTERNAL_BYTE_ELEMENTS:
3311 case EXTERNAL_SHORT_ELEMENTS:
3312 case EXTERNAL_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003313 return true;
3314
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003315 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3316 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3317 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3318 case EXTERNAL_PIXEL_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003319 return false;
3320
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003321 case EXTERNAL_FLOAT_ELEMENTS:
3322 case EXTERNAL_DOUBLE_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003323 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003324 case FAST_ELEMENTS:
3325 case FAST_DOUBLE_ELEMENTS:
3326 case DICTIONARY_ELEMENTS:
3327 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003328 UNREACHABLE();
3329 return false;
3330 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003331 return false;
lrn@chromium.org7516f052011-03-30 08:52:27 +00003332}
3333
3334
danno@chromium.org40cb8782011-05-25 07:58:50 +00003335void KeyedLoadStubCompiler::GenerateLoadExternalArray(
3336 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003337 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003338 // ---------- S t a t e --------------
3339 // -- ra : return address
3340 // -- a0 : key
3341 // -- a1 : receiver
3342 // -----------------------------------
danno@chromium.org40cb8782011-05-25 07:58:50 +00003343 Label miss_force_generic, slow, failed_allocation;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003344
3345 Register key = a0;
3346 Register receiver = a1;
3347
danno@chromium.org40cb8782011-05-25 07:58:50 +00003348 // This stub is meant to be tail-jumped to, the receiver must already
3349 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003350
3351 // Check that the key is a smi.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003352 __ JumpIfNotSmi(key, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003353
3354 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3355 // a3: elements array
3356
3357 // Check that the index is in range.
3358 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3359 __ sra(t2, key, kSmiTagSize);
3360 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003361 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003362
3363 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3364 // a3: base pointer of external storage
3365
3366 // We are not untagging smi key and instead work with it
3367 // as if it was premultiplied by 2.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003368 STATIC_ASSERT((kSmiTag == 0) && (kSmiTagSize == 1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003369
3370 Register value = a2;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003371 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003372 case EXTERNAL_BYTE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003373 __ srl(t2, key, 1);
3374 __ addu(t3, a3, t2);
3375 __ lb(value, MemOperand(t3, 0));
3376 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003377 case EXTERNAL_PIXEL_ELEMENTS:
3378 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003379 __ srl(t2, key, 1);
3380 __ addu(t3, a3, t2);
3381 __ lbu(value, MemOperand(t3, 0));
3382 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003383 case EXTERNAL_SHORT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003384 __ addu(t3, a3, key);
3385 __ lh(value, MemOperand(t3, 0));
3386 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003387 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003388 __ addu(t3, a3, key);
3389 __ lhu(value, MemOperand(t3, 0));
3390 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003391 case EXTERNAL_INT_ELEMENTS:
3392 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003393 __ sll(t2, key, 1);
3394 __ addu(t3, a3, t2);
3395 __ lw(value, MemOperand(t3, 0));
3396 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003397 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003398 __ sll(t3, t2, 2);
3399 __ addu(t3, a3, t3);
3400 if (CpuFeatures::IsSupported(FPU)) {
3401 CpuFeatures::Scope scope(FPU);
3402 __ lwc1(f0, MemOperand(t3, 0));
3403 } else {
3404 __ lw(value, MemOperand(t3, 0));
3405 }
3406 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003407 case EXTERNAL_DOUBLE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003408 __ sll(t2, key, 2);
3409 __ addu(t3, a3, t2);
3410 if (CpuFeatures::IsSupported(FPU)) {
3411 CpuFeatures::Scope scope(FPU);
3412 __ ldc1(f0, MemOperand(t3, 0));
3413 } else {
3414 // t3: pointer to the beginning of the double we want to load.
3415 __ lw(a2, MemOperand(t3, 0));
3416 __ lw(a3, MemOperand(t3, Register::kSizeInBytes));
3417 }
3418 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003419 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003420 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003421 case FAST_DOUBLE_ELEMENTS:
3422 case DICTIONARY_ELEMENTS:
3423 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003424 UNREACHABLE();
3425 break;
3426 }
3427
3428 // For integer array types:
3429 // a2: value
3430 // For float array type:
3431 // f0: value (if FPU is supported)
3432 // a2: value (if FPU is not supported)
3433 // For double array type:
3434 // f0: value (if FPU is supported)
3435 // a2/a3: value (if FPU is not supported)
3436
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003437 if (elements_kind == EXTERNAL_INT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003438 // For the Int and UnsignedInt array types, we need to see whether
3439 // the value can be represented in a Smi. If not, we need to convert
3440 // it to a HeapNumber.
3441 Label box_int;
3442 __ Subu(t3, value, Operand(0xC0000000)); // Non-smi value gives neg result.
3443 __ Branch(&box_int, lt, t3, Operand(zero_reg));
3444 // Tag integer as smi and return it.
3445 __ sll(v0, value, kSmiTagSize);
3446 __ Ret();
3447
3448 __ bind(&box_int);
3449 // Allocate a HeapNumber for the result and perform int-to-double
3450 // conversion.
3451 // The arm version uses a temporary here to save r0, but we don't need to
3452 // (a0 is not modified).
3453 __ LoadRoot(t1, Heap::kHeapNumberMapRootIndex);
3454 __ AllocateHeapNumber(v0, a3, t0, t1, &slow);
3455
3456 if (CpuFeatures::IsSupported(FPU)) {
3457 CpuFeatures::Scope scope(FPU);
3458 __ mtc1(value, f0);
3459 __ cvt_d_w(f0, f0);
3460 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag));
3461 __ Ret();
3462 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003463 Register dst1 = t2;
3464 Register dst2 = t3;
3465 FloatingPointHelper::Destination dest =
3466 FloatingPointHelper::kCoreRegisters;
3467 FloatingPointHelper::ConvertIntToDouble(masm,
3468 value,
3469 dest,
3470 f0,
3471 dst1,
3472 dst2,
3473 t1,
3474 f2);
3475 __ sw(dst1, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3476 __ sw(dst2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3477 __ Ret();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003478 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003479 } else if (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003480 // The test is different for unsigned int values. Since we need
3481 // the value to be in the range of a positive smi, we can't
3482 // handle either of the top two bits being set in the value.
3483 if (CpuFeatures::IsSupported(FPU)) {
3484 CpuFeatures::Scope scope(FPU);
3485 Label pl_box_int;
3486 __ And(t2, value, Operand(0xC0000000));
3487 __ Branch(&pl_box_int, ne, t2, Operand(zero_reg));
3488
3489 // It can fit in an Smi.
3490 // Tag integer as smi and return it.
3491 __ sll(v0, value, kSmiTagSize);
3492 __ Ret();
3493
3494 __ bind(&pl_box_int);
3495 // Allocate a HeapNumber for the result and perform int-to-double
3496 // conversion. Don't use a0 and a1 as AllocateHeapNumber clobbers all
3497 // registers - also when jumping due to exhausted young space.
3498 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3499 __ AllocateHeapNumber(v0, t2, t3, t6, &slow);
3500
3501 // This is replaced by a macro:
3502 // __ mtc1(value, f0); // LS 32-bits.
3503 // __ mtc1(zero_reg, f1); // MS 32-bits are all zero.
3504 // __ cvt_d_l(f0, f0); // Use 64 bit conv to get correct unsigned 32-bit.
3505
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003506 __ Cvt_d_uw(f0, value, f22);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003507
3508 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag));
3509
3510 __ Ret();
3511 } else {
3512 // Check whether unsigned integer fits into smi.
3513 Label box_int_0, box_int_1, done;
3514 __ And(t2, value, Operand(0x80000000));
3515 __ Branch(&box_int_0, ne, t2, Operand(zero_reg));
3516 __ And(t2, value, Operand(0x40000000));
3517 __ Branch(&box_int_1, ne, t2, Operand(zero_reg));
3518
3519 // Tag integer as smi and return it.
3520 __ sll(v0, value, kSmiTagSize);
3521 __ Ret();
3522
3523 Register hiword = value; // a2.
3524 Register loword = a3;
3525
3526 __ bind(&box_int_0);
3527 // Integer does not have leading zeros.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003528 GenerateUInt2Double(masm, hiword, loword, t0, 0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003529 __ Branch(&done);
3530
3531 __ bind(&box_int_1);
3532 // Integer has one leading zero.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003533 GenerateUInt2Double(masm, hiword, loword, t0, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003534
3535
3536 __ bind(&done);
3537 // Integer was converted to double in registers hiword:loword.
3538 // Wrap it into a HeapNumber. Don't use a0 and a1 as AllocateHeapNumber
3539 // clobbers all registers - also when jumping due to exhausted young
3540 // space.
3541 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3542 __ AllocateHeapNumber(t2, t3, t5, t6, &slow);
3543
3544 __ sw(hiword, FieldMemOperand(t2, HeapNumber::kExponentOffset));
3545 __ sw(loword, FieldMemOperand(t2, HeapNumber::kMantissaOffset));
3546
3547 __ mov(v0, t2);
3548 __ Ret();
3549 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003550 } else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003551 // For the floating-point array type, we need to always allocate a
3552 // HeapNumber.
3553 if (CpuFeatures::IsSupported(FPU)) {
3554 CpuFeatures::Scope scope(FPU);
3555 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3556 // AllocateHeapNumber clobbers all registers - also when jumping due to
3557 // exhausted young space.
3558 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3559 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3560 // The float (single) value is already in fpu reg f0 (if we use float).
3561 __ cvt_d_s(f0, f0);
3562 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag));
3563 __ Ret();
3564 } else {
3565 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3566 // AllocateHeapNumber clobbers all registers - also when jumping due to
3567 // exhausted young space.
3568 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3569 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3570 // FPU is not available, do manual single to double conversion.
3571
3572 // a2: floating point value (binary32).
3573 // v0: heap number for result
3574
3575 // Extract mantissa to t4.
3576 __ And(t4, value, Operand(kBinary32MantissaMask));
3577
3578 // Extract exponent to t5.
3579 __ srl(t5, value, kBinary32MantissaBits);
3580 __ And(t5, t5, Operand(kBinary32ExponentMask >> kBinary32MantissaBits));
3581
3582 Label exponent_rebiased;
3583 __ Branch(&exponent_rebiased, eq, t5, Operand(zero_reg));
3584
3585 __ li(t0, 0x7ff);
3586 __ Xor(t1, t5, Operand(0xFF));
3587 __ movz(t5, t0, t1); // Set t5 to 0x7ff only if t5 is equal to 0xff.
3588 __ Branch(&exponent_rebiased, eq, t0, Operand(0xff));
3589
3590 // Rebias exponent.
3591 __ Addu(t5,
3592 t5,
3593 Operand(-kBinary32ExponentBias + HeapNumber::kExponentBias));
3594
3595 __ bind(&exponent_rebiased);
3596 __ And(a2, value, Operand(kBinary32SignMask));
3597 value = no_reg;
3598 __ sll(t0, t5, HeapNumber::kMantissaBitsInTopWord);
3599 __ or_(a2, a2, t0);
3600
3601 // Shift mantissa.
3602 static const int kMantissaShiftForHiWord =
3603 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3604
3605 static const int kMantissaShiftForLoWord =
3606 kBitsPerInt - kMantissaShiftForHiWord;
3607
3608 __ srl(t0, t4, kMantissaShiftForHiWord);
3609 __ or_(a2, a2, t0);
3610 __ sll(a0, t4, kMantissaShiftForLoWord);
3611
3612 __ sw(a2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3613 __ sw(a0, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3614 __ Ret();
3615 }
3616
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003617 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003618 if (CpuFeatures::IsSupported(FPU)) {
3619 CpuFeatures::Scope scope(FPU);
3620 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3621 // AllocateHeapNumber clobbers all registers - also when jumping due to
3622 // exhausted young space.
3623 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3624 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3625 // The double value is already in f0
3626 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
3627 __ Ret();
3628 } else {
3629 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3630 // AllocateHeapNumber clobbers all registers - also when jumping due to
3631 // exhausted young space.
3632 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3633 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3634
3635 __ sw(a2, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3636 __ sw(a3, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3637 __ Ret();
3638 }
3639
3640 } else {
3641 // Tag integer as smi and return it.
3642 __ sll(v0, value, kSmiTagSize);
3643 __ Ret();
3644 }
3645
3646 // Slow case, key and receiver still in a0 and a1.
3647 __ bind(&slow);
3648 __ IncrementCounter(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003649 masm->isolate()->counters()->keyed_load_external_array_slow(),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003650 1, a2, a3);
3651
3652 // ---------- S t a t e --------------
3653 // -- ra : return address
3654 // -- a0 : key
3655 // -- a1 : receiver
3656 // -----------------------------------
3657
3658 __ Push(a1, a0);
3659
3660 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
3661
danno@chromium.org40cb8782011-05-25 07:58:50 +00003662 __ bind(&miss_force_generic);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003663 Handle<Code> stub =
3664 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3665 __ Jump(stub, RelocInfo::CODE_TARGET);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003666}
3667
3668
danno@chromium.org40cb8782011-05-25 07:58:50 +00003669void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3670 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003671 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003672 // ---------- S t a t e --------------
3673 // -- a0 : value
3674 // -- a1 : key
3675 // -- a2 : receiver
3676 // -- ra : return address
3677 // -----------------------------------
3678
danno@chromium.org40cb8782011-05-25 07:58:50 +00003679 Label slow, check_heap_number, miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003680
3681 // Register usage.
3682 Register value = a0;
3683 Register key = a1;
3684 Register receiver = a2;
3685 // a3 mostly holds the elements array or the destination external array.
3686
danno@chromium.org40cb8782011-05-25 07:58:50 +00003687 // This stub is meant to be tail-jumped to, the receiver must already
3688 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003689
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003690 // Check that the key is a smi.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003691 __ JumpIfNotSmi(key, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003692
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003693 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3694
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003695 // Check that the index is in range.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003696 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3697 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003698 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003699
3700 // Handle both smis and HeapNumbers in the fast path. Go to the
3701 // runtime for all other kinds of values.
3702 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003703
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003704 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003705 // Double to pixel conversion is only implemented in the runtime for now.
3706 __ JumpIfNotSmi(value, &slow);
3707 } else {
3708 __ JumpIfNotSmi(value, &check_heap_number);
3709 }
3710 __ SmiUntag(t1, value);
3711 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3712
3713 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003714 // t1: value (integer).
3715
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003716 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003717 case EXTERNAL_PIXEL_ELEMENTS: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003718 // Clamp the value to [0..255].
3719 // v0 is used as a scratch register here.
3720 Label done;
3721 __ li(v0, Operand(255));
3722 // Normal branch: nop in delay slot.
3723 __ Branch(&done, gt, t1, Operand(v0));
3724 // Use delay slot in this branch.
3725 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg));
3726 __ mov(v0, zero_reg); // In delay slot.
3727 __ mov(v0, t1); // Value is in range 0..255.
3728 __ bind(&done);
3729 __ mov(t1, v0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003730
3731 __ srl(t8, key, 1);
3732 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003733 __ sb(t1, MemOperand(t8, 0));
3734 }
3735 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003736 case EXTERNAL_BYTE_ELEMENTS:
3737 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003738 __ srl(t8, key, 1);
3739 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003740 __ sb(t1, MemOperand(t8, 0));
3741 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003742 case EXTERNAL_SHORT_ELEMENTS:
3743 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003744 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003745 __ sh(t1, MemOperand(t8, 0));
3746 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003747 case EXTERNAL_INT_ELEMENTS:
3748 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003749 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003750 __ addu(t8, a3, t8);
3751 __ sw(t1, MemOperand(t8, 0));
3752 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003753 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003754 // Perform int-to-float conversion and store to memory.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003755 __ SmiUntag(t0, key);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003756 StoreIntAsFloat(masm, a3, t0, t1, t2, t3, t4);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003757 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003758 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003759 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003760 __ addu(a3, a3, t8);
3761 // a3: effective address of the double element
3762 FloatingPointHelper::Destination destination;
3763 if (CpuFeatures::IsSupported(FPU)) {
3764 destination = FloatingPointHelper::kFPURegisters;
3765 } else {
3766 destination = FloatingPointHelper::kCoreRegisters;
3767 }
3768 FloatingPointHelper::ConvertIntToDouble(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003769 masm, t1, destination,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003770 f0, t2, t3, // These are: double_dst, dst1, dst2.
3771 t0, f2); // These are: scratch2, single_scratch.
3772 if (destination == FloatingPointHelper::kFPURegisters) {
3773 CpuFeatures::Scope scope(FPU);
3774 __ sdc1(f0, MemOperand(a3, 0));
3775 } else {
3776 __ sw(t2, MemOperand(a3, 0));
3777 __ sw(t3, MemOperand(a3, Register::kSizeInBytes));
3778 }
3779 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003780 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003781 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003782 case FAST_DOUBLE_ELEMENTS:
3783 case DICTIONARY_ELEMENTS:
3784 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003785 UNREACHABLE();
3786 break;
3787 }
3788
3789 // Entry registers are intact, a0 holds the value which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003790 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003791 __ Ret();
3792
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003793 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003794 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003795 __ bind(&check_heap_number);
3796 __ GetObjectType(value, t1, t2);
3797 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE));
3798
3799 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3800
3801 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003802
3803 // The WebGL specification leaves the behavior of storing NaN and
3804 // +/-Infinity into integer arrays basically undefined. For more
3805 // reproducible behavior, convert these to zero.
3806
3807 if (CpuFeatures::IsSupported(FPU)) {
3808 CpuFeatures::Scope scope(FPU);
3809
3810 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
3811
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003812 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003813 __ cvt_s_d(f0, f0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003814 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003815 __ addu(t8, a3, t8);
3816 __ swc1(f0, MemOperand(t8, 0));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003817 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003818 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003819 __ addu(t8, a3, t8);
3820 __ sdc1(f0, MemOperand(t8, 0));
3821 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003822 __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003823
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003824 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003825 case EXTERNAL_BYTE_ELEMENTS:
3826 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003827 __ srl(t8, key, 1);
3828 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003829 __ sb(t3, MemOperand(t8, 0));
3830 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003831 case EXTERNAL_SHORT_ELEMENTS:
3832 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003833 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003834 __ sh(t3, MemOperand(t8, 0));
3835 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003836 case EXTERNAL_INT_ELEMENTS:
3837 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003838 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003839 __ addu(t8, a3, t8);
3840 __ sw(t3, MemOperand(t8, 0));
3841 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003842 case EXTERNAL_PIXEL_ELEMENTS:
3843 case EXTERNAL_FLOAT_ELEMENTS:
3844 case EXTERNAL_DOUBLE_ELEMENTS:
3845 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003846 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003847 case FAST_DOUBLE_ELEMENTS:
3848 case DICTIONARY_ELEMENTS:
3849 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003850 UNREACHABLE();
3851 break;
3852 }
3853 }
3854
3855 // Entry registers are intact, a0 holds the value
3856 // which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003857 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003858 __ Ret();
3859 } else {
3860 // FPU is not available, do manual conversions.
3861
3862 __ lw(t3, FieldMemOperand(value, HeapNumber::kExponentOffset));
3863 __ lw(t4, FieldMemOperand(value, HeapNumber::kMantissaOffset));
3864
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003865 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003866 Label done, nan_or_infinity_or_zero;
3867 static const int kMantissaInHiWordShift =
3868 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3869
3870 static const int kMantissaInLoWordShift =
3871 kBitsPerInt - kMantissaInHiWordShift;
3872
3873 // Test for all special exponent values: zeros, subnormal numbers, NaNs
3874 // and infinities. All these should be converted to 0.
3875 __ li(t5, HeapNumber::kExponentMask);
3876 __ and_(t6, t3, t5);
3877 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(zero_reg));
3878
3879 __ xor_(t1, t6, t5);
3880 __ li(t2, kBinary32ExponentMask);
3881 __ movz(t6, t2, t1); // Only if t6 is equal to t5.
3882 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(t5));
3883
3884 // Rebias exponent.
3885 __ srl(t6, t6, HeapNumber::kExponentShift);
3886 __ Addu(t6,
3887 t6,
3888 Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
3889
3890 __ li(t1, Operand(kBinary32MaxExponent));
3891 __ Slt(t1, t1, t6);
3892 __ And(t2, t3, Operand(HeapNumber::kSignMask));
3893 __ Or(t2, t2, Operand(kBinary32ExponentMask));
3894 __ movn(t3, t2, t1); // Only if t6 is gt kBinary32MaxExponent.
3895 __ Branch(&done, gt, t6, Operand(kBinary32MaxExponent));
3896
3897 __ Slt(t1, t6, Operand(kBinary32MinExponent));
3898 __ And(t2, t3, Operand(HeapNumber::kSignMask));
3899 __ movn(t3, t2, t1); // Only if t6 is lt kBinary32MinExponent.
3900 __ Branch(&done, lt, t6, Operand(kBinary32MinExponent));
3901
3902 __ And(t7, t3, Operand(HeapNumber::kSignMask));
3903 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3904 __ sll(t3, t3, kMantissaInHiWordShift);
3905 __ or_(t7, t7, t3);
3906 __ srl(t4, t4, kMantissaInLoWordShift);
3907 __ or_(t7, t7, t4);
3908 __ sll(t6, t6, kBinary32ExponentShift);
3909 __ or_(t3, t7, t6);
3910
3911 __ bind(&done);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003912 __ sll(t9, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003913 __ addu(t9, a2, t9);
3914 __ sw(t3, MemOperand(t9, 0));
3915
3916 // Entry registers are intact, a0 holds the value which is the return
3917 // value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003918 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003919 __ Ret();
3920
3921 __ bind(&nan_or_infinity_or_zero);
3922 __ And(t7, t3, Operand(HeapNumber::kSignMask));
3923 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3924 __ or_(t6, t6, t7);
3925 __ sll(t3, t3, kMantissaInHiWordShift);
3926 __ or_(t6, t6, t3);
3927 __ srl(t4, t4, kMantissaInLoWordShift);
3928 __ or_(t3, t6, t4);
3929 __ Branch(&done);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003930 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003931 __ sll(t8, t0, 3);
3932 __ addu(t8, a3, t8);
3933 // t8: effective address of destination element.
3934 __ sw(t4, MemOperand(t8, 0));
3935 __ sw(t3, MemOperand(t8, Register::kSizeInBytes));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003936 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003937 __ Ret();
3938 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003939 bool is_signed_type = IsElementTypeSigned(elements_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003940 int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
3941 int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
3942
3943 Label done, sign;
3944
3945 // Test for all special exponent values: zeros, subnormal numbers, NaNs
3946 // and infinities. All these should be converted to 0.
3947 __ li(t5, HeapNumber::kExponentMask);
3948 __ and_(t6, t3, t5);
3949 __ movz(t3, zero_reg, t6); // Only if t6 is equal to zero.
3950 __ Branch(&done, eq, t6, Operand(zero_reg));
3951
3952 __ xor_(t2, t6, t5);
3953 __ movz(t3, zero_reg, t2); // Only if t6 is equal to t5.
3954 __ Branch(&done, eq, t6, Operand(t5));
3955
3956 // Unbias exponent.
3957 __ srl(t6, t6, HeapNumber::kExponentShift);
3958 __ Subu(t6, t6, Operand(HeapNumber::kExponentBias));
3959 // If exponent is negative then result is 0.
3960 __ slt(t2, t6, zero_reg);
3961 __ movn(t3, zero_reg, t2); // Only if exponent is negative.
3962 __ Branch(&done, lt, t6, Operand(zero_reg));
3963
3964 // If exponent is too big then result is minimal value.
3965 __ slti(t1, t6, meaningfull_bits - 1);
3966 __ li(t2, min_value);
3967 __ movz(t3, t2, t1); // Only if t6 is ge meaningfull_bits - 1.
3968 __ Branch(&done, ge, t6, Operand(meaningfull_bits - 1));
3969
3970 __ And(t5, t3, Operand(HeapNumber::kSignMask));
3971 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3972 __ Or(t3, t3, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
3973
3974 __ li(t9, HeapNumber::kMantissaBitsInTopWord);
3975 __ subu(t6, t9, t6);
3976 __ slt(t1, t6, zero_reg);
3977 __ srlv(t2, t3, t6);
3978 __ movz(t3, t2, t1); // Only if t6 is positive.
3979 __ Branch(&sign, ge, t6, Operand(zero_reg));
3980
3981 __ subu(t6, zero_reg, t6);
3982 __ sllv(t3, t3, t6);
3983 __ li(t9, meaningfull_bits);
3984 __ subu(t6, t9, t6);
3985 __ srlv(t4, t4, t6);
3986 __ or_(t3, t3, t4);
3987
3988 __ bind(&sign);
3989 __ subu(t2, t3, zero_reg);
3990 __ movz(t3, t2, t5); // Only if t5 is zero.
3991
3992 __ bind(&done);
3993
3994 // Result is in t3.
3995 // This switch block should be exactly the same as above (FPU mode).
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003996 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003997 case EXTERNAL_BYTE_ELEMENTS:
3998 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003999 __ srl(t8, key, 1);
4000 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004001 __ sb(t3, MemOperand(t8, 0));
4002 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004003 case EXTERNAL_SHORT_ELEMENTS:
4004 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004005 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004006 __ sh(t3, MemOperand(t8, 0));
4007 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004008 case EXTERNAL_INT_ELEMENTS:
4009 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004010 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004011 __ addu(t8, a3, t8);
4012 __ sw(t3, MemOperand(t8, 0));
4013 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004014 case EXTERNAL_PIXEL_ELEMENTS:
4015 case EXTERNAL_FLOAT_ELEMENTS:
4016 case EXTERNAL_DOUBLE_ELEMENTS:
4017 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004018 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004019 case FAST_DOUBLE_ELEMENTS:
4020 case DICTIONARY_ELEMENTS:
4021 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004022 UNREACHABLE();
4023 break;
4024 }
4025 }
4026 }
4027 }
4028
danno@chromium.org40cb8782011-05-25 07:58:50 +00004029 // Slow case, key and receiver still in a0 and a1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004030 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004031 __ IncrementCounter(
4032 masm->isolate()->counters()->keyed_load_external_array_slow(),
4033 1, a2, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004034 // Entry registers are intact.
4035 // ---------- S t a t e --------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004036 // -- ra : return address
danno@chromium.org40cb8782011-05-25 07:58:50 +00004037 // -- a0 : key
4038 // -- a1 : receiver
4039 // -----------------------------------
4040 Handle<Code> slow_ic =
4041 masm->isolate()->builtins()->KeyedStoreIC_Slow();
4042 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4043
4044 // Miss case, call the runtime.
4045 __ bind(&miss_force_generic);
4046
4047 // ---------- S t a t e --------------
4048 // -- ra : return address
4049 // -- a0 : key
4050 // -- a1 : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004051 // -----------------------------------
4052
danno@chromium.org40cb8782011-05-25 07:58:50 +00004053 Handle<Code> miss_ic =
4054 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4055 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
4056}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004057
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004058
danno@chromium.org40cb8782011-05-25 07:58:50 +00004059void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
4060 // ----------- S t a t e -------------
4061 // -- ra : return address
4062 // -- a0 : key
4063 // -- a1 : receiver
4064 // -----------------------------------
4065 Label miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004066
danno@chromium.org40cb8782011-05-25 07:58:50 +00004067 // This stub is meant to be tail-jumped to, the receiver must already
4068 // have been verified by the caller to not be a smi.
4069
4070 // Check that the key is a smi.
4071 __ JumpIfNotSmi(a0, &miss_force_generic);
4072
4073 // Get the elements array.
4074 __ lw(a2, FieldMemOperand(a1, JSObject::kElementsOffset));
4075 __ AssertFastElements(a2);
4076
4077 // Check that the key is within bounds.
4078 __ lw(a3, FieldMemOperand(a2, FixedArray::kLengthOffset));
4079 __ Branch(&miss_force_generic, hs, a0, Operand(a3));
4080
4081 // Load the result and make sure it's not the hole.
4082 __ Addu(a3, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004083 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004084 __ sll(t0, a0, kPointerSizeLog2 - kSmiTagSize);
4085 __ Addu(t0, t0, a3);
4086 __ lw(t0, MemOperand(t0));
4087 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
4088 __ Branch(&miss_force_generic, eq, t0, Operand(t1));
4089 __ mov(v0, t0);
4090 __ Ret();
4091
4092 __ bind(&miss_force_generic);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004093 Handle<Code> stub =
4094 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4095 __ Jump(stub, RelocInfo::CODE_TARGET);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004096}
4097
4098
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004099void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
4100 MacroAssembler* masm) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004101 // ----------- S t a t e -------------
4102 // -- ra : return address
4103 // -- a0 : key
4104 // -- a1 : receiver
4105 // -----------------------------------
4106 Label miss_force_generic, slow_allocate_heapnumber;
4107
4108 Register key_reg = a0;
4109 Register receiver_reg = a1;
4110 Register elements_reg = a2;
4111 Register heap_number_reg = a2;
4112 Register indexed_double_offset = a3;
4113 Register scratch = t0;
4114 Register scratch2 = t1;
4115 Register scratch3 = t2;
4116 Register heap_number_map = t3;
4117
4118 // This stub is meant to be tail-jumped to, the receiver must already
4119 // have been verified by the caller to not be a smi.
4120
4121 // Check that the key is a smi.
4122 __ JumpIfNotSmi(key_reg, &miss_force_generic);
4123
4124 // Get the elements array.
4125 __ lw(elements_reg,
4126 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4127
4128 // Check that the key is within bounds.
4129 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4130 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4131
4132 // Load the upper word of the double in the fixed array and test for NaN.
4133 __ sll(scratch2, key_reg, kDoubleSizeLog2 - kSmiTagSize);
4134 __ Addu(indexed_double_offset, elements_reg, Operand(scratch2));
4135 uint32_t upper_32_offset = FixedArray::kHeaderSize + sizeof(kHoleNanLower32);
4136 __ lw(scratch, FieldMemOperand(indexed_double_offset, upper_32_offset));
4137 __ Branch(&miss_force_generic, eq, scratch, Operand(kHoleNanUpper32));
4138
4139 // Non-NaN. Allocate a new heap number and copy the double value into it.
4140 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
4141 __ AllocateHeapNumber(heap_number_reg, scratch2, scratch3,
4142 heap_number_map, &slow_allocate_heapnumber);
4143
4144 // Don't need to reload the upper 32 bits of the double, it's already in
4145 // scratch.
4146 __ sw(scratch, FieldMemOperand(heap_number_reg,
4147 HeapNumber::kExponentOffset));
4148 __ lw(scratch, FieldMemOperand(indexed_double_offset,
4149 FixedArray::kHeaderSize));
4150 __ sw(scratch, FieldMemOperand(heap_number_reg,
4151 HeapNumber::kMantissaOffset));
4152
4153 __ mov(v0, heap_number_reg);
4154 __ Ret();
4155
4156 __ bind(&slow_allocate_heapnumber);
4157 Handle<Code> slow_ic =
4158 masm->isolate()->builtins()->KeyedLoadIC_Slow();
4159 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4160
4161 __ bind(&miss_force_generic);
4162 Handle<Code> miss_ic =
4163 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4164 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004165}
4166
4167
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004168void KeyedStoreStubCompiler::GenerateStoreFastElement(
4169 MacroAssembler* masm,
4170 bool is_js_array,
4171 ElementsKind elements_kind) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00004172 // ----------- S t a t e -------------
4173 // -- a0 : value
4174 // -- a1 : key
4175 // -- a2 : receiver
4176 // -- ra : return address
4177 // -- a3 : scratch
4178 // -- a4 : scratch (elements)
4179 // -----------------------------------
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004180 Label miss_force_generic, transition_elements_kind;
danno@chromium.org40cb8782011-05-25 07:58:50 +00004181
4182 Register value_reg = a0;
4183 Register key_reg = a1;
4184 Register receiver_reg = a2;
4185 Register scratch = a3;
4186 Register elements_reg = t0;
4187 Register scratch2 = t1;
4188 Register scratch3 = t2;
4189
4190 // This stub is meant to be tail-jumped to, the receiver must already
4191 // have been verified by the caller to not be a smi.
4192
4193 // Check that the key is a smi.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00004194 __ JumpIfNotSmi(key_reg, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004195
4196 // Get the elements array and make sure it is a fast element array, not 'cow'.
4197 __ lw(elements_reg,
4198 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4199 __ CheckMap(elements_reg,
4200 scratch,
4201 Heap::kFixedArrayMapRootIndex,
4202 &miss_force_generic,
4203 DONT_DO_SMI_CHECK);
4204
4205 // Check that the key is within bounds.
4206 if (is_js_array) {
4207 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4208 } else {
4209 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4210 }
4211 // Compare smis.
4212 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4213
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004214 if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
4215 __ JumpIfNotSmi(value_reg, &transition_elements_kind);
4216 __ Addu(scratch,
4217 elements_reg,
4218 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4219 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4220 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4221 __ Addu(scratch, scratch, scratch2);
4222 __ sw(value_reg, MemOperand(scratch));
4223 } else {
4224 ASSERT(elements_kind == FAST_ELEMENTS);
4225 __ Addu(scratch,
4226 elements_reg,
4227 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4228 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4229 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4230 __ Addu(scratch, scratch, scratch2);
4231 __ sw(value_reg, MemOperand(scratch));
4232 __ mov(receiver_reg, value_reg);
4233 ASSERT(elements_kind == FAST_ELEMENTS);
4234 __ RecordWrite(elements_reg, // Object.
4235 scratch, // Address.
4236 receiver_reg, // Value.
4237 kRAHasNotBeenSaved,
4238 kDontSaveFPRegs);
4239 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004240 // value_reg (a0) is preserved.
4241 // Done.
4242 __ Ret();
4243
4244 __ bind(&miss_force_generic);
4245 Handle<Code> ic =
4246 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4247 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004248
4249 __ bind(&transition_elements_kind);
4250 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4251 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004252}
4253
4254
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004255void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
4256 MacroAssembler* masm,
4257 bool is_js_array) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004258 // ----------- S t a t e -------------
4259 // -- a0 : value
4260 // -- a1 : key
4261 // -- a2 : receiver
4262 // -- ra : return address
4263 // -- a3 : scratch
4264 // -- t0 : scratch (elements_reg)
4265 // -- t1 : scratch (mantissa_reg)
4266 // -- t2 : scratch (exponent_reg)
4267 // -- t3 : scratch4
4268 // -----------------------------------
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004269 Label miss_force_generic, transition_elements_kind;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004270
4271 Register value_reg = a0;
4272 Register key_reg = a1;
4273 Register receiver_reg = a2;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004274 Register elements_reg = a3;
4275 Register scratch1 = t0;
4276 Register scratch2 = t1;
4277 Register scratch3 = t2;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004278 Register scratch4 = t3;
4279
4280 // This stub is meant to be tail-jumped to, the receiver must already
4281 // have been verified by the caller to not be a smi.
4282 __ JumpIfNotSmi(key_reg, &miss_force_generic);
4283
4284 __ lw(elements_reg,
4285 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4286
4287 // Check that the key is within bounds.
4288 if (is_js_array) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004289 __ lw(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004290 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004291 __ lw(scratch1,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004292 FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4293 }
4294 // Compare smis, unsigned compare catches both negative and out-of-bound
4295 // indexes.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004296 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch1));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004297
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004298 __ StoreNumberToDoubleElements(value_reg,
4299 key_reg,
4300 receiver_reg,
4301 elements_reg,
4302 scratch1,
4303 scratch2,
4304 scratch3,
4305 scratch4,
4306 &transition_elements_kind);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004307
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004308 __ Ret(USE_DELAY_SLOT);
4309 __ mov(v0, value_reg); // In delay slot.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004310
4311 // Handle store cache miss, replacing the ic with the generic stub.
4312 __ bind(&miss_force_generic);
4313 Handle<Code> ic =
4314 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4315 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004316
4317 __ bind(&transition_elements_kind);
4318 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4319 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004320}
4321
4322
ager@chromium.org5c838252010-02-19 08:53:10 +00004323#undef __
4324
4325} } // namespace v8::internal
4326
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004327#endif // V8_TARGET_ARCH_MIPS