blob: 0051edfb6c65f95e35de6f8d0fa93d791ad17db4 [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 Register elements = a3;
1472 Register end_elements = t1;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001473 // Get the elements array of the object.
1474 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1475
1476 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001477 __ CheckMap(elements,
1478 v0,
1479 Heap::kFixedArrayMapRootIndex,
1480 &call_builtin,
1481 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001482
1483 if (argc == 1) { // Otherwise fall through to call the builtin.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001484 Label attempt_to_grow_elements;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001485
1486 // 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
1492 // Get the element's length.
1493 __ 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
1506 // Push the element.
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
1522 __ lw(t2, FieldMemOperand(receiver, HeapObject::kMapOffset));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001523 __ CheckFastObjectElements(t2, t2, &call_builtin);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001524
1525 // Save new length.
1526 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1527
1528 // Push the element.
1529 // We may need a register containing the address end_elements below,
1530 // so write back the value in end_elements.
1531 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1532 __ Addu(end_elements, elements, end_elements);
1533 __ Addu(end_elements, end_elements, kEndElementsOffset);
1534 __ sw(t0, MemOperand(end_elements));
1535
1536 __ RecordWrite(elements,
1537 end_elements,
1538 t0,
1539 kRAHasNotBeenSaved,
1540 kDontSaveFPRegs,
1541 EMIT_REMEMBERED_SET,
1542 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001543 __ Drop(argc + 1);
1544 __ Ret();
1545
1546 __ bind(&attempt_to_grow_elements);
1547 // v0: array's length + 1.
1548 // t0: elements' length.
1549
1550 if (!FLAG_inline_new) {
1551 __ Branch(&call_builtin);
1552 }
1553
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001554 __ lw(a2, MemOperand(sp, (argc - 1) * kPointerSize));
1555 // Growing elements that are SMI-only requires special handling in case
1556 // the new element is non-Smi. For now, delegate to the builtin.
1557 Label no_fast_elements_check;
1558 __ JumpIfSmi(a2, &no_fast_elements_check);
1559 __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1560 __ CheckFastObjectElements(t3, t3, &call_builtin);
1561 __ bind(&no_fast_elements_check);
1562
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001563 ExternalReference new_space_allocation_top =
1564 ExternalReference::new_space_allocation_top_address(
1565 masm()->isolate());
1566 ExternalReference new_space_allocation_limit =
1567 ExternalReference::new_space_allocation_limit_address(
1568 masm()->isolate());
1569
1570 const int kAllocationDelta = 4;
1571 // Load top and check if it is the end of elements.
1572 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1573 __ Addu(end_elements, elements, end_elements);
1574 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset));
1575 __ li(t3, Operand(new_space_allocation_top));
1576 __ lw(t2, MemOperand(t3));
1577 __ Branch(&call_builtin, ne, end_elements, Operand(t2));
1578
1579 __ li(t5, Operand(new_space_allocation_limit));
1580 __ lw(t5, MemOperand(t5));
1581 __ Addu(t2, t2, Operand(kAllocationDelta * kPointerSize));
1582 __ Branch(&call_builtin, hi, t2, Operand(t5));
1583
1584 // We fit and could grow elements.
1585 // Update new_space_allocation_top.
1586 __ sw(t2, MemOperand(t3));
1587 // Push the argument.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001588 __ sw(a2, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001589 // Fill the rest with holes.
1590 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1591 for (int i = 1; i < kAllocationDelta; i++) {
1592 __ sw(t2, MemOperand(end_elements, i * kPointerSize));
1593 }
1594
1595 // Update elements' and array's sizes.
1596 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1597 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta)));
1598 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1599
1600 // Elements are in new space, so write barrier is not required.
1601 __ Drop(argc + 1);
1602 __ Ret();
1603 }
1604 __ bind(&call_builtin);
1605 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
1606 masm()->isolate()),
1607 argc + 1,
1608 1);
1609 }
1610
1611 // Handle call cache miss.
1612 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001613 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001614
1615 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001616 return GetCode(function);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001617}
1618
1619
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001620Handle<Code> CallStubCompiler::CompileArrayPopCall(
1621 Handle<Object> object,
1622 Handle<JSObject> holder,
1623 Handle<JSGlobalPropertyCell> cell,
1624 Handle<JSFunction> function,
1625 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001626 // ----------- S t a t e -------------
1627 // -- a2 : name
1628 // -- ra : return address
1629 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1630 // -- ...
1631 // -- sp[argc * 4] : receiver
1632 // -----------------------------------
1633
1634 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001635 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001636
1637 Label miss, return_undefined, call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001638 Register receiver = a1;
1639 Register elements = a3;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001640 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001641
1642 // Get the receiver from the stack.
1643 const int argc = arguments().immediate();
1644 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001645 // Check that the receiver isn't a smi.
1646 __ JumpIfSmi(receiver, &miss);
1647
1648 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001649 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, elements,
1650 t0, v0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001651
1652 // Get the elements array of the object.
1653 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1654
1655 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001656 __ CheckMap(elements,
1657 v0,
1658 Heap::kFixedArrayMapRootIndex,
1659 &call_builtin,
1660 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001661
1662 // Get the array's length into t0 and calculate new length.
1663 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1664 __ Subu(t0, t0, Operand(Smi::FromInt(1)));
1665 __ Branch(&return_undefined, lt, t0, Operand(zero_reg));
1666
1667 // Get the last element.
1668 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1669 STATIC_ASSERT(kSmiTagSize == 1);
1670 STATIC_ASSERT(kSmiTag == 0);
1671 // We can't address the last element in one operation. Compute the more
1672 // expensive shift first, and use an offset later on.
1673 __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize);
1674 __ Addu(elements, elements, t1);
1675 __ lw(v0, MemOperand(elements, FixedArray::kHeaderSize - kHeapObjectTag));
1676 __ Branch(&call_builtin, eq, v0, Operand(t2));
1677
1678 // Set the array's length.
1679 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1680
1681 // Fill with the hole.
1682 __ sw(t2, MemOperand(elements, FixedArray::kHeaderSize - kHeapObjectTag));
1683 __ Drop(argc + 1);
1684 __ Ret();
1685
1686 __ bind(&return_undefined);
1687 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
1688 __ Drop(argc + 1);
1689 __ Ret();
1690
1691 __ bind(&call_builtin);
1692 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop,
1693 masm()->isolate()),
1694 argc + 1,
1695 1);
1696
1697 // Handle call cache miss.
1698 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001699 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001700
1701 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001702 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001703}
1704
1705
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001706Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1707 Handle<Object> object,
1708 Handle<JSObject> holder,
1709 Handle<JSGlobalPropertyCell> cell,
1710 Handle<JSFunction> function,
1711 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001712 // ----------- S t a t e -------------
1713 // -- a2 : function name
1714 // -- ra : return address
1715 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1716 // -- ...
1717 // -- sp[argc * 4] : receiver
1718 // -----------------------------------
1719
1720 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001721 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001722
1723 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001724 Label miss;
1725 Label name_miss;
1726 Label index_out_of_range;
1727
1728 Label* index_out_of_range_label = &index_out_of_range;
1729
danno@chromium.org40cb8782011-05-25 07:58:50 +00001730 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001731 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001732 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001733 index_out_of_range_label = &miss;
1734 }
1735
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001736 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001737
1738 // Check that the maps starting from the prototype haven't changed.
1739 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1740 Context::STRING_FUNCTION_INDEX,
1741 v0,
1742 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001743 ASSERT(!object.is_identical_to(holder));
1744 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1745 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001746
1747 Register receiver = a1;
1748 Register index = t1;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001749 Register result = v0;
1750 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1751 if (argc > 0) {
1752 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1753 } else {
1754 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1755 }
1756
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001757 StringCharCodeAtGenerator generator(receiver,
1758 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001759 result,
1760 &miss, // When not a string.
1761 &miss, // When not a number.
1762 index_out_of_range_label,
1763 STRING_INDEX_IS_NUMBER);
1764 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001765 __ Drop(argc + 1);
1766 __ Ret();
1767
1768 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001769 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001770
1771 if (index_out_of_range.is_linked()) {
1772 __ bind(&index_out_of_range);
1773 __ LoadRoot(v0, Heap::kNanValueRootIndex);
1774 __ Drop(argc + 1);
1775 __ Ret();
1776 }
1777
1778 __ bind(&miss);
1779 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001780 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001781 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001782 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001783
1784 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001785 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001786}
1787
1788
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001789Handle<Code> CallStubCompiler::CompileStringCharAtCall(
1790 Handle<Object> object,
1791 Handle<JSObject> holder,
1792 Handle<JSGlobalPropertyCell> cell,
1793 Handle<JSFunction> function,
1794 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001795 // ----------- S t a t e -------------
1796 // -- a2 : function name
1797 // -- ra : return address
1798 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1799 // -- ...
1800 // -- sp[argc * 4] : receiver
1801 // -----------------------------------
1802
1803 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001804 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001805
1806 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001807 Label miss;
1808 Label name_miss;
1809 Label index_out_of_range;
1810 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00001811 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001812 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001813 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001814 index_out_of_range_label = &miss;
1815 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001816 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001817
1818 // Check that the maps starting from the prototype haven't changed.
1819 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1820 Context::STRING_FUNCTION_INDEX,
1821 v0,
1822 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001823 ASSERT(!object.is_identical_to(holder));
1824 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1825 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001826
1827 Register receiver = v0;
1828 Register index = t1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001829 Register scratch = a3;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001830 Register result = v0;
1831 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1832 if (argc > 0) {
1833 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1834 } else {
1835 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1836 }
1837
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001838 StringCharAtGenerator generator(receiver,
1839 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00001840 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001841 result,
1842 &miss, // When not a string.
1843 &miss, // When not a number.
1844 index_out_of_range_label,
1845 STRING_INDEX_IS_NUMBER);
1846 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001847 __ Drop(argc + 1);
1848 __ Ret();
1849
1850 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001851 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001852
1853 if (index_out_of_range.is_linked()) {
1854 __ bind(&index_out_of_range);
1855 __ LoadRoot(v0, Heap::kEmptyStringRootIndex);
1856 __ Drop(argc + 1);
1857 __ Ret();
1858 }
1859
1860 __ bind(&miss);
1861 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001862 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001863 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001864 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001865
1866 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001867 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001868}
1869
1870
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001871Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
1872 Handle<Object> object,
1873 Handle<JSObject> holder,
1874 Handle<JSGlobalPropertyCell> cell,
1875 Handle<JSFunction> function,
1876 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001877 // ----------- S t a t e -------------
1878 // -- a2 : function name
1879 // -- ra : return address
1880 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1881 // -- ...
1882 // -- sp[argc * 4] : receiver
1883 // -----------------------------------
1884
1885 const int argc = arguments().immediate();
1886
1887 // If the object is not a JSObject or we got an unexpected number of
1888 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001889 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001890
1891 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001892 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001893
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001894 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001895 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
1896
1897 STATIC_ASSERT(kSmiTag == 0);
1898 __ JumpIfSmi(a1, &miss);
1899
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001900 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
1901 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001902 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001903 ASSERT(cell->value() == *function);
1904 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
1905 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001906 GenerateLoadFunctionFromCell(cell, function, &miss);
1907 }
1908
1909 // Load the char code argument.
1910 Register code = a1;
1911 __ lw(code, MemOperand(sp, 0 * kPointerSize));
1912
1913 // Check the code is a smi.
1914 Label slow;
1915 STATIC_ASSERT(kSmiTag == 0);
1916 __ JumpIfNotSmi(code, &slow);
1917
1918 // Convert the smi code to uint16.
1919 __ And(code, code, Operand(Smi::FromInt(0xffff)));
1920
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001921 StringCharFromCodeGenerator generator(code, v0);
1922 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001923 __ Drop(argc + 1);
1924 __ Ret();
1925
1926 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001927 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001928
1929 // Tail call the full function. We do not have to patch the receiver
1930 // because the function makes no use of it.
1931 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001932 __ InvokeFunction(
1933 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001934
1935 __ bind(&miss);
1936 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001937 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001938
1939 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001940 return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001941}
1942
1943
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001944Handle<Code> CallStubCompiler::CompileMathFloorCall(
1945 Handle<Object> object,
1946 Handle<JSObject> holder,
1947 Handle<JSGlobalPropertyCell> cell,
1948 Handle<JSFunction> function,
1949 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001950 // ----------- S t a t e -------------
1951 // -- a2 : function name
1952 // -- ra : return address
1953 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1954 // -- ...
1955 // -- sp[argc * 4] : receiver
1956 // -----------------------------------
1957
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001958 if (!CpuFeatures::IsSupported(FPU)) {
1959 return Handle<Code>::null();
1960 }
1961
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001962 CpuFeatures::Scope scope_fpu(FPU);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001963 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001964 // If the object is not a JSObject or we got an unexpected number of
1965 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001966 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001967
1968 Label miss, slow;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001969 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001970
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001971 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001972 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001973 STATIC_ASSERT(kSmiTag == 0);
1974 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001975 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
1976 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001977 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001978 ASSERT(cell->value() == *function);
1979 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
1980 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001981 GenerateLoadFunctionFromCell(cell, function, &miss);
1982 }
1983
1984 // Load the (only) argument into v0.
1985 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
1986
1987 // If the argument is a smi, just return.
1988 STATIC_ASSERT(kSmiTag == 0);
1989 __ And(t0, v0, Operand(kSmiTagMask));
1990 __ Drop(argc + 1, eq, t0, Operand(zero_reg));
1991 __ Ret(eq, t0, Operand(zero_reg));
1992
danno@chromium.org40cb8782011-05-25 07:58:50 +00001993 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001994
1995 Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return;
1996
1997 // If fpu is enabled, we use the floor instruction.
1998
1999 // Load the HeapNumber value.
2000 __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2001
2002 // Backup FCSR.
2003 __ cfc1(a3, FCSR);
2004 // Clearing FCSR clears the exception mask with no side-effects.
2005 __ ctc1(zero_reg, FCSR);
2006 // Convert the argument to an integer.
2007 __ floor_w_d(f0, f0);
2008
2009 // Start checking for special cases.
2010 // Get the argument exponent and clear the sign bit.
2011 __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize));
2012 __ And(t2, t1, Operand(~HeapNumber::kSignMask));
2013 __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord);
2014
2015 // Retrieve FCSR and check for fpu errors.
2016 __ cfc1(t5, FCSR);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002017 __ And(t5, t5, Operand(kFCSRExceptionFlagMask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002018 __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));
2019
2020 // Check for NaN, Infinity, and -Infinity.
2021 // They are invariant through a Math.Floor call, so just
2022 // return the original argument.
2023 __ Subu(t3, t2, Operand(HeapNumber::kExponentMask
2024 >> HeapNumber::kMantissaBitsInTopWord));
2025 __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg));
2026 // We had an overflow or underflow in the conversion. Check if we
2027 // have a big exponent.
2028 // If greater or equal, the argument is already round and in v0.
2029 __ Branch(&restore_fcsr_and_return, ge, t3,
2030 Operand(HeapNumber::kMantissaBits));
2031 __ Branch(&wont_fit_smi);
2032
2033 __ bind(&no_fpu_error);
2034 // Move the result back to v0.
2035 __ mfc1(v0, f0);
2036 // Check if the result fits into a smi.
2037 __ Addu(a1, v0, Operand(0x40000000));
2038 __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg));
2039 // Tag the result.
2040 STATIC_ASSERT(kSmiTag == 0);
2041 __ sll(v0, v0, kSmiTagSize);
2042
2043 // Check for -0.
2044 __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg));
2045 // t1 already holds the HeapNumber exponent.
2046 __ And(t0, t1, Operand(HeapNumber::kSignMask));
2047 // If our HeapNumber is negative it was -0, so load its address and return.
2048 // Else v0 is loaded with 0, so we can also just return.
2049 __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg));
2050 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2051
2052 __ bind(&restore_fcsr_and_return);
2053 // Restore FCSR and return.
2054 __ ctc1(a3, FCSR);
2055
2056 __ Drop(argc + 1);
2057 __ Ret();
2058
2059 __ bind(&wont_fit_smi);
2060 // Restore FCSR and fall to slow case.
2061 __ ctc1(a3, FCSR);
2062
2063 __ bind(&slow);
2064 // Tail call the full function. We do not have to patch the receiver
2065 // because the function makes no use of it.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002066 __ InvokeFunction(
2067 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002068
2069 __ bind(&miss);
2070 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002071 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002072
2073 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002074 return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002075}
2076
2077
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002078Handle<Code> CallStubCompiler::CompileMathAbsCall(
2079 Handle<Object> object,
2080 Handle<JSObject> holder,
2081 Handle<JSGlobalPropertyCell> cell,
2082 Handle<JSFunction> function,
2083 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002084 // ----------- S t a t e -------------
2085 // -- a2 : function name
2086 // -- ra : return address
2087 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2088 // -- ...
2089 // -- sp[argc * 4] : receiver
2090 // -----------------------------------
2091
2092 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002093 // If the object is not a JSObject or we got an unexpected number of
2094 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002095 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002096
2097 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002098
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002099 GenerateNameCheck(name, &miss);
2100 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002101 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002102 STATIC_ASSERT(kSmiTag == 0);
2103 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002104 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2105 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002106 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002107 ASSERT(cell->value() == *function);
2108 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2109 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002110 GenerateLoadFunctionFromCell(cell, function, &miss);
2111 }
2112
2113 // Load the (only) argument into v0.
2114 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2115
2116 // Check if the argument is a smi.
2117 Label not_smi;
2118 STATIC_ASSERT(kSmiTag == 0);
2119 __ JumpIfNotSmi(v0, &not_smi);
2120
2121 // Do bitwise not or do nothing depending on the sign of the
2122 // argument.
2123 __ sra(t0, v0, kBitsPerInt - 1);
2124 __ Xor(a1, v0, t0);
2125
2126 // Add 1 or do nothing depending on the sign of the argument.
2127 __ Subu(v0, a1, t0);
2128
2129 // If the result is still negative, go to the slow case.
2130 // This only happens for the most negative smi.
2131 Label slow;
2132 __ Branch(&slow, lt, v0, Operand(zero_reg));
2133
2134 // Smi case done.
2135 __ Drop(argc + 1);
2136 __ Ret();
2137
2138 // Check if the argument is a heap number and load its exponent and
2139 // sign.
2140 __ bind(&not_smi);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002141 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002142 __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2143
2144 // Check the sign of the argument. If the argument is positive,
2145 // just return it.
2146 Label negative_sign;
2147 __ And(t0, a1, Operand(HeapNumber::kSignMask));
2148 __ Branch(&negative_sign, ne, t0, Operand(zero_reg));
2149 __ Drop(argc + 1);
2150 __ Ret();
2151
2152 // If the argument is negative, clear the sign, and return a new
2153 // number.
2154 __ bind(&negative_sign);
2155 __ Xor(a1, a1, Operand(HeapNumber::kSignMask));
2156 __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2157 __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
2158 __ AllocateHeapNumber(v0, t0, t1, t2, &slow);
2159 __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2160 __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2161 __ Drop(argc + 1);
2162 __ Ret();
2163
2164 // Tail call the full function. We do not have to patch the receiver
2165 // because the function makes no use of it.
2166 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002167 __ InvokeFunction(
2168 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002169
2170 __ bind(&miss);
2171 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002172 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002173
2174 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002175 return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002176}
2177
2178
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002179Handle<Code> CallStubCompiler::CompileFastApiCall(
lrn@chromium.org7516f052011-03-30 08:52:27 +00002180 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002181 Handle<Object> object,
2182 Handle<JSObject> holder,
2183 Handle<JSGlobalPropertyCell> cell,
2184 Handle<JSFunction> function,
2185 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002186
danno@chromium.org40cb8782011-05-25 07:58:50 +00002187 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002188
2189 ASSERT(optimization.is_simple_api_call());
2190 // Bail out if object is a global object as we don't want to
2191 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002192 if (object->IsGlobalObject()) return Handle<Code>::null();
2193 if (!cell.is_null()) return Handle<Code>::null();
2194 if (!object->IsJSObject()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002195 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002196 Handle<JSObject>::cast(object), holder);
2197 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002198
2199 Label miss, miss_before_stack_reserved;
2200
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002201 GenerateNameCheck(name, &miss_before_stack_reserved);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002202
2203 // Get the receiver from the stack.
2204 const int argc = arguments().immediate();
2205 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2206
2207 // Check that the receiver isn't a smi.
2208 __ JumpIfSmi(a1, &miss_before_stack_reserved);
2209
2210 __ IncrementCounter(counters->call_const(), 1, a0, a3);
2211 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2212
2213 ReserveSpaceForFastApiCall(masm(), a0);
2214
2215 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002216 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002217 depth, &miss);
2218
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002219 GenerateFastApiDirectCall(masm(), optimization, argc);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002220
2221 __ bind(&miss);
2222 FreeSpaceForFastApiCall(masm());
2223
2224 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002225 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002226
2227 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002228 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002229}
2230
2231
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002232Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object,
2233 Handle<JSObject> holder,
2234 Handle<JSFunction> function,
2235 Handle<String> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002236 CheckType check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002237 // ----------- S t a t e -------------
2238 // -- a2 : name
2239 // -- ra : return address
2240 // -----------------------------------
2241 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002242 Handle<Code> code = CompileCustomCall(object, holder,
2243 Handle<JSGlobalPropertyCell>::null(),
2244 function, name);
2245 // A null handle means bail out to the regular compiler code below.
2246 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002247 }
2248
2249 Label miss;
2250
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002251 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002252
2253 // Get the receiver from the stack.
2254 const int argc = arguments().immediate();
2255 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2256
2257 // Check that the receiver isn't a smi.
2258 if (check != NUMBER_CHECK) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002259 __ JumpIfSmi(a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002260 }
2261
2262 // Make sure that it's okay not to patch the on stack receiver
2263 // unless we're doing a receiver map check.
2264 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002265 switch (check) {
2266 case RECEIVER_MAP_CHECK:
2267 __ IncrementCounter(masm()->isolate()->counters()->call_const(),
2268 1, a0, a3);
2269
2270 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002271 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2272 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002273
2274 // Patch the receiver on the stack with the global proxy if
2275 // necessary.
2276 if (object->IsGlobalObject()) {
2277 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2278 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2279 }
2280 break;
2281
2282 case STRING_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002283 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002284 // Check that the object is a two-byte string or a symbol.
2285 __ GetObjectType(a1, a3, a3);
2286 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2287 // Check that the maps starting from the prototype haven't changed.
2288 GenerateDirectLoadGlobalFunctionPrototype(
2289 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002290 CheckPrototypes(
2291 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2292 a0, holder, a3, a1, t0, name, &miss);
2293 } else {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002294 // Calling non-strict non-builtins with a value as the receiver
2295 // requires boxing.
2296 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002297 }
2298 break;
2299
2300 case NUMBER_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002301 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002302 Label fast;
2303 // Check that the object is a smi or a heap number.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002304 __ JumpIfSmi(a1, &fast);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002305 __ GetObjectType(a1, a0, a0);
2306 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
2307 __ bind(&fast);
2308 // Check that the maps starting from the prototype haven't changed.
2309 GenerateDirectLoadGlobalFunctionPrototype(
2310 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002311 CheckPrototypes(
2312 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2313 a0, holder, a3, a1, t0, name, &miss);
2314 } else {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002315 // Calling non-strict non-builtins with a value as the receiver
2316 // requires boxing.
2317 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002318 }
2319 break;
2320
2321 case BOOLEAN_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002322 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002323 Label fast;
2324 // Check that the object is a boolean.
2325 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
2326 __ Branch(&fast, eq, a1, Operand(t0));
2327 __ LoadRoot(t0, Heap::kFalseValueRootIndex);
2328 __ Branch(&miss, ne, a1, Operand(t0));
2329 __ bind(&fast);
2330 // Check that the maps starting from the prototype haven't changed.
2331 GenerateDirectLoadGlobalFunctionPrototype(
2332 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002333 CheckPrototypes(
2334 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2335 a0, holder, a3, a1, t0, name, &miss);
2336 } else {
2337 // Calling non-strict non-builtins with a value as the receiver
2338 // requires boxing.
2339 __ jmp(&miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002340 }
2341 break;
2342 }
2343
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002344 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002345 ? CALL_AS_FUNCTION
2346 : CALL_AS_METHOD;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002347 __ InvokeFunction(
2348 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002349
2350 // Handle call cache miss.
2351 __ bind(&miss);
2352
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002353 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002354
2355 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002356 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002357}
2358
2359
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002360Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2361 Handle<JSObject> holder,
2362 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002363 // ----------- S t a t e -------------
2364 // -- a2 : name
2365 // -- ra : return address
2366 // -----------------------------------
2367
2368 Label miss;
2369
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002370 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002371
2372 // Get the number of arguments.
2373 const int argc = arguments().immediate();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002374 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002375 LookupPostInterceptor(holder, name, &lookup);
2376
2377 // Get the receiver from the stack.
2378 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2379
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002380 CallInterceptorCompiler compiler(this, arguments(), a2, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002381 compiler.Compile(masm(), object, holder, name, &lookup, a1, a3, t0, a0,
2382 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002383
2384 // Move returned value, the function to call, to a1.
2385 __ mov(a1, v0);
2386 // Restore receiver.
2387 __ lw(a0, MemOperand(sp, argc * kPointerSize));
2388
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002389 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002390
2391 // Handle call cache miss.
2392 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002393 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002394
2395 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002396 return GetCode(INTERCEPTOR, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002397}
2398
2399
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002400Handle<Code> CallStubCompiler::CompileCallGlobal(
2401 Handle<JSObject> object,
2402 Handle<GlobalObject> holder,
2403 Handle<JSGlobalPropertyCell> cell,
2404 Handle<JSFunction> function,
2405 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002406 // ----------- S t a t e -------------
2407 // -- a2 : name
2408 // -- ra : return address
2409 // -----------------------------------
2410
2411 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002412 Handle<Code> code = CompileCustomCall(object, holder, cell, function, name);
2413 // A null handle means bail out to the regular compiler code below.
2414 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002415 }
2416
2417 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002418 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002419
2420 // Get the number of arguments.
2421 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002422 GenerateGlobalReceiverCheck(object, holder, name, &miss);
2423 GenerateLoadFunctionFromCell(cell, function, &miss);
2424
2425 // Patch the receiver on the stack with the global proxy if
2426 // necessary.
2427 if (object->IsGlobalObject()) {
2428 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
2429 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2430 }
2431
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002432 // Set up the context (function already in r1).
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002433 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
2434
2435 // Jump to the cached code (tail call).
2436 Counters* counters = masm()->isolate()->counters();
2437 __ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002438 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002439 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002440 ? CALL_AS_FUNCTION
2441 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002442 // We call indirectly through the code field in the function to
2443 // allow recompilation to take effect without changing any of the
2444 // call sites.
2445 __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
2446 __ InvokeCode(a3, expected, arguments(), JUMP_FUNCTION,
2447 NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002448
2449 // Handle call cache miss.
2450 __ bind(&miss);
2451 __ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002452 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002453
2454 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002455 return GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002456}
2457
2458
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002459Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +00002460 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002461 Handle<Map> transition,
2462 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002463 // ----------- S t a t e -------------
2464 // -- a0 : value
2465 // -- a1 : receiver
2466 // -- a2 : name
2467 // -- ra : return address
2468 // -----------------------------------
2469 Label miss;
2470
2471 // Name register might be clobbered.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002472 GenerateStoreField(masm(), object, index, transition, a1, a2, a3, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002473 __ bind(&miss);
2474 __ li(a2, Operand(Handle<String>(name))); // Restore name.
2475 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2476 __ Jump(ic, RelocInfo::CODE_TARGET);
2477
2478 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002479 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002480}
2481
2482
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002483Handle<Code> StoreStubCompiler::CompileStoreCallback(
2484 Handle<JSObject> object,
2485 Handle<AccessorInfo> callback,
2486 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002487 // ----------- S t a t e -------------
2488 // -- a0 : value
2489 // -- a1 : receiver
2490 // -- a2 : name
2491 // -- ra : return address
2492 // -----------------------------------
2493 Label miss;
2494
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002495 // Check that the map of the object hasn't changed.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002496 __ CheckMap(a1, a3, Handle<Map>(object->map()), &miss,
2497 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002498
2499 // Perform global security token check if needed.
2500 if (object->IsJSGlobalProxy()) {
2501 __ CheckAccessGlobalProxy(a1, a3, &miss);
2502 }
2503
2504 // Stub never generated for non-global objects that require access
2505 // checks.
2506 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
2507
2508 __ push(a1); // Receiver.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002509 __ li(a3, Operand(callback)); // Callback info.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002510 __ Push(a3, a2, a0);
2511
2512 // Do tail-call to the runtime system.
2513 ExternalReference store_callback_property =
2514 ExternalReference(IC_Utility(IC::kStoreCallbackProperty),
2515 masm()->isolate());
2516 __ TailCallExternalReference(store_callback_property, 4, 1);
2517
2518 // Handle store cache miss.
2519 __ bind(&miss);
2520 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2521 __ Jump(ic, RelocInfo::CODE_TARGET);
2522
2523 // Return the generated code.
2524 return GetCode(CALLBACKS, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002525}
2526
2527
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002528Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
2529 Handle<JSObject> receiver,
2530 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002531 // ----------- S t a t e -------------
2532 // -- a0 : value
2533 // -- a1 : receiver
2534 // -- a2 : name
2535 // -- ra : return address
2536 // -----------------------------------
2537 Label miss;
2538
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002539 // Check that the map of the object hasn't changed.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002540 __ CheckMap(a1, a3, Handle<Map>(receiver->map()), &miss,
2541 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002542
2543 // Perform global security token check if needed.
2544 if (receiver->IsJSGlobalProxy()) {
2545 __ CheckAccessGlobalProxy(a1, a3, &miss);
2546 }
2547
2548 // Stub is never generated for non-global objects that require access
2549 // checks.
2550 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2551
2552 __ Push(a1, a2, a0); // Receiver, name, value.
2553
2554 __ li(a0, Operand(Smi::FromInt(strict_mode_)));
2555 __ push(a0); // Strict mode.
2556
2557 // Do tail-call to the runtime system.
2558 ExternalReference store_ic_property =
2559 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty),
2560 masm()->isolate());
2561 __ TailCallExternalReference(store_ic_property, 4, 1);
2562
2563 // Handle store cache miss.
2564 __ bind(&miss);
2565 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2566 __ Jump(ic, RelocInfo::CODE_TARGET);
2567
2568 // Return the generated code.
2569 return GetCode(INTERCEPTOR, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002570}
2571
2572
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002573Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2574 Handle<GlobalObject> object,
2575 Handle<JSGlobalPropertyCell> cell,
2576 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002577 // ----------- S t a t e -------------
2578 // -- a0 : value
2579 // -- a1 : receiver
2580 // -- a2 : name
2581 // -- ra : return address
2582 // -----------------------------------
2583 Label miss;
2584
2585 // Check that the map of the global has not changed.
2586 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2587 __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map())));
2588
2589 // Check that the value in the cell is not the hole. If it is, this
2590 // cell could have been deleted and reintroducing the global needs
2591 // to update the property details in the property dictionary of the
2592 // global object. We bail out to the runtime system to do that.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002593 __ li(t0, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002594 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
2595 __ lw(t2, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2596 __ Branch(&miss, eq, t1, Operand(t2));
2597
2598 // Store the value in the cell.
2599 __ sw(a0, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2600 __ mov(v0, a0); // Stored value must be returned in v0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002601 // Cells are always rescanned, so no write barrier here.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002602
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002603 Counters* counters = masm()->isolate()->counters();
2604 __ IncrementCounter(counters->named_store_global_inline(), 1, a1, a3);
2605 __ Ret();
2606
2607 // Handle store cache miss.
2608 __ bind(&miss);
2609 __ IncrementCounter(counters->named_store_global_inline_miss(), 1, a1, a3);
2610 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2611 __ Jump(ic, RelocInfo::CODE_TARGET);
2612
2613 // Return the generated code.
2614 return GetCode(NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002615}
2616
2617
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002618Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
2619 Handle<JSObject> object,
2620 Handle<JSObject> last) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002621 // ----------- S t a t e -------------
2622 // -- a0 : receiver
2623 // -- ra : return address
2624 // -----------------------------------
2625 Label miss;
2626
2627 // Check that the receiver is not a smi.
2628 __ JumpIfSmi(a0, &miss);
2629
2630 // Check the maps of the full prototype chain.
2631 CheckPrototypes(object, a0, last, a3, a1, t0, name, &miss);
2632
2633 // If the last object in the prototype chain is a global object,
2634 // check that the global property cell is empty.
2635 if (last->IsGlobalObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002636 GenerateCheckPropertyCell(
2637 masm(), Handle<GlobalObject>::cast(last), name, a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002638 }
2639
2640 // Return undefined if maps of the full prototype chain is still the same.
2641 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2642 __ Ret();
2643
2644 __ bind(&miss);
2645 GenerateLoadMiss(masm(), Code::LOAD_IC);
2646
2647 // Return the generated code.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002648 return GetCode(NONEXISTENT, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00002649}
2650
2651
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002652Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object,
2653 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002654 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002655 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002656 // ----------- S t a t e -------------
2657 // -- a0 : receiver
2658 // -- a2 : name
2659 // -- ra : return address
2660 // -----------------------------------
2661 Label miss;
2662
2663 __ mov(v0, a0);
2664
2665 GenerateLoadField(object, holder, v0, a3, a1, t0, index, name, &miss);
2666 __ bind(&miss);
2667 GenerateLoadMiss(masm(), Code::LOAD_IC);
2668
2669 // Return the generated code.
2670 return GetCode(FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002671}
2672
2673
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002674Handle<Code> LoadStubCompiler::CompileLoadCallback(
2675 Handle<String> name,
2676 Handle<JSObject> object,
2677 Handle<JSObject> holder,
2678 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002679 // ----------- S t a t e -------------
2680 // -- a0 : receiver
2681 // -- a2 : name
2682 // -- ra : return address
2683 // -----------------------------------
2684 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002685 GenerateLoadCallback(object, holder, a0, a2, a3, a1, t0, callback, name,
2686 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002687 __ bind(&miss);
2688 GenerateLoadMiss(masm(), Code::LOAD_IC);
2689
2690 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002691 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002692}
2693
2694
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002695Handle<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object,
2696 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002697 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002698 Handle<String> name) {
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;
2705
2706 GenerateLoadConstant(object, holder, a0, a3, a1, t0, value, name, &miss);
2707 __ bind(&miss);
2708 GenerateLoadMiss(masm(), Code::LOAD_IC);
2709
2710 // Return the generated code.
2711 return GetCode(CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002712}
2713
2714
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002715Handle<Code> LoadStubCompiler::CompileLoadInterceptor(Handle<JSObject> object,
2716 Handle<JSObject> holder,
2717 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002718 // ----------- S t a t e -------------
2719 // -- a0 : receiver
2720 // -- a2 : name
2721 // -- ra : return address
2722 // -- [sp] : receiver
2723 // -----------------------------------
2724 Label miss;
2725
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002726 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002727 LookupPostInterceptor(holder, name, &lookup);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002728 GenerateLoadInterceptor(object, holder, &lookup, a0, a2, a3, a1, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002729 &miss);
2730 __ bind(&miss);
2731 GenerateLoadMiss(masm(), Code::LOAD_IC);
2732
2733 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002734 return GetCode(INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002735}
2736
2737
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002738Handle<Code> LoadStubCompiler::CompileLoadGlobal(
2739 Handle<JSObject> object,
2740 Handle<GlobalObject> holder,
2741 Handle<JSGlobalPropertyCell> cell,
2742 Handle<String> name,
2743 bool is_dont_delete) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002744 // ----------- S t a t e -------------
2745 // -- a0 : receiver
2746 // -- a2 : name
2747 // -- ra : return address
2748 // -----------------------------------
2749 Label miss;
2750
2751 // If the object is the holder then we know that it's a global
2752 // object which can only happen for contextual calls. In this case,
2753 // the receiver cannot be a smi.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002754 if (!object.is_identical_to(holder)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002755 __ JumpIfSmi(a0, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002756 }
2757
2758 // Check that the map of the global has not changed.
2759 CheckPrototypes(object, a0, holder, a3, t0, a1, name, &miss);
2760
2761 // Get the value from the cell.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002762 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002763 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
2764
2765 // Check for deleted property if property can actually be deleted.
2766 if (!is_dont_delete) {
2767 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
2768 __ Branch(&miss, eq, t0, Operand(at));
2769 }
2770
2771 __ mov(v0, t0);
2772 Counters* counters = masm()->isolate()->counters();
2773 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
2774 __ Ret();
2775
2776 __ bind(&miss);
2777 __ IncrementCounter(counters->named_load_global_stub_miss(), 1, a1, a3);
2778 GenerateLoadMiss(masm(), Code::LOAD_IC);
2779
2780 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002781 return GetCode(NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002782}
2783
2784
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002785Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
2786 Handle<JSObject> receiver,
2787 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002788 int index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002789 // ----------- S t a t e -------------
2790 // -- ra : return address
2791 // -- a0 : key
2792 // -- a1 : receiver
2793 // -----------------------------------
2794 Label miss;
2795
2796 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002797 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002798
2799 GenerateLoadField(receiver, holder, a1, a2, a3, t0, index, name, &miss);
2800 __ bind(&miss);
2801 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2802
2803 return GetCode(FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002804}
2805
2806
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002807Handle<Code> KeyedLoadStubCompiler::CompileLoadCallback(
2808 Handle<String> name,
2809 Handle<JSObject> receiver,
2810 Handle<JSObject> holder,
2811 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002812 // ----------- S t a t e -------------
2813 // -- ra : return address
2814 // -- a0 : key
2815 // -- a1 : receiver
2816 // -----------------------------------
2817 Label miss;
2818
2819 // Check the key is the cached one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002820 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002821
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002822 GenerateLoadCallback(receiver, holder, a1, a0, a2, a3, t0, callback, name,
2823 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002824 __ bind(&miss);
2825 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2826
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002827 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002828}
2829
2830
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002831Handle<Code> KeyedLoadStubCompiler::CompileLoadConstant(
2832 Handle<String> name,
2833 Handle<JSObject> receiver,
2834 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002835 Handle<JSFunction> value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002836 // ----------- S t a t e -------------
2837 // -- ra : return address
2838 // -- a0 : key
2839 // -- a1 : receiver
2840 // -----------------------------------
2841 Label miss;
2842
2843 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002844 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002845
2846 GenerateLoadConstant(receiver, holder, a1, a2, a3, t0, value, name, &miss);
2847 __ bind(&miss);
2848 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2849
2850 // Return the generated code.
2851 return GetCode(CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002852}
2853
2854
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002855Handle<Code> KeyedLoadStubCompiler::CompileLoadInterceptor(
2856 Handle<JSObject> receiver,
2857 Handle<JSObject> holder,
2858 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002859 // ----------- S t a t e -------------
2860 // -- ra : return address
2861 // -- a0 : key
2862 // -- a1 : receiver
2863 // -----------------------------------
2864 Label miss;
2865
2866 // Check the key is the cached one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002867 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002868
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002869 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002870 LookupPostInterceptor(holder, name, &lookup);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002871 GenerateLoadInterceptor(receiver, holder, &lookup, a1, a0, a2, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002872 &miss);
2873 __ bind(&miss);
2874 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2875
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002876 return GetCode(INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002877}
2878
2879
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002880Handle<Code> KeyedLoadStubCompiler::CompileLoadArrayLength(
2881 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002882 // ----------- S t a t e -------------
2883 // -- ra : return address
2884 // -- a0 : key
2885 // -- a1 : receiver
2886 // -----------------------------------
2887 Label miss;
2888
2889 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002890 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002891
2892 GenerateLoadArrayLength(masm(), a1, a2, &miss);
2893 __ bind(&miss);
2894 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2895
2896 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002897}
2898
2899
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002900Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength(
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 Counters* counters = masm()->isolate()->counters();
2910 __ IncrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
2911
2912 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002913 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002914
2915 GenerateLoadStringLength(masm(), a1, a2, a3, &miss, true);
2916 __ bind(&miss);
2917 __ DecrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
2918
2919 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2920
2921 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002922}
2923
2924
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002925Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype(
2926 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002927 // ----------- S t a t e -------------
2928 // -- ra : return address
2929 // -- a0 : key
2930 // -- a1 : receiver
2931 // -----------------------------------
2932 Label miss;
2933
2934 Counters* counters = masm()->isolate()->counters();
2935 __ IncrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
2936
2937 // Check the name hasn't changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002938 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002939
2940 GenerateLoadFunctionPrototype(masm(), a1, a2, a3, &miss);
2941 __ bind(&miss);
2942 __ DecrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
2943 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2944
2945 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002946}
2947
2948
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002949Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
2950 Handle<Map> receiver_map) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00002951 // ----------- S t a t e -------------
2952 // -- ra : return address
2953 // -- a0 : key
2954 // -- a1 : receiver
2955 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002956 ElementsKind elements_kind = receiver_map->elements_kind();
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002957 Handle<Code> stub = KeyedLoadElementStub(elements_kind).GetCode();
2958
2959 __ DispatchMap(a1, a2, receiver_map, stub, DO_SMI_CHECK);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002960
2961 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
2962 __ Jump(ic, RelocInfo::CODE_TARGET);
2963
2964 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002965 return GetCode(NORMAL, factory()->empty_string());
danno@chromium.org40cb8782011-05-25 07:58:50 +00002966}
2967
2968
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002969Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
2970 MapHandleList* receiver_maps,
2971 CodeHandleList* handler_ics) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002972 // ----------- S t a t e -------------
2973 // -- ra : return address
2974 // -- a0 : key
2975 // -- a1 : receiver
2976 // -----------------------------------
2977 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002978 __ JumpIfSmi(a1, &miss);
2979
danno@chromium.org40cb8782011-05-25 07:58:50 +00002980 int receiver_count = receiver_maps->length();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002981 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00002982 for (int current = 0; current < receiver_count; ++current) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002983 __ Jump(handler_ics->at(current), RelocInfo::CODE_TARGET,
2984 eq, a2, Operand(receiver_maps->at(current)));
danno@chromium.org40cb8782011-05-25 07:58:50 +00002985 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002986
2987 __ bind(&miss);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002988 Handle<Code> miss_ic = isolate()->builtins()->KeyedLoadIC_Miss();
2989 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002990
2991 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002992 return GetCode(NORMAL, factory()->empty_string(), MEGAMORPHIC);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002993}
2994
2995
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002996Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002997 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002998 Handle<Map> transition,
2999 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003000 // ----------- S t a t e -------------
3001 // -- a0 : value
3002 // -- a1 : key
3003 // -- a2 : receiver
3004 // -- ra : return address
3005 // -----------------------------------
3006
3007 Label miss;
3008
3009 Counters* counters = masm()->isolate()->counters();
3010 __ IncrementCounter(counters->keyed_store_field(), 1, a3, t0);
3011
3012 // Check that the name has not changed.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003013 __ Branch(&miss, ne, a1, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003014
3015 // a3 is used as scratch register. a1 and a2 keep their values if a jump to
3016 // the miss label is generated.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003017 GenerateStoreField(masm(), object, index, transition, a2, a1, a3, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003018 __ bind(&miss);
3019
3020 __ DecrementCounter(counters->keyed_store_field(), 1, a3, t0);
3021 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss();
3022 __ Jump(ic, RelocInfo::CODE_TARGET);
3023
3024 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003025 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003026}
3027
3028
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003029Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
3030 Handle<Map> receiver_map) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003031 // ----------- S t a t e -------------
3032 // -- a0 : value
3033 // -- a1 : key
3034 // -- a2 : receiver
3035 // -- ra : return address
3036 // -- a3 : scratch
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003037 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003038 ElementsKind elements_kind = receiver_map->elements_kind();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003039 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003040 Handle<Code> stub =
3041 KeyedStoreElementStub(is_js_array, elements_kind).GetCode();
3042
3043 __ DispatchMap(a2, a3, receiver_map, stub, DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003044
danno@chromium.org40cb8782011-05-25 07:58:50 +00003045 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003046 __ Jump(ic, RelocInfo::CODE_TARGET);
3047
3048 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003049 return GetCode(NORMAL, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00003050}
3051
3052
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003053Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
3054 MapHandleList* receiver_maps,
3055 CodeHandleList* handler_stubs,
3056 MapHandleList* transitioned_maps) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003057 // ----------- S t a t e -------------
3058 // -- a0 : value
3059 // -- a1 : key
3060 // -- a2 : receiver
3061 // -- ra : return address
3062 // -- a3 : scratch
3063 // -----------------------------------
3064 Label miss;
3065 __ JumpIfSmi(a2, &miss);
3066
3067 int receiver_count = receiver_maps->length();
3068 __ lw(a3, FieldMemOperand(a2, HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003069 for (int i = 0; i < receiver_count; ++i) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003070 if (transitioned_maps->at(i).is_null()) {
3071 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq,
3072 a3, Operand(receiver_maps->at(i)));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003073 } else {
3074 Label next_map;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003075 __ Branch(&next_map, ne, a3, Operand(receiver_maps->at(i)));
3076 __ li(a3, Operand(transitioned_maps->at(i)));
3077 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003078 __ bind(&next_map);
3079 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003080 }
3081
3082 __ bind(&miss);
3083 Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
3084 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3085
3086 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003087 return GetCode(NORMAL, factory()->empty_string(), MEGAMORPHIC);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003088}
3089
3090
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003091Handle<Code> ConstructStubCompiler::CompileConstructStub(
3092 Handle<JSFunction> function) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003093 // a0 : argc
3094 // a1 : constructor
3095 // ra : return address
3096 // [sp] : last argument
3097 Label generic_stub_call;
3098
3099 // Use t7 for holding undefined which is used in several places below.
3100 __ LoadRoot(t7, Heap::kUndefinedValueRootIndex);
3101
3102#ifdef ENABLE_DEBUGGER_SUPPORT
3103 // Check to see whether there are any break points in the function code. If
3104 // there are jump to the generic constructor stub which calls the actual
3105 // code for the function thereby hitting the break points.
3106 __ lw(t5, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3107 __ lw(a2, FieldMemOperand(t5, SharedFunctionInfo::kDebugInfoOffset));
3108 __ Branch(&generic_stub_call, ne, a2, Operand(t7));
3109#endif
3110
3111 // Load the initial map and verify that it is in fact a map.
3112 // a1: constructor function
3113 // t7: undefined
3114 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003115 __ JumpIfSmi(a2, &generic_stub_call);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003116 __ GetObjectType(a2, a3, t0);
3117 __ Branch(&generic_stub_call, ne, t0, Operand(MAP_TYPE));
3118
3119#ifdef DEBUG
3120 // Cannot construct functions this way.
3121 // a0: argc
3122 // a1: constructor function
3123 // a2: initial map
3124 // t7: undefined
3125 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
3126 __ Check(ne, "Function constructed by construct stub.",
3127 a3, Operand(JS_FUNCTION_TYPE));
3128#endif
3129
3130 // Now allocate the JSObject in new space.
3131 // a0: argc
3132 // a1: constructor function
3133 // a2: initial map
3134 // t7: undefined
3135 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003136 __ AllocateInNewSpace(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003137
3138 // Allocated the JSObject, now initialize the fields. Map is set to initial
3139 // map and properties and elements are set to empty fixed array.
3140 // a0: argc
3141 // a1: constructor function
3142 // a2: initial map
3143 // a3: object size (in words)
3144 // t4: JSObject (not tagged)
3145 // t7: undefined
3146 __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex);
3147 __ mov(t5, t4);
3148 __ sw(a2, MemOperand(t5, JSObject::kMapOffset));
3149 __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset));
3150 __ sw(t6, MemOperand(t5, JSObject::kElementsOffset));
3151 __ Addu(t5, t5, Operand(3 * kPointerSize));
3152 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
3153 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
3154 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
3155
3156
3157 // Calculate the location of the first argument. The stack contains only the
3158 // argc arguments.
3159 __ sll(a1, a0, kPointerSizeLog2);
3160 __ Addu(a1, a1, sp);
3161
3162 // Fill all the in-object properties with undefined.
3163 // a0: argc
3164 // a1: first argument
3165 // a3: object size (in words)
3166 // t4: JSObject (not tagged)
3167 // t5: First in-object property of JSObject (not tagged)
3168 // t7: undefined
3169 // Fill the initialized properties with a constant value or a passed argument
3170 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003171 Handle<SharedFunctionInfo> shared(function->shared());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003172 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3173 if (shared->IsThisPropertyAssignmentArgument(i)) {
3174 Label not_passed, next;
3175 // Check if the argument assigned to the property is actually passed.
3176 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3177 __ Branch(&not_passed, less_equal, a0, Operand(arg_number));
3178 // Argument passed - find it on the stack.
3179 __ lw(a2, MemOperand(a1, (arg_number + 1) * -kPointerSize));
3180 __ sw(a2, MemOperand(t5));
3181 __ Addu(t5, t5, kPointerSize);
3182 __ jmp(&next);
3183 __ bind(&not_passed);
3184 // Set the property to undefined.
3185 __ sw(t7, MemOperand(t5));
3186 __ Addu(t5, t5, Operand(kPointerSize));
3187 __ bind(&next);
3188 } else {
3189 // Set the property to the constant value.
3190 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
3191 __ li(a2, Operand(constant));
3192 __ sw(a2, MemOperand(t5));
3193 __ Addu(t5, t5, kPointerSize);
3194 }
3195 }
3196
3197 // Fill the unused in-object property fields with undefined.
3198 ASSERT(function->has_initial_map());
3199 for (int i = shared->this_property_assignments_count();
3200 i < function->initial_map()->inobject_properties();
3201 i++) {
3202 __ sw(t7, MemOperand(t5));
3203 __ Addu(t5, t5, kPointerSize);
3204 }
3205
3206 // a0: argc
3207 // t4: JSObject (not tagged)
3208 // Move argc to a1 and the JSObject to return to v0 and tag it.
3209 __ mov(a1, a0);
3210 __ mov(v0, t4);
3211 __ Or(v0, v0, Operand(kHeapObjectTag));
3212
3213 // v0: JSObject
3214 // a1: argc
3215 // Remove caller arguments and receiver from the stack and return.
3216 __ sll(t0, a1, kPointerSizeLog2);
3217 __ Addu(sp, sp, t0);
3218 __ Addu(sp, sp, Operand(kPointerSize));
3219 Counters* counters = masm()->isolate()->counters();
3220 __ IncrementCounter(counters->constructed_objects(), 1, a1, a2);
3221 __ IncrementCounter(counters->constructed_objects_stub(), 1, a1, a2);
3222 __ Ret();
3223
3224 // Jump to the generic stub in case the specialized code cannot handle the
3225 // construction.
3226 __ bind(&generic_stub_call);
3227 Handle<Code> generic_construct_stub =
3228 masm()->isolate()->builtins()->JSConstructStubGeneric();
3229 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
3230
3231 // Return the generated code.
3232 return GetCode();
3233}
3234
3235
danno@chromium.org40cb8782011-05-25 07:58:50 +00003236#undef __
3237#define __ ACCESS_MASM(masm)
3238
3239
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003240void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3241 MacroAssembler* masm) {
3242 // ---------- S t a t e --------------
3243 // -- ra : return address
3244 // -- a0 : key
3245 // -- a1 : receiver
3246 // -----------------------------------
3247 Label slow, miss_force_generic;
3248
3249 Register key = a0;
3250 Register receiver = a1;
3251
3252 __ JumpIfNotSmi(key, &miss_force_generic);
3253 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
3254 __ sra(a2, a0, kSmiTagSize);
3255 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
3256 __ Ret();
3257
3258 // Slow case, key and receiver still in a0 and a1.
3259 __ bind(&slow);
3260 __ IncrementCounter(
3261 masm->isolate()->counters()->keyed_load_external_array_slow(),
3262 1, a2, a3);
3263 // Entry registers are intact.
3264 // ---------- S t a t e --------------
3265 // -- ra : return address
3266 // -- a0 : key
3267 // -- a1 : receiver
3268 // -----------------------------------
3269 Handle<Code> slow_ic =
3270 masm->isolate()->builtins()->KeyedLoadIC_Slow();
3271 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
3272
3273 // Miss case, call the runtime.
3274 __ bind(&miss_force_generic);
3275
3276 // ---------- S t a t e --------------
3277 // -- ra : return address
3278 // -- a0 : key
3279 // -- a1 : receiver
3280 // -----------------------------------
3281
3282 Handle<Code> miss_ic =
3283 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3284 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3285}
3286
3287
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003288static bool IsElementTypeSigned(ElementsKind elements_kind) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003289 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003290 case EXTERNAL_BYTE_ELEMENTS:
3291 case EXTERNAL_SHORT_ELEMENTS:
3292 case EXTERNAL_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003293 return true;
3294
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003295 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3296 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3297 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3298 case EXTERNAL_PIXEL_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003299 return false;
3300
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003301 case EXTERNAL_FLOAT_ELEMENTS:
3302 case EXTERNAL_DOUBLE_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003303 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003304 case FAST_ELEMENTS:
3305 case FAST_DOUBLE_ELEMENTS:
3306 case DICTIONARY_ELEMENTS:
3307 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003308 UNREACHABLE();
3309 return false;
3310 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003311 return false;
lrn@chromium.org7516f052011-03-30 08:52:27 +00003312}
3313
3314
danno@chromium.org40cb8782011-05-25 07:58:50 +00003315void KeyedLoadStubCompiler::GenerateLoadExternalArray(
3316 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003317 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003318 // ---------- S t a t e --------------
3319 // -- ra : return address
3320 // -- a0 : key
3321 // -- a1 : receiver
3322 // -----------------------------------
danno@chromium.org40cb8782011-05-25 07:58:50 +00003323 Label miss_force_generic, slow, failed_allocation;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003324
3325 Register key = a0;
3326 Register receiver = a1;
3327
danno@chromium.org40cb8782011-05-25 07:58:50 +00003328 // This stub is meant to be tail-jumped to, the receiver must already
3329 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003330
3331 // Check that the key is a smi.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003332 __ JumpIfNotSmi(key, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003333
3334 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3335 // a3: elements array
3336
3337 // Check that the index is in range.
3338 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3339 __ sra(t2, key, kSmiTagSize);
3340 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003341 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003342
3343 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3344 // a3: base pointer of external storage
3345
3346 // We are not untagging smi key and instead work with it
3347 // as if it was premultiplied by 2.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003348 STATIC_ASSERT((kSmiTag == 0) && (kSmiTagSize == 1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003349
3350 Register value = a2;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003351 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003352 case EXTERNAL_BYTE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003353 __ srl(t2, key, 1);
3354 __ addu(t3, a3, t2);
3355 __ lb(value, MemOperand(t3, 0));
3356 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003357 case EXTERNAL_PIXEL_ELEMENTS:
3358 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003359 __ srl(t2, key, 1);
3360 __ addu(t3, a3, t2);
3361 __ lbu(value, MemOperand(t3, 0));
3362 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003363 case EXTERNAL_SHORT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003364 __ addu(t3, a3, key);
3365 __ lh(value, MemOperand(t3, 0));
3366 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003367 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003368 __ addu(t3, a3, key);
3369 __ lhu(value, MemOperand(t3, 0));
3370 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003371 case EXTERNAL_INT_ELEMENTS:
3372 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003373 __ sll(t2, key, 1);
3374 __ addu(t3, a3, t2);
3375 __ lw(value, MemOperand(t3, 0));
3376 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003377 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003378 __ sll(t3, t2, 2);
3379 __ addu(t3, a3, t3);
3380 if (CpuFeatures::IsSupported(FPU)) {
3381 CpuFeatures::Scope scope(FPU);
3382 __ lwc1(f0, MemOperand(t3, 0));
3383 } else {
3384 __ lw(value, MemOperand(t3, 0));
3385 }
3386 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003387 case EXTERNAL_DOUBLE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003388 __ sll(t2, key, 2);
3389 __ addu(t3, a3, t2);
3390 if (CpuFeatures::IsSupported(FPU)) {
3391 CpuFeatures::Scope scope(FPU);
3392 __ ldc1(f0, MemOperand(t3, 0));
3393 } else {
3394 // t3: pointer to the beginning of the double we want to load.
3395 __ lw(a2, MemOperand(t3, 0));
3396 __ lw(a3, MemOperand(t3, Register::kSizeInBytes));
3397 }
3398 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003399 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003400 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003401 case FAST_DOUBLE_ELEMENTS:
3402 case DICTIONARY_ELEMENTS:
3403 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003404 UNREACHABLE();
3405 break;
3406 }
3407
3408 // For integer array types:
3409 // a2: value
3410 // For float array type:
3411 // f0: value (if FPU is supported)
3412 // a2: value (if FPU is not supported)
3413 // For double array type:
3414 // f0: value (if FPU is supported)
3415 // a2/a3: value (if FPU is not supported)
3416
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003417 if (elements_kind == EXTERNAL_INT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003418 // For the Int and UnsignedInt array types, we need to see whether
3419 // the value can be represented in a Smi. If not, we need to convert
3420 // it to a HeapNumber.
3421 Label box_int;
3422 __ Subu(t3, value, Operand(0xC0000000)); // Non-smi value gives neg result.
3423 __ Branch(&box_int, lt, t3, Operand(zero_reg));
3424 // Tag integer as smi and return it.
3425 __ sll(v0, value, kSmiTagSize);
3426 __ Ret();
3427
3428 __ bind(&box_int);
3429 // Allocate a HeapNumber for the result and perform int-to-double
3430 // conversion.
3431 // The arm version uses a temporary here to save r0, but we don't need to
3432 // (a0 is not modified).
3433 __ LoadRoot(t1, Heap::kHeapNumberMapRootIndex);
3434 __ AllocateHeapNumber(v0, a3, t0, t1, &slow);
3435
3436 if (CpuFeatures::IsSupported(FPU)) {
3437 CpuFeatures::Scope scope(FPU);
3438 __ mtc1(value, f0);
3439 __ cvt_d_w(f0, f0);
3440 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag));
3441 __ Ret();
3442 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003443 Register dst1 = t2;
3444 Register dst2 = t3;
3445 FloatingPointHelper::Destination dest =
3446 FloatingPointHelper::kCoreRegisters;
3447 FloatingPointHelper::ConvertIntToDouble(masm,
3448 value,
3449 dest,
3450 f0,
3451 dst1,
3452 dst2,
3453 t1,
3454 f2);
3455 __ sw(dst1, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3456 __ sw(dst2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3457 __ Ret();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003458 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003459 } else if (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003460 // The test is different for unsigned int values. Since we need
3461 // the value to be in the range of a positive smi, we can't
3462 // handle either of the top two bits being set in the value.
3463 if (CpuFeatures::IsSupported(FPU)) {
3464 CpuFeatures::Scope scope(FPU);
3465 Label pl_box_int;
3466 __ And(t2, value, Operand(0xC0000000));
3467 __ Branch(&pl_box_int, ne, t2, Operand(zero_reg));
3468
3469 // It can fit in an Smi.
3470 // Tag integer as smi and return it.
3471 __ sll(v0, value, kSmiTagSize);
3472 __ Ret();
3473
3474 __ bind(&pl_box_int);
3475 // Allocate a HeapNumber for the result and perform int-to-double
3476 // conversion. Don't use a0 and a1 as AllocateHeapNumber clobbers all
3477 // registers - also when jumping due to exhausted young space.
3478 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3479 __ AllocateHeapNumber(v0, t2, t3, t6, &slow);
3480
3481 // This is replaced by a macro:
3482 // __ mtc1(value, f0); // LS 32-bits.
3483 // __ mtc1(zero_reg, f1); // MS 32-bits are all zero.
3484 // __ cvt_d_l(f0, f0); // Use 64 bit conv to get correct unsigned 32-bit.
3485
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003486 __ Cvt_d_uw(f0, value, f22);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003487
3488 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag));
3489
3490 __ Ret();
3491 } else {
3492 // Check whether unsigned integer fits into smi.
3493 Label box_int_0, box_int_1, done;
3494 __ And(t2, value, Operand(0x80000000));
3495 __ Branch(&box_int_0, ne, t2, Operand(zero_reg));
3496 __ And(t2, value, Operand(0x40000000));
3497 __ Branch(&box_int_1, ne, t2, Operand(zero_reg));
3498
3499 // Tag integer as smi and return it.
3500 __ sll(v0, value, kSmiTagSize);
3501 __ Ret();
3502
3503 Register hiword = value; // a2.
3504 Register loword = a3;
3505
3506 __ bind(&box_int_0);
3507 // Integer does not have leading zeros.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003508 GenerateUInt2Double(masm, hiword, loword, t0, 0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003509 __ Branch(&done);
3510
3511 __ bind(&box_int_1);
3512 // Integer has one leading zero.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003513 GenerateUInt2Double(masm, hiword, loword, t0, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003514
3515
3516 __ bind(&done);
3517 // Integer was converted to double in registers hiword:loword.
3518 // Wrap it into a HeapNumber. Don't use a0 and a1 as AllocateHeapNumber
3519 // clobbers all registers - also when jumping due to exhausted young
3520 // space.
3521 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3522 __ AllocateHeapNumber(t2, t3, t5, t6, &slow);
3523
3524 __ sw(hiword, FieldMemOperand(t2, HeapNumber::kExponentOffset));
3525 __ sw(loword, FieldMemOperand(t2, HeapNumber::kMantissaOffset));
3526
3527 __ mov(v0, t2);
3528 __ Ret();
3529 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003530 } else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003531 // For the floating-point array type, we need to always allocate a
3532 // HeapNumber.
3533 if (CpuFeatures::IsSupported(FPU)) {
3534 CpuFeatures::Scope scope(FPU);
3535 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3536 // AllocateHeapNumber clobbers all registers - also when jumping due to
3537 // exhausted young space.
3538 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3539 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3540 // The float (single) value is already in fpu reg f0 (if we use float).
3541 __ cvt_d_s(f0, f0);
3542 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag));
3543 __ Ret();
3544 } else {
3545 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3546 // AllocateHeapNumber clobbers all registers - also when jumping due to
3547 // exhausted young space.
3548 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3549 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3550 // FPU is not available, do manual single to double conversion.
3551
3552 // a2: floating point value (binary32).
3553 // v0: heap number for result
3554
3555 // Extract mantissa to t4.
3556 __ And(t4, value, Operand(kBinary32MantissaMask));
3557
3558 // Extract exponent to t5.
3559 __ srl(t5, value, kBinary32MantissaBits);
3560 __ And(t5, t5, Operand(kBinary32ExponentMask >> kBinary32MantissaBits));
3561
3562 Label exponent_rebiased;
3563 __ Branch(&exponent_rebiased, eq, t5, Operand(zero_reg));
3564
3565 __ li(t0, 0x7ff);
3566 __ Xor(t1, t5, Operand(0xFF));
3567 __ movz(t5, t0, t1); // Set t5 to 0x7ff only if t5 is equal to 0xff.
3568 __ Branch(&exponent_rebiased, eq, t0, Operand(0xff));
3569
3570 // Rebias exponent.
3571 __ Addu(t5,
3572 t5,
3573 Operand(-kBinary32ExponentBias + HeapNumber::kExponentBias));
3574
3575 __ bind(&exponent_rebiased);
3576 __ And(a2, value, Operand(kBinary32SignMask));
3577 value = no_reg;
3578 __ sll(t0, t5, HeapNumber::kMantissaBitsInTopWord);
3579 __ or_(a2, a2, t0);
3580
3581 // Shift mantissa.
3582 static const int kMantissaShiftForHiWord =
3583 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3584
3585 static const int kMantissaShiftForLoWord =
3586 kBitsPerInt - kMantissaShiftForHiWord;
3587
3588 __ srl(t0, t4, kMantissaShiftForHiWord);
3589 __ or_(a2, a2, t0);
3590 __ sll(a0, t4, kMantissaShiftForLoWord);
3591
3592 __ sw(a2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3593 __ sw(a0, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3594 __ Ret();
3595 }
3596
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003597 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003598 if (CpuFeatures::IsSupported(FPU)) {
3599 CpuFeatures::Scope scope(FPU);
3600 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3601 // AllocateHeapNumber clobbers all registers - also when jumping due to
3602 // exhausted young space.
3603 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3604 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3605 // The double value is already in f0
3606 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
3607 __ Ret();
3608 } else {
3609 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3610 // AllocateHeapNumber clobbers all registers - also when jumping due to
3611 // exhausted young space.
3612 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3613 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3614
3615 __ sw(a2, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3616 __ sw(a3, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3617 __ Ret();
3618 }
3619
3620 } else {
3621 // Tag integer as smi and return it.
3622 __ sll(v0, value, kSmiTagSize);
3623 __ Ret();
3624 }
3625
3626 // Slow case, key and receiver still in a0 and a1.
3627 __ bind(&slow);
3628 __ IncrementCounter(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003629 masm->isolate()->counters()->keyed_load_external_array_slow(),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003630 1, a2, a3);
3631
3632 // ---------- S t a t e --------------
3633 // -- ra : return address
3634 // -- a0 : key
3635 // -- a1 : receiver
3636 // -----------------------------------
3637
3638 __ Push(a1, a0);
3639
3640 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
3641
danno@chromium.org40cb8782011-05-25 07:58:50 +00003642 __ bind(&miss_force_generic);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003643 Handle<Code> stub =
3644 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3645 __ Jump(stub, RelocInfo::CODE_TARGET);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003646}
3647
3648
danno@chromium.org40cb8782011-05-25 07:58:50 +00003649void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3650 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003651 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003652 // ---------- S t a t e --------------
3653 // -- a0 : value
3654 // -- a1 : key
3655 // -- a2 : receiver
3656 // -- ra : return address
3657 // -----------------------------------
3658
danno@chromium.org40cb8782011-05-25 07:58:50 +00003659 Label slow, check_heap_number, miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003660
3661 // Register usage.
3662 Register value = a0;
3663 Register key = a1;
3664 Register receiver = a2;
3665 // a3 mostly holds the elements array or the destination external array.
3666
danno@chromium.org40cb8782011-05-25 07:58:50 +00003667 // This stub is meant to be tail-jumped to, the receiver must already
3668 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003669
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003670 // Check that the key is a smi.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003671 __ JumpIfNotSmi(key, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003672
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003673 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3674
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003675 // Check that the index is in range.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003676 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3677 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003678 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003679
3680 // Handle both smis and HeapNumbers in the fast path. Go to the
3681 // runtime for all other kinds of values.
3682 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003683
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003684 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003685 // Double to pixel conversion is only implemented in the runtime for now.
3686 __ JumpIfNotSmi(value, &slow);
3687 } else {
3688 __ JumpIfNotSmi(value, &check_heap_number);
3689 }
3690 __ SmiUntag(t1, value);
3691 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3692
3693 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003694 // t1: value (integer).
3695
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003696 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003697 case EXTERNAL_PIXEL_ELEMENTS: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003698 // Clamp the value to [0..255].
3699 // v0 is used as a scratch register here.
3700 Label done;
3701 __ li(v0, Operand(255));
3702 // Normal branch: nop in delay slot.
3703 __ Branch(&done, gt, t1, Operand(v0));
3704 // Use delay slot in this branch.
3705 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg));
3706 __ mov(v0, zero_reg); // In delay slot.
3707 __ mov(v0, t1); // Value is in range 0..255.
3708 __ bind(&done);
3709 __ mov(t1, v0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003710
3711 __ srl(t8, key, 1);
3712 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003713 __ sb(t1, MemOperand(t8, 0));
3714 }
3715 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003716 case EXTERNAL_BYTE_ELEMENTS:
3717 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003718 __ srl(t8, key, 1);
3719 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003720 __ sb(t1, MemOperand(t8, 0));
3721 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003722 case EXTERNAL_SHORT_ELEMENTS:
3723 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003724 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003725 __ sh(t1, MemOperand(t8, 0));
3726 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003727 case EXTERNAL_INT_ELEMENTS:
3728 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003729 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003730 __ addu(t8, a3, t8);
3731 __ sw(t1, MemOperand(t8, 0));
3732 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003733 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003734 // Perform int-to-float conversion and store to memory.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003735 __ SmiUntag(t0, key);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003736 StoreIntAsFloat(masm, a3, t0, t1, t2, t3, t4);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003737 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003738 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003739 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003740 __ addu(a3, a3, t8);
3741 // a3: effective address of the double element
3742 FloatingPointHelper::Destination destination;
3743 if (CpuFeatures::IsSupported(FPU)) {
3744 destination = FloatingPointHelper::kFPURegisters;
3745 } else {
3746 destination = FloatingPointHelper::kCoreRegisters;
3747 }
3748 FloatingPointHelper::ConvertIntToDouble(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003749 masm, t1, destination,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003750 f0, t2, t3, // These are: double_dst, dst1, dst2.
3751 t0, f2); // These are: scratch2, single_scratch.
3752 if (destination == FloatingPointHelper::kFPURegisters) {
3753 CpuFeatures::Scope scope(FPU);
3754 __ sdc1(f0, MemOperand(a3, 0));
3755 } else {
3756 __ sw(t2, MemOperand(a3, 0));
3757 __ sw(t3, MemOperand(a3, Register::kSizeInBytes));
3758 }
3759 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003760 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003761 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003762 case FAST_DOUBLE_ELEMENTS:
3763 case DICTIONARY_ELEMENTS:
3764 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003765 UNREACHABLE();
3766 break;
3767 }
3768
3769 // Entry registers are intact, a0 holds the value which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003770 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003771 __ Ret();
3772
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003773 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003774 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003775 __ bind(&check_heap_number);
3776 __ GetObjectType(value, t1, t2);
3777 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE));
3778
3779 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3780
3781 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003782
3783 // The WebGL specification leaves the behavior of storing NaN and
3784 // +/-Infinity into integer arrays basically undefined. For more
3785 // reproducible behavior, convert these to zero.
3786
3787 if (CpuFeatures::IsSupported(FPU)) {
3788 CpuFeatures::Scope scope(FPU);
3789
3790 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
3791
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003792 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003793 __ cvt_s_d(f0, f0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003794 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003795 __ addu(t8, a3, t8);
3796 __ swc1(f0, MemOperand(t8, 0));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003797 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003798 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003799 __ addu(t8, a3, t8);
3800 __ sdc1(f0, MemOperand(t8, 0));
3801 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003802 __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003803
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003804 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003805 case EXTERNAL_BYTE_ELEMENTS:
3806 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003807 __ srl(t8, key, 1);
3808 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003809 __ sb(t3, MemOperand(t8, 0));
3810 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003811 case EXTERNAL_SHORT_ELEMENTS:
3812 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003813 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003814 __ sh(t3, MemOperand(t8, 0));
3815 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003816 case EXTERNAL_INT_ELEMENTS:
3817 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003818 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003819 __ addu(t8, a3, t8);
3820 __ sw(t3, MemOperand(t8, 0));
3821 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003822 case EXTERNAL_PIXEL_ELEMENTS:
3823 case EXTERNAL_FLOAT_ELEMENTS:
3824 case EXTERNAL_DOUBLE_ELEMENTS:
3825 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003826 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003827 case FAST_DOUBLE_ELEMENTS:
3828 case DICTIONARY_ELEMENTS:
3829 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003830 UNREACHABLE();
3831 break;
3832 }
3833 }
3834
3835 // Entry registers are intact, a0 holds the value
3836 // which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003837 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003838 __ Ret();
3839 } else {
3840 // FPU is not available, do manual conversions.
3841
3842 __ lw(t3, FieldMemOperand(value, HeapNumber::kExponentOffset));
3843 __ lw(t4, FieldMemOperand(value, HeapNumber::kMantissaOffset));
3844
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003845 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003846 Label done, nan_or_infinity_or_zero;
3847 static const int kMantissaInHiWordShift =
3848 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3849
3850 static const int kMantissaInLoWordShift =
3851 kBitsPerInt - kMantissaInHiWordShift;
3852
3853 // Test for all special exponent values: zeros, subnormal numbers, NaNs
3854 // and infinities. All these should be converted to 0.
3855 __ li(t5, HeapNumber::kExponentMask);
3856 __ and_(t6, t3, t5);
3857 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(zero_reg));
3858
3859 __ xor_(t1, t6, t5);
3860 __ li(t2, kBinary32ExponentMask);
3861 __ movz(t6, t2, t1); // Only if t6 is equal to t5.
3862 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(t5));
3863
3864 // Rebias exponent.
3865 __ srl(t6, t6, HeapNumber::kExponentShift);
3866 __ Addu(t6,
3867 t6,
3868 Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
3869
3870 __ li(t1, Operand(kBinary32MaxExponent));
3871 __ Slt(t1, t1, t6);
3872 __ And(t2, t3, Operand(HeapNumber::kSignMask));
3873 __ Or(t2, t2, Operand(kBinary32ExponentMask));
3874 __ movn(t3, t2, t1); // Only if t6 is gt kBinary32MaxExponent.
3875 __ Branch(&done, gt, t6, Operand(kBinary32MaxExponent));
3876
3877 __ Slt(t1, t6, Operand(kBinary32MinExponent));
3878 __ And(t2, t3, Operand(HeapNumber::kSignMask));
3879 __ movn(t3, t2, t1); // Only if t6 is lt kBinary32MinExponent.
3880 __ Branch(&done, lt, t6, Operand(kBinary32MinExponent));
3881
3882 __ And(t7, t3, Operand(HeapNumber::kSignMask));
3883 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3884 __ sll(t3, t3, kMantissaInHiWordShift);
3885 __ or_(t7, t7, t3);
3886 __ srl(t4, t4, kMantissaInLoWordShift);
3887 __ or_(t7, t7, t4);
3888 __ sll(t6, t6, kBinary32ExponentShift);
3889 __ or_(t3, t7, t6);
3890
3891 __ bind(&done);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003892 __ sll(t9, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003893 __ addu(t9, a2, t9);
3894 __ sw(t3, MemOperand(t9, 0));
3895
3896 // Entry registers are intact, a0 holds the value which is the return
3897 // value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003898 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003899 __ Ret();
3900
3901 __ bind(&nan_or_infinity_or_zero);
3902 __ And(t7, t3, Operand(HeapNumber::kSignMask));
3903 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3904 __ or_(t6, t6, t7);
3905 __ sll(t3, t3, kMantissaInHiWordShift);
3906 __ or_(t6, t6, t3);
3907 __ srl(t4, t4, kMantissaInLoWordShift);
3908 __ or_(t3, t6, t4);
3909 __ Branch(&done);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003910 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003911 __ sll(t8, t0, 3);
3912 __ addu(t8, a3, t8);
3913 // t8: effective address of destination element.
3914 __ sw(t4, MemOperand(t8, 0));
3915 __ sw(t3, MemOperand(t8, Register::kSizeInBytes));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003916 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003917 __ Ret();
3918 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003919 bool is_signed_type = IsElementTypeSigned(elements_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003920 int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
3921 int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
3922
3923 Label done, sign;
3924
3925 // Test for all special exponent values: zeros, subnormal numbers, NaNs
3926 // and infinities. All these should be converted to 0.
3927 __ li(t5, HeapNumber::kExponentMask);
3928 __ and_(t6, t3, t5);
3929 __ movz(t3, zero_reg, t6); // Only if t6 is equal to zero.
3930 __ Branch(&done, eq, t6, Operand(zero_reg));
3931
3932 __ xor_(t2, t6, t5);
3933 __ movz(t3, zero_reg, t2); // Only if t6 is equal to t5.
3934 __ Branch(&done, eq, t6, Operand(t5));
3935
3936 // Unbias exponent.
3937 __ srl(t6, t6, HeapNumber::kExponentShift);
3938 __ Subu(t6, t6, Operand(HeapNumber::kExponentBias));
3939 // If exponent is negative then result is 0.
3940 __ slt(t2, t6, zero_reg);
3941 __ movn(t3, zero_reg, t2); // Only if exponent is negative.
3942 __ Branch(&done, lt, t6, Operand(zero_reg));
3943
3944 // If exponent is too big then result is minimal value.
3945 __ slti(t1, t6, meaningfull_bits - 1);
3946 __ li(t2, min_value);
3947 __ movz(t3, t2, t1); // Only if t6 is ge meaningfull_bits - 1.
3948 __ Branch(&done, ge, t6, Operand(meaningfull_bits - 1));
3949
3950 __ And(t5, t3, Operand(HeapNumber::kSignMask));
3951 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3952 __ Or(t3, t3, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
3953
3954 __ li(t9, HeapNumber::kMantissaBitsInTopWord);
3955 __ subu(t6, t9, t6);
3956 __ slt(t1, t6, zero_reg);
3957 __ srlv(t2, t3, t6);
3958 __ movz(t3, t2, t1); // Only if t6 is positive.
3959 __ Branch(&sign, ge, t6, Operand(zero_reg));
3960
3961 __ subu(t6, zero_reg, t6);
3962 __ sllv(t3, t3, t6);
3963 __ li(t9, meaningfull_bits);
3964 __ subu(t6, t9, t6);
3965 __ srlv(t4, t4, t6);
3966 __ or_(t3, t3, t4);
3967
3968 __ bind(&sign);
3969 __ subu(t2, t3, zero_reg);
3970 __ movz(t3, t2, t5); // Only if t5 is zero.
3971
3972 __ bind(&done);
3973
3974 // Result is in t3.
3975 // This switch block should be exactly the same as above (FPU mode).
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003976 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003977 case EXTERNAL_BYTE_ELEMENTS:
3978 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003979 __ srl(t8, key, 1);
3980 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003981 __ sb(t3, MemOperand(t8, 0));
3982 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003983 case EXTERNAL_SHORT_ELEMENTS:
3984 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003985 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003986 __ sh(t3, MemOperand(t8, 0));
3987 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003988 case EXTERNAL_INT_ELEMENTS:
3989 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003990 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003991 __ addu(t8, a3, t8);
3992 __ sw(t3, MemOperand(t8, 0));
3993 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003994 case EXTERNAL_PIXEL_ELEMENTS:
3995 case EXTERNAL_FLOAT_ELEMENTS:
3996 case EXTERNAL_DOUBLE_ELEMENTS:
3997 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003998 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003999 case FAST_DOUBLE_ELEMENTS:
4000 case DICTIONARY_ELEMENTS:
4001 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004002 UNREACHABLE();
4003 break;
4004 }
4005 }
4006 }
4007 }
4008
danno@chromium.org40cb8782011-05-25 07:58:50 +00004009 // Slow case, key and receiver still in a0 and a1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004010 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004011 __ IncrementCounter(
4012 masm->isolate()->counters()->keyed_load_external_array_slow(),
4013 1, a2, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004014 // Entry registers are intact.
4015 // ---------- S t a t e --------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004016 // -- ra : return address
danno@chromium.org40cb8782011-05-25 07:58:50 +00004017 // -- a0 : key
4018 // -- a1 : receiver
4019 // -----------------------------------
4020 Handle<Code> slow_ic =
4021 masm->isolate()->builtins()->KeyedStoreIC_Slow();
4022 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4023
4024 // Miss case, call the runtime.
4025 __ bind(&miss_force_generic);
4026
4027 // ---------- S t a t e --------------
4028 // -- ra : return address
4029 // -- a0 : key
4030 // -- a1 : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004031 // -----------------------------------
4032
danno@chromium.org40cb8782011-05-25 07:58:50 +00004033 Handle<Code> miss_ic =
4034 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4035 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
4036}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004037
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004038
danno@chromium.org40cb8782011-05-25 07:58:50 +00004039void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
4040 // ----------- S t a t e -------------
4041 // -- ra : return address
4042 // -- a0 : key
4043 // -- a1 : receiver
4044 // -----------------------------------
4045 Label miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004046
danno@chromium.org40cb8782011-05-25 07:58:50 +00004047 // This stub is meant to be tail-jumped to, the receiver must already
4048 // have been verified by the caller to not be a smi.
4049
4050 // Check that the key is a smi.
4051 __ JumpIfNotSmi(a0, &miss_force_generic);
4052
4053 // Get the elements array.
4054 __ lw(a2, FieldMemOperand(a1, JSObject::kElementsOffset));
4055 __ AssertFastElements(a2);
4056
4057 // Check that the key is within bounds.
4058 __ lw(a3, FieldMemOperand(a2, FixedArray::kLengthOffset));
4059 __ Branch(&miss_force_generic, hs, a0, Operand(a3));
4060
4061 // Load the result and make sure it's not the hole.
4062 __ Addu(a3, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004063 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004064 __ sll(t0, a0, kPointerSizeLog2 - kSmiTagSize);
4065 __ Addu(t0, t0, a3);
4066 __ lw(t0, MemOperand(t0));
4067 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
4068 __ Branch(&miss_force_generic, eq, t0, Operand(t1));
4069 __ mov(v0, t0);
4070 __ Ret();
4071
4072 __ bind(&miss_force_generic);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004073 Handle<Code> stub =
4074 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4075 __ Jump(stub, RelocInfo::CODE_TARGET);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004076}
4077
4078
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004079void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
4080 MacroAssembler* masm) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004081 // ----------- S t a t e -------------
4082 // -- ra : return address
4083 // -- a0 : key
4084 // -- a1 : receiver
4085 // -----------------------------------
4086 Label miss_force_generic, slow_allocate_heapnumber;
4087
4088 Register key_reg = a0;
4089 Register receiver_reg = a1;
4090 Register elements_reg = a2;
4091 Register heap_number_reg = a2;
4092 Register indexed_double_offset = a3;
4093 Register scratch = t0;
4094 Register scratch2 = t1;
4095 Register scratch3 = t2;
4096 Register heap_number_map = t3;
4097
4098 // This stub is meant to be tail-jumped to, the receiver must already
4099 // have been verified by the caller to not be a smi.
4100
4101 // Check that the key is a smi.
4102 __ JumpIfNotSmi(key_reg, &miss_force_generic);
4103
4104 // Get the elements array.
4105 __ lw(elements_reg,
4106 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4107
4108 // Check that the key is within bounds.
4109 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4110 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4111
4112 // Load the upper word of the double in the fixed array and test for NaN.
4113 __ sll(scratch2, key_reg, kDoubleSizeLog2 - kSmiTagSize);
4114 __ Addu(indexed_double_offset, elements_reg, Operand(scratch2));
4115 uint32_t upper_32_offset = FixedArray::kHeaderSize + sizeof(kHoleNanLower32);
4116 __ lw(scratch, FieldMemOperand(indexed_double_offset, upper_32_offset));
4117 __ Branch(&miss_force_generic, eq, scratch, Operand(kHoleNanUpper32));
4118
4119 // Non-NaN. Allocate a new heap number and copy the double value into it.
4120 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
4121 __ AllocateHeapNumber(heap_number_reg, scratch2, scratch3,
4122 heap_number_map, &slow_allocate_heapnumber);
4123
4124 // Don't need to reload the upper 32 bits of the double, it's already in
4125 // scratch.
4126 __ sw(scratch, FieldMemOperand(heap_number_reg,
4127 HeapNumber::kExponentOffset));
4128 __ lw(scratch, FieldMemOperand(indexed_double_offset,
4129 FixedArray::kHeaderSize));
4130 __ sw(scratch, FieldMemOperand(heap_number_reg,
4131 HeapNumber::kMantissaOffset));
4132
4133 __ mov(v0, heap_number_reg);
4134 __ Ret();
4135
4136 __ bind(&slow_allocate_heapnumber);
4137 Handle<Code> slow_ic =
4138 masm->isolate()->builtins()->KeyedLoadIC_Slow();
4139 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4140
4141 __ bind(&miss_force_generic);
4142 Handle<Code> miss_ic =
4143 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4144 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004145}
4146
4147
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004148void KeyedStoreStubCompiler::GenerateStoreFastElement(
4149 MacroAssembler* masm,
4150 bool is_js_array,
4151 ElementsKind elements_kind) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00004152 // ----------- S t a t e -------------
4153 // -- a0 : value
4154 // -- a1 : key
4155 // -- a2 : receiver
4156 // -- ra : return address
4157 // -- a3 : scratch
4158 // -- a4 : scratch (elements)
4159 // -----------------------------------
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004160 Label miss_force_generic, transition_elements_kind;
danno@chromium.org40cb8782011-05-25 07:58:50 +00004161
4162 Register value_reg = a0;
4163 Register key_reg = a1;
4164 Register receiver_reg = a2;
4165 Register scratch = a3;
4166 Register elements_reg = t0;
4167 Register scratch2 = t1;
4168 Register scratch3 = t2;
4169
4170 // This stub is meant to be tail-jumped to, the receiver must already
4171 // have been verified by the caller to not be a smi.
4172
4173 // Check that the key is a smi.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00004174 __ JumpIfNotSmi(key_reg, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004175
4176 // Get the elements array and make sure it is a fast element array, not 'cow'.
4177 __ lw(elements_reg,
4178 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4179 __ CheckMap(elements_reg,
4180 scratch,
4181 Heap::kFixedArrayMapRootIndex,
4182 &miss_force_generic,
4183 DONT_DO_SMI_CHECK);
4184
4185 // Check that the key is within bounds.
4186 if (is_js_array) {
4187 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4188 } else {
4189 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4190 }
4191 // Compare smis.
4192 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4193
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004194 if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
4195 __ JumpIfNotSmi(value_reg, &transition_elements_kind);
4196 __ Addu(scratch,
4197 elements_reg,
4198 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4199 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4200 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4201 __ Addu(scratch, scratch, scratch2);
4202 __ sw(value_reg, MemOperand(scratch));
4203 } else {
4204 ASSERT(elements_kind == FAST_ELEMENTS);
4205 __ Addu(scratch,
4206 elements_reg,
4207 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4208 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4209 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4210 __ Addu(scratch, scratch, scratch2);
4211 __ sw(value_reg, MemOperand(scratch));
4212 __ mov(receiver_reg, value_reg);
4213 ASSERT(elements_kind == FAST_ELEMENTS);
4214 __ RecordWrite(elements_reg, // Object.
4215 scratch, // Address.
4216 receiver_reg, // Value.
4217 kRAHasNotBeenSaved,
4218 kDontSaveFPRegs);
4219 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004220 // value_reg (a0) is preserved.
4221 // Done.
4222 __ Ret();
4223
4224 __ bind(&miss_force_generic);
4225 Handle<Code> ic =
4226 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4227 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004228
4229 __ bind(&transition_elements_kind);
4230 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4231 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004232}
4233
4234
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004235void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
4236 MacroAssembler* masm,
4237 bool is_js_array) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004238 // ----------- S t a t e -------------
4239 // -- a0 : value
4240 // -- a1 : key
4241 // -- a2 : receiver
4242 // -- ra : return address
4243 // -- a3 : scratch
4244 // -- t0 : scratch (elements_reg)
4245 // -- t1 : scratch (mantissa_reg)
4246 // -- t2 : scratch (exponent_reg)
4247 // -- t3 : scratch4
4248 // -----------------------------------
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004249 Label miss_force_generic, transition_elements_kind;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004250
4251 Register value_reg = a0;
4252 Register key_reg = a1;
4253 Register receiver_reg = a2;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004254 Register elements_reg = a3;
4255 Register scratch1 = t0;
4256 Register scratch2 = t1;
4257 Register scratch3 = t2;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004258 Register scratch4 = t3;
4259
4260 // This stub is meant to be tail-jumped to, the receiver must already
4261 // have been verified by the caller to not be a smi.
4262 __ JumpIfNotSmi(key_reg, &miss_force_generic);
4263
4264 __ lw(elements_reg,
4265 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4266
4267 // Check that the key is within bounds.
4268 if (is_js_array) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004269 __ lw(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004270 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004271 __ lw(scratch1,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004272 FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4273 }
4274 // Compare smis, unsigned compare catches both negative and out-of-bound
4275 // indexes.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004276 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch1));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004277
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004278 __ StoreNumberToDoubleElements(value_reg,
4279 key_reg,
4280 receiver_reg,
4281 elements_reg,
4282 scratch1,
4283 scratch2,
4284 scratch3,
4285 scratch4,
4286 &transition_elements_kind);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004287
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004288 __ Ret(USE_DELAY_SLOT);
4289 __ mov(v0, value_reg); // In delay slot.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004290
4291 // Handle store cache miss, replacing the ic with the generic stub.
4292 __ bind(&miss_force_generic);
4293 Handle<Code> ic =
4294 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4295 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004296
4297 __ bind(&transition_elements_kind);
4298 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4299 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004300}
4301
4302
ager@chromium.org5c838252010-02-19 08:53:10 +00004303#undef __
4304
4305} } // namespace v8::internal
4306
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004307#endif // V8_TARGET_ARCH_MIPS