blob: 97a58c763b79ab5df446e2db33ff42f4132b3ac9 [file] [log] [blame]
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001// Copyright 2011 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;
380
381 // Check that the receiver isn't a smi.
382 __ JumpIfSmi(receiver_reg, miss_label, scratch);
383
384 // Check that the map of the receiver hasn't changed.
385 __ lw(scratch, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
386 __ Branch(miss_label, ne, scratch, Operand(Handle<Map>(object->map())));
387
388 // Perform global security token check if needed.
389 if (object->IsJSGlobalProxy()) {
390 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
391 }
392
393 // Stub never generated for non-global objects that require access
394 // checks.
395 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
396
397 // Perform map transition for the receiver if necessary.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000398 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000399 // The properties must be extended before we can store the value.
400 // We jump to a runtime call that extends the properties array.
401 __ push(receiver_reg);
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000402 __ li(a2, Operand(transition));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000403 __ Push(a2, a0);
404 __ TailCallExternalReference(
405 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
406 masm->isolate()),
407 3, 1);
408 return;
409 }
410
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000411 if (!transition.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000412 // Update the map of the object; no write barrier updating is
413 // needed because the map is never in new space.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000414 __ li(t0, Operand(transition));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000415 __ sw(t0, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
416 }
417
418 // Adjust for the number of properties stored in the object. Even in the
419 // face of a transition we can use the old map here because the size of the
420 // object and the number of in-object properties is not going to change.
421 index -= object->map()->inobject_properties();
422
423 if (index < 0) {
424 // Set the property straight into the object.
425 int offset = object->map()->instance_size() + (index * kPointerSize);
426 __ sw(a0, FieldMemOperand(receiver_reg, offset));
427
428 // Skip updating write barrier if storing a smi.
429 __ JumpIfSmi(a0, &exit, scratch);
430
431 // Update the write barrier for the array address.
432 // Pass the now unused name_reg as a scratch register.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000433 __ mov(name_reg, a0);
434 __ RecordWriteField(receiver_reg,
435 offset,
436 name_reg,
437 scratch,
438 kRAHasNotBeenSaved,
439 kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000440 } else {
441 // Write to the properties array.
442 int offset = index * kPointerSize + FixedArray::kHeaderSize;
443 // Get the properties array.
444 __ lw(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
445 __ sw(a0, FieldMemOperand(scratch, offset));
446
447 // Skip updating write barrier if storing a smi.
448 __ JumpIfSmi(a0, &exit);
449
450 // Update the write barrier for the array address.
451 // Ok to clobber receiver_reg and name_reg, since we return.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000452 __ mov(name_reg, a0);
453 __ RecordWriteField(scratch,
454 offset,
455 name_reg,
456 receiver_reg,
457 kRAHasNotBeenSaved,
458 kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000459 }
460
461 // Return the value (register v0).
462 __ bind(&exit);
463 __ mov(v0, a0);
464 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000465}
466
467
468void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000469 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000470 Handle<Code> code = (kind == Code::LOAD_IC)
471 ? masm->isolate()->builtins()->LoadIC_Miss()
472 : masm->isolate()->builtins()->KeyedLoadIC_Miss();
473 __ Jump(code, RelocInfo::CODE_TARGET);
ager@chromium.org5c838252010-02-19 08:53:10 +0000474}
475
476
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000477static void GenerateCallFunction(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000478 Handle<Object> object,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000479 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000480 Label* miss,
481 Code::ExtraICState extra_ic_state) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000482 // ----------- S t a t e -------------
483 // -- a0: receiver
484 // -- a1: function to call
485 // -----------------------------------
486 // Check that the function really is a function.
487 __ JumpIfSmi(a1, miss);
488 __ GetObjectType(a1, a3, a3);
489 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
490
491 // Patch the receiver on the stack with the global proxy if
492 // necessary.
493 if (object->IsGlobalObject()) {
494 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
495 __ sw(a3, MemOperand(sp, arguments.immediate() * kPointerSize));
496 }
497
498 // Invoke the function.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000499 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
500 ? CALL_AS_FUNCTION
501 : CALL_AS_METHOD;
502 __ InvokeFunction(a1, arguments, JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000503}
504
505
506static void PushInterceptorArguments(MacroAssembler* masm,
507 Register receiver,
508 Register holder,
509 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000510 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000511 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000512 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
513 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000514 Register scratch = name;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000515 __ li(scratch, Operand(interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000516 __ Push(scratch, receiver, holder);
517 __ lw(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
518 __ push(scratch);
519}
520
521
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000522static void CompileCallLoadPropertyWithInterceptor(
523 MacroAssembler* masm,
524 Register receiver,
525 Register holder,
526 Register name,
527 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000528 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
529
530 ExternalReference ref =
531 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
532 masm->isolate());
533 __ li(a0, Operand(5));
534 __ li(a1, Operand(ref));
535
536 CEntryStub stub(1);
537 __ CallStub(&stub);
538}
539
540
541static const int kFastApiCallArguments = 3;
542
543
544// Reserves space for the extra arguments to FastHandleApiCall in the
545// caller's frame.
546//
547// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
548static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
549 Register scratch) {
550 ASSERT(Smi::FromInt(0) == 0);
551 for (int i = 0; i < kFastApiCallArguments; i++) {
552 __ push(zero_reg);
553 }
554}
555
556
557// Undoes the effects of ReserveSpaceForFastApiCall.
558static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
559 __ Drop(kFastApiCallArguments);
560}
561
562
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000563static void GenerateFastApiDirectCall(MacroAssembler* masm,
564 const CallOptimization& optimization,
565 int argc) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000566 // ----------- S t a t e -------------
567 // -- sp[0] : holder (set by CheckPrototypes)
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000568 // -- sp[4] : callee JS function
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000569 // -- sp[8] : call data
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000570 // -- sp[12] : last JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000571 // -- ...
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000572 // -- sp[(argc + 3) * 4] : first JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000573 // -- sp[(argc + 4) * 4] : receiver
574 // -----------------------------------
575 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000576 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000577 __ LoadHeapObject(t1, function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000578 __ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset));
579
580 // Pass the additional arguments FastHandleApiCall expects.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000581 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
582 Handle<Object> call_data(api_call_info->data());
583 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
584 __ li(a0, api_call_info);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000585 __ lw(t2, FieldMemOperand(a0, CallHandlerInfo::kDataOffset));
586 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000587 __ li(t2, call_data);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000588 }
589
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000590 // Store JS function and call data.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000591 __ sw(t1, MemOperand(sp, 1 * kPointerSize));
592 __ sw(t2, MemOperand(sp, 2 * kPointerSize));
593
594 // a2 points to call data as expected by Arguments
595 // (refer to layout above).
596 __ Addu(a2, sp, Operand(2 * kPointerSize));
597
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000598 const int kApiStackSpace = 4;
599
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000600 FrameScope frame_scope(masm, StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000601 __ EnterExitFrame(false, kApiStackSpace);
602
603 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
604 // struct from the function (which is currently the case). This means we pass
605 // the first argument in a1 instead of a0. TryCallApiFunctionAndReturn
606 // will handle setting up a0.
607
608 // a1 = v8::Arguments&
609 // Arguments is built at sp + 1 (sp is a reserved spot for ra).
610 __ Addu(a1, sp, kPointerSize);
611
612 // v8::Arguments::implicit_args = data
613 __ sw(a2, MemOperand(a1, 0 * kPointerSize));
614 // v8::Arguments::values = last argument
615 __ Addu(t0, a2, Operand(argc * kPointerSize));
616 __ sw(t0, MemOperand(a1, 1 * kPointerSize));
617 // v8::Arguments::length_ = argc
618 __ li(t0, Operand(argc));
619 __ sw(t0, MemOperand(a1, 2 * kPointerSize));
620 // v8::Arguments::is_construct_call = 0
621 __ sw(zero_reg, MemOperand(a1, 3 * kPointerSize));
622
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000623 const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000624 Address function_address = v8::ToCData<Address>(api_call_info->callback());
625 ApiFunction fun(function_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000626 ExternalReference ref =
627 ExternalReference(&fun,
628 ExternalReference::DIRECT_API_CALL,
629 masm->isolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000630 AllowExternalCallThatCantCauseGC scope(masm);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000631 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000632}
633
lrn@chromium.org7516f052011-03-30 08:52:27 +0000634class CallInterceptorCompiler BASE_EMBEDDED {
635 public:
636 CallInterceptorCompiler(StubCompiler* stub_compiler,
637 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000638 Register name,
639 Code::ExtraICState extra_ic_state)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000640 : stub_compiler_(stub_compiler),
641 arguments_(arguments),
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000642 name_(name),
643 extra_ic_state_(extra_ic_state) {}
lrn@chromium.org7516f052011-03-30 08:52:27 +0000644
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000645 void Compile(MacroAssembler* masm,
646 Handle<JSObject> object,
647 Handle<JSObject> holder,
648 Handle<String> name,
649 LookupResult* lookup,
650 Register receiver,
651 Register scratch1,
652 Register scratch2,
653 Register scratch3,
654 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000655 ASSERT(holder->HasNamedInterceptor());
656 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
657
658 // Check that the receiver isn't a smi.
659 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000660 CallOptimization optimization(lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000661 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000662 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
663 holder, lookup, name, optimization, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000664 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000665 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
666 name, holder, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000667 }
668 }
669
670 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000671 void CompileCacheable(MacroAssembler* masm,
672 Handle<JSObject> object,
673 Register receiver,
674 Register scratch1,
675 Register scratch2,
676 Register scratch3,
677 Handle<JSObject> interceptor_holder,
678 LookupResult* lookup,
679 Handle<String> name,
680 const CallOptimization& optimization,
681 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000682 ASSERT(optimization.is_constant_call());
683 ASSERT(!lookup->holder()->IsGlobalObject());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000684 Counters* counters = masm->isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000685 int depth1 = kInvalidProtoDepth;
686 int depth2 = kInvalidProtoDepth;
687 bool can_do_fast_api_call = false;
688 if (optimization.is_simple_api_call() &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000689 !lookup->holder()->IsGlobalObject()) {
690 depth1 = optimization.GetPrototypeDepthOfExpectedType(
691 object, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000692 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000693 depth2 = optimization.GetPrototypeDepthOfExpectedType(
694 interceptor_holder, Handle<JSObject>(lookup->holder()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000695 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000696 can_do_fast_api_call =
697 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000698 }
699
700 __ IncrementCounter(counters->call_const_interceptor(), 1,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000701 scratch1, scratch2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000702
703 if (can_do_fast_api_call) {
704 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
705 scratch1, scratch2);
706 ReserveSpaceForFastApiCall(masm, scratch1);
707 }
708
709 // Check that the maps from receiver to interceptor's holder
710 // haven't changed and thus we can invoke interceptor.
711 Label miss_cleanup;
712 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
713 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000714 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
715 scratch1, scratch2, scratch3,
716 name, depth1, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000717
718 // Invoke an interceptor and if it provides a value,
719 // branch to |regular_invoke|.
720 Label regular_invoke;
721 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
722 &regular_invoke);
723
724 // Interceptor returned nothing for this property. Try to use cached
725 // constant function.
726
727 // Check that the maps from interceptor's holder to constant function's
728 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000729 if (*interceptor_holder != lookup->holder()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000730 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000731 Handle<JSObject>(lookup->holder()),
732 scratch1, scratch2, scratch3,
733 name, depth2, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000734 } else {
735 // CheckPrototypes has a side effect of fetching a 'holder'
736 // for API (object which is instanceof for the signature). It's
737 // safe to omit it here, as if present, it should be fetched
738 // by the previous CheckPrototypes.
739 ASSERT(depth2 == kInvalidProtoDepth);
740 }
741
742 // Invoke function.
743 if (can_do_fast_api_call) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000744 GenerateFastApiDirectCall(masm, optimization, arguments_.immediate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000745 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000746 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
747 ? CALL_AS_FUNCTION
748 : CALL_AS_METHOD;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000749 __ InvokeFunction(optimization.constant_function(), arguments_,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000750 JUMP_FUNCTION, call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000751 }
752
753 // Deferred code for fast API call case---clean preallocated space.
754 if (can_do_fast_api_call) {
755 __ bind(&miss_cleanup);
756 FreeSpaceForFastApiCall(masm);
757 __ Branch(miss_label);
758 }
759
760 // Invoke a regular function.
761 __ bind(&regular_invoke);
762 if (can_do_fast_api_call) {
763 FreeSpaceForFastApiCall(masm);
764 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000765 }
766
767 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000768 Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000769 Register receiver,
770 Register scratch1,
771 Register scratch2,
772 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000773 Handle<String> name,
774 Handle<JSObject> interceptor_holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000775 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000776 Register holder =
777 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000778 scratch1, scratch2, scratch3,
779 name, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000780
781 // Call a runtime function to load the interceptor property.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000782 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000783 // Save the name_ register across the call.
784 __ push(name_);
785
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000786 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000787
788 __ CallExternalReference(
789 ExternalReference(
790 IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
791 masm->isolate()),
792 5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000793 // Restore the name_ register.
794 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000795 // Leave the internal frame.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000796 }
797
798 void LoadWithInterceptor(MacroAssembler* masm,
799 Register receiver,
800 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000801 Handle<JSObject> holder_obj,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000802 Register scratch,
803 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000804 {
805 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000806
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000807 __ Push(holder, name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000808 CompileCallLoadPropertyWithInterceptor(masm,
809 receiver,
810 holder,
811 name_,
812 holder_obj);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000813 __ pop(name_); // Restore the name.
814 __ pop(receiver); // Restore the holder.
815 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000816 // If interceptor returns no-result sentinel, call the constant function.
817 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
818 __ Branch(interceptor_succeeded, ne, v0, Operand(scratch));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000819 }
820
821 StubCompiler* stub_compiler_;
822 const ParameterCount& arguments_;
823 Register name_;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000824 Code::ExtraICState extra_ic_state_;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000825};
826
827
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000828
829// Generate code to check that a global property cell is empty. Create
830// the property cell at compilation time if no cell exists for the
831// property.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000832static void GenerateCheckPropertyCell(MacroAssembler* masm,
833 Handle<GlobalObject> global,
834 Handle<String> name,
835 Register scratch,
836 Label* miss) {
837 Handle<JSGlobalPropertyCell> cell =
838 GlobalObject::EnsurePropertyCell(global, name);
839 ASSERT(cell->value()->IsTheHole());
840 __ li(scratch, Operand(cell));
841 __ lw(scratch,
842 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
843 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
844 __ Branch(miss, ne, scratch, Operand(at));
845}
846
847
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000848// Calls GenerateCheckPropertyCell for each global object in the prototype chain
849// from object to (but not including) holder.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000850static void GenerateCheckPropertyCells(MacroAssembler* masm,
851 Handle<JSObject> object,
852 Handle<JSObject> holder,
853 Handle<String> name,
854 Register scratch,
855 Label* miss) {
856 Handle<JSObject> current = object;
857 while (!current.is_identical_to(holder)) {
858 if (current->IsGlobalObject()) {
859 GenerateCheckPropertyCell(masm,
860 Handle<GlobalObject>::cast(current),
861 name,
862 scratch,
863 miss);
864 }
865 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
866 }
867}
868
869
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000870// Convert and store int passed in register ival to IEEE 754 single precision
871// floating point value at memory location (dst + 4 * wordoffset)
872// If FPU is available use it for conversion.
873static void StoreIntAsFloat(MacroAssembler* masm,
874 Register dst,
875 Register wordoffset,
876 Register ival,
877 Register fval,
878 Register scratch1,
879 Register scratch2) {
880 if (CpuFeatures::IsSupported(FPU)) {
881 CpuFeatures::Scope scope(FPU);
882 __ mtc1(ival, f0);
883 __ cvt_s_w(f0, f0);
884 __ sll(scratch1, wordoffset, 2);
885 __ addu(scratch1, dst, scratch1);
886 __ swc1(f0, MemOperand(scratch1, 0));
887 } else {
888 // FPU is not available, do manual conversions.
889
890 Label not_special, done;
891 // Move sign bit from source to destination. This works because the sign
892 // bit in the exponent word of the double has the same position and polarity
893 // as the 2's complement sign bit in a Smi.
894 ASSERT(kBinary32SignMask == 0x80000000u);
895
896 __ And(fval, ival, Operand(kBinary32SignMask));
897 // Negate value if it is negative.
898 __ subu(scratch1, zero_reg, ival);
899 __ movn(ival, scratch1, fval);
900
901 // We have -1, 0 or 1, which we treat specially. Register ival contains
902 // absolute value: it is either equal to 1 (special case of -1 and 1),
903 // greater than 1 (not a special case) or less than 1 (special case of 0).
904 __ Branch(&not_special, gt, ival, Operand(1));
905
906 // For 1 or -1 we need to or in the 0 exponent (biased).
907 static const uint32_t exponent_word_for_1 =
908 kBinary32ExponentBias << kBinary32ExponentShift;
909
910 __ Xor(scratch1, ival, Operand(1));
911 __ li(scratch2, exponent_word_for_1);
912 __ or_(scratch2, fval, scratch2);
913 __ movz(fval, scratch2, scratch1); // Only if ival is equal to 1.
914 __ Branch(&done);
915
916 __ bind(&not_special);
917 // Count leading zeros.
918 // Gets the wrong answer for 0, but we already checked for that case above.
919 Register zeros = scratch2;
920 __ clz(zeros, ival);
921
922 // Compute exponent and or it into the exponent register.
923 __ li(scratch1, (kBitsPerInt - 1) + kBinary32ExponentBias);
924 __ subu(scratch1, scratch1, zeros);
925
926 __ sll(scratch1, scratch1, kBinary32ExponentShift);
927 __ or_(fval, fval, scratch1);
928
929 // Shift up the source chopping the top bit off.
930 __ Addu(zeros, zeros, Operand(1));
931 // This wouldn't work for 1 and -1 as the shift would be 32 which means 0.
932 __ sllv(ival, ival, zeros);
933 // And the top (top 20 bits).
934 __ srl(scratch1, ival, kBitsPerInt - kBinary32MantissaBits);
935 __ or_(fval, fval, scratch1);
936
937 __ bind(&done);
938
939 __ sll(scratch1, wordoffset, 2);
940 __ addu(scratch1, dst, scratch1);
941 __ sw(fval, MemOperand(scratch1, 0));
942 }
943}
944
945
946// Convert unsigned integer with specified number of leading zeroes in binary
947// representation to IEEE 754 double.
948// Integer to convert is passed in register hiword.
949// Resulting double is returned in registers hiword:loword.
950// This functions does not work correctly for 0.
951static void GenerateUInt2Double(MacroAssembler* masm,
952 Register hiword,
953 Register loword,
954 Register scratch,
955 int leading_zeroes) {
956 const int meaningful_bits = kBitsPerInt - leading_zeroes - 1;
957 const int biased_exponent = HeapNumber::kExponentBias + meaningful_bits;
958
959 const int mantissa_shift_for_hi_word =
960 meaningful_bits - HeapNumber::kMantissaBitsInTopWord;
961
962 const int mantissa_shift_for_lo_word =
963 kBitsPerInt - mantissa_shift_for_hi_word;
964
965 __ li(scratch, biased_exponent << HeapNumber::kExponentShift);
966 if (mantissa_shift_for_hi_word > 0) {
967 __ sll(loword, hiword, mantissa_shift_for_lo_word);
968 __ srl(hiword, hiword, mantissa_shift_for_hi_word);
969 __ or_(hiword, scratch, hiword);
970 } else {
971 __ mov(loword, zero_reg);
972 __ sll(hiword, hiword, mantissa_shift_for_hi_word);
973 __ or_(hiword, scratch, hiword);
974 }
975
976 // If least significant bit of biased exponent was not 1 it was corrupted
977 // by most significant bit of mantissa so we should fix that.
978 if (!(biased_exponent & 1)) {
979 __ li(scratch, 1 << HeapNumber::kExponentShift);
980 __ nor(scratch, scratch, scratch);
981 __ and_(hiword, hiword, scratch);
982 }
983}
984
985
ager@chromium.org5c838252010-02-19 08:53:10 +0000986#undef __
987#define __ ACCESS_MASM(masm())
988
989
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000990Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
991 Register object_reg,
992 Handle<JSObject> holder,
993 Register holder_reg,
994 Register scratch1,
995 Register scratch2,
996 Handle<String> name,
997 int save_at_depth,
998 Label* miss) {
999 // Make sure there's no overlap between holder and object registers.
1000 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1001 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1002 && !scratch2.is(scratch1));
1003
1004 // Keep track of the current object in register reg.
1005 Register reg = object_reg;
1006 int depth = 0;
1007
1008 if (save_at_depth == depth) {
1009 __ sw(reg, MemOperand(sp));
1010 }
1011
1012 // Check the maps in the prototype chain.
1013 // Traverse the prototype chain from the object and do map checks.
1014 Handle<JSObject> current = object;
1015 while (!current.is_identical_to(holder)) {
1016 ++depth;
1017
1018 // Only global objects and objects that do not require access
1019 // checks are allowed in stubs.
1020 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1021
1022 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
1023 if (!current->HasFastProperties() &&
1024 !current->IsJSGlobalObject() &&
1025 !current->IsJSGlobalProxy()) {
1026 if (!name->IsSymbol()) {
1027 name = factory()->LookupSymbol(name);
1028 }
1029 ASSERT(current->property_dictionary()->FindEntry(*name) ==
1030 StringDictionary::kNotFound);
1031
1032 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1033 scratch1, scratch2);
1034
1035 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1036 reg = holder_reg; // From now on the object will be in holder_reg.
1037 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1038 } else {
1039 Handle<Map> current_map(current->map());
1040 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1041 // Branch on the result of the map check.
1042 __ Branch(miss, ne, scratch1, Operand(current_map));
1043 // Check access rights to the global object. This has to happen after
1044 // the map check so that we know that the object is actually a global
1045 // object.
1046 if (current->IsJSGlobalProxy()) {
1047 __ CheckAccessGlobalProxy(reg, scratch2, miss);
1048 }
1049 reg = holder_reg; // From now on the object will be in holder_reg.
1050
1051 if (heap()->InNewSpace(*prototype)) {
1052 // The prototype is in new space; we cannot store a reference to it
1053 // in the code. Load it from the map.
1054 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1055 } else {
1056 // The prototype is in old space; load it directly.
1057 __ li(reg, Operand(prototype));
1058 }
1059 }
1060
1061 if (save_at_depth == depth) {
1062 __ sw(reg, MemOperand(sp));
1063 }
1064
1065 // Go to the next object in the prototype chain.
1066 current = prototype;
1067 }
1068
1069 // Log the check depth.
1070 LOG(masm()->isolate(), IntEvent("check-maps-depth", depth + 1));
1071
1072 // Check the holder map.
1073 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1074 __ Branch(miss, ne, scratch1, Operand(Handle<Map>(current->map())));
1075
1076 // Perform security check for access to the global object.
1077 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1078 if (holder->IsJSGlobalProxy()) {
1079 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1080 }
1081
1082 // If we've skipped any global objects, it's not enough to verify that
1083 // their maps haven't changed. We also need to check that the property
1084 // cell for the property is still empty.
1085 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1086
1087 // Return the register containing the holder.
1088 return reg;
1089}
1090
1091
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001092void StubCompiler::GenerateLoadField(Handle<JSObject> object,
1093 Handle<JSObject> holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001094 Register receiver,
1095 Register scratch1,
1096 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001097 Register scratch3,
ager@chromium.org5c838252010-02-19 08:53:10 +00001098 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001099 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001100 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001101 // Check that the receiver isn't a smi.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001102 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001103
1104 // Check that the maps haven't changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001105 Register reg = CheckPrototypes(
1106 object, receiver, holder, scratch1, scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001107 GenerateFastPropertyLoad(masm(), v0, reg, holder, index);
1108 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001109}
1110
1111
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001112void StubCompiler::GenerateLoadConstant(Handle<JSObject> object,
1113 Handle<JSObject> holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001114 Register receiver,
1115 Register scratch1,
1116 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001117 Register scratch3,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001118 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001119 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001120 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001121 // Check that the receiver isn't a smi.
1122 __ JumpIfSmi(receiver, miss, scratch1);
1123
1124 // Check that the maps haven't changed.
1125 Register reg =
1126 CheckPrototypes(object, receiver, holder,
1127 scratch1, scratch2, scratch3, name, miss);
1128
1129 // Return the constant value.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001130 __ LoadHeapObject(v0, value);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001131 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001132}
1133
1134
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001135void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
1136 Handle<JSObject> holder,
1137 Register receiver,
1138 Register name_reg,
1139 Register scratch1,
1140 Register scratch2,
1141 Register scratch3,
1142 Handle<AccessorInfo> callback,
1143 Handle<String> name,
1144 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001145 // Check that the receiver isn't a smi.
1146 __ JumpIfSmi(receiver, miss, scratch1);
1147
1148 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001149 Register reg = CheckPrototypes(object, receiver, holder, scratch1,
1150 scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001151
1152 // Build AccessorInfo::args_ list on the stack and push property name below
1153 // the exit frame to make GC aware of them and store pointers to them.
1154 __ push(receiver);
1155 __ mov(scratch2, sp); // scratch2 = AccessorInfo::args_
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001156 if (heap()->InNewSpace(callback->data())) {
1157 __ li(scratch3, callback);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001158 __ lw(scratch3, FieldMemOperand(scratch3, AccessorInfo::kDataOffset));
1159 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001160 __ li(scratch3, Handle<Object>(callback->data()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001161 }
1162 __ Push(reg, scratch3, name_reg);
1163 __ mov(a2, scratch2); // Saved in case scratch2 == a1.
1164 __ mov(a1, sp); // a1 (first argument - see note below) = Handle<String>
1165
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001166 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
1167 // struct from the function (which is currently the case). This means we pass
1168 // the arguments in a1-a2 instead of a0-a1. TryCallApiFunctionAndReturn
1169 // will handle setting up a0.
1170
1171 const int kApiStackSpace = 1;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001172 FrameScope frame_scope(masm(), StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001173 __ EnterExitFrame(false, kApiStackSpace);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001174
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001175 // Create AccessorInfo instance on the stack above the exit frame with
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001176 // scratch2 (internal::Object** args_) as the data.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001177 __ sw(a2, MemOperand(sp, kPointerSize));
1178 // a2 (second argument - see note above) = AccessorInfo&
1179 __ Addu(a2, sp, kPointerSize);
1180
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001181 const int kStackUnwindSpace = 4;
1182 Address getter_address = v8::ToCData<Address>(callback->getter());
1183 ApiFunction fun(getter_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001184 ExternalReference ref =
1185 ExternalReference(&fun,
1186 ExternalReference::DIRECT_GETTER_CALL,
1187 masm()->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001188 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
ager@chromium.org5c838252010-02-19 08:53:10 +00001189}
1190
1191
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001192void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
1193 Handle<JSObject> interceptor_holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001194 LookupResult* lookup,
1195 Register receiver,
1196 Register name_reg,
1197 Register scratch1,
1198 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001199 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001200 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001201 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001202 ASSERT(interceptor_holder->HasNamedInterceptor());
1203 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1204
1205 // Check that the receiver isn't a smi.
1206 __ JumpIfSmi(receiver, miss);
1207
1208 // So far the most popular follow ups for interceptor loads are FIELD
1209 // and CALLBACKS, so inline only them, other cases may be added
1210 // later.
1211 bool compile_followup_inline = false;
1212 if (lookup->IsProperty() && lookup->IsCacheable()) {
1213 if (lookup->type() == FIELD) {
1214 compile_followup_inline = true;
1215 } else if (lookup->type() == CALLBACKS &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001216 lookup->GetCallbackObject()->IsAccessorInfo()) {
1217 compile_followup_inline =
1218 AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001219 }
1220 }
1221
1222 if (compile_followup_inline) {
1223 // Compile the interceptor call, followed by inline code to load the
1224 // property from further up the prototype chain if the call fails.
1225 // Check that the maps haven't changed.
1226 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1227 scratch1, scratch2, scratch3,
1228 name, miss);
1229 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
1230
1231 // Save necessary data before invoking an interceptor.
1232 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001233 {
1234 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001235 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
1236 // CALLBACKS case needs a receiver to be passed into C++ callback.
1237 __ Push(receiver, holder_reg, name_reg);
1238 } else {
1239 __ Push(holder_reg, name_reg);
1240 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001241 // Invoke an interceptor. Note: map checks from receiver to
1242 // interceptor's holder has been compiled before (see a caller
1243 // of this method).
1244 CompileCallLoadPropertyWithInterceptor(masm(),
1245 receiver,
1246 holder_reg,
1247 name_reg,
1248 interceptor_holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001249 // Check if interceptor provided a value for property. If it's
1250 // the case, return immediately.
1251 Label interceptor_failed;
1252 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
1253 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1));
1254 frame_scope.GenerateLeaveFrame();
1255 __ Ret();
1256
1257 __ bind(&interceptor_failed);
1258 __ pop(name_reg);
1259 __ pop(holder_reg);
1260 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
1261 __ pop(receiver);
1262 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001263 // Leave the internal frame.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001264 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001265 // Check that the maps from interceptor's holder to lookup's holder
1266 // haven't changed. And load lookup's holder into |holder| register.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001267 if (*interceptor_holder != lookup->holder()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001268 holder_reg = CheckPrototypes(interceptor_holder,
1269 holder_reg,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001270 Handle<JSObject>(lookup->holder()),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001271 scratch1,
1272 scratch2,
1273 scratch3,
1274 name,
1275 miss);
1276 }
1277
1278 if (lookup->type() == FIELD) {
1279 // We found FIELD property in prototype chain of interceptor's holder.
1280 // Retrieve a field from field's holder.
1281 GenerateFastPropertyLoad(masm(), v0, holder_reg,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001282 Handle<JSObject>(lookup->holder()),
1283 lookup->GetFieldIndex());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001284 __ Ret();
1285 } else {
1286 // We found CALLBACKS property in prototype chain of interceptor's
1287 // holder.
1288 ASSERT(lookup->type() == CALLBACKS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001289 Handle<AccessorInfo> callback(
1290 AccessorInfo::cast(lookup->GetCallbackObject()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001291 ASSERT(callback->getter() != NULL);
1292
1293 // Tail call to runtime.
1294 // Important invariant in CALLBACKS case: the code above must be
1295 // structured to never clobber |receiver| register.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001296 __ li(scratch2, callback);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001297 // holder_reg is either receiver or scratch1.
1298 if (!receiver.is(holder_reg)) {
1299 ASSERT(scratch1.is(holder_reg));
1300 __ Push(receiver, holder_reg);
1301 __ lw(scratch3,
1302 FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
1303 __ Push(scratch3, scratch2, name_reg);
1304 } else {
1305 __ push(receiver);
1306 __ lw(scratch3,
1307 FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
1308 __ Push(holder_reg, scratch3, scratch2, name_reg);
1309 }
1310
1311 ExternalReference ref =
1312 ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
1313 masm()->isolate());
1314 __ TailCallExternalReference(ref, 5, 1);
1315 }
1316 } else { // !compile_followup_inline
1317 // Call the runtime system to load the interceptor.
1318 // Check that the maps haven't changed.
1319 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1320 scratch1, scratch2, scratch3,
1321 name, miss);
1322 PushInterceptorArguments(masm(), receiver, holder_reg,
1323 name_reg, interceptor_holder);
1324
1325 ExternalReference ref = ExternalReference(
1326 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), masm()->isolate());
1327 __ TailCallExternalReference(ref, 5, 1);
1328 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001329}
1330
1331
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001332void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001333 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001334 __ Branch(miss, ne, a2, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001335 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001336}
1337
1338
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001339void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1340 Handle<JSObject> holder,
1341 Handle<String> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001342 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001343 ASSERT(holder->IsGlobalObject());
1344
1345 // Get the number of arguments.
1346 const int argc = arguments().immediate();
1347
1348 // Get the receiver from the stack.
1349 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1350
1351 // If the object is the holder then we know that it's a global
1352 // object which can only happen for contextual calls. In this case,
1353 // the receiver cannot be a smi.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001354 if (!object.is_identical_to(holder)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001355 __ JumpIfSmi(a0, miss);
1356 }
1357
1358 // Check that the maps haven't changed.
1359 CheckPrototypes(object, a0, holder, a3, a1, t0, name, miss);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001360}
1361
1362
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001363void CallStubCompiler::GenerateLoadFunctionFromCell(
1364 Handle<JSGlobalPropertyCell> cell,
1365 Handle<JSFunction> function,
1366 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001367 // Get the value from the cell.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001368 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001369 __ lw(a1, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
1370
1371 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001372 if (heap()->InNewSpace(*function)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001373 // We can't embed a pointer to a function in new space so we have
1374 // to verify that the shared function info is unchanged. This has
1375 // the nice side effect that multiple closures based on the same
1376 // function can all use this call IC. Before we load through the
1377 // function, we have to verify that it still is a function.
1378 __ JumpIfSmi(a1, miss);
1379 __ GetObjectType(a1, a3, a3);
1380 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
1381
1382 // Check the shared function info. Make sure it hasn't changed.
1383 __ li(a3, Handle<SharedFunctionInfo>(function->shared()));
1384 __ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
1385 __ Branch(miss, ne, t0, Operand(a3));
1386 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001387 __ Branch(miss, ne, a1, Operand(function));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001388 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001389}
1390
1391
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001392void CallStubCompiler::GenerateMissBranch() {
1393 Handle<Code> code =
danno@chromium.org40cb8782011-05-25 07:58:50 +00001394 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1395 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001396 extra_state_);
1397 __ Jump(code, RelocInfo::CODE_TARGET);
1398}
1399
1400
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001401Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1402 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001403 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001404 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001405 // ----------- S t a t e -------------
1406 // -- a2 : name
1407 // -- ra : return address
1408 // -----------------------------------
1409 Label miss;
1410
1411 GenerateNameCheck(name, &miss);
1412
1413 const int argc = arguments().immediate();
1414
1415 // Get the receiver of the function from the stack into a0.
1416 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1417 // Check that the receiver isn't a smi.
1418 __ JumpIfSmi(a0, &miss, t0);
1419
1420 // Do the right check and compute the holder register.
1421 Register reg = CheckPrototypes(object, a0, holder, a1, a3, t0, name, &miss);
1422 GenerateFastPropertyLoad(masm(), a1, reg, holder, index);
1423
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001424 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001425
1426 // Handle call cache miss.
1427 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001428 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001429
1430 // Return the generated code.
1431 return GetCode(FIELD, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001432}
1433
1434
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001435Handle<Code> CallStubCompiler::CompileArrayPushCall(
1436 Handle<Object> object,
1437 Handle<JSObject> holder,
1438 Handle<JSGlobalPropertyCell> cell,
1439 Handle<JSFunction> function,
1440 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001441 // ----------- S t a t e -------------
1442 // -- a2 : name
1443 // -- ra : return address
1444 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1445 // -- ...
1446 // -- sp[argc * 4] : receiver
1447 // -----------------------------------
1448
1449 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001450 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001451
1452 Label miss;
1453
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001454 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001455
1456 Register receiver = a1;
1457
1458 // Get the receiver from the stack.
1459 const int argc = arguments().immediate();
1460 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1461
1462 // Check that the receiver isn't a smi.
1463 __ JumpIfSmi(receiver, &miss);
1464
1465 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001466 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, a3, v0, t0,
1467 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001468
1469 if (argc == 0) {
1470 // Nothing to do, just return the length.
1471 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1472 __ Drop(argc + 1);
1473 __ Ret();
1474 } else {
1475 Label call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001476 Register elements = a3;
1477 Register end_elements = t1;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001478 // Get the elements array of the object.
1479 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1480
1481 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001482 __ CheckMap(elements,
1483 v0,
1484 Heap::kFixedArrayMapRootIndex,
1485 &call_builtin,
1486 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001487
1488 if (argc == 1) { // Otherwise fall through to call the builtin.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001489 Label attempt_to_grow_elements;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001490
1491 // Get the array's length into v0 and calculate new length.
1492 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1493 STATIC_ASSERT(kSmiTagSize == 1);
1494 STATIC_ASSERT(kSmiTag == 0);
1495 __ Addu(v0, v0, Operand(Smi::FromInt(argc)));
1496
1497 // Get the element's length.
1498 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1499
1500 // Check if we could survive without allocation.
1501 __ Branch(&attempt_to_grow_elements, gt, v0, Operand(t0));
1502
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001503 // Check if value is a smi.
1504 Label with_write_barrier;
1505 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1506 __ JumpIfNotSmi(t0, &with_write_barrier);
1507
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001508 // Save new length.
1509 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1510
1511 // Push the element.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001512 // We may need a register containing the address end_elements below,
1513 // so write back the value in end_elements.
1514 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1515 __ Addu(end_elements, elements, end_elements);
1516 const int kEndElementsOffset =
1517 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001518 __ Addu(end_elements, end_elements, kEndElementsOffset);
1519 __ sw(t0, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001520
1521 // Check for a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001522 __ Drop(argc + 1);
1523 __ Ret();
1524
1525 __ bind(&with_write_barrier);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001526
1527 __ lw(t2, FieldMemOperand(receiver, HeapObject::kMapOffset));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001528 __ CheckFastObjectElements(t2, t2, &call_builtin);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001529
1530 // Save new length.
1531 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1532
1533 // Push the element.
1534 // We may need a register containing the address end_elements below,
1535 // so write back the value in end_elements.
1536 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1537 __ Addu(end_elements, elements, end_elements);
1538 __ Addu(end_elements, end_elements, kEndElementsOffset);
1539 __ sw(t0, MemOperand(end_elements));
1540
1541 __ RecordWrite(elements,
1542 end_elements,
1543 t0,
1544 kRAHasNotBeenSaved,
1545 kDontSaveFPRegs,
1546 EMIT_REMEMBERED_SET,
1547 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001548 __ Drop(argc + 1);
1549 __ Ret();
1550
1551 __ bind(&attempt_to_grow_elements);
1552 // v0: array's length + 1.
1553 // t0: elements' length.
1554
1555 if (!FLAG_inline_new) {
1556 __ Branch(&call_builtin);
1557 }
1558
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001559 __ lw(a2, MemOperand(sp, (argc - 1) * kPointerSize));
1560 // Growing elements that are SMI-only requires special handling in case
1561 // the new element is non-Smi. For now, delegate to the builtin.
1562 Label no_fast_elements_check;
1563 __ JumpIfSmi(a2, &no_fast_elements_check);
1564 __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1565 __ CheckFastObjectElements(t3, t3, &call_builtin);
1566 __ bind(&no_fast_elements_check);
1567
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001568 ExternalReference new_space_allocation_top =
1569 ExternalReference::new_space_allocation_top_address(
1570 masm()->isolate());
1571 ExternalReference new_space_allocation_limit =
1572 ExternalReference::new_space_allocation_limit_address(
1573 masm()->isolate());
1574
1575 const int kAllocationDelta = 4;
1576 // Load top and check if it is the end of elements.
1577 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1578 __ Addu(end_elements, elements, end_elements);
1579 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset));
1580 __ li(t3, Operand(new_space_allocation_top));
1581 __ lw(t2, MemOperand(t3));
1582 __ Branch(&call_builtin, ne, end_elements, Operand(t2));
1583
1584 __ li(t5, Operand(new_space_allocation_limit));
1585 __ lw(t5, MemOperand(t5));
1586 __ Addu(t2, t2, Operand(kAllocationDelta * kPointerSize));
1587 __ Branch(&call_builtin, hi, t2, Operand(t5));
1588
1589 // We fit and could grow elements.
1590 // Update new_space_allocation_top.
1591 __ sw(t2, MemOperand(t3));
1592 // Push the argument.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001593 __ sw(a2, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001594 // Fill the rest with holes.
1595 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1596 for (int i = 1; i < kAllocationDelta; i++) {
1597 __ sw(t2, MemOperand(end_elements, i * kPointerSize));
1598 }
1599
1600 // Update elements' and array's sizes.
1601 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1602 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta)));
1603 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1604
1605 // Elements are in new space, so write barrier is not required.
1606 __ Drop(argc + 1);
1607 __ Ret();
1608 }
1609 __ bind(&call_builtin);
1610 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
1611 masm()->isolate()),
1612 argc + 1,
1613 1);
1614 }
1615
1616 // Handle call cache miss.
1617 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001618 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001619
1620 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001621 return GetCode(function);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001622}
1623
1624
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001625Handle<Code> CallStubCompiler::CompileArrayPopCall(
1626 Handle<Object> object,
1627 Handle<JSObject> holder,
1628 Handle<JSGlobalPropertyCell> cell,
1629 Handle<JSFunction> function,
1630 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001631 // ----------- S t a t e -------------
1632 // -- a2 : name
1633 // -- ra : return address
1634 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1635 // -- ...
1636 // -- sp[argc * 4] : receiver
1637 // -----------------------------------
1638
1639 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001640 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001641
1642 Label miss, return_undefined, call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001643 Register receiver = a1;
1644 Register elements = a3;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001645 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001646
1647 // Get the receiver from the stack.
1648 const int argc = arguments().immediate();
1649 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001650 // Check that the receiver isn't a smi.
1651 __ JumpIfSmi(receiver, &miss);
1652
1653 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001654 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, elements,
1655 t0, v0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001656
1657 // Get the elements array of the object.
1658 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1659
1660 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001661 __ CheckMap(elements,
1662 v0,
1663 Heap::kFixedArrayMapRootIndex,
1664 &call_builtin,
1665 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001666
1667 // Get the array's length into t0 and calculate new length.
1668 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1669 __ Subu(t0, t0, Operand(Smi::FromInt(1)));
1670 __ Branch(&return_undefined, lt, t0, Operand(zero_reg));
1671
1672 // Get the last element.
1673 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1674 STATIC_ASSERT(kSmiTagSize == 1);
1675 STATIC_ASSERT(kSmiTag == 0);
1676 // We can't address the last element in one operation. Compute the more
1677 // expensive shift first, and use an offset later on.
1678 __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize);
1679 __ Addu(elements, elements, t1);
1680 __ lw(v0, MemOperand(elements, FixedArray::kHeaderSize - kHeapObjectTag));
1681 __ Branch(&call_builtin, eq, v0, Operand(t2));
1682
1683 // Set the array's length.
1684 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1685
1686 // Fill with the hole.
1687 __ sw(t2, MemOperand(elements, FixedArray::kHeaderSize - kHeapObjectTag));
1688 __ Drop(argc + 1);
1689 __ Ret();
1690
1691 __ bind(&return_undefined);
1692 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
1693 __ Drop(argc + 1);
1694 __ Ret();
1695
1696 __ bind(&call_builtin);
1697 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop,
1698 masm()->isolate()),
1699 argc + 1,
1700 1);
1701
1702 // Handle call cache miss.
1703 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001704 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001705
1706 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001707 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001708}
1709
1710
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001711Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1712 Handle<Object> object,
1713 Handle<JSObject> holder,
1714 Handle<JSGlobalPropertyCell> cell,
1715 Handle<JSFunction> function,
1716 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001717 // ----------- S t a t e -------------
1718 // -- a2 : function name
1719 // -- ra : return address
1720 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1721 // -- ...
1722 // -- sp[argc * 4] : receiver
1723 // -----------------------------------
1724
1725 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001726 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001727
1728 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001729 Label miss;
1730 Label name_miss;
1731 Label index_out_of_range;
1732
1733 Label* index_out_of_range_label = &index_out_of_range;
1734
danno@chromium.org40cb8782011-05-25 07:58:50 +00001735 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001736 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001737 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001738 index_out_of_range_label = &miss;
1739 }
1740
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001741 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001742
1743 // Check that the maps starting from the prototype haven't changed.
1744 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1745 Context::STRING_FUNCTION_INDEX,
1746 v0,
1747 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001748 ASSERT(!object.is_identical_to(holder));
1749 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1750 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001751
1752 Register receiver = a1;
1753 Register index = t1;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001754 Register result = v0;
1755 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1756 if (argc > 0) {
1757 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1758 } else {
1759 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1760 }
1761
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001762 StringCharCodeAtGenerator generator(receiver,
1763 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001764 result,
1765 &miss, // When not a string.
1766 &miss, // When not a number.
1767 index_out_of_range_label,
1768 STRING_INDEX_IS_NUMBER);
1769 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001770 __ Drop(argc + 1);
1771 __ Ret();
1772
1773 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001774 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001775
1776 if (index_out_of_range.is_linked()) {
1777 __ bind(&index_out_of_range);
1778 __ LoadRoot(v0, Heap::kNanValueRootIndex);
1779 __ Drop(argc + 1);
1780 __ Ret();
1781 }
1782
1783 __ bind(&miss);
1784 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001785 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001786 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001787 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001788
1789 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001790 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001791}
1792
1793
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001794Handle<Code> CallStubCompiler::CompileStringCharAtCall(
1795 Handle<Object> object,
1796 Handle<JSObject> holder,
1797 Handle<JSGlobalPropertyCell> cell,
1798 Handle<JSFunction> function,
1799 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001800 // ----------- S t a t e -------------
1801 // -- a2 : function name
1802 // -- ra : return address
1803 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1804 // -- ...
1805 // -- sp[argc * 4] : receiver
1806 // -----------------------------------
1807
1808 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001809 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001810
1811 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001812 Label miss;
1813 Label name_miss;
1814 Label index_out_of_range;
1815 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00001816 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001817 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001818 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001819 index_out_of_range_label = &miss;
1820 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001821 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001822
1823 // Check that the maps starting from the prototype haven't changed.
1824 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1825 Context::STRING_FUNCTION_INDEX,
1826 v0,
1827 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001828 ASSERT(!object.is_identical_to(holder));
1829 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1830 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001831
1832 Register receiver = v0;
1833 Register index = t1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001834 Register scratch = a3;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001835 Register result = v0;
1836 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1837 if (argc > 0) {
1838 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1839 } else {
1840 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1841 }
1842
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001843 StringCharAtGenerator generator(receiver,
1844 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00001845 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001846 result,
1847 &miss, // When not a string.
1848 &miss, // When not a number.
1849 index_out_of_range_label,
1850 STRING_INDEX_IS_NUMBER);
1851 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001852 __ Drop(argc + 1);
1853 __ Ret();
1854
1855 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001856 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001857
1858 if (index_out_of_range.is_linked()) {
1859 __ bind(&index_out_of_range);
1860 __ LoadRoot(v0, Heap::kEmptyStringRootIndex);
1861 __ Drop(argc + 1);
1862 __ Ret();
1863 }
1864
1865 __ bind(&miss);
1866 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001867 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001868 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001869 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001870
1871 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001872 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001873}
1874
1875
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001876Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
1877 Handle<Object> object,
1878 Handle<JSObject> holder,
1879 Handle<JSGlobalPropertyCell> cell,
1880 Handle<JSFunction> function,
1881 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001882 // ----------- S t a t e -------------
1883 // -- a2 : function name
1884 // -- ra : return address
1885 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1886 // -- ...
1887 // -- sp[argc * 4] : receiver
1888 // -----------------------------------
1889
1890 const int argc = arguments().immediate();
1891
1892 // If the object is not a JSObject or we got an unexpected number of
1893 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001894 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001895
1896 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001897 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001898
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001899 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001900 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
1901
1902 STATIC_ASSERT(kSmiTag == 0);
1903 __ JumpIfSmi(a1, &miss);
1904
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001905 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
1906 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001907 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001908 ASSERT(cell->value() == *function);
1909 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
1910 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001911 GenerateLoadFunctionFromCell(cell, function, &miss);
1912 }
1913
1914 // Load the char code argument.
1915 Register code = a1;
1916 __ lw(code, MemOperand(sp, 0 * kPointerSize));
1917
1918 // Check the code is a smi.
1919 Label slow;
1920 STATIC_ASSERT(kSmiTag == 0);
1921 __ JumpIfNotSmi(code, &slow);
1922
1923 // Convert the smi code to uint16.
1924 __ And(code, code, Operand(Smi::FromInt(0xffff)));
1925
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001926 StringCharFromCodeGenerator generator(code, v0);
1927 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001928 __ Drop(argc + 1);
1929 __ Ret();
1930
1931 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001932 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001933
1934 // Tail call the full function. We do not have to patch the receiver
1935 // because the function makes no use of it.
1936 __ bind(&slow);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001937 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001938
1939 __ bind(&miss);
1940 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001941 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001942
1943 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001944 return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001945}
1946
1947
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001948Handle<Code> CallStubCompiler::CompileMathFloorCall(
1949 Handle<Object> object,
1950 Handle<JSObject> holder,
1951 Handle<JSGlobalPropertyCell> cell,
1952 Handle<JSFunction> function,
1953 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001954 // ----------- S t a t e -------------
1955 // -- a2 : function name
1956 // -- ra : return address
1957 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1958 // -- ...
1959 // -- sp[argc * 4] : receiver
1960 // -----------------------------------
1961
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001962 if (!CpuFeatures::IsSupported(FPU)) {
1963 return Handle<Code>::null();
1964 }
1965
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001966 CpuFeatures::Scope scope_fpu(FPU);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001967 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001968 // If the object is not a JSObject or we got an unexpected number of
1969 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001970 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001971
1972 Label miss, slow;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001973 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001974
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001975 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001976 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001977 STATIC_ASSERT(kSmiTag == 0);
1978 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001979 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
1980 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001981 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001982 ASSERT(cell->value() == *function);
1983 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
1984 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001985 GenerateLoadFunctionFromCell(cell, function, &miss);
1986 }
1987
1988 // Load the (only) argument into v0.
1989 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
1990
1991 // If the argument is a smi, just return.
1992 STATIC_ASSERT(kSmiTag == 0);
1993 __ And(t0, v0, Operand(kSmiTagMask));
1994 __ Drop(argc + 1, eq, t0, Operand(zero_reg));
1995 __ Ret(eq, t0, Operand(zero_reg));
1996
danno@chromium.org40cb8782011-05-25 07:58:50 +00001997 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001998
1999 Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return;
2000
2001 // If fpu is enabled, we use the floor instruction.
2002
2003 // Load the HeapNumber value.
2004 __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2005
2006 // Backup FCSR.
2007 __ cfc1(a3, FCSR);
2008 // Clearing FCSR clears the exception mask with no side-effects.
2009 __ ctc1(zero_reg, FCSR);
2010 // Convert the argument to an integer.
2011 __ floor_w_d(f0, f0);
2012
2013 // Start checking for special cases.
2014 // Get the argument exponent and clear the sign bit.
2015 __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize));
2016 __ And(t2, t1, Operand(~HeapNumber::kSignMask));
2017 __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord);
2018
2019 // Retrieve FCSR and check for fpu errors.
2020 __ cfc1(t5, FCSR);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002021 __ And(t5, t5, Operand(kFCSRExceptionFlagMask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002022 __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));
2023
2024 // Check for NaN, Infinity, and -Infinity.
2025 // They are invariant through a Math.Floor call, so just
2026 // return the original argument.
2027 __ Subu(t3, t2, Operand(HeapNumber::kExponentMask
2028 >> HeapNumber::kMantissaBitsInTopWord));
2029 __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg));
2030 // We had an overflow or underflow in the conversion. Check if we
2031 // have a big exponent.
2032 // If greater or equal, the argument is already round and in v0.
2033 __ Branch(&restore_fcsr_and_return, ge, t3,
2034 Operand(HeapNumber::kMantissaBits));
2035 __ Branch(&wont_fit_smi);
2036
2037 __ bind(&no_fpu_error);
2038 // Move the result back to v0.
2039 __ mfc1(v0, f0);
2040 // Check if the result fits into a smi.
2041 __ Addu(a1, v0, Operand(0x40000000));
2042 __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg));
2043 // Tag the result.
2044 STATIC_ASSERT(kSmiTag == 0);
2045 __ sll(v0, v0, kSmiTagSize);
2046
2047 // Check for -0.
2048 __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg));
2049 // t1 already holds the HeapNumber exponent.
2050 __ And(t0, t1, Operand(HeapNumber::kSignMask));
2051 // If our HeapNumber is negative it was -0, so load its address and return.
2052 // Else v0 is loaded with 0, so we can also just return.
2053 __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg));
2054 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2055
2056 __ bind(&restore_fcsr_and_return);
2057 // Restore FCSR and return.
2058 __ ctc1(a3, FCSR);
2059
2060 __ Drop(argc + 1);
2061 __ Ret();
2062
2063 __ bind(&wont_fit_smi);
2064 // Restore FCSR and fall to slow case.
2065 __ ctc1(a3, FCSR);
2066
2067 __ bind(&slow);
2068 // Tail call the full function. We do not have to patch the receiver
2069 // because the function makes no use of it.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002070 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002071
2072 __ bind(&miss);
2073 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002074 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002075
2076 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002077 return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002078}
2079
2080
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002081Handle<Code> CallStubCompiler::CompileMathAbsCall(
2082 Handle<Object> object,
2083 Handle<JSObject> holder,
2084 Handle<JSGlobalPropertyCell> cell,
2085 Handle<JSFunction> function,
2086 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002087 // ----------- S t a t e -------------
2088 // -- a2 : function name
2089 // -- ra : return address
2090 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2091 // -- ...
2092 // -- sp[argc * 4] : receiver
2093 // -----------------------------------
2094
2095 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002096 // If the object is not a JSObject or we got an unexpected number of
2097 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002098 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002099
2100 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002101
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002102 GenerateNameCheck(name, &miss);
2103 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002104 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002105 STATIC_ASSERT(kSmiTag == 0);
2106 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002107 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2108 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002109 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002110 ASSERT(cell->value() == *function);
2111 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2112 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002113 GenerateLoadFunctionFromCell(cell, function, &miss);
2114 }
2115
2116 // Load the (only) argument into v0.
2117 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2118
2119 // Check if the argument is a smi.
2120 Label not_smi;
2121 STATIC_ASSERT(kSmiTag == 0);
2122 __ JumpIfNotSmi(v0, &not_smi);
2123
2124 // Do bitwise not or do nothing depending on the sign of the
2125 // argument.
2126 __ sra(t0, v0, kBitsPerInt - 1);
2127 __ Xor(a1, v0, t0);
2128
2129 // Add 1 or do nothing depending on the sign of the argument.
2130 __ Subu(v0, a1, t0);
2131
2132 // If the result is still negative, go to the slow case.
2133 // This only happens for the most negative smi.
2134 Label slow;
2135 __ Branch(&slow, lt, v0, Operand(zero_reg));
2136
2137 // Smi case done.
2138 __ Drop(argc + 1);
2139 __ Ret();
2140
2141 // Check if the argument is a heap number and load its exponent and
2142 // sign.
2143 __ bind(&not_smi);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002144 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002145 __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2146
2147 // Check the sign of the argument. If the argument is positive,
2148 // just return it.
2149 Label negative_sign;
2150 __ And(t0, a1, Operand(HeapNumber::kSignMask));
2151 __ Branch(&negative_sign, ne, t0, Operand(zero_reg));
2152 __ Drop(argc + 1);
2153 __ Ret();
2154
2155 // If the argument is negative, clear the sign, and return a new
2156 // number.
2157 __ bind(&negative_sign);
2158 __ Xor(a1, a1, Operand(HeapNumber::kSignMask));
2159 __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2160 __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
2161 __ AllocateHeapNumber(v0, t0, t1, t2, &slow);
2162 __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2163 __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2164 __ Drop(argc + 1);
2165 __ Ret();
2166
2167 // Tail call the full function. We do not have to patch the receiver
2168 // because the function makes no use of it.
2169 __ bind(&slow);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002170 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002171
2172 __ bind(&miss);
2173 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002174 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002175
2176 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002177 return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002178}
2179
2180
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002181Handle<Code> CallStubCompiler::CompileFastApiCall(
lrn@chromium.org7516f052011-03-30 08:52:27 +00002182 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002183 Handle<Object> object,
2184 Handle<JSObject> holder,
2185 Handle<JSGlobalPropertyCell> cell,
2186 Handle<JSFunction> function,
2187 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002188
danno@chromium.org40cb8782011-05-25 07:58:50 +00002189 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002190
2191 ASSERT(optimization.is_simple_api_call());
2192 // Bail out if object is a global object as we don't want to
2193 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002194 if (object->IsGlobalObject()) return Handle<Code>::null();
2195 if (!cell.is_null()) return Handle<Code>::null();
2196 if (!object->IsJSObject()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002197 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002198 Handle<JSObject>::cast(object), holder);
2199 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002200
2201 Label miss, miss_before_stack_reserved;
2202
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002203 GenerateNameCheck(name, &miss_before_stack_reserved);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002204
2205 // Get the receiver from the stack.
2206 const int argc = arguments().immediate();
2207 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2208
2209 // Check that the receiver isn't a smi.
2210 __ JumpIfSmi(a1, &miss_before_stack_reserved);
2211
2212 __ IncrementCounter(counters->call_const(), 1, a0, a3);
2213 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2214
2215 ReserveSpaceForFastApiCall(masm(), a0);
2216
2217 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002218 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002219 depth, &miss);
2220
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002221 GenerateFastApiDirectCall(masm(), optimization, argc);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002222
2223 __ bind(&miss);
2224 FreeSpaceForFastApiCall(masm());
2225
2226 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002227 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002228
2229 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002230 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002231}
2232
2233
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002234Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object,
2235 Handle<JSObject> holder,
2236 Handle<JSFunction> function,
2237 Handle<String> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002238 CheckType check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002239 // ----------- S t a t e -------------
2240 // -- a2 : name
2241 // -- ra : return address
2242 // -----------------------------------
2243 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002244 Handle<Code> code = CompileCustomCall(object, holder,
2245 Handle<JSGlobalPropertyCell>::null(),
2246 function, name);
2247 // A null handle means bail out to the regular compiler code below.
2248 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002249 }
2250
2251 Label miss;
2252
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002253 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002254
2255 // Get the receiver from the stack.
2256 const int argc = arguments().immediate();
2257 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2258
2259 // Check that the receiver isn't a smi.
2260 if (check != NUMBER_CHECK) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002261 __ JumpIfSmi(a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002262 }
2263
2264 // Make sure that it's okay not to patch the on stack receiver
2265 // unless we're doing a receiver map check.
2266 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002267 switch (check) {
2268 case RECEIVER_MAP_CHECK:
2269 __ IncrementCounter(masm()->isolate()->counters()->call_const(),
2270 1, a0, a3);
2271
2272 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002273 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2274 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002275
2276 // Patch the receiver on the stack with the global proxy if
2277 // necessary.
2278 if (object->IsGlobalObject()) {
2279 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2280 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2281 }
2282 break;
2283
2284 case STRING_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002285 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002286 // Check that the object is a two-byte string or a symbol.
2287 __ GetObjectType(a1, a3, a3);
2288 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2289 // Check that the maps starting from the prototype haven't changed.
2290 GenerateDirectLoadGlobalFunctionPrototype(
2291 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002292 CheckPrototypes(
2293 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2294 a0, holder, a3, a1, t0, name, &miss);
2295 } else {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002296 // Calling non-strict non-builtins with a value as the receiver
2297 // requires boxing.
2298 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002299 }
2300 break;
2301
2302 case NUMBER_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002303 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002304 Label fast;
2305 // Check that the object is a smi or a heap number.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002306 __ JumpIfSmi(a1, &fast);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002307 __ GetObjectType(a1, a0, a0);
2308 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
2309 __ bind(&fast);
2310 // Check that the maps starting from the prototype haven't changed.
2311 GenerateDirectLoadGlobalFunctionPrototype(
2312 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002313 CheckPrototypes(
2314 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2315 a0, holder, a3, a1, t0, name, &miss);
2316 } else {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002317 // Calling non-strict non-builtins with a value as the receiver
2318 // requires boxing.
2319 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002320 }
2321 break;
2322
2323 case BOOLEAN_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002324 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002325 Label fast;
2326 // Check that the object is a boolean.
2327 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
2328 __ Branch(&fast, eq, a1, Operand(t0));
2329 __ LoadRoot(t0, Heap::kFalseValueRootIndex);
2330 __ Branch(&miss, ne, a1, Operand(t0));
2331 __ bind(&fast);
2332 // Check that the maps starting from the prototype haven't changed.
2333 GenerateDirectLoadGlobalFunctionPrototype(
2334 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002335 CheckPrototypes(
2336 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2337 a0, holder, a3, a1, t0, name, &miss);
2338 } else {
2339 // Calling non-strict non-builtins with a value as the receiver
2340 // requires boxing.
2341 __ jmp(&miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002342 }
2343 break;
2344 }
2345
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002346 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002347 ? CALL_AS_FUNCTION
2348 : CALL_AS_METHOD;
2349 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002350
2351 // Handle call cache miss.
2352 __ bind(&miss);
2353
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002354 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002355
2356 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002357 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002358}
2359
2360
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002361Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2362 Handle<JSObject> holder,
2363 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002364 // ----------- S t a t e -------------
2365 // -- a2 : name
2366 // -- ra : return address
2367 // -----------------------------------
2368
2369 Label miss;
2370
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002371 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002372
2373 // Get the number of arguments.
2374 const int argc = arguments().immediate();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002375 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002376 LookupPostInterceptor(holder, name, &lookup);
2377
2378 // Get the receiver from the stack.
2379 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2380
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002381 CallInterceptorCompiler compiler(this, arguments(), a2, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002382 compiler.Compile(masm(), object, holder, name, &lookup, a1, a3, t0, a0,
2383 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002384
2385 // Move returned value, the function to call, to a1.
2386 __ mov(a1, v0);
2387 // Restore receiver.
2388 __ lw(a0, MemOperand(sp, argc * kPointerSize));
2389
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002390 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002391
2392 // Handle call cache miss.
2393 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002394 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002395
2396 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002397 return GetCode(INTERCEPTOR, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002398}
2399
2400
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002401Handle<Code> CallStubCompiler::CompileCallGlobal(
2402 Handle<JSObject> object,
2403 Handle<GlobalObject> holder,
2404 Handle<JSGlobalPropertyCell> cell,
2405 Handle<JSFunction> function,
2406 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002407 // ----------- S t a t e -------------
2408 // -- a2 : name
2409 // -- ra : return address
2410 // -----------------------------------
2411
2412 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002413 Handle<Code> code = CompileCustomCall(object, holder, cell, function, name);
2414 // A null handle means bail out to the regular compiler code below.
2415 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002416 }
2417
2418 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002419 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002420
2421 // Get the number of arguments.
2422 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002423 GenerateGlobalReceiverCheck(object, holder, name, &miss);
2424 GenerateLoadFunctionFromCell(cell, function, &miss);
2425
2426 // Patch the receiver on the stack with the global proxy if
2427 // necessary.
2428 if (object->IsGlobalObject()) {
2429 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
2430 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2431 }
2432
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002433 // Set up the context (function already in r1).
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002434 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
2435
2436 // Jump to the cached code (tail call).
2437 Counters* counters = masm()->isolate()->counters();
2438 __ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002439 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002440 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002441 ? CALL_AS_FUNCTION
2442 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002443 // We call indirectly through the code field in the function to
2444 // allow recompilation to take effect without changing any of the
2445 // call sites.
2446 __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
2447 __ InvokeCode(a3, expected, arguments(), JUMP_FUNCTION,
2448 NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002449
2450 // Handle call cache miss.
2451 __ bind(&miss);
2452 __ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002453 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002454
2455 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002456 return GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002457}
2458
2459
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002460Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +00002461 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002462 Handle<Map> transition,
2463 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002464 // ----------- S t a t e -------------
2465 // -- a0 : value
2466 // -- a1 : receiver
2467 // -- a2 : name
2468 // -- ra : return address
2469 // -----------------------------------
2470 Label miss;
2471
2472 // Name register might be clobbered.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002473 GenerateStoreField(masm(), object, index, transition, a1, a2, a3, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002474 __ bind(&miss);
2475 __ li(a2, Operand(Handle<String>(name))); // Restore name.
2476 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2477 __ Jump(ic, RelocInfo::CODE_TARGET);
2478
2479 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002480 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002481}
2482
2483
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002484Handle<Code> StoreStubCompiler::CompileStoreCallback(
2485 Handle<JSObject> object,
2486 Handle<AccessorInfo> callback,
2487 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002488 // ----------- S t a t e -------------
2489 // -- a0 : value
2490 // -- a1 : receiver
2491 // -- a2 : name
2492 // -- ra : return address
2493 // -----------------------------------
2494 Label miss;
2495
2496 // Check that the object isn't a smi.
2497 __ JumpIfSmi(a1, &miss);
2498
2499 // Check that the map of the object hasn't changed.
2500 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2501 __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map())));
2502
2503 // Perform global security token check if needed.
2504 if (object->IsJSGlobalProxy()) {
2505 __ CheckAccessGlobalProxy(a1, a3, &miss);
2506 }
2507
2508 // Stub never generated for non-global objects that require access
2509 // checks.
2510 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
2511
2512 __ push(a1); // Receiver.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002513 __ li(a3, Operand(callback)); // Callback info.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002514 __ Push(a3, a2, a0);
2515
2516 // Do tail-call to the runtime system.
2517 ExternalReference store_callback_property =
2518 ExternalReference(IC_Utility(IC::kStoreCallbackProperty),
2519 masm()->isolate());
2520 __ TailCallExternalReference(store_callback_property, 4, 1);
2521
2522 // Handle store cache miss.
2523 __ bind(&miss);
2524 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2525 __ Jump(ic, RelocInfo::CODE_TARGET);
2526
2527 // Return the generated code.
2528 return GetCode(CALLBACKS, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002529}
2530
2531
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002532Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
2533 Handle<JSObject> receiver,
2534 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002535 // ----------- S t a t e -------------
2536 // -- a0 : value
2537 // -- a1 : receiver
2538 // -- a2 : name
2539 // -- ra : return address
2540 // -----------------------------------
2541 Label miss;
2542
2543 // Check that the object isn't a smi.
2544 __ JumpIfSmi(a1, &miss);
2545
2546 // Check that the map of the object hasn't changed.
2547 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2548 __ Branch(&miss, ne, a3, Operand(Handle<Map>(receiver->map())));
2549
2550 // Perform global security token check if needed.
2551 if (receiver->IsJSGlobalProxy()) {
2552 __ CheckAccessGlobalProxy(a1, a3, &miss);
2553 }
2554
2555 // Stub is never generated for non-global objects that require access
2556 // checks.
2557 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2558
2559 __ Push(a1, a2, a0); // Receiver, name, value.
2560
2561 __ li(a0, Operand(Smi::FromInt(strict_mode_)));
2562 __ push(a0); // Strict mode.
2563
2564 // Do tail-call to the runtime system.
2565 ExternalReference store_ic_property =
2566 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty),
2567 masm()->isolate());
2568 __ TailCallExternalReference(store_ic_property, 4, 1);
2569
2570 // Handle store cache miss.
2571 __ bind(&miss);
2572 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2573 __ Jump(ic, RelocInfo::CODE_TARGET);
2574
2575 // Return the generated code.
2576 return GetCode(INTERCEPTOR, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002577}
2578
2579
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002580Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2581 Handle<GlobalObject> object,
2582 Handle<JSGlobalPropertyCell> cell,
2583 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002584 // ----------- S t a t e -------------
2585 // -- a0 : value
2586 // -- a1 : receiver
2587 // -- a2 : name
2588 // -- ra : return address
2589 // -----------------------------------
2590 Label miss;
2591
2592 // Check that the map of the global has not changed.
2593 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2594 __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map())));
2595
2596 // Check that the value in the cell is not the hole. If it is, this
2597 // cell could have been deleted and reintroducing the global needs
2598 // to update the property details in the property dictionary of the
2599 // global object. We bail out to the runtime system to do that.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002600 __ li(t0, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002601 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
2602 __ lw(t2, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2603 __ Branch(&miss, eq, t1, Operand(t2));
2604
2605 // Store the value in the cell.
2606 __ sw(a0, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2607 __ mov(v0, a0); // Stored value must be returned in v0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002608 // Cells are always rescanned, so no write barrier here.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002609
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002610 Counters* counters = masm()->isolate()->counters();
2611 __ IncrementCounter(counters->named_store_global_inline(), 1, a1, a3);
2612 __ Ret();
2613
2614 // Handle store cache miss.
2615 __ bind(&miss);
2616 __ IncrementCounter(counters->named_store_global_inline_miss(), 1, a1, a3);
2617 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2618 __ Jump(ic, RelocInfo::CODE_TARGET);
2619
2620 // Return the generated code.
2621 return GetCode(NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002622}
2623
2624
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002625Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
2626 Handle<JSObject> object,
2627 Handle<JSObject> last) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002628 // ----------- S t a t e -------------
2629 // -- a0 : receiver
2630 // -- ra : return address
2631 // -----------------------------------
2632 Label miss;
2633
2634 // Check that the receiver is not a smi.
2635 __ JumpIfSmi(a0, &miss);
2636
2637 // Check the maps of the full prototype chain.
2638 CheckPrototypes(object, a0, last, a3, a1, t0, name, &miss);
2639
2640 // If the last object in the prototype chain is a global object,
2641 // check that the global property cell is empty.
2642 if (last->IsGlobalObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002643 GenerateCheckPropertyCell(
2644 masm(), Handle<GlobalObject>::cast(last), name, a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002645 }
2646
2647 // Return undefined if maps of the full prototype chain is still the same.
2648 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2649 __ Ret();
2650
2651 __ bind(&miss);
2652 GenerateLoadMiss(masm(), Code::LOAD_IC);
2653
2654 // Return the generated code.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002655 return GetCode(NONEXISTENT, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00002656}
2657
2658
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002659Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object,
2660 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002661 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002662 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002663 // ----------- S t a t e -------------
2664 // -- a0 : receiver
2665 // -- a2 : name
2666 // -- ra : return address
2667 // -----------------------------------
2668 Label miss;
2669
2670 __ mov(v0, a0);
2671
2672 GenerateLoadField(object, holder, v0, a3, a1, t0, index, name, &miss);
2673 __ bind(&miss);
2674 GenerateLoadMiss(masm(), Code::LOAD_IC);
2675
2676 // Return the generated code.
2677 return GetCode(FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002678}
2679
2680
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002681Handle<Code> LoadStubCompiler::CompileLoadCallback(
2682 Handle<String> name,
2683 Handle<JSObject> object,
2684 Handle<JSObject> holder,
2685 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002686 // ----------- S t a t e -------------
2687 // -- a0 : receiver
2688 // -- a2 : name
2689 // -- ra : return address
2690 // -----------------------------------
2691 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002692 GenerateLoadCallback(object, holder, a0, a2, a3, a1, t0, callback, name,
2693 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002694 __ bind(&miss);
2695 GenerateLoadMiss(masm(), Code::LOAD_IC);
2696
2697 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002698 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002699}
2700
2701
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002702Handle<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object,
2703 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002704 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002705 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002706 // ----------- S t a t e -------------
2707 // -- a0 : receiver
2708 // -- a2 : name
2709 // -- ra : return address
2710 // -----------------------------------
2711 Label miss;
2712
2713 GenerateLoadConstant(object, holder, a0, a3, a1, t0, value, name, &miss);
2714 __ bind(&miss);
2715 GenerateLoadMiss(masm(), Code::LOAD_IC);
2716
2717 // Return the generated code.
2718 return GetCode(CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002719}
2720
2721
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002722Handle<Code> LoadStubCompiler::CompileLoadInterceptor(Handle<JSObject> object,
2723 Handle<JSObject> holder,
2724 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002725 // ----------- S t a t e -------------
2726 // -- a0 : receiver
2727 // -- a2 : name
2728 // -- ra : return address
2729 // -- [sp] : receiver
2730 // -----------------------------------
2731 Label miss;
2732
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002733 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002734 LookupPostInterceptor(holder, name, &lookup);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002735 GenerateLoadInterceptor(object, holder, &lookup, a0, a2, a3, a1, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002736 &miss);
2737 __ bind(&miss);
2738 GenerateLoadMiss(masm(), Code::LOAD_IC);
2739
2740 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002741 return GetCode(INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002742}
2743
2744
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002745Handle<Code> LoadStubCompiler::CompileLoadGlobal(
2746 Handle<JSObject> object,
2747 Handle<GlobalObject> holder,
2748 Handle<JSGlobalPropertyCell> cell,
2749 Handle<String> name,
2750 bool is_dont_delete) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002751 // ----------- S t a t e -------------
2752 // -- a0 : receiver
2753 // -- a2 : name
2754 // -- ra : return address
2755 // -----------------------------------
2756 Label miss;
2757
2758 // If the object is the holder then we know that it's a global
2759 // object which can only happen for contextual calls. In this case,
2760 // the receiver cannot be a smi.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002761 if (!object.is_identical_to(holder)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002762 __ JumpIfSmi(a0, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002763 }
2764
2765 // Check that the map of the global has not changed.
2766 CheckPrototypes(object, a0, holder, a3, t0, a1, name, &miss);
2767
2768 // Get the value from the cell.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002769 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002770 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
2771
2772 // Check for deleted property if property can actually be deleted.
2773 if (!is_dont_delete) {
2774 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
2775 __ Branch(&miss, eq, t0, Operand(at));
2776 }
2777
2778 __ mov(v0, t0);
2779 Counters* counters = masm()->isolate()->counters();
2780 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
2781 __ Ret();
2782
2783 __ bind(&miss);
2784 __ IncrementCounter(counters->named_load_global_stub_miss(), 1, a1, a3);
2785 GenerateLoadMiss(masm(), Code::LOAD_IC);
2786
2787 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002788 return GetCode(NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002789}
2790
2791
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002792Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
2793 Handle<JSObject> receiver,
2794 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002795 int index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002796 // ----------- S t a t e -------------
2797 // -- ra : return address
2798 // -- a0 : key
2799 // -- a1 : receiver
2800 // -----------------------------------
2801 Label miss;
2802
2803 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002804 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002805
2806 GenerateLoadField(receiver, holder, a1, a2, a3, t0, index, name, &miss);
2807 __ bind(&miss);
2808 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2809
2810 return GetCode(FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002811}
2812
2813
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002814Handle<Code> KeyedLoadStubCompiler::CompileLoadCallback(
2815 Handle<String> name,
2816 Handle<JSObject> receiver,
2817 Handle<JSObject> holder,
2818 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002819 // ----------- S t a t e -------------
2820 // -- ra : return address
2821 // -- a0 : key
2822 // -- a1 : receiver
2823 // -----------------------------------
2824 Label miss;
2825
2826 // Check the key is the cached one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002827 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002828
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002829 GenerateLoadCallback(receiver, holder, a1, a0, a2, a3, t0, callback, name,
2830 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002831 __ bind(&miss);
2832 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2833
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002834 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002835}
2836
2837
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002838Handle<Code> KeyedLoadStubCompiler::CompileLoadConstant(
2839 Handle<String> name,
2840 Handle<JSObject> receiver,
2841 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002842 Handle<JSFunction> value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002843 // ----------- S t a t e -------------
2844 // -- ra : return address
2845 // -- a0 : key
2846 // -- a1 : receiver
2847 // -----------------------------------
2848 Label miss;
2849
2850 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002851 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002852
2853 GenerateLoadConstant(receiver, holder, a1, a2, a3, t0, value, name, &miss);
2854 __ bind(&miss);
2855 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2856
2857 // Return the generated code.
2858 return GetCode(CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002859}
2860
2861
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002862Handle<Code> KeyedLoadStubCompiler::CompileLoadInterceptor(
2863 Handle<JSObject> receiver,
2864 Handle<JSObject> holder,
2865 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002866 // ----------- S t a t e -------------
2867 // -- ra : return address
2868 // -- a0 : key
2869 // -- a1 : receiver
2870 // -----------------------------------
2871 Label miss;
2872
2873 // Check the key is the cached one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002874 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002875
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002876 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002877 LookupPostInterceptor(holder, name, &lookup);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002878 GenerateLoadInterceptor(receiver, holder, &lookup, a1, a0, a2, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002879 &miss);
2880 __ bind(&miss);
2881 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2882
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002883 return GetCode(INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002884}
2885
2886
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002887Handle<Code> KeyedLoadStubCompiler::CompileLoadArrayLength(
2888 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002889 // ----------- S t a t e -------------
2890 // -- ra : return address
2891 // -- a0 : key
2892 // -- a1 : receiver
2893 // -----------------------------------
2894 Label miss;
2895
2896 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002897 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002898
2899 GenerateLoadArrayLength(masm(), a1, a2, &miss);
2900 __ bind(&miss);
2901 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2902
2903 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002904}
2905
2906
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002907Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength(
2908 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002909 // ----------- S t a t e -------------
2910 // -- ra : return address
2911 // -- a0 : key
2912 // -- a1 : receiver
2913 // -----------------------------------
2914 Label miss;
2915
2916 Counters* counters = masm()->isolate()->counters();
2917 __ IncrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
2918
2919 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002920 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002921
2922 GenerateLoadStringLength(masm(), a1, a2, a3, &miss, true);
2923 __ bind(&miss);
2924 __ DecrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
2925
2926 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2927
2928 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002929}
2930
2931
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002932Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype(
2933 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002934 // ----------- S t a t e -------------
2935 // -- ra : return address
2936 // -- a0 : key
2937 // -- a1 : receiver
2938 // -----------------------------------
2939 Label miss;
2940
2941 Counters* counters = masm()->isolate()->counters();
2942 __ IncrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
2943
2944 // Check the name hasn't changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002945 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002946
2947 GenerateLoadFunctionPrototype(masm(), a1, a2, a3, &miss);
2948 __ bind(&miss);
2949 __ DecrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
2950 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2951
2952 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002953}
2954
2955
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002956Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
2957 Handle<Map> receiver_map) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00002958 // ----------- S t a t e -------------
2959 // -- ra : return address
2960 // -- a0 : key
2961 // -- a1 : receiver
2962 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002963 ElementsKind elements_kind = receiver_map->elements_kind();
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002964 Handle<Code> stub = KeyedLoadElementStub(elements_kind).GetCode();
2965
2966 __ DispatchMap(a1, a2, receiver_map, stub, DO_SMI_CHECK);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002967
2968 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
2969 __ Jump(ic, RelocInfo::CODE_TARGET);
2970
2971 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002972 return GetCode(NORMAL, factory()->empty_string());
danno@chromium.org40cb8782011-05-25 07:58:50 +00002973}
2974
2975
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002976Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
2977 MapHandleList* receiver_maps,
2978 CodeHandleList* handler_ics) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002979 // ----------- S t a t e -------------
2980 // -- ra : return address
2981 // -- a0 : key
2982 // -- a1 : receiver
2983 // -----------------------------------
2984 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002985 __ JumpIfSmi(a1, &miss);
2986
danno@chromium.org40cb8782011-05-25 07:58:50 +00002987 int receiver_count = receiver_maps->length();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002988 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00002989 for (int current = 0; current < receiver_count; ++current) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002990 __ Jump(handler_ics->at(current), RelocInfo::CODE_TARGET,
2991 eq, a2, Operand(receiver_maps->at(current)));
danno@chromium.org40cb8782011-05-25 07:58:50 +00002992 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002993
2994 __ bind(&miss);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002995 Handle<Code> miss_ic = isolate()->builtins()->KeyedLoadIC_Miss();
2996 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002997
2998 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002999 return GetCode(NORMAL, factory()->empty_string(), MEGAMORPHIC);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003000}
3001
3002
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003003Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +00003004 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003005 Handle<Map> transition,
3006 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003007 // ----------- S t a t e -------------
3008 // -- a0 : value
3009 // -- a1 : key
3010 // -- a2 : receiver
3011 // -- ra : return address
3012 // -----------------------------------
3013
3014 Label miss;
3015
3016 Counters* counters = masm()->isolate()->counters();
3017 __ IncrementCounter(counters->keyed_store_field(), 1, a3, t0);
3018
3019 // Check that the name has not changed.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003020 __ Branch(&miss, ne, a1, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003021
3022 // a3 is used as scratch register. a1 and a2 keep their values if a jump to
3023 // the miss label is generated.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003024 GenerateStoreField(masm(), object, index, transition, a2, a1, a3, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003025 __ bind(&miss);
3026
3027 __ DecrementCounter(counters->keyed_store_field(), 1, a3, t0);
3028 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss();
3029 __ Jump(ic, RelocInfo::CODE_TARGET);
3030
3031 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003032 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003033}
3034
3035
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003036Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
3037 Handle<Map> receiver_map) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003038 // ----------- S t a t e -------------
3039 // -- a0 : value
3040 // -- a1 : key
3041 // -- a2 : receiver
3042 // -- ra : return address
3043 // -- a3 : scratch
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003044 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003045 ElementsKind elements_kind = receiver_map->elements_kind();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003046 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003047 Handle<Code> stub =
3048 KeyedStoreElementStub(is_js_array, elements_kind).GetCode();
3049
3050 __ DispatchMap(a2, a3, receiver_map, stub, DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003051
danno@chromium.org40cb8782011-05-25 07:58:50 +00003052 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003053 __ Jump(ic, RelocInfo::CODE_TARGET);
3054
3055 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003056 return GetCode(NORMAL, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00003057}
3058
3059
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003060Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
3061 MapHandleList* receiver_maps,
3062 CodeHandleList* handler_stubs,
3063 MapHandleList* transitioned_maps) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003064 // ----------- S t a t e -------------
3065 // -- a0 : value
3066 // -- a1 : key
3067 // -- a2 : receiver
3068 // -- ra : return address
3069 // -- a3 : scratch
3070 // -----------------------------------
3071 Label miss;
3072 __ JumpIfSmi(a2, &miss);
3073
3074 int receiver_count = receiver_maps->length();
3075 __ lw(a3, FieldMemOperand(a2, HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003076 for (int i = 0; i < receiver_count; ++i) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003077 if (transitioned_maps->at(i).is_null()) {
3078 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq,
3079 a3, Operand(receiver_maps->at(i)));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003080 } else {
3081 Label next_map;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003082 __ Branch(&next_map, ne, a3, Operand(receiver_maps->at(i)));
3083 __ li(a3, Operand(transitioned_maps->at(i)));
3084 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003085 __ bind(&next_map);
3086 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003087 }
3088
3089 __ bind(&miss);
3090 Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
3091 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3092
3093 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003094 return GetCode(NORMAL, factory()->empty_string(), MEGAMORPHIC);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003095}
3096
3097
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003098Handle<Code> ConstructStubCompiler::CompileConstructStub(
3099 Handle<JSFunction> function) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003100 // a0 : argc
3101 // a1 : constructor
3102 // ra : return address
3103 // [sp] : last argument
3104 Label generic_stub_call;
3105
3106 // Use t7 for holding undefined which is used in several places below.
3107 __ LoadRoot(t7, Heap::kUndefinedValueRootIndex);
3108
3109#ifdef ENABLE_DEBUGGER_SUPPORT
3110 // Check to see whether there are any break points in the function code. If
3111 // there are jump to the generic constructor stub which calls the actual
3112 // code for the function thereby hitting the break points.
3113 __ lw(t5, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3114 __ lw(a2, FieldMemOperand(t5, SharedFunctionInfo::kDebugInfoOffset));
3115 __ Branch(&generic_stub_call, ne, a2, Operand(t7));
3116#endif
3117
3118 // Load the initial map and verify that it is in fact a map.
3119 // a1: constructor function
3120 // t7: undefined
3121 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003122 __ JumpIfSmi(a2, &generic_stub_call);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003123 __ GetObjectType(a2, a3, t0);
3124 __ Branch(&generic_stub_call, ne, t0, Operand(MAP_TYPE));
3125
3126#ifdef DEBUG
3127 // Cannot construct functions this way.
3128 // a0: argc
3129 // a1: constructor function
3130 // a2: initial map
3131 // t7: undefined
3132 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
3133 __ Check(ne, "Function constructed by construct stub.",
3134 a3, Operand(JS_FUNCTION_TYPE));
3135#endif
3136
3137 // Now allocate the JSObject in new space.
3138 // a0: argc
3139 // a1: constructor function
3140 // a2: initial map
3141 // t7: undefined
3142 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003143 __ AllocateInNewSpace(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003144
3145 // Allocated the JSObject, now initialize the fields. Map is set to initial
3146 // map and properties and elements are set to empty fixed array.
3147 // a0: argc
3148 // a1: constructor function
3149 // a2: initial map
3150 // a3: object size (in words)
3151 // t4: JSObject (not tagged)
3152 // t7: undefined
3153 __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex);
3154 __ mov(t5, t4);
3155 __ sw(a2, MemOperand(t5, JSObject::kMapOffset));
3156 __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset));
3157 __ sw(t6, MemOperand(t5, JSObject::kElementsOffset));
3158 __ Addu(t5, t5, Operand(3 * kPointerSize));
3159 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
3160 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
3161 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
3162
3163
3164 // Calculate the location of the first argument. The stack contains only the
3165 // argc arguments.
3166 __ sll(a1, a0, kPointerSizeLog2);
3167 __ Addu(a1, a1, sp);
3168
3169 // Fill all the in-object properties with undefined.
3170 // a0: argc
3171 // a1: first argument
3172 // a3: object size (in words)
3173 // t4: JSObject (not tagged)
3174 // t5: First in-object property of JSObject (not tagged)
3175 // t7: undefined
3176 // Fill the initialized properties with a constant value or a passed argument
3177 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003178 Handle<SharedFunctionInfo> shared(function->shared());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003179 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3180 if (shared->IsThisPropertyAssignmentArgument(i)) {
3181 Label not_passed, next;
3182 // Check if the argument assigned to the property is actually passed.
3183 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3184 __ Branch(&not_passed, less_equal, a0, Operand(arg_number));
3185 // Argument passed - find it on the stack.
3186 __ lw(a2, MemOperand(a1, (arg_number + 1) * -kPointerSize));
3187 __ sw(a2, MemOperand(t5));
3188 __ Addu(t5, t5, kPointerSize);
3189 __ jmp(&next);
3190 __ bind(&not_passed);
3191 // Set the property to undefined.
3192 __ sw(t7, MemOperand(t5));
3193 __ Addu(t5, t5, Operand(kPointerSize));
3194 __ bind(&next);
3195 } else {
3196 // Set the property to the constant value.
3197 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
3198 __ li(a2, Operand(constant));
3199 __ sw(a2, MemOperand(t5));
3200 __ Addu(t5, t5, kPointerSize);
3201 }
3202 }
3203
3204 // Fill the unused in-object property fields with undefined.
3205 ASSERT(function->has_initial_map());
3206 for (int i = shared->this_property_assignments_count();
3207 i < function->initial_map()->inobject_properties();
3208 i++) {
3209 __ sw(t7, MemOperand(t5));
3210 __ Addu(t5, t5, kPointerSize);
3211 }
3212
3213 // a0: argc
3214 // t4: JSObject (not tagged)
3215 // Move argc to a1 and the JSObject to return to v0 and tag it.
3216 __ mov(a1, a0);
3217 __ mov(v0, t4);
3218 __ Or(v0, v0, Operand(kHeapObjectTag));
3219
3220 // v0: JSObject
3221 // a1: argc
3222 // Remove caller arguments and receiver from the stack and return.
3223 __ sll(t0, a1, kPointerSizeLog2);
3224 __ Addu(sp, sp, t0);
3225 __ Addu(sp, sp, Operand(kPointerSize));
3226 Counters* counters = masm()->isolate()->counters();
3227 __ IncrementCounter(counters->constructed_objects(), 1, a1, a2);
3228 __ IncrementCounter(counters->constructed_objects_stub(), 1, a1, a2);
3229 __ Ret();
3230
3231 // Jump to the generic stub in case the specialized code cannot handle the
3232 // construction.
3233 __ bind(&generic_stub_call);
3234 Handle<Code> generic_construct_stub =
3235 masm()->isolate()->builtins()->JSConstructStubGeneric();
3236 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
3237
3238 // Return the generated code.
3239 return GetCode();
3240}
3241
3242
danno@chromium.org40cb8782011-05-25 07:58:50 +00003243#undef __
3244#define __ ACCESS_MASM(masm)
3245
3246
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003247void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3248 MacroAssembler* masm) {
3249 // ---------- S t a t e --------------
3250 // -- ra : return address
3251 // -- a0 : key
3252 // -- a1 : receiver
3253 // -----------------------------------
3254 Label slow, miss_force_generic;
3255
3256 Register key = a0;
3257 Register receiver = a1;
3258
3259 __ JumpIfNotSmi(key, &miss_force_generic);
3260 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
3261 __ sra(a2, a0, kSmiTagSize);
3262 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
3263 __ Ret();
3264
3265 // Slow case, key and receiver still in a0 and a1.
3266 __ bind(&slow);
3267 __ IncrementCounter(
3268 masm->isolate()->counters()->keyed_load_external_array_slow(),
3269 1, a2, a3);
3270 // Entry registers are intact.
3271 // ---------- S t a t e --------------
3272 // -- ra : return address
3273 // -- a0 : key
3274 // -- a1 : receiver
3275 // -----------------------------------
3276 Handle<Code> slow_ic =
3277 masm->isolate()->builtins()->KeyedLoadIC_Slow();
3278 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
3279
3280 // Miss case, call the runtime.
3281 __ bind(&miss_force_generic);
3282
3283 // ---------- S t a t e --------------
3284 // -- ra : return address
3285 // -- a0 : key
3286 // -- a1 : receiver
3287 // -----------------------------------
3288
3289 Handle<Code> miss_ic =
3290 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3291 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3292}
3293
3294
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003295static bool IsElementTypeSigned(ElementsKind elements_kind) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003296 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003297 case EXTERNAL_BYTE_ELEMENTS:
3298 case EXTERNAL_SHORT_ELEMENTS:
3299 case EXTERNAL_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003300 return true;
3301
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003302 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3303 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3304 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3305 case EXTERNAL_PIXEL_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003306 return false;
3307
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003308 case EXTERNAL_FLOAT_ELEMENTS:
3309 case EXTERNAL_DOUBLE_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003310 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003311 case FAST_ELEMENTS:
3312 case FAST_DOUBLE_ELEMENTS:
3313 case DICTIONARY_ELEMENTS:
3314 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003315 UNREACHABLE();
3316 return false;
3317 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003318 return false;
lrn@chromium.org7516f052011-03-30 08:52:27 +00003319}
3320
3321
danno@chromium.org40cb8782011-05-25 07:58:50 +00003322void KeyedLoadStubCompiler::GenerateLoadExternalArray(
3323 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003324 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003325 // ---------- S t a t e --------------
3326 // -- ra : return address
3327 // -- a0 : key
3328 // -- a1 : receiver
3329 // -----------------------------------
danno@chromium.org40cb8782011-05-25 07:58:50 +00003330 Label miss_force_generic, slow, failed_allocation;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003331
3332 Register key = a0;
3333 Register receiver = a1;
3334
danno@chromium.org40cb8782011-05-25 07:58:50 +00003335 // This stub is meant to be tail-jumped to, the receiver must already
3336 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003337
3338 // Check that the key is a smi.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003339 __ JumpIfNotSmi(key, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003340
3341 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3342 // a3: elements array
3343
3344 // Check that the index is in range.
3345 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3346 __ sra(t2, key, kSmiTagSize);
3347 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003348 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003349
3350 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3351 // a3: base pointer of external storage
3352
3353 // We are not untagging smi key and instead work with it
3354 // as if it was premultiplied by 2.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003355 STATIC_ASSERT((kSmiTag == 0) && (kSmiTagSize == 1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003356
3357 Register value = a2;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003358 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003359 case EXTERNAL_BYTE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003360 __ srl(t2, key, 1);
3361 __ addu(t3, a3, t2);
3362 __ lb(value, MemOperand(t3, 0));
3363 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003364 case EXTERNAL_PIXEL_ELEMENTS:
3365 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003366 __ srl(t2, key, 1);
3367 __ addu(t3, a3, t2);
3368 __ lbu(value, MemOperand(t3, 0));
3369 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003370 case EXTERNAL_SHORT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003371 __ addu(t3, a3, key);
3372 __ lh(value, MemOperand(t3, 0));
3373 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003374 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003375 __ addu(t3, a3, key);
3376 __ lhu(value, MemOperand(t3, 0));
3377 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003378 case EXTERNAL_INT_ELEMENTS:
3379 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003380 __ sll(t2, key, 1);
3381 __ addu(t3, a3, t2);
3382 __ lw(value, MemOperand(t3, 0));
3383 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003384 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003385 __ sll(t3, t2, 2);
3386 __ addu(t3, a3, t3);
3387 if (CpuFeatures::IsSupported(FPU)) {
3388 CpuFeatures::Scope scope(FPU);
3389 __ lwc1(f0, MemOperand(t3, 0));
3390 } else {
3391 __ lw(value, MemOperand(t3, 0));
3392 }
3393 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003394 case EXTERNAL_DOUBLE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003395 __ sll(t2, key, 2);
3396 __ addu(t3, a3, t2);
3397 if (CpuFeatures::IsSupported(FPU)) {
3398 CpuFeatures::Scope scope(FPU);
3399 __ ldc1(f0, MemOperand(t3, 0));
3400 } else {
3401 // t3: pointer to the beginning of the double we want to load.
3402 __ lw(a2, MemOperand(t3, 0));
3403 __ lw(a3, MemOperand(t3, Register::kSizeInBytes));
3404 }
3405 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003406 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003407 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003408 case FAST_DOUBLE_ELEMENTS:
3409 case DICTIONARY_ELEMENTS:
3410 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003411 UNREACHABLE();
3412 break;
3413 }
3414
3415 // For integer array types:
3416 // a2: value
3417 // For float array type:
3418 // f0: value (if FPU is supported)
3419 // a2: value (if FPU is not supported)
3420 // For double array type:
3421 // f0: value (if FPU is supported)
3422 // a2/a3: value (if FPU is not supported)
3423
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003424 if (elements_kind == EXTERNAL_INT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003425 // For the Int and UnsignedInt array types, we need to see whether
3426 // the value can be represented in a Smi. If not, we need to convert
3427 // it to a HeapNumber.
3428 Label box_int;
3429 __ Subu(t3, value, Operand(0xC0000000)); // Non-smi value gives neg result.
3430 __ Branch(&box_int, lt, t3, Operand(zero_reg));
3431 // Tag integer as smi and return it.
3432 __ sll(v0, value, kSmiTagSize);
3433 __ Ret();
3434
3435 __ bind(&box_int);
3436 // Allocate a HeapNumber for the result and perform int-to-double
3437 // conversion.
3438 // The arm version uses a temporary here to save r0, but we don't need to
3439 // (a0 is not modified).
3440 __ LoadRoot(t1, Heap::kHeapNumberMapRootIndex);
3441 __ AllocateHeapNumber(v0, a3, t0, t1, &slow);
3442
3443 if (CpuFeatures::IsSupported(FPU)) {
3444 CpuFeatures::Scope scope(FPU);
3445 __ mtc1(value, f0);
3446 __ cvt_d_w(f0, f0);
3447 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag));
3448 __ Ret();
3449 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003450 Register dst1 = t2;
3451 Register dst2 = t3;
3452 FloatingPointHelper::Destination dest =
3453 FloatingPointHelper::kCoreRegisters;
3454 FloatingPointHelper::ConvertIntToDouble(masm,
3455 value,
3456 dest,
3457 f0,
3458 dst1,
3459 dst2,
3460 t1,
3461 f2);
3462 __ sw(dst1, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3463 __ sw(dst2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3464 __ Ret();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003465 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003466 } else if (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003467 // The test is different for unsigned int values. Since we need
3468 // the value to be in the range of a positive smi, we can't
3469 // handle either of the top two bits being set in the value.
3470 if (CpuFeatures::IsSupported(FPU)) {
3471 CpuFeatures::Scope scope(FPU);
3472 Label pl_box_int;
3473 __ And(t2, value, Operand(0xC0000000));
3474 __ Branch(&pl_box_int, ne, t2, Operand(zero_reg));
3475
3476 // It can fit in an Smi.
3477 // Tag integer as smi and return it.
3478 __ sll(v0, value, kSmiTagSize);
3479 __ Ret();
3480
3481 __ bind(&pl_box_int);
3482 // Allocate a HeapNumber for the result and perform int-to-double
3483 // conversion. Don't use a0 and a1 as AllocateHeapNumber clobbers all
3484 // registers - also when jumping due to exhausted young space.
3485 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3486 __ AllocateHeapNumber(v0, t2, t3, t6, &slow);
3487
3488 // This is replaced by a macro:
3489 // __ mtc1(value, f0); // LS 32-bits.
3490 // __ mtc1(zero_reg, f1); // MS 32-bits are all zero.
3491 // __ cvt_d_l(f0, f0); // Use 64 bit conv to get correct unsigned 32-bit.
3492
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003493 __ Cvt_d_uw(f0, value, f22);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003494
3495 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag));
3496
3497 __ Ret();
3498 } else {
3499 // Check whether unsigned integer fits into smi.
3500 Label box_int_0, box_int_1, done;
3501 __ And(t2, value, Operand(0x80000000));
3502 __ Branch(&box_int_0, ne, t2, Operand(zero_reg));
3503 __ And(t2, value, Operand(0x40000000));
3504 __ Branch(&box_int_1, ne, t2, Operand(zero_reg));
3505
3506 // Tag integer as smi and return it.
3507 __ sll(v0, value, kSmiTagSize);
3508 __ Ret();
3509
3510 Register hiword = value; // a2.
3511 Register loword = a3;
3512
3513 __ bind(&box_int_0);
3514 // Integer does not have leading zeros.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003515 GenerateUInt2Double(masm, hiword, loword, t0, 0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003516 __ Branch(&done);
3517
3518 __ bind(&box_int_1);
3519 // Integer has one leading zero.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003520 GenerateUInt2Double(masm, hiword, loword, t0, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003521
3522
3523 __ bind(&done);
3524 // Integer was converted to double in registers hiword:loword.
3525 // Wrap it into a HeapNumber. Don't use a0 and a1 as AllocateHeapNumber
3526 // clobbers all registers - also when jumping due to exhausted young
3527 // space.
3528 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3529 __ AllocateHeapNumber(t2, t3, t5, t6, &slow);
3530
3531 __ sw(hiword, FieldMemOperand(t2, HeapNumber::kExponentOffset));
3532 __ sw(loword, FieldMemOperand(t2, HeapNumber::kMantissaOffset));
3533
3534 __ mov(v0, t2);
3535 __ Ret();
3536 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003537 } else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003538 // For the floating-point array type, we need to always allocate a
3539 // HeapNumber.
3540 if (CpuFeatures::IsSupported(FPU)) {
3541 CpuFeatures::Scope scope(FPU);
3542 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3543 // AllocateHeapNumber clobbers all registers - also when jumping due to
3544 // exhausted young space.
3545 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3546 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3547 // The float (single) value is already in fpu reg f0 (if we use float).
3548 __ cvt_d_s(f0, f0);
3549 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag));
3550 __ Ret();
3551 } else {
3552 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3553 // AllocateHeapNumber clobbers all registers - also when jumping due to
3554 // exhausted young space.
3555 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3556 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3557 // FPU is not available, do manual single to double conversion.
3558
3559 // a2: floating point value (binary32).
3560 // v0: heap number for result
3561
3562 // Extract mantissa to t4.
3563 __ And(t4, value, Operand(kBinary32MantissaMask));
3564
3565 // Extract exponent to t5.
3566 __ srl(t5, value, kBinary32MantissaBits);
3567 __ And(t5, t5, Operand(kBinary32ExponentMask >> kBinary32MantissaBits));
3568
3569 Label exponent_rebiased;
3570 __ Branch(&exponent_rebiased, eq, t5, Operand(zero_reg));
3571
3572 __ li(t0, 0x7ff);
3573 __ Xor(t1, t5, Operand(0xFF));
3574 __ movz(t5, t0, t1); // Set t5 to 0x7ff only if t5 is equal to 0xff.
3575 __ Branch(&exponent_rebiased, eq, t0, Operand(0xff));
3576
3577 // Rebias exponent.
3578 __ Addu(t5,
3579 t5,
3580 Operand(-kBinary32ExponentBias + HeapNumber::kExponentBias));
3581
3582 __ bind(&exponent_rebiased);
3583 __ And(a2, value, Operand(kBinary32SignMask));
3584 value = no_reg;
3585 __ sll(t0, t5, HeapNumber::kMantissaBitsInTopWord);
3586 __ or_(a2, a2, t0);
3587
3588 // Shift mantissa.
3589 static const int kMantissaShiftForHiWord =
3590 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3591
3592 static const int kMantissaShiftForLoWord =
3593 kBitsPerInt - kMantissaShiftForHiWord;
3594
3595 __ srl(t0, t4, kMantissaShiftForHiWord);
3596 __ or_(a2, a2, t0);
3597 __ sll(a0, t4, kMantissaShiftForLoWord);
3598
3599 __ sw(a2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3600 __ sw(a0, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3601 __ Ret();
3602 }
3603
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003604 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003605 if (CpuFeatures::IsSupported(FPU)) {
3606 CpuFeatures::Scope scope(FPU);
3607 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3608 // AllocateHeapNumber clobbers all registers - also when jumping due to
3609 // exhausted young space.
3610 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3611 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3612 // The double value is already in f0
3613 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
3614 __ Ret();
3615 } else {
3616 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3617 // AllocateHeapNumber clobbers all registers - also when jumping due to
3618 // exhausted young space.
3619 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3620 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3621
3622 __ sw(a2, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3623 __ sw(a3, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3624 __ Ret();
3625 }
3626
3627 } else {
3628 // Tag integer as smi and return it.
3629 __ sll(v0, value, kSmiTagSize);
3630 __ Ret();
3631 }
3632
3633 // Slow case, key and receiver still in a0 and a1.
3634 __ bind(&slow);
3635 __ IncrementCounter(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003636 masm->isolate()->counters()->keyed_load_external_array_slow(),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003637 1, a2, a3);
3638
3639 // ---------- S t a t e --------------
3640 // -- ra : return address
3641 // -- a0 : key
3642 // -- a1 : receiver
3643 // -----------------------------------
3644
3645 __ Push(a1, a0);
3646
3647 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
3648
danno@chromium.org40cb8782011-05-25 07:58:50 +00003649 __ bind(&miss_force_generic);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003650 Handle<Code> stub =
3651 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3652 __ Jump(stub, RelocInfo::CODE_TARGET);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003653}
3654
3655
danno@chromium.org40cb8782011-05-25 07:58:50 +00003656void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3657 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003658 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003659 // ---------- S t a t e --------------
3660 // -- a0 : value
3661 // -- a1 : key
3662 // -- a2 : receiver
3663 // -- ra : return address
3664 // -----------------------------------
3665
danno@chromium.org40cb8782011-05-25 07:58:50 +00003666 Label slow, check_heap_number, miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003667
3668 // Register usage.
3669 Register value = a0;
3670 Register key = a1;
3671 Register receiver = a2;
3672 // a3 mostly holds the elements array or the destination external array.
3673
danno@chromium.org40cb8782011-05-25 07:58:50 +00003674 // This stub is meant to be tail-jumped to, the receiver must already
3675 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003676
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003677 // Check that the key is a smi.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003678 __ JumpIfNotSmi(key, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003679
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003680 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3681
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003682 // Check that the index is in range.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003683 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3684 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003685 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003686
3687 // Handle both smis and HeapNumbers in the fast path. Go to the
3688 // runtime for all other kinds of values.
3689 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003690
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003691 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003692 // Double to pixel conversion is only implemented in the runtime for now.
3693 __ JumpIfNotSmi(value, &slow);
3694 } else {
3695 __ JumpIfNotSmi(value, &check_heap_number);
3696 }
3697 __ SmiUntag(t1, value);
3698 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3699
3700 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003701 // t1: value (integer).
3702
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003703 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003704 case EXTERNAL_PIXEL_ELEMENTS: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003705 // Clamp the value to [0..255].
3706 // v0 is used as a scratch register here.
3707 Label done;
3708 __ li(v0, Operand(255));
3709 // Normal branch: nop in delay slot.
3710 __ Branch(&done, gt, t1, Operand(v0));
3711 // Use delay slot in this branch.
3712 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg));
3713 __ mov(v0, zero_reg); // In delay slot.
3714 __ mov(v0, t1); // Value is in range 0..255.
3715 __ bind(&done);
3716 __ mov(t1, v0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003717
3718 __ srl(t8, key, 1);
3719 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003720 __ sb(t1, MemOperand(t8, 0));
3721 }
3722 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003723 case EXTERNAL_BYTE_ELEMENTS:
3724 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003725 __ srl(t8, key, 1);
3726 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003727 __ sb(t1, MemOperand(t8, 0));
3728 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003729 case EXTERNAL_SHORT_ELEMENTS:
3730 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003731 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003732 __ sh(t1, MemOperand(t8, 0));
3733 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003734 case EXTERNAL_INT_ELEMENTS:
3735 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003736 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003737 __ addu(t8, a3, t8);
3738 __ sw(t1, MemOperand(t8, 0));
3739 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003740 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003741 // Perform int-to-float conversion and store to memory.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003742 __ SmiUntag(t0, key);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003743 StoreIntAsFloat(masm, a3, t0, t1, t2, t3, t4);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003744 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003745 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003746 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003747 __ addu(a3, a3, t8);
3748 // a3: effective address of the double element
3749 FloatingPointHelper::Destination destination;
3750 if (CpuFeatures::IsSupported(FPU)) {
3751 destination = FloatingPointHelper::kFPURegisters;
3752 } else {
3753 destination = FloatingPointHelper::kCoreRegisters;
3754 }
3755 FloatingPointHelper::ConvertIntToDouble(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003756 masm, t1, destination,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003757 f0, t2, t3, // These are: double_dst, dst1, dst2.
3758 t0, f2); // These are: scratch2, single_scratch.
3759 if (destination == FloatingPointHelper::kFPURegisters) {
3760 CpuFeatures::Scope scope(FPU);
3761 __ sdc1(f0, MemOperand(a3, 0));
3762 } else {
3763 __ sw(t2, MemOperand(a3, 0));
3764 __ sw(t3, MemOperand(a3, Register::kSizeInBytes));
3765 }
3766 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003767 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003768 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003769 case FAST_DOUBLE_ELEMENTS:
3770 case DICTIONARY_ELEMENTS:
3771 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003772 UNREACHABLE();
3773 break;
3774 }
3775
3776 // Entry registers are intact, a0 holds the value which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003777 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003778 __ Ret();
3779
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003780 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003781 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003782 __ bind(&check_heap_number);
3783 __ GetObjectType(value, t1, t2);
3784 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE));
3785
3786 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3787
3788 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003789
3790 // The WebGL specification leaves the behavior of storing NaN and
3791 // +/-Infinity into integer arrays basically undefined. For more
3792 // reproducible behavior, convert these to zero.
3793
3794 if (CpuFeatures::IsSupported(FPU)) {
3795 CpuFeatures::Scope scope(FPU);
3796
3797 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
3798
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003799 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003800 __ cvt_s_d(f0, f0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003801 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003802 __ addu(t8, a3, t8);
3803 __ swc1(f0, MemOperand(t8, 0));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003804 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003805 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003806 __ addu(t8, a3, t8);
3807 __ sdc1(f0, MemOperand(t8, 0));
3808 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003809 __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003810
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003811 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003812 case EXTERNAL_BYTE_ELEMENTS:
3813 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003814 __ srl(t8, key, 1);
3815 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003816 __ sb(t3, MemOperand(t8, 0));
3817 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003818 case EXTERNAL_SHORT_ELEMENTS:
3819 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003820 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003821 __ sh(t3, MemOperand(t8, 0));
3822 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003823 case EXTERNAL_INT_ELEMENTS:
3824 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003825 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003826 __ addu(t8, a3, t8);
3827 __ sw(t3, MemOperand(t8, 0));
3828 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003829 case EXTERNAL_PIXEL_ELEMENTS:
3830 case EXTERNAL_FLOAT_ELEMENTS:
3831 case EXTERNAL_DOUBLE_ELEMENTS:
3832 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003833 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003834 case FAST_DOUBLE_ELEMENTS:
3835 case DICTIONARY_ELEMENTS:
3836 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003837 UNREACHABLE();
3838 break;
3839 }
3840 }
3841
3842 // Entry registers are intact, a0 holds the value
3843 // which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003844 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003845 __ Ret();
3846 } else {
3847 // FPU is not available, do manual conversions.
3848
3849 __ lw(t3, FieldMemOperand(value, HeapNumber::kExponentOffset));
3850 __ lw(t4, FieldMemOperand(value, HeapNumber::kMantissaOffset));
3851
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003852 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003853 Label done, nan_or_infinity_or_zero;
3854 static const int kMantissaInHiWordShift =
3855 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3856
3857 static const int kMantissaInLoWordShift =
3858 kBitsPerInt - kMantissaInHiWordShift;
3859
3860 // Test for all special exponent values: zeros, subnormal numbers, NaNs
3861 // and infinities. All these should be converted to 0.
3862 __ li(t5, HeapNumber::kExponentMask);
3863 __ and_(t6, t3, t5);
3864 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(zero_reg));
3865
3866 __ xor_(t1, t6, t5);
3867 __ li(t2, kBinary32ExponentMask);
3868 __ movz(t6, t2, t1); // Only if t6 is equal to t5.
3869 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(t5));
3870
3871 // Rebias exponent.
3872 __ srl(t6, t6, HeapNumber::kExponentShift);
3873 __ Addu(t6,
3874 t6,
3875 Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
3876
3877 __ li(t1, Operand(kBinary32MaxExponent));
3878 __ Slt(t1, t1, t6);
3879 __ And(t2, t3, Operand(HeapNumber::kSignMask));
3880 __ Or(t2, t2, Operand(kBinary32ExponentMask));
3881 __ movn(t3, t2, t1); // Only if t6 is gt kBinary32MaxExponent.
3882 __ Branch(&done, gt, t6, Operand(kBinary32MaxExponent));
3883
3884 __ Slt(t1, t6, Operand(kBinary32MinExponent));
3885 __ And(t2, t3, Operand(HeapNumber::kSignMask));
3886 __ movn(t3, t2, t1); // Only if t6 is lt kBinary32MinExponent.
3887 __ Branch(&done, lt, t6, Operand(kBinary32MinExponent));
3888
3889 __ And(t7, t3, Operand(HeapNumber::kSignMask));
3890 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3891 __ sll(t3, t3, kMantissaInHiWordShift);
3892 __ or_(t7, t7, t3);
3893 __ srl(t4, t4, kMantissaInLoWordShift);
3894 __ or_(t7, t7, t4);
3895 __ sll(t6, t6, kBinary32ExponentShift);
3896 __ or_(t3, t7, t6);
3897
3898 __ bind(&done);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003899 __ sll(t9, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003900 __ addu(t9, a2, t9);
3901 __ sw(t3, MemOperand(t9, 0));
3902
3903 // Entry registers are intact, a0 holds the value which is the return
3904 // value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003905 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003906 __ Ret();
3907
3908 __ bind(&nan_or_infinity_or_zero);
3909 __ And(t7, t3, Operand(HeapNumber::kSignMask));
3910 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3911 __ or_(t6, t6, t7);
3912 __ sll(t3, t3, kMantissaInHiWordShift);
3913 __ or_(t6, t6, t3);
3914 __ srl(t4, t4, kMantissaInLoWordShift);
3915 __ or_(t3, t6, t4);
3916 __ Branch(&done);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003917 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003918 __ sll(t8, t0, 3);
3919 __ addu(t8, a3, t8);
3920 // t8: effective address of destination element.
3921 __ sw(t4, MemOperand(t8, 0));
3922 __ sw(t3, MemOperand(t8, Register::kSizeInBytes));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003923 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003924 __ Ret();
3925 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003926 bool is_signed_type = IsElementTypeSigned(elements_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003927 int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
3928 int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
3929
3930 Label done, sign;
3931
3932 // Test for all special exponent values: zeros, subnormal numbers, NaNs
3933 // and infinities. All these should be converted to 0.
3934 __ li(t5, HeapNumber::kExponentMask);
3935 __ and_(t6, t3, t5);
3936 __ movz(t3, zero_reg, t6); // Only if t6 is equal to zero.
3937 __ Branch(&done, eq, t6, Operand(zero_reg));
3938
3939 __ xor_(t2, t6, t5);
3940 __ movz(t3, zero_reg, t2); // Only if t6 is equal to t5.
3941 __ Branch(&done, eq, t6, Operand(t5));
3942
3943 // Unbias exponent.
3944 __ srl(t6, t6, HeapNumber::kExponentShift);
3945 __ Subu(t6, t6, Operand(HeapNumber::kExponentBias));
3946 // If exponent is negative then result is 0.
3947 __ slt(t2, t6, zero_reg);
3948 __ movn(t3, zero_reg, t2); // Only if exponent is negative.
3949 __ Branch(&done, lt, t6, Operand(zero_reg));
3950
3951 // If exponent is too big then result is minimal value.
3952 __ slti(t1, t6, meaningfull_bits - 1);
3953 __ li(t2, min_value);
3954 __ movz(t3, t2, t1); // Only if t6 is ge meaningfull_bits - 1.
3955 __ Branch(&done, ge, t6, Operand(meaningfull_bits - 1));
3956
3957 __ And(t5, t3, Operand(HeapNumber::kSignMask));
3958 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3959 __ Or(t3, t3, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
3960
3961 __ li(t9, HeapNumber::kMantissaBitsInTopWord);
3962 __ subu(t6, t9, t6);
3963 __ slt(t1, t6, zero_reg);
3964 __ srlv(t2, t3, t6);
3965 __ movz(t3, t2, t1); // Only if t6 is positive.
3966 __ Branch(&sign, ge, t6, Operand(zero_reg));
3967
3968 __ subu(t6, zero_reg, t6);
3969 __ sllv(t3, t3, t6);
3970 __ li(t9, meaningfull_bits);
3971 __ subu(t6, t9, t6);
3972 __ srlv(t4, t4, t6);
3973 __ or_(t3, t3, t4);
3974
3975 __ bind(&sign);
3976 __ subu(t2, t3, zero_reg);
3977 __ movz(t3, t2, t5); // Only if t5 is zero.
3978
3979 __ bind(&done);
3980
3981 // Result is in t3.
3982 // This switch block should be exactly the same as above (FPU mode).
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003983 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003984 case EXTERNAL_BYTE_ELEMENTS:
3985 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003986 __ srl(t8, key, 1);
3987 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003988 __ sb(t3, MemOperand(t8, 0));
3989 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003990 case EXTERNAL_SHORT_ELEMENTS:
3991 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003992 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003993 __ sh(t3, MemOperand(t8, 0));
3994 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003995 case EXTERNAL_INT_ELEMENTS:
3996 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003997 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003998 __ addu(t8, a3, t8);
3999 __ sw(t3, MemOperand(t8, 0));
4000 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004001 case EXTERNAL_PIXEL_ELEMENTS:
4002 case EXTERNAL_FLOAT_ELEMENTS:
4003 case EXTERNAL_DOUBLE_ELEMENTS:
4004 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004005 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004006 case FAST_DOUBLE_ELEMENTS:
4007 case DICTIONARY_ELEMENTS:
4008 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004009 UNREACHABLE();
4010 break;
4011 }
4012 }
4013 }
4014 }
4015
danno@chromium.org40cb8782011-05-25 07:58:50 +00004016 // Slow case, key and receiver still in a0 and a1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004017 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004018 __ IncrementCounter(
4019 masm->isolate()->counters()->keyed_load_external_array_slow(),
4020 1, a2, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004021 // Entry registers are intact.
4022 // ---------- S t a t e --------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004023 // -- ra : return address
danno@chromium.org40cb8782011-05-25 07:58:50 +00004024 // -- a0 : key
4025 // -- a1 : receiver
4026 // -----------------------------------
4027 Handle<Code> slow_ic =
4028 masm->isolate()->builtins()->KeyedStoreIC_Slow();
4029 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4030
4031 // Miss case, call the runtime.
4032 __ bind(&miss_force_generic);
4033
4034 // ---------- S t a t e --------------
4035 // -- ra : return address
4036 // -- a0 : key
4037 // -- a1 : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004038 // -----------------------------------
4039
danno@chromium.org40cb8782011-05-25 07:58:50 +00004040 Handle<Code> miss_ic =
4041 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4042 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
4043}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004044
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004045
danno@chromium.org40cb8782011-05-25 07:58:50 +00004046void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
4047 // ----------- S t a t e -------------
4048 // -- ra : return address
4049 // -- a0 : key
4050 // -- a1 : receiver
4051 // -----------------------------------
4052 Label miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004053
danno@chromium.org40cb8782011-05-25 07:58:50 +00004054 // This stub is meant to be tail-jumped to, the receiver must already
4055 // have been verified by the caller to not be a smi.
4056
4057 // Check that the key is a smi.
4058 __ JumpIfNotSmi(a0, &miss_force_generic);
4059
4060 // Get the elements array.
4061 __ lw(a2, FieldMemOperand(a1, JSObject::kElementsOffset));
4062 __ AssertFastElements(a2);
4063
4064 // Check that the key is within bounds.
4065 __ lw(a3, FieldMemOperand(a2, FixedArray::kLengthOffset));
4066 __ Branch(&miss_force_generic, hs, a0, Operand(a3));
4067
4068 // Load the result and make sure it's not the hole.
4069 __ Addu(a3, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004070 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004071 __ sll(t0, a0, kPointerSizeLog2 - kSmiTagSize);
4072 __ Addu(t0, t0, a3);
4073 __ lw(t0, MemOperand(t0));
4074 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
4075 __ Branch(&miss_force_generic, eq, t0, Operand(t1));
4076 __ mov(v0, t0);
4077 __ Ret();
4078
4079 __ bind(&miss_force_generic);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004080 Handle<Code> stub =
4081 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4082 __ Jump(stub, RelocInfo::CODE_TARGET);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004083}
4084
4085
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004086void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
4087 MacroAssembler* masm) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004088 // ----------- S t a t e -------------
4089 // -- ra : return address
4090 // -- a0 : key
4091 // -- a1 : receiver
4092 // -----------------------------------
4093 Label miss_force_generic, slow_allocate_heapnumber;
4094
4095 Register key_reg = a0;
4096 Register receiver_reg = a1;
4097 Register elements_reg = a2;
4098 Register heap_number_reg = a2;
4099 Register indexed_double_offset = a3;
4100 Register scratch = t0;
4101 Register scratch2 = t1;
4102 Register scratch3 = t2;
4103 Register heap_number_map = t3;
4104
4105 // This stub is meant to be tail-jumped to, the receiver must already
4106 // have been verified by the caller to not be a smi.
4107
4108 // Check that the key is a smi.
4109 __ JumpIfNotSmi(key_reg, &miss_force_generic);
4110
4111 // Get the elements array.
4112 __ lw(elements_reg,
4113 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4114
4115 // Check that the key is within bounds.
4116 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4117 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4118
4119 // Load the upper word of the double in the fixed array and test for NaN.
4120 __ sll(scratch2, key_reg, kDoubleSizeLog2 - kSmiTagSize);
4121 __ Addu(indexed_double_offset, elements_reg, Operand(scratch2));
4122 uint32_t upper_32_offset = FixedArray::kHeaderSize + sizeof(kHoleNanLower32);
4123 __ lw(scratch, FieldMemOperand(indexed_double_offset, upper_32_offset));
4124 __ Branch(&miss_force_generic, eq, scratch, Operand(kHoleNanUpper32));
4125
4126 // Non-NaN. Allocate a new heap number and copy the double value into it.
4127 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
4128 __ AllocateHeapNumber(heap_number_reg, scratch2, scratch3,
4129 heap_number_map, &slow_allocate_heapnumber);
4130
4131 // Don't need to reload the upper 32 bits of the double, it's already in
4132 // scratch.
4133 __ sw(scratch, FieldMemOperand(heap_number_reg,
4134 HeapNumber::kExponentOffset));
4135 __ lw(scratch, FieldMemOperand(indexed_double_offset,
4136 FixedArray::kHeaderSize));
4137 __ sw(scratch, FieldMemOperand(heap_number_reg,
4138 HeapNumber::kMantissaOffset));
4139
4140 __ mov(v0, heap_number_reg);
4141 __ Ret();
4142
4143 __ bind(&slow_allocate_heapnumber);
4144 Handle<Code> slow_ic =
4145 masm->isolate()->builtins()->KeyedLoadIC_Slow();
4146 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4147
4148 __ bind(&miss_force_generic);
4149 Handle<Code> miss_ic =
4150 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4151 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004152}
4153
4154
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004155void KeyedStoreStubCompiler::GenerateStoreFastElement(
4156 MacroAssembler* masm,
4157 bool is_js_array,
4158 ElementsKind elements_kind) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00004159 // ----------- S t a t e -------------
4160 // -- a0 : value
4161 // -- a1 : key
4162 // -- a2 : receiver
4163 // -- ra : return address
4164 // -- a3 : scratch
4165 // -- a4 : scratch (elements)
4166 // -----------------------------------
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004167 Label miss_force_generic, transition_elements_kind;
danno@chromium.org40cb8782011-05-25 07:58:50 +00004168
4169 Register value_reg = a0;
4170 Register key_reg = a1;
4171 Register receiver_reg = a2;
4172 Register scratch = a3;
4173 Register elements_reg = t0;
4174 Register scratch2 = t1;
4175 Register scratch3 = t2;
4176
4177 // This stub is meant to be tail-jumped to, the receiver must already
4178 // have been verified by the caller to not be a smi.
4179
4180 // Check that the key is a smi.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00004181 __ JumpIfNotSmi(key_reg, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004182
4183 // Get the elements array and make sure it is a fast element array, not 'cow'.
4184 __ lw(elements_reg,
4185 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4186 __ CheckMap(elements_reg,
4187 scratch,
4188 Heap::kFixedArrayMapRootIndex,
4189 &miss_force_generic,
4190 DONT_DO_SMI_CHECK);
4191
4192 // Check that the key is within bounds.
4193 if (is_js_array) {
4194 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4195 } else {
4196 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4197 }
4198 // Compare smis.
4199 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4200
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004201 if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
4202 __ JumpIfNotSmi(value_reg, &transition_elements_kind);
4203 __ Addu(scratch,
4204 elements_reg,
4205 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4206 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4207 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4208 __ Addu(scratch, scratch, scratch2);
4209 __ sw(value_reg, MemOperand(scratch));
4210 } else {
4211 ASSERT(elements_kind == FAST_ELEMENTS);
4212 __ Addu(scratch,
4213 elements_reg,
4214 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4215 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4216 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4217 __ Addu(scratch, scratch, scratch2);
4218 __ sw(value_reg, MemOperand(scratch));
4219 __ mov(receiver_reg, value_reg);
4220 ASSERT(elements_kind == FAST_ELEMENTS);
4221 __ RecordWrite(elements_reg, // Object.
4222 scratch, // Address.
4223 receiver_reg, // Value.
4224 kRAHasNotBeenSaved,
4225 kDontSaveFPRegs);
4226 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004227 // value_reg (a0) is preserved.
4228 // Done.
4229 __ Ret();
4230
4231 __ bind(&miss_force_generic);
4232 Handle<Code> ic =
4233 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4234 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004235
4236 __ bind(&transition_elements_kind);
4237 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4238 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004239}
4240
4241
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004242void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
4243 MacroAssembler* masm,
4244 bool is_js_array) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004245 // ----------- S t a t e -------------
4246 // -- a0 : value
4247 // -- a1 : key
4248 // -- a2 : receiver
4249 // -- ra : return address
4250 // -- a3 : scratch
4251 // -- t0 : scratch (elements_reg)
4252 // -- t1 : scratch (mantissa_reg)
4253 // -- t2 : scratch (exponent_reg)
4254 // -- t3 : scratch4
4255 // -----------------------------------
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004256 Label miss_force_generic, transition_elements_kind;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004257
4258 Register value_reg = a0;
4259 Register key_reg = a1;
4260 Register receiver_reg = a2;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004261 Register elements_reg = a3;
4262 Register scratch1 = t0;
4263 Register scratch2 = t1;
4264 Register scratch3 = t2;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004265 Register scratch4 = t3;
4266
4267 // This stub is meant to be tail-jumped to, the receiver must already
4268 // have been verified by the caller to not be a smi.
4269 __ JumpIfNotSmi(key_reg, &miss_force_generic);
4270
4271 __ lw(elements_reg,
4272 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4273
4274 // Check that the key is within bounds.
4275 if (is_js_array) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004276 __ lw(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004277 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004278 __ lw(scratch1,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004279 FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4280 }
4281 // Compare smis, unsigned compare catches both negative and out-of-bound
4282 // indexes.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004283 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch1));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004284
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004285 __ StoreNumberToDoubleElements(value_reg,
4286 key_reg,
4287 receiver_reg,
4288 elements_reg,
4289 scratch1,
4290 scratch2,
4291 scratch3,
4292 scratch4,
4293 &transition_elements_kind);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004294
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004295 __ Ret(USE_DELAY_SLOT);
4296 __ mov(v0, value_reg); // In delay slot.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004297
4298 // Handle store cache miss, replacing the ic with the generic stub.
4299 __ bind(&miss_force_generic);
4300 Handle<Code> ic =
4301 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4302 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004303
4304 __ bind(&transition_elements_kind);
4305 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4306 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004307}
4308
4309
ager@chromium.org5c838252010-02-19 08:53:10 +00004310#undef __
4311
4312} } // namespace v8::internal
4313
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004314#endif // V8_TARGET_ARCH_MIPS