blob: 2d6069369748fd981d34d7562a1ef4bf11c09af7 [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)
568 // -- sp[4] : callee js function
569 // -- sp[8] : call data
570 // -- sp[12] : last js argument
571 // -- ...
572 // -- sp[(argc + 3) * 4] : first js argument
573 // -- 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();
577 __ li(t1, Operand(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
590 // Store js function and call data.
591 __ 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,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001118 Handle<Object> value,
1119 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.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001130 __ li(v0, Operand(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
1176 // scratch2 (internal::Object **args_) as the data.
1177 __ 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;
1754 Register scratch = a3;
1755 Register result = v0;
1756 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1757 if (argc > 0) {
1758 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1759 } else {
1760 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1761 }
1762
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001763 StringCharCodeAtGenerator generator(receiver,
1764 index,
1765 scratch,
1766 result,
1767 &miss, // When not a string.
1768 &miss, // When not a number.
1769 index_out_of_range_label,
1770 STRING_INDEX_IS_NUMBER);
1771 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001772 __ Drop(argc + 1);
1773 __ Ret();
1774
1775 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001776 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001777
1778 if (index_out_of_range.is_linked()) {
1779 __ bind(&index_out_of_range);
1780 __ LoadRoot(v0, Heap::kNanValueRootIndex);
1781 __ Drop(argc + 1);
1782 __ Ret();
1783 }
1784
1785 __ bind(&miss);
1786 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001787 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001788 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001789 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001790
1791 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001792 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001793}
1794
1795
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001796Handle<Code> CallStubCompiler::CompileStringCharAtCall(
1797 Handle<Object> object,
1798 Handle<JSObject> holder,
1799 Handle<JSGlobalPropertyCell> cell,
1800 Handle<JSFunction> function,
1801 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001802 // ----------- S t a t e -------------
1803 // -- a2 : function name
1804 // -- ra : return address
1805 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1806 // -- ...
1807 // -- sp[argc * 4] : receiver
1808 // -----------------------------------
1809
1810 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001811 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001812
1813 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001814 Label miss;
1815 Label name_miss;
1816 Label index_out_of_range;
1817 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00001818 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001819 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001820 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001821 index_out_of_range_label = &miss;
1822 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001823 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001824
1825 // Check that the maps starting from the prototype haven't changed.
1826 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1827 Context::STRING_FUNCTION_INDEX,
1828 v0,
1829 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001830 ASSERT(!object.is_identical_to(holder));
1831 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1832 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001833
1834 Register receiver = v0;
1835 Register index = t1;
1836 Register scratch1 = a1;
1837 Register scratch2 = a3;
1838 Register result = v0;
1839 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1840 if (argc > 0) {
1841 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1842 } else {
1843 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1844 }
1845
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001846 StringCharAtGenerator generator(receiver,
1847 index,
1848 scratch1,
1849 scratch2,
1850 result,
1851 &miss, // When not a string.
1852 &miss, // When not a number.
1853 index_out_of_range_label,
1854 STRING_INDEX_IS_NUMBER);
1855 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001856 __ Drop(argc + 1);
1857 __ Ret();
1858
1859 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001860 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001861
1862 if (index_out_of_range.is_linked()) {
1863 __ bind(&index_out_of_range);
1864 __ LoadRoot(v0, Heap::kEmptyStringRootIndex);
1865 __ Drop(argc + 1);
1866 __ Ret();
1867 }
1868
1869 __ bind(&miss);
1870 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001871 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001872 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001873 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001874
1875 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001876 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001877}
1878
1879
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001880Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
1881 Handle<Object> object,
1882 Handle<JSObject> holder,
1883 Handle<JSGlobalPropertyCell> cell,
1884 Handle<JSFunction> function,
1885 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001886 // ----------- S t a t e -------------
1887 // -- a2 : function name
1888 // -- ra : return address
1889 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1890 // -- ...
1891 // -- sp[argc * 4] : receiver
1892 // -----------------------------------
1893
1894 const int argc = arguments().immediate();
1895
1896 // If the object is not a JSObject or we got an unexpected number of
1897 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001898 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001899
1900 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001901 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001902
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001903 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001904 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
1905
1906 STATIC_ASSERT(kSmiTag == 0);
1907 __ JumpIfSmi(a1, &miss);
1908
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001909 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
1910 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001911 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001912 ASSERT(cell->value() == *function);
1913 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
1914 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001915 GenerateLoadFunctionFromCell(cell, function, &miss);
1916 }
1917
1918 // Load the char code argument.
1919 Register code = a1;
1920 __ lw(code, MemOperand(sp, 0 * kPointerSize));
1921
1922 // Check the code is a smi.
1923 Label slow;
1924 STATIC_ASSERT(kSmiTag == 0);
1925 __ JumpIfNotSmi(code, &slow);
1926
1927 // Convert the smi code to uint16.
1928 __ And(code, code, Operand(Smi::FromInt(0xffff)));
1929
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001930 StringCharFromCodeGenerator generator(code, v0);
1931 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001932 __ Drop(argc + 1);
1933 __ Ret();
1934
1935 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001936 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001937
1938 // Tail call the full function. We do not have to patch the receiver
1939 // because the function makes no use of it.
1940 __ bind(&slow);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001941 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001942
1943 __ bind(&miss);
1944 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001945 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001946
1947 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001948 return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001949}
1950
1951
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001952Handle<Code> CallStubCompiler::CompileMathFloorCall(
1953 Handle<Object> object,
1954 Handle<JSObject> holder,
1955 Handle<JSGlobalPropertyCell> cell,
1956 Handle<JSFunction> function,
1957 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001958 // ----------- S t a t e -------------
1959 // -- a2 : function name
1960 // -- ra : return address
1961 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1962 // -- ...
1963 // -- sp[argc * 4] : receiver
1964 // -----------------------------------
1965
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001966 if (!CpuFeatures::IsSupported(FPU)) {
1967 return Handle<Code>::null();
1968 }
1969
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001970 CpuFeatures::Scope scope_fpu(FPU);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001971 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001972 // If the object is not a JSObject or we got an unexpected number of
1973 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001974 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001975
1976 Label miss, slow;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001977 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001978
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001979 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001980 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001981 STATIC_ASSERT(kSmiTag == 0);
1982 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001983 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
1984 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001985 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001986 ASSERT(cell->value() == *function);
1987 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
1988 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001989 GenerateLoadFunctionFromCell(cell, function, &miss);
1990 }
1991
1992 // Load the (only) argument into v0.
1993 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
1994
1995 // If the argument is a smi, just return.
1996 STATIC_ASSERT(kSmiTag == 0);
1997 __ And(t0, v0, Operand(kSmiTagMask));
1998 __ Drop(argc + 1, eq, t0, Operand(zero_reg));
1999 __ Ret(eq, t0, Operand(zero_reg));
2000
danno@chromium.org40cb8782011-05-25 07:58:50 +00002001 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002002
2003 Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return;
2004
2005 // If fpu is enabled, we use the floor instruction.
2006
2007 // Load the HeapNumber value.
2008 __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2009
2010 // Backup FCSR.
2011 __ cfc1(a3, FCSR);
2012 // Clearing FCSR clears the exception mask with no side-effects.
2013 __ ctc1(zero_reg, FCSR);
2014 // Convert the argument to an integer.
2015 __ floor_w_d(f0, f0);
2016
2017 // Start checking for special cases.
2018 // Get the argument exponent and clear the sign bit.
2019 __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize));
2020 __ And(t2, t1, Operand(~HeapNumber::kSignMask));
2021 __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord);
2022
2023 // Retrieve FCSR and check for fpu errors.
2024 __ cfc1(t5, FCSR);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002025 __ And(t5, t5, Operand(kFCSRExceptionFlagMask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002026 __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));
2027
2028 // Check for NaN, Infinity, and -Infinity.
2029 // They are invariant through a Math.Floor call, so just
2030 // return the original argument.
2031 __ Subu(t3, t2, Operand(HeapNumber::kExponentMask
2032 >> HeapNumber::kMantissaBitsInTopWord));
2033 __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg));
2034 // We had an overflow or underflow in the conversion. Check if we
2035 // have a big exponent.
2036 // If greater or equal, the argument is already round and in v0.
2037 __ Branch(&restore_fcsr_and_return, ge, t3,
2038 Operand(HeapNumber::kMantissaBits));
2039 __ Branch(&wont_fit_smi);
2040
2041 __ bind(&no_fpu_error);
2042 // Move the result back to v0.
2043 __ mfc1(v0, f0);
2044 // Check if the result fits into a smi.
2045 __ Addu(a1, v0, Operand(0x40000000));
2046 __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg));
2047 // Tag the result.
2048 STATIC_ASSERT(kSmiTag == 0);
2049 __ sll(v0, v0, kSmiTagSize);
2050
2051 // Check for -0.
2052 __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg));
2053 // t1 already holds the HeapNumber exponent.
2054 __ And(t0, t1, Operand(HeapNumber::kSignMask));
2055 // If our HeapNumber is negative it was -0, so load its address and return.
2056 // Else v0 is loaded with 0, so we can also just return.
2057 __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg));
2058 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2059
2060 __ bind(&restore_fcsr_and_return);
2061 // Restore FCSR and return.
2062 __ ctc1(a3, FCSR);
2063
2064 __ Drop(argc + 1);
2065 __ Ret();
2066
2067 __ bind(&wont_fit_smi);
2068 // Restore FCSR and fall to slow case.
2069 __ ctc1(a3, FCSR);
2070
2071 __ bind(&slow);
2072 // Tail call the full function. We do not have to patch the receiver
2073 // because the function makes no use of it.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002074 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002075
2076 __ bind(&miss);
2077 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002078 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002079
2080 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002081 return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002082}
2083
2084
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002085Handle<Code> CallStubCompiler::CompileMathAbsCall(
2086 Handle<Object> object,
2087 Handle<JSObject> holder,
2088 Handle<JSGlobalPropertyCell> cell,
2089 Handle<JSFunction> function,
2090 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002091 // ----------- S t a t e -------------
2092 // -- a2 : function name
2093 // -- ra : return address
2094 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2095 // -- ...
2096 // -- sp[argc * 4] : receiver
2097 // -----------------------------------
2098
2099 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002100 // If the object is not a JSObject or we got an unexpected number of
2101 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002102 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002103
2104 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002105
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002106 GenerateNameCheck(name, &miss);
2107 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002108 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002109 STATIC_ASSERT(kSmiTag == 0);
2110 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002111 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2112 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002113 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002114 ASSERT(cell->value() == *function);
2115 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2116 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002117 GenerateLoadFunctionFromCell(cell, function, &miss);
2118 }
2119
2120 // Load the (only) argument into v0.
2121 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2122
2123 // Check if the argument is a smi.
2124 Label not_smi;
2125 STATIC_ASSERT(kSmiTag == 0);
2126 __ JumpIfNotSmi(v0, &not_smi);
2127
2128 // Do bitwise not or do nothing depending on the sign of the
2129 // argument.
2130 __ sra(t0, v0, kBitsPerInt - 1);
2131 __ Xor(a1, v0, t0);
2132
2133 // Add 1 or do nothing depending on the sign of the argument.
2134 __ Subu(v0, a1, t0);
2135
2136 // If the result is still negative, go to the slow case.
2137 // This only happens for the most negative smi.
2138 Label slow;
2139 __ Branch(&slow, lt, v0, Operand(zero_reg));
2140
2141 // Smi case done.
2142 __ Drop(argc + 1);
2143 __ Ret();
2144
2145 // Check if the argument is a heap number and load its exponent and
2146 // sign.
2147 __ bind(&not_smi);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002148 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002149 __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2150
2151 // Check the sign of the argument. If the argument is positive,
2152 // just return it.
2153 Label negative_sign;
2154 __ And(t0, a1, Operand(HeapNumber::kSignMask));
2155 __ Branch(&negative_sign, ne, t0, Operand(zero_reg));
2156 __ Drop(argc + 1);
2157 __ Ret();
2158
2159 // If the argument is negative, clear the sign, and return a new
2160 // number.
2161 __ bind(&negative_sign);
2162 __ Xor(a1, a1, Operand(HeapNumber::kSignMask));
2163 __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2164 __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
2165 __ AllocateHeapNumber(v0, t0, t1, t2, &slow);
2166 __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2167 __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2168 __ Drop(argc + 1);
2169 __ Ret();
2170
2171 // Tail call the full function. We do not have to patch the receiver
2172 // because the function makes no use of it.
2173 __ bind(&slow);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002174 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002175
2176 __ bind(&miss);
2177 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002178 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002179
2180 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002181 return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002182}
2183
2184
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002185Handle<Code> CallStubCompiler::CompileFastApiCall(
lrn@chromium.org7516f052011-03-30 08:52:27 +00002186 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002187 Handle<Object> object,
2188 Handle<JSObject> holder,
2189 Handle<JSGlobalPropertyCell> cell,
2190 Handle<JSFunction> function,
2191 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002192
danno@chromium.org40cb8782011-05-25 07:58:50 +00002193 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002194
2195 ASSERT(optimization.is_simple_api_call());
2196 // Bail out if object is a global object as we don't want to
2197 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002198 if (object->IsGlobalObject()) return Handle<Code>::null();
2199 if (!cell.is_null()) return Handle<Code>::null();
2200 if (!object->IsJSObject()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002201 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002202 Handle<JSObject>::cast(object), holder);
2203 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002204
2205 Label miss, miss_before_stack_reserved;
2206
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002207 GenerateNameCheck(name, &miss_before_stack_reserved);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002208
2209 // Get the receiver from the stack.
2210 const int argc = arguments().immediate();
2211 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2212
2213 // Check that the receiver isn't a smi.
2214 __ JumpIfSmi(a1, &miss_before_stack_reserved);
2215
2216 __ IncrementCounter(counters->call_const(), 1, a0, a3);
2217 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2218
2219 ReserveSpaceForFastApiCall(masm(), a0);
2220
2221 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002222 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002223 depth, &miss);
2224
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002225 GenerateFastApiDirectCall(masm(), optimization, argc);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002226
2227 __ bind(&miss);
2228 FreeSpaceForFastApiCall(masm());
2229
2230 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002231 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002232
2233 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002234 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002235}
2236
2237
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002238Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object,
2239 Handle<JSObject> holder,
2240 Handle<JSFunction> function,
2241 Handle<String> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002242 CheckType check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002243 // ----------- S t a t e -------------
2244 // -- a2 : name
2245 // -- ra : return address
2246 // -----------------------------------
2247 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002248 Handle<Code> code = CompileCustomCall(object, holder,
2249 Handle<JSGlobalPropertyCell>::null(),
2250 function, name);
2251 // A null handle means bail out to the regular compiler code below.
2252 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002253 }
2254
2255 Label miss;
2256
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002257 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002258
2259 // Get the receiver from the stack.
2260 const int argc = arguments().immediate();
2261 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2262
2263 // Check that the receiver isn't a smi.
2264 if (check != NUMBER_CHECK) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002265 __ JumpIfSmi(a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002266 }
2267
2268 // Make sure that it's okay not to patch the on stack receiver
2269 // unless we're doing a receiver map check.
2270 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002271 switch (check) {
2272 case RECEIVER_MAP_CHECK:
2273 __ IncrementCounter(masm()->isolate()->counters()->call_const(),
2274 1, a0, a3);
2275
2276 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002277 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2278 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002279
2280 // Patch the receiver on the stack with the global proxy if
2281 // necessary.
2282 if (object->IsGlobalObject()) {
2283 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2284 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2285 }
2286 break;
2287
2288 case STRING_CHECK:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002289 if (function->IsBuiltin() || function->shared()->strict_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002290 // Check that the object is a two-byte string or a symbol.
2291 __ GetObjectType(a1, a3, a3);
2292 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2293 // Check that the maps starting from the prototype haven't changed.
2294 GenerateDirectLoadGlobalFunctionPrototype(
2295 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002296 CheckPrototypes(
2297 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2298 a0, holder, a3, a1, t0, name, &miss);
2299 } else {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002300 // Calling non-strict non-builtins with a value as the receiver
2301 // requires boxing.
2302 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002303 }
2304 break;
2305
2306 case NUMBER_CHECK:
2307 if (function->IsBuiltin() || function->shared()->strict_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002308 Label fast;
2309 // Check that the object is a smi or a heap number.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002310 __ JumpIfSmi(a1, &fast);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002311 __ GetObjectType(a1, a0, a0);
2312 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
2313 __ bind(&fast);
2314 // Check that the maps starting from the prototype haven't changed.
2315 GenerateDirectLoadGlobalFunctionPrototype(
2316 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002317 CheckPrototypes(
2318 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2319 a0, holder, a3, a1, t0, name, &miss);
2320 } else {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002321 // Calling non-strict non-builtins with a value as the receiver
2322 // requires boxing.
2323 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002324 }
2325 break;
2326
2327 case BOOLEAN_CHECK:
2328 if (function->IsBuiltin() || function->shared()->strict_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002329 Label fast;
2330 // Check that the object is a boolean.
2331 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
2332 __ Branch(&fast, eq, a1, Operand(t0));
2333 __ LoadRoot(t0, Heap::kFalseValueRootIndex);
2334 __ Branch(&miss, ne, a1, Operand(t0));
2335 __ bind(&fast);
2336 // Check that the maps starting from the prototype haven't changed.
2337 GenerateDirectLoadGlobalFunctionPrototype(
2338 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002339 CheckPrototypes(
2340 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2341 a0, holder, a3, a1, t0, name, &miss);
2342 } else {
2343 // Calling non-strict non-builtins with a value as the receiver
2344 // requires boxing.
2345 __ jmp(&miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002346 }
2347 break;
2348 }
2349
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002350 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002351 ? CALL_AS_FUNCTION
2352 : CALL_AS_METHOD;
2353 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002354
2355 // Handle call cache miss.
2356 __ bind(&miss);
2357
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002358 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002359
2360 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002361 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002362}
2363
2364
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002365Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2366 Handle<JSObject> holder,
2367 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002368 // ----------- S t a t e -------------
2369 // -- a2 : name
2370 // -- ra : return address
2371 // -----------------------------------
2372
2373 Label miss;
2374
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002375 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002376
2377 // Get the number of arguments.
2378 const int argc = arguments().immediate();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002379 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002380 LookupPostInterceptor(holder, name, &lookup);
2381
2382 // Get the receiver from the stack.
2383 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2384
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002385 CallInterceptorCompiler compiler(this, arguments(), a2, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002386 compiler.Compile(masm(), object, holder, name, &lookup, a1, a3, t0, a0,
2387 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002388
2389 // Move returned value, the function to call, to a1.
2390 __ mov(a1, v0);
2391 // Restore receiver.
2392 __ lw(a0, MemOperand(sp, argc * kPointerSize));
2393
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002394 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002395
2396 // Handle call cache miss.
2397 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002398 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002399
2400 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002401 return GetCode(INTERCEPTOR, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002402}
2403
2404
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002405Handle<Code> CallStubCompiler::CompileCallGlobal(
2406 Handle<JSObject> object,
2407 Handle<GlobalObject> holder,
2408 Handle<JSGlobalPropertyCell> cell,
2409 Handle<JSFunction> function,
2410 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002411 // ----------- S t a t e -------------
2412 // -- a2 : name
2413 // -- ra : return address
2414 // -----------------------------------
2415
2416 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002417 Handle<Code> code = CompileCustomCall(object, holder, cell, function, name);
2418 // A null handle means bail out to the regular compiler code below.
2419 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002420 }
2421
2422 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002423 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002424
2425 // Get the number of arguments.
2426 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002427 GenerateGlobalReceiverCheck(object, holder, name, &miss);
2428 GenerateLoadFunctionFromCell(cell, function, &miss);
2429
2430 // Patch the receiver on the stack with the global proxy if
2431 // necessary.
2432 if (object->IsGlobalObject()) {
2433 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
2434 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2435 }
2436
2437 // Setup the context (function already in r1).
2438 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
2439
2440 // Jump to the cached code (tail call).
2441 Counters* counters = masm()->isolate()->counters();
2442 __ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002443 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002444 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002445 ? CALL_AS_FUNCTION
2446 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002447 // We call indirectly through the code field in the function to
2448 // allow recompilation to take effect without changing any of the
2449 // call sites.
2450 __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
2451 __ InvokeCode(a3, expected, arguments(), JUMP_FUNCTION,
2452 NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002453
2454 // Handle call cache miss.
2455 __ bind(&miss);
2456 __ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002457 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002458
2459 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002460 return GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002461}
2462
2463
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002464Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +00002465 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002466 Handle<Map> transition,
2467 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002468 // ----------- S t a t e -------------
2469 // -- a0 : value
2470 // -- a1 : receiver
2471 // -- a2 : name
2472 // -- ra : return address
2473 // -----------------------------------
2474 Label miss;
2475
2476 // Name register might be clobbered.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002477 GenerateStoreField(masm(), object, index, transition, a1, a2, a3, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002478 __ bind(&miss);
2479 __ li(a2, Operand(Handle<String>(name))); // Restore name.
2480 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2481 __ Jump(ic, RelocInfo::CODE_TARGET);
2482
2483 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002484 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002485}
2486
2487
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002488Handle<Code> StoreStubCompiler::CompileStoreCallback(
2489 Handle<JSObject> object,
2490 Handle<AccessorInfo> callback,
2491 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002492 // ----------- S t a t e -------------
2493 // -- a0 : value
2494 // -- a1 : receiver
2495 // -- a2 : name
2496 // -- ra : return address
2497 // -----------------------------------
2498 Label miss;
2499
2500 // Check that the object isn't a smi.
2501 __ JumpIfSmi(a1, &miss);
2502
2503 // Check that the map of the object hasn't changed.
2504 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2505 __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map())));
2506
2507 // Perform global security token check if needed.
2508 if (object->IsJSGlobalProxy()) {
2509 __ CheckAccessGlobalProxy(a1, a3, &miss);
2510 }
2511
2512 // Stub never generated for non-global objects that require access
2513 // checks.
2514 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
2515
2516 __ push(a1); // Receiver.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002517 __ li(a3, Operand(callback)); // Callback info.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002518 __ Push(a3, a2, a0);
2519
2520 // Do tail-call to the runtime system.
2521 ExternalReference store_callback_property =
2522 ExternalReference(IC_Utility(IC::kStoreCallbackProperty),
2523 masm()->isolate());
2524 __ TailCallExternalReference(store_callback_property, 4, 1);
2525
2526 // Handle store cache miss.
2527 __ bind(&miss);
2528 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2529 __ Jump(ic, RelocInfo::CODE_TARGET);
2530
2531 // Return the generated code.
2532 return GetCode(CALLBACKS, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002533}
2534
2535
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002536Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
2537 Handle<JSObject> receiver,
2538 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002539 // ----------- S t a t e -------------
2540 // -- a0 : value
2541 // -- a1 : receiver
2542 // -- a2 : name
2543 // -- ra : return address
2544 // -----------------------------------
2545 Label miss;
2546
2547 // Check that the object isn't a smi.
2548 __ JumpIfSmi(a1, &miss);
2549
2550 // Check that the map of the object hasn't changed.
2551 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2552 __ Branch(&miss, ne, a3, Operand(Handle<Map>(receiver->map())));
2553
2554 // Perform global security token check if needed.
2555 if (receiver->IsJSGlobalProxy()) {
2556 __ CheckAccessGlobalProxy(a1, a3, &miss);
2557 }
2558
2559 // Stub is never generated for non-global objects that require access
2560 // checks.
2561 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2562
2563 __ Push(a1, a2, a0); // Receiver, name, value.
2564
2565 __ li(a0, Operand(Smi::FromInt(strict_mode_)));
2566 __ push(a0); // Strict mode.
2567
2568 // Do tail-call to the runtime system.
2569 ExternalReference store_ic_property =
2570 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty),
2571 masm()->isolate());
2572 __ TailCallExternalReference(store_ic_property, 4, 1);
2573
2574 // Handle store cache miss.
2575 __ bind(&miss);
2576 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2577 __ Jump(ic, RelocInfo::CODE_TARGET);
2578
2579 // Return the generated code.
2580 return GetCode(INTERCEPTOR, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002581}
2582
2583
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002584Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2585 Handle<GlobalObject> object,
2586 Handle<JSGlobalPropertyCell> cell,
2587 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002588 // ----------- S t a t e -------------
2589 // -- a0 : value
2590 // -- a1 : receiver
2591 // -- a2 : name
2592 // -- ra : return address
2593 // -----------------------------------
2594 Label miss;
2595
2596 // Check that the map of the global has not changed.
2597 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2598 __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map())));
2599
2600 // Check that the value in the cell is not the hole. If it is, this
2601 // cell could have been deleted and reintroducing the global needs
2602 // to update the property details in the property dictionary of the
2603 // global object. We bail out to the runtime system to do that.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002604 __ li(t0, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002605 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
2606 __ lw(t2, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2607 __ Branch(&miss, eq, t1, Operand(t2));
2608
2609 // Store the value in the cell.
2610 __ sw(a0, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2611 __ mov(v0, a0); // Stored value must be returned in v0.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002612
2613 // This trashes a0 but the value is returned in v0 anyway.
2614 __ RecordWriteField(t0,
2615 JSGlobalPropertyCell::kValueOffset,
2616 a0,
2617 a2,
2618 kRAHasNotBeenSaved,
2619 kDontSaveFPRegs,
2620 OMIT_REMEMBERED_SET);
2621
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002622 Counters* counters = masm()->isolate()->counters();
2623 __ IncrementCounter(counters->named_store_global_inline(), 1, a1, a3);
2624 __ Ret();
2625
2626 // Handle store cache miss.
2627 __ bind(&miss);
2628 __ IncrementCounter(counters->named_store_global_inline_miss(), 1, a1, a3);
2629 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2630 __ Jump(ic, RelocInfo::CODE_TARGET);
2631
2632 // Return the generated code.
2633 return GetCode(NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002634}
2635
2636
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002637Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
2638 Handle<JSObject> object,
2639 Handle<JSObject> last) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002640 // ----------- S t a t e -------------
2641 // -- a0 : receiver
2642 // -- ra : return address
2643 // -----------------------------------
2644 Label miss;
2645
2646 // Check that the receiver is not a smi.
2647 __ JumpIfSmi(a0, &miss);
2648
2649 // Check the maps of the full prototype chain.
2650 CheckPrototypes(object, a0, last, a3, a1, t0, name, &miss);
2651
2652 // If the last object in the prototype chain is a global object,
2653 // check that the global property cell is empty.
2654 if (last->IsGlobalObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002655 GenerateCheckPropertyCell(
2656 masm(), Handle<GlobalObject>::cast(last), name, a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002657 }
2658
2659 // Return undefined if maps of the full prototype chain is still the same.
2660 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2661 __ Ret();
2662
2663 __ bind(&miss);
2664 GenerateLoadMiss(masm(), Code::LOAD_IC);
2665
2666 // Return the generated code.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002667 return GetCode(NONEXISTENT, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00002668}
2669
2670
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002671Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object,
2672 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002673 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002674 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002675 // ----------- S t a t e -------------
2676 // -- a0 : receiver
2677 // -- a2 : name
2678 // -- ra : return address
2679 // -----------------------------------
2680 Label miss;
2681
2682 __ mov(v0, a0);
2683
2684 GenerateLoadField(object, holder, v0, a3, a1, t0, index, name, &miss);
2685 __ bind(&miss);
2686 GenerateLoadMiss(masm(), Code::LOAD_IC);
2687
2688 // Return the generated code.
2689 return GetCode(FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002690}
2691
2692
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002693Handle<Code> LoadStubCompiler::CompileLoadCallback(
2694 Handle<String> name,
2695 Handle<JSObject> object,
2696 Handle<JSObject> holder,
2697 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002698 // ----------- S t a t e -------------
2699 // -- a0 : receiver
2700 // -- a2 : name
2701 // -- ra : return address
2702 // -----------------------------------
2703 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002704 GenerateLoadCallback(object, holder, a0, a2, a3, a1, t0, callback, name,
2705 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002706 __ bind(&miss);
2707 GenerateLoadMiss(masm(), Code::LOAD_IC);
2708
2709 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002710 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002711}
2712
2713
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002714Handle<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object,
2715 Handle<JSObject> holder,
2716 Handle<Object> value,
2717 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002718 // ----------- S t a t e -------------
2719 // -- a0 : receiver
2720 // -- a2 : name
2721 // -- ra : return address
2722 // -----------------------------------
2723 Label miss;
2724
2725 GenerateLoadConstant(object, holder, a0, a3, a1, t0, value, name, &miss);
2726 __ bind(&miss);
2727 GenerateLoadMiss(masm(), Code::LOAD_IC);
2728
2729 // Return the generated code.
2730 return GetCode(CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002731}
2732
2733
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002734Handle<Code> LoadStubCompiler::CompileLoadInterceptor(Handle<JSObject> object,
2735 Handle<JSObject> holder,
2736 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002737 // ----------- S t a t e -------------
2738 // -- a0 : receiver
2739 // -- a2 : name
2740 // -- ra : return address
2741 // -- [sp] : receiver
2742 // -----------------------------------
2743 Label miss;
2744
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002745 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002746 LookupPostInterceptor(holder, name, &lookup);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002747 GenerateLoadInterceptor(object, holder, &lookup, a0, a2, a3, a1, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002748 &miss);
2749 __ bind(&miss);
2750 GenerateLoadMiss(masm(), Code::LOAD_IC);
2751
2752 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002753 return GetCode(INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002754}
2755
2756
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002757Handle<Code> LoadStubCompiler::CompileLoadGlobal(
2758 Handle<JSObject> object,
2759 Handle<GlobalObject> holder,
2760 Handle<JSGlobalPropertyCell> cell,
2761 Handle<String> name,
2762 bool is_dont_delete) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002763 // ----------- S t a t e -------------
2764 // -- a0 : receiver
2765 // -- a2 : name
2766 // -- ra : return address
2767 // -----------------------------------
2768 Label miss;
2769
2770 // If the object is the holder then we know that it's a global
2771 // object which can only happen for contextual calls. In this case,
2772 // the receiver cannot be a smi.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002773 if (!object.is_identical_to(holder)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002774 __ JumpIfSmi(a0, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002775 }
2776
2777 // Check that the map of the global has not changed.
2778 CheckPrototypes(object, a0, holder, a3, t0, a1, name, &miss);
2779
2780 // Get the value from the cell.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002781 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002782 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
2783
2784 // Check for deleted property if property can actually be deleted.
2785 if (!is_dont_delete) {
2786 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
2787 __ Branch(&miss, eq, t0, Operand(at));
2788 }
2789
2790 __ mov(v0, t0);
2791 Counters* counters = masm()->isolate()->counters();
2792 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
2793 __ Ret();
2794
2795 __ bind(&miss);
2796 __ IncrementCounter(counters->named_load_global_stub_miss(), 1, a1, a3);
2797 GenerateLoadMiss(masm(), Code::LOAD_IC);
2798
2799 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002800 return GetCode(NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002801}
2802
2803
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002804Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
2805 Handle<JSObject> receiver,
2806 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002807 int index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002808 // ----------- S t a t e -------------
2809 // -- ra : return address
2810 // -- a0 : key
2811 // -- a1 : receiver
2812 // -----------------------------------
2813 Label miss;
2814
2815 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002816 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002817
2818 GenerateLoadField(receiver, holder, a1, a2, a3, t0, index, name, &miss);
2819 __ bind(&miss);
2820 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2821
2822 return GetCode(FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002823}
2824
2825
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002826Handle<Code> KeyedLoadStubCompiler::CompileLoadCallback(
2827 Handle<String> name,
2828 Handle<JSObject> receiver,
2829 Handle<JSObject> holder,
2830 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002831 // ----------- S t a t e -------------
2832 // -- ra : return address
2833 // -- a0 : key
2834 // -- a1 : receiver
2835 // -----------------------------------
2836 Label miss;
2837
2838 // Check the key is the cached one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002839 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002840
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002841 GenerateLoadCallback(receiver, holder, a1, a0, a2, a3, t0, callback, name,
2842 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002843 __ bind(&miss);
2844 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2845
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002846 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002847}
2848
2849
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002850Handle<Code> KeyedLoadStubCompiler::CompileLoadConstant(
2851 Handle<String> name,
2852 Handle<JSObject> receiver,
2853 Handle<JSObject> holder,
2854 Handle<Object> value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002855 // ----------- S t a t e -------------
2856 // -- ra : return address
2857 // -- a0 : key
2858 // -- a1 : receiver
2859 // -----------------------------------
2860 Label miss;
2861
2862 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002863 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002864
2865 GenerateLoadConstant(receiver, holder, a1, a2, a3, t0, value, name, &miss);
2866 __ bind(&miss);
2867 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2868
2869 // Return the generated code.
2870 return GetCode(CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002871}
2872
2873
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002874Handle<Code> KeyedLoadStubCompiler::CompileLoadInterceptor(
2875 Handle<JSObject> receiver,
2876 Handle<JSObject> holder,
2877 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002878 // ----------- S t a t e -------------
2879 // -- ra : return address
2880 // -- a0 : key
2881 // -- a1 : receiver
2882 // -----------------------------------
2883 Label miss;
2884
2885 // Check the key is the cached one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002886 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002887
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002888 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002889 LookupPostInterceptor(holder, name, &lookup);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002890 GenerateLoadInterceptor(receiver, holder, &lookup, a1, a0, a2, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002891 &miss);
2892 __ bind(&miss);
2893 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2894
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002895 return GetCode(INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002896}
2897
2898
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002899Handle<Code> KeyedLoadStubCompiler::CompileLoadArrayLength(
2900 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002901 // ----------- S t a t e -------------
2902 // -- ra : return address
2903 // -- a0 : key
2904 // -- a1 : receiver
2905 // -----------------------------------
2906 Label miss;
2907
2908 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002909 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002910
2911 GenerateLoadArrayLength(masm(), a1, a2, &miss);
2912 __ bind(&miss);
2913 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2914
2915 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002916}
2917
2918
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002919Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength(
2920 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002921 // ----------- S t a t e -------------
2922 // -- ra : return address
2923 // -- a0 : key
2924 // -- a1 : receiver
2925 // -----------------------------------
2926 Label miss;
2927
2928 Counters* counters = masm()->isolate()->counters();
2929 __ IncrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
2930
2931 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002932 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002933
2934 GenerateLoadStringLength(masm(), a1, a2, a3, &miss, true);
2935 __ bind(&miss);
2936 __ DecrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
2937
2938 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2939
2940 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002941}
2942
2943
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002944Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype(
2945 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002946 // ----------- S t a t e -------------
2947 // -- ra : return address
2948 // -- a0 : key
2949 // -- a1 : receiver
2950 // -----------------------------------
2951 Label miss;
2952
2953 Counters* counters = masm()->isolate()->counters();
2954 __ IncrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
2955
2956 // Check the name hasn't changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002957 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002958
2959 GenerateLoadFunctionPrototype(masm(), a1, a2, a3, &miss);
2960 __ bind(&miss);
2961 __ DecrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
2962 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2963
2964 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002965}
2966
2967
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002968Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
2969 Handle<Map> receiver_map) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00002970 // ----------- S t a t e -------------
2971 // -- ra : return address
2972 // -- a0 : key
2973 // -- a1 : receiver
2974 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002975 ElementsKind elements_kind = receiver_map->elements_kind();
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002976 Handle<Code> stub = KeyedLoadElementStub(elements_kind).GetCode();
2977
2978 __ DispatchMap(a1, a2, receiver_map, stub, DO_SMI_CHECK);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002979
2980 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
2981 __ Jump(ic, RelocInfo::CODE_TARGET);
2982
2983 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002984 return GetCode(NORMAL, factory()->empty_string());
danno@chromium.org40cb8782011-05-25 07:58:50 +00002985}
2986
2987
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002988Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
2989 MapHandleList* receiver_maps,
2990 CodeHandleList* handler_ics) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002991 // ----------- S t a t e -------------
2992 // -- ra : return address
2993 // -- a0 : key
2994 // -- a1 : receiver
2995 // -----------------------------------
2996 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002997 __ JumpIfSmi(a1, &miss);
2998
danno@chromium.org40cb8782011-05-25 07:58:50 +00002999 int receiver_count = receiver_maps->length();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003000 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003001 for (int current = 0; current < receiver_count; ++current) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003002 __ Jump(handler_ics->at(current), RelocInfo::CODE_TARGET,
3003 eq, a2, Operand(receiver_maps->at(current)));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003004 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003005
3006 __ bind(&miss);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003007 Handle<Code> miss_ic = isolate()->builtins()->KeyedLoadIC_Miss();
3008 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003009
3010 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003011 return GetCode(NORMAL, factory()->empty_string(), MEGAMORPHIC);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003012}
3013
3014
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003015Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +00003016 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003017 Handle<Map> transition,
3018 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003019 // ----------- S t a t e -------------
3020 // -- a0 : value
3021 // -- a1 : key
3022 // -- a2 : receiver
3023 // -- ra : return address
3024 // -----------------------------------
3025
3026 Label miss;
3027
3028 Counters* counters = masm()->isolate()->counters();
3029 __ IncrementCounter(counters->keyed_store_field(), 1, a3, t0);
3030
3031 // Check that the name has not changed.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003032 __ Branch(&miss, ne, a1, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003033
3034 // a3 is used as scratch register. a1 and a2 keep their values if a jump to
3035 // the miss label is generated.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003036 GenerateStoreField(masm(), object, index, transition, a2, a1, a3, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003037 __ bind(&miss);
3038
3039 __ DecrementCounter(counters->keyed_store_field(), 1, a3, t0);
3040 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss();
3041 __ Jump(ic, RelocInfo::CODE_TARGET);
3042
3043 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003044 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003045}
3046
3047
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003048Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
3049 Handle<Map> receiver_map) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003050 // ----------- S t a t e -------------
3051 // -- a0 : value
3052 // -- a1 : key
3053 // -- a2 : receiver
3054 // -- ra : return address
3055 // -- a3 : scratch
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003056 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003057 ElementsKind elements_kind = receiver_map->elements_kind();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003058 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003059 Handle<Code> stub =
3060 KeyedStoreElementStub(is_js_array, elements_kind).GetCode();
3061
3062 __ DispatchMap(a2, a3, receiver_map, stub, DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003063
danno@chromium.org40cb8782011-05-25 07:58:50 +00003064 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003065 __ Jump(ic, RelocInfo::CODE_TARGET);
3066
3067 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003068 return GetCode(NORMAL, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00003069}
3070
3071
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003072Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
3073 MapHandleList* receiver_maps,
3074 CodeHandleList* handler_stubs,
3075 MapHandleList* transitioned_maps) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003076 // ----------- S t a t e -------------
3077 // -- a0 : value
3078 // -- a1 : key
3079 // -- a2 : receiver
3080 // -- ra : return address
3081 // -- a3 : scratch
3082 // -----------------------------------
3083 Label miss;
3084 __ JumpIfSmi(a2, &miss);
3085
3086 int receiver_count = receiver_maps->length();
3087 __ lw(a3, FieldMemOperand(a2, HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003088 for (int i = 0; i < receiver_count; ++i) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003089 if (transitioned_maps->at(i).is_null()) {
3090 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq,
3091 a3, Operand(receiver_maps->at(i)));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003092 } else {
3093 Label next_map;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003094 __ Branch(&next_map, ne, a3, Operand(receiver_maps->at(i)));
3095 __ li(a3, Operand(transitioned_maps->at(i)));
3096 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003097 __ bind(&next_map);
3098 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003099 }
3100
3101 __ bind(&miss);
3102 Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
3103 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3104
3105 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003106 return GetCode(NORMAL, factory()->empty_string(), MEGAMORPHIC);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003107}
3108
3109
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003110Handle<Code> ConstructStubCompiler::CompileConstructStub(
3111 Handle<JSFunction> function) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003112 // a0 : argc
3113 // a1 : constructor
3114 // ra : return address
3115 // [sp] : last argument
3116 Label generic_stub_call;
3117
3118 // Use t7 for holding undefined which is used in several places below.
3119 __ LoadRoot(t7, Heap::kUndefinedValueRootIndex);
3120
3121#ifdef ENABLE_DEBUGGER_SUPPORT
3122 // Check to see whether there are any break points in the function code. If
3123 // there are jump to the generic constructor stub which calls the actual
3124 // code for the function thereby hitting the break points.
3125 __ lw(t5, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3126 __ lw(a2, FieldMemOperand(t5, SharedFunctionInfo::kDebugInfoOffset));
3127 __ Branch(&generic_stub_call, ne, a2, Operand(t7));
3128#endif
3129
3130 // Load the initial map and verify that it is in fact a map.
3131 // a1: constructor function
3132 // t7: undefined
3133 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003134 __ JumpIfSmi(a2, &generic_stub_call);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003135 __ GetObjectType(a2, a3, t0);
3136 __ Branch(&generic_stub_call, ne, t0, Operand(MAP_TYPE));
3137
3138#ifdef DEBUG
3139 // Cannot construct functions this way.
3140 // a0: argc
3141 // a1: constructor function
3142 // a2: initial map
3143 // t7: undefined
3144 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
3145 __ Check(ne, "Function constructed by construct stub.",
3146 a3, Operand(JS_FUNCTION_TYPE));
3147#endif
3148
3149 // Now allocate the JSObject in new space.
3150 // a0: argc
3151 // a1: constructor function
3152 // a2: initial map
3153 // t7: undefined
3154 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003155 __ AllocateInNewSpace(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003156
3157 // Allocated the JSObject, now initialize the fields. Map is set to initial
3158 // map and properties and elements are set to empty fixed array.
3159 // a0: argc
3160 // a1: constructor function
3161 // a2: initial map
3162 // a3: object size (in words)
3163 // t4: JSObject (not tagged)
3164 // t7: undefined
3165 __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex);
3166 __ mov(t5, t4);
3167 __ sw(a2, MemOperand(t5, JSObject::kMapOffset));
3168 __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset));
3169 __ sw(t6, MemOperand(t5, JSObject::kElementsOffset));
3170 __ Addu(t5, t5, Operand(3 * kPointerSize));
3171 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
3172 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
3173 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
3174
3175
3176 // Calculate the location of the first argument. The stack contains only the
3177 // argc arguments.
3178 __ sll(a1, a0, kPointerSizeLog2);
3179 __ Addu(a1, a1, sp);
3180
3181 // Fill all the in-object properties with undefined.
3182 // a0: argc
3183 // a1: first argument
3184 // a3: object size (in words)
3185 // t4: JSObject (not tagged)
3186 // t5: First in-object property of JSObject (not tagged)
3187 // t7: undefined
3188 // Fill the initialized properties with a constant value or a passed argument
3189 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003190 Handle<SharedFunctionInfo> shared(function->shared());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003191 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3192 if (shared->IsThisPropertyAssignmentArgument(i)) {
3193 Label not_passed, next;
3194 // Check if the argument assigned to the property is actually passed.
3195 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3196 __ Branch(&not_passed, less_equal, a0, Operand(arg_number));
3197 // Argument passed - find it on the stack.
3198 __ lw(a2, MemOperand(a1, (arg_number + 1) * -kPointerSize));
3199 __ sw(a2, MemOperand(t5));
3200 __ Addu(t5, t5, kPointerSize);
3201 __ jmp(&next);
3202 __ bind(&not_passed);
3203 // Set the property to undefined.
3204 __ sw(t7, MemOperand(t5));
3205 __ Addu(t5, t5, Operand(kPointerSize));
3206 __ bind(&next);
3207 } else {
3208 // Set the property to the constant value.
3209 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
3210 __ li(a2, Operand(constant));
3211 __ sw(a2, MemOperand(t5));
3212 __ Addu(t5, t5, kPointerSize);
3213 }
3214 }
3215
3216 // Fill the unused in-object property fields with undefined.
3217 ASSERT(function->has_initial_map());
3218 for (int i = shared->this_property_assignments_count();
3219 i < function->initial_map()->inobject_properties();
3220 i++) {
3221 __ sw(t7, MemOperand(t5));
3222 __ Addu(t5, t5, kPointerSize);
3223 }
3224
3225 // a0: argc
3226 // t4: JSObject (not tagged)
3227 // Move argc to a1 and the JSObject to return to v0 and tag it.
3228 __ mov(a1, a0);
3229 __ mov(v0, t4);
3230 __ Or(v0, v0, Operand(kHeapObjectTag));
3231
3232 // v0: JSObject
3233 // a1: argc
3234 // Remove caller arguments and receiver from the stack and return.
3235 __ sll(t0, a1, kPointerSizeLog2);
3236 __ Addu(sp, sp, t0);
3237 __ Addu(sp, sp, Operand(kPointerSize));
3238 Counters* counters = masm()->isolate()->counters();
3239 __ IncrementCounter(counters->constructed_objects(), 1, a1, a2);
3240 __ IncrementCounter(counters->constructed_objects_stub(), 1, a1, a2);
3241 __ Ret();
3242
3243 // Jump to the generic stub in case the specialized code cannot handle the
3244 // construction.
3245 __ bind(&generic_stub_call);
3246 Handle<Code> generic_construct_stub =
3247 masm()->isolate()->builtins()->JSConstructStubGeneric();
3248 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
3249
3250 // Return the generated code.
3251 return GetCode();
3252}
3253
3254
danno@chromium.org40cb8782011-05-25 07:58:50 +00003255#undef __
3256#define __ ACCESS_MASM(masm)
3257
3258
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003259void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3260 MacroAssembler* masm) {
3261 // ---------- S t a t e --------------
3262 // -- ra : return address
3263 // -- a0 : key
3264 // -- a1 : receiver
3265 // -----------------------------------
3266 Label slow, miss_force_generic;
3267
3268 Register key = a0;
3269 Register receiver = a1;
3270
3271 __ JumpIfNotSmi(key, &miss_force_generic);
3272 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
3273 __ sra(a2, a0, kSmiTagSize);
3274 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
3275 __ Ret();
3276
3277 // Slow case, key and receiver still in a0 and a1.
3278 __ bind(&slow);
3279 __ IncrementCounter(
3280 masm->isolate()->counters()->keyed_load_external_array_slow(),
3281 1, a2, a3);
3282 // Entry registers are intact.
3283 // ---------- S t a t e --------------
3284 // -- ra : return address
3285 // -- a0 : key
3286 // -- a1 : receiver
3287 // -----------------------------------
3288 Handle<Code> slow_ic =
3289 masm->isolate()->builtins()->KeyedLoadIC_Slow();
3290 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
3291
3292 // Miss case, call the runtime.
3293 __ bind(&miss_force_generic);
3294
3295 // ---------- S t a t e --------------
3296 // -- ra : return address
3297 // -- a0 : key
3298 // -- a1 : receiver
3299 // -----------------------------------
3300
3301 Handle<Code> miss_ic =
3302 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3303 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3304}
3305
3306
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003307static bool IsElementTypeSigned(ElementsKind elements_kind) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003308 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003309 case EXTERNAL_BYTE_ELEMENTS:
3310 case EXTERNAL_SHORT_ELEMENTS:
3311 case EXTERNAL_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003312 return true;
3313
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003314 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3315 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3316 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3317 case EXTERNAL_PIXEL_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003318 return false;
3319
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003320 case EXTERNAL_FLOAT_ELEMENTS:
3321 case EXTERNAL_DOUBLE_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003322 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003323 case FAST_ELEMENTS:
3324 case FAST_DOUBLE_ELEMENTS:
3325 case DICTIONARY_ELEMENTS:
3326 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003327 UNREACHABLE();
3328 return false;
3329 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003330 return false;
lrn@chromium.org7516f052011-03-30 08:52:27 +00003331}
3332
3333
danno@chromium.org40cb8782011-05-25 07:58:50 +00003334void KeyedLoadStubCompiler::GenerateLoadExternalArray(
3335 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003336 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003337 // ---------- S t a t e --------------
3338 // -- ra : return address
3339 // -- a0 : key
3340 // -- a1 : receiver
3341 // -----------------------------------
danno@chromium.org40cb8782011-05-25 07:58:50 +00003342 Label miss_force_generic, slow, failed_allocation;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003343
3344 Register key = a0;
3345 Register receiver = a1;
3346
danno@chromium.org40cb8782011-05-25 07:58:50 +00003347 // This stub is meant to be tail-jumped to, the receiver must already
3348 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003349
3350 // Check that the key is a smi.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003351 __ JumpIfNotSmi(key, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003352
3353 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3354 // a3: elements array
3355
3356 // Check that the index is in range.
3357 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3358 __ sra(t2, key, kSmiTagSize);
3359 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003360 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003361
3362 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3363 // a3: base pointer of external storage
3364
3365 // We are not untagging smi key and instead work with it
3366 // as if it was premultiplied by 2.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003367 STATIC_ASSERT((kSmiTag == 0) && (kSmiTagSize == 1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003368
3369 Register value = a2;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003370 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003371 case EXTERNAL_BYTE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003372 __ srl(t2, key, 1);
3373 __ addu(t3, a3, t2);
3374 __ lb(value, MemOperand(t3, 0));
3375 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003376 case EXTERNAL_PIXEL_ELEMENTS:
3377 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003378 __ srl(t2, key, 1);
3379 __ addu(t3, a3, t2);
3380 __ lbu(value, MemOperand(t3, 0));
3381 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003382 case EXTERNAL_SHORT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003383 __ addu(t3, a3, key);
3384 __ lh(value, MemOperand(t3, 0));
3385 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003386 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003387 __ addu(t3, a3, key);
3388 __ lhu(value, MemOperand(t3, 0));
3389 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003390 case EXTERNAL_INT_ELEMENTS:
3391 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003392 __ sll(t2, key, 1);
3393 __ addu(t3, a3, t2);
3394 __ lw(value, MemOperand(t3, 0));
3395 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003396 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003397 __ sll(t3, t2, 2);
3398 __ addu(t3, a3, t3);
3399 if (CpuFeatures::IsSupported(FPU)) {
3400 CpuFeatures::Scope scope(FPU);
3401 __ lwc1(f0, MemOperand(t3, 0));
3402 } else {
3403 __ lw(value, MemOperand(t3, 0));
3404 }
3405 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003406 case EXTERNAL_DOUBLE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003407 __ sll(t2, key, 2);
3408 __ addu(t3, a3, t2);
3409 if (CpuFeatures::IsSupported(FPU)) {
3410 CpuFeatures::Scope scope(FPU);
3411 __ ldc1(f0, MemOperand(t3, 0));
3412 } else {
3413 // t3: pointer to the beginning of the double we want to load.
3414 __ lw(a2, MemOperand(t3, 0));
3415 __ lw(a3, MemOperand(t3, Register::kSizeInBytes));
3416 }
3417 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003418 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003419 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003420 case FAST_DOUBLE_ELEMENTS:
3421 case DICTIONARY_ELEMENTS:
3422 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003423 UNREACHABLE();
3424 break;
3425 }
3426
3427 // For integer array types:
3428 // a2: value
3429 // For float array type:
3430 // f0: value (if FPU is supported)
3431 // a2: value (if FPU is not supported)
3432 // For double array type:
3433 // f0: value (if FPU is supported)
3434 // a2/a3: value (if FPU is not supported)
3435
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003436 if (elements_kind == EXTERNAL_INT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003437 // For the Int and UnsignedInt array types, we need to see whether
3438 // the value can be represented in a Smi. If not, we need to convert
3439 // it to a HeapNumber.
3440 Label box_int;
3441 __ Subu(t3, value, Operand(0xC0000000)); // Non-smi value gives neg result.
3442 __ Branch(&box_int, lt, t3, Operand(zero_reg));
3443 // Tag integer as smi and return it.
3444 __ sll(v0, value, kSmiTagSize);
3445 __ Ret();
3446
3447 __ bind(&box_int);
3448 // Allocate a HeapNumber for the result and perform int-to-double
3449 // conversion.
3450 // The arm version uses a temporary here to save r0, but we don't need to
3451 // (a0 is not modified).
3452 __ LoadRoot(t1, Heap::kHeapNumberMapRootIndex);
3453 __ AllocateHeapNumber(v0, a3, t0, t1, &slow);
3454
3455 if (CpuFeatures::IsSupported(FPU)) {
3456 CpuFeatures::Scope scope(FPU);
3457 __ mtc1(value, f0);
3458 __ cvt_d_w(f0, f0);
3459 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag));
3460 __ Ret();
3461 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003462 Register dst1 = t2;
3463 Register dst2 = t3;
3464 FloatingPointHelper::Destination dest =
3465 FloatingPointHelper::kCoreRegisters;
3466 FloatingPointHelper::ConvertIntToDouble(masm,
3467 value,
3468 dest,
3469 f0,
3470 dst1,
3471 dst2,
3472 t1,
3473 f2);
3474 __ sw(dst1, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3475 __ sw(dst2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3476 __ Ret();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003477 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003478 } else if (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003479 // The test is different for unsigned int values. Since we need
3480 // the value to be in the range of a positive smi, we can't
3481 // handle either of the top two bits being set in the value.
3482 if (CpuFeatures::IsSupported(FPU)) {
3483 CpuFeatures::Scope scope(FPU);
3484 Label pl_box_int;
3485 __ And(t2, value, Operand(0xC0000000));
3486 __ Branch(&pl_box_int, ne, t2, Operand(zero_reg));
3487
3488 // It can fit in an Smi.
3489 // Tag integer as smi and return it.
3490 __ sll(v0, value, kSmiTagSize);
3491 __ Ret();
3492
3493 __ bind(&pl_box_int);
3494 // Allocate a HeapNumber for the result and perform int-to-double
3495 // conversion. Don't use a0 and a1 as AllocateHeapNumber clobbers all
3496 // registers - also when jumping due to exhausted young space.
3497 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3498 __ AllocateHeapNumber(v0, t2, t3, t6, &slow);
3499
3500 // This is replaced by a macro:
3501 // __ mtc1(value, f0); // LS 32-bits.
3502 // __ mtc1(zero_reg, f1); // MS 32-bits are all zero.
3503 // __ cvt_d_l(f0, f0); // Use 64 bit conv to get correct unsigned 32-bit.
3504
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003505 __ Cvt_d_uw(f0, value, f22);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003506
3507 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag));
3508
3509 __ Ret();
3510 } else {
3511 // Check whether unsigned integer fits into smi.
3512 Label box_int_0, box_int_1, done;
3513 __ And(t2, value, Operand(0x80000000));
3514 __ Branch(&box_int_0, ne, t2, Operand(zero_reg));
3515 __ And(t2, value, Operand(0x40000000));
3516 __ Branch(&box_int_1, ne, t2, Operand(zero_reg));
3517
3518 // Tag integer as smi and return it.
3519 __ sll(v0, value, kSmiTagSize);
3520 __ Ret();
3521
3522 Register hiword = value; // a2.
3523 Register loword = a3;
3524
3525 __ bind(&box_int_0);
3526 // Integer does not have leading zeros.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003527 GenerateUInt2Double(masm, hiword, loword, t0, 0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003528 __ Branch(&done);
3529
3530 __ bind(&box_int_1);
3531 // Integer has one leading zero.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003532 GenerateUInt2Double(masm, hiword, loword, t0, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003533
3534
3535 __ bind(&done);
3536 // Integer was converted to double in registers hiword:loword.
3537 // Wrap it into a HeapNumber. Don't use a0 and a1 as AllocateHeapNumber
3538 // clobbers all registers - also when jumping due to exhausted young
3539 // space.
3540 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3541 __ AllocateHeapNumber(t2, t3, t5, t6, &slow);
3542
3543 __ sw(hiword, FieldMemOperand(t2, HeapNumber::kExponentOffset));
3544 __ sw(loword, FieldMemOperand(t2, HeapNumber::kMantissaOffset));
3545
3546 __ mov(v0, t2);
3547 __ Ret();
3548 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003549 } else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003550 // For the floating-point array type, we need to always allocate a
3551 // HeapNumber.
3552 if (CpuFeatures::IsSupported(FPU)) {
3553 CpuFeatures::Scope scope(FPU);
3554 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3555 // AllocateHeapNumber clobbers all registers - also when jumping due to
3556 // exhausted young space.
3557 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3558 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3559 // The float (single) value is already in fpu reg f0 (if we use float).
3560 __ cvt_d_s(f0, f0);
3561 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag));
3562 __ Ret();
3563 } else {
3564 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3565 // AllocateHeapNumber clobbers all registers - also when jumping due to
3566 // exhausted young space.
3567 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3568 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3569 // FPU is not available, do manual single to double conversion.
3570
3571 // a2: floating point value (binary32).
3572 // v0: heap number for result
3573
3574 // Extract mantissa to t4.
3575 __ And(t4, value, Operand(kBinary32MantissaMask));
3576
3577 // Extract exponent to t5.
3578 __ srl(t5, value, kBinary32MantissaBits);
3579 __ And(t5, t5, Operand(kBinary32ExponentMask >> kBinary32MantissaBits));
3580
3581 Label exponent_rebiased;
3582 __ Branch(&exponent_rebiased, eq, t5, Operand(zero_reg));
3583
3584 __ li(t0, 0x7ff);
3585 __ Xor(t1, t5, Operand(0xFF));
3586 __ movz(t5, t0, t1); // Set t5 to 0x7ff only if t5 is equal to 0xff.
3587 __ Branch(&exponent_rebiased, eq, t0, Operand(0xff));
3588
3589 // Rebias exponent.
3590 __ Addu(t5,
3591 t5,
3592 Operand(-kBinary32ExponentBias + HeapNumber::kExponentBias));
3593
3594 __ bind(&exponent_rebiased);
3595 __ And(a2, value, Operand(kBinary32SignMask));
3596 value = no_reg;
3597 __ sll(t0, t5, HeapNumber::kMantissaBitsInTopWord);
3598 __ or_(a2, a2, t0);
3599
3600 // Shift mantissa.
3601 static const int kMantissaShiftForHiWord =
3602 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3603
3604 static const int kMantissaShiftForLoWord =
3605 kBitsPerInt - kMantissaShiftForHiWord;
3606
3607 __ srl(t0, t4, kMantissaShiftForHiWord);
3608 __ or_(a2, a2, t0);
3609 __ sll(a0, t4, kMantissaShiftForLoWord);
3610
3611 __ sw(a2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3612 __ sw(a0, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3613 __ Ret();
3614 }
3615
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003616 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003617 if (CpuFeatures::IsSupported(FPU)) {
3618 CpuFeatures::Scope scope(FPU);
3619 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3620 // AllocateHeapNumber clobbers all registers - also when jumping due to
3621 // exhausted young space.
3622 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3623 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3624 // The double value is already in f0
3625 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
3626 __ Ret();
3627 } else {
3628 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3629 // AllocateHeapNumber clobbers all registers - also when jumping due to
3630 // exhausted young space.
3631 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3632 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3633
3634 __ sw(a2, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3635 __ sw(a3, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3636 __ Ret();
3637 }
3638
3639 } else {
3640 // Tag integer as smi and return it.
3641 __ sll(v0, value, kSmiTagSize);
3642 __ Ret();
3643 }
3644
3645 // Slow case, key and receiver still in a0 and a1.
3646 __ bind(&slow);
3647 __ IncrementCounter(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003648 masm->isolate()->counters()->keyed_load_external_array_slow(),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003649 1, a2, a3);
3650
3651 // ---------- S t a t e --------------
3652 // -- ra : return address
3653 // -- a0 : key
3654 // -- a1 : receiver
3655 // -----------------------------------
3656
3657 __ Push(a1, a0);
3658
3659 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
3660
danno@chromium.org40cb8782011-05-25 07:58:50 +00003661 __ bind(&miss_force_generic);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003662 Handle<Code> stub =
3663 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3664 __ Jump(stub, RelocInfo::CODE_TARGET);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003665}
3666
3667
danno@chromium.org40cb8782011-05-25 07:58:50 +00003668void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3669 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003670 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003671 // ---------- S t a t e --------------
3672 // -- a0 : value
3673 // -- a1 : key
3674 // -- a2 : receiver
3675 // -- ra : return address
3676 // -----------------------------------
3677
danno@chromium.org40cb8782011-05-25 07:58:50 +00003678 Label slow, check_heap_number, miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003679
3680 // Register usage.
3681 Register value = a0;
3682 Register key = a1;
3683 Register receiver = a2;
3684 // a3 mostly holds the elements array or the destination external array.
3685
danno@chromium.org40cb8782011-05-25 07:58:50 +00003686 // This stub is meant to be tail-jumped to, the receiver must already
3687 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003688
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003689 // Check that the key is a smi.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003690 __ JumpIfNotSmi(key, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003691
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003692 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3693
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003694 // Check that the index is in range.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003695 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3696 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003697 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003698
3699 // Handle both smis and HeapNumbers in the fast path. Go to the
3700 // runtime for all other kinds of values.
3701 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003702
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003703 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003704 // Double to pixel conversion is only implemented in the runtime for now.
3705 __ JumpIfNotSmi(value, &slow);
3706 } else {
3707 __ JumpIfNotSmi(value, &check_heap_number);
3708 }
3709 __ SmiUntag(t1, value);
3710 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3711
3712 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003713 // t1: value (integer).
3714
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003715 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003716 case EXTERNAL_PIXEL_ELEMENTS: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003717 // Clamp the value to [0..255].
3718 // v0 is used as a scratch register here.
3719 Label done;
3720 __ li(v0, Operand(255));
3721 // Normal branch: nop in delay slot.
3722 __ Branch(&done, gt, t1, Operand(v0));
3723 // Use delay slot in this branch.
3724 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg));
3725 __ mov(v0, zero_reg); // In delay slot.
3726 __ mov(v0, t1); // Value is in range 0..255.
3727 __ bind(&done);
3728 __ mov(t1, v0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003729
3730 __ srl(t8, key, 1);
3731 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003732 __ sb(t1, MemOperand(t8, 0));
3733 }
3734 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003735 case EXTERNAL_BYTE_ELEMENTS:
3736 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003737 __ srl(t8, key, 1);
3738 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003739 __ sb(t1, MemOperand(t8, 0));
3740 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003741 case EXTERNAL_SHORT_ELEMENTS:
3742 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003743 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003744 __ sh(t1, MemOperand(t8, 0));
3745 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003746 case EXTERNAL_INT_ELEMENTS:
3747 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003748 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003749 __ addu(t8, a3, t8);
3750 __ sw(t1, MemOperand(t8, 0));
3751 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003752 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003753 // Perform int-to-float conversion and store to memory.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003754 __ SmiUntag(t0, key);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003755 StoreIntAsFloat(masm, a3, t0, t1, t2, t3, t4);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003756 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003757 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003758 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003759 __ addu(a3, a3, t8);
3760 // a3: effective address of the double element
3761 FloatingPointHelper::Destination destination;
3762 if (CpuFeatures::IsSupported(FPU)) {
3763 destination = FloatingPointHelper::kFPURegisters;
3764 } else {
3765 destination = FloatingPointHelper::kCoreRegisters;
3766 }
3767 FloatingPointHelper::ConvertIntToDouble(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003768 masm, t1, destination,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003769 f0, t2, t3, // These are: double_dst, dst1, dst2.
3770 t0, f2); // These are: scratch2, single_scratch.
3771 if (destination == FloatingPointHelper::kFPURegisters) {
3772 CpuFeatures::Scope scope(FPU);
3773 __ sdc1(f0, MemOperand(a3, 0));
3774 } else {
3775 __ sw(t2, MemOperand(a3, 0));
3776 __ sw(t3, MemOperand(a3, Register::kSizeInBytes));
3777 }
3778 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003779 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003780 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003781 case FAST_DOUBLE_ELEMENTS:
3782 case DICTIONARY_ELEMENTS:
3783 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003784 UNREACHABLE();
3785 break;
3786 }
3787
3788 // Entry registers are intact, a0 holds the value which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003789 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003790 __ Ret();
3791
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003792 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003793 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003794 __ bind(&check_heap_number);
3795 __ GetObjectType(value, t1, t2);
3796 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE));
3797
3798 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3799
3800 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003801
3802 // The WebGL specification leaves the behavior of storing NaN and
3803 // +/-Infinity into integer arrays basically undefined. For more
3804 // reproducible behavior, convert these to zero.
3805
3806 if (CpuFeatures::IsSupported(FPU)) {
3807 CpuFeatures::Scope scope(FPU);
3808
3809 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
3810
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003811 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003812 __ cvt_s_d(f0, f0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003813 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003814 __ addu(t8, a3, t8);
3815 __ swc1(f0, MemOperand(t8, 0));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003816 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003817 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003818 __ addu(t8, a3, t8);
3819 __ sdc1(f0, MemOperand(t8, 0));
3820 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003821 __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003822
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003823 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003824 case EXTERNAL_BYTE_ELEMENTS:
3825 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003826 __ srl(t8, key, 1);
3827 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003828 __ sb(t3, MemOperand(t8, 0));
3829 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003830 case EXTERNAL_SHORT_ELEMENTS:
3831 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003832 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003833 __ sh(t3, MemOperand(t8, 0));
3834 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003835 case EXTERNAL_INT_ELEMENTS:
3836 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003837 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003838 __ addu(t8, a3, t8);
3839 __ sw(t3, MemOperand(t8, 0));
3840 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003841 case EXTERNAL_PIXEL_ELEMENTS:
3842 case EXTERNAL_FLOAT_ELEMENTS:
3843 case EXTERNAL_DOUBLE_ELEMENTS:
3844 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003845 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003846 case FAST_DOUBLE_ELEMENTS:
3847 case DICTIONARY_ELEMENTS:
3848 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003849 UNREACHABLE();
3850 break;
3851 }
3852 }
3853
3854 // Entry registers are intact, a0 holds the value
3855 // which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003856 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003857 __ Ret();
3858 } else {
3859 // FPU is not available, do manual conversions.
3860
3861 __ lw(t3, FieldMemOperand(value, HeapNumber::kExponentOffset));
3862 __ lw(t4, FieldMemOperand(value, HeapNumber::kMantissaOffset));
3863
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003864 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003865 Label done, nan_or_infinity_or_zero;
3866 static const int kMantissaInHiWordShift =
3867 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3868
3869 static const int kMantissaInLoWordShift =
3870 kBitsPerInt - kMantissaInHiWordShift;
3871
3872 // Test for all special exponent values: zeros, subnormal numbers, NaNs
3873 // and infinities. All these should be converted to 0.
3874 __ li(t5, HeapNumber::kExponentMask);
3875 __ and_(t6, t3, t5);
3876 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(zero_reg));
3877
3878 __ xor_(t1, t6, t5);
3879 __ li(t2, kBinary32ExponentMask);
3880 __ movz(t6, t2, t1); // Only if t6 is equal to t5.
3881 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(t5));
3882
3883 // Rebias exponent.
3884 __ srl(t6, t6, HeapNumber::kExponentShift);
3885 __ Addu(t6,
3886 t6,
3887 Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
3888
3889 __ li(t1, Operand(kBinary32MaxExponent));
3890 __ Slt(t1, t1, t6);
3891 __ And(t2, t3, Operand(HeapNumber::kSignMask));
3892 __ Or(t2, t2, Operand(kBinary32ExponentMask));
3893 __ movn(t3, t2, t1); // Only if t6 is gt kBinary32MaxExponent.
3894 __ Branch(&done, gt, t6, Operand(kBinary32MaxExponent));
3895
3896 __ Slt(t1, t6, Operand(kBinary32MinExponent));
3897 __ And(t2, t3, Operand(HeapNumber::kSignMask));
3898 __ movn(t3, t2, t1); // Only if t6 is lt kBinary32MinExponent.
3899 __ Branch(&done, lt, t6, Operand(kBinary32MinExponent));
3900
3901 __ And(t7, t3, Operand(HeapNumber::kSignMask));
3902 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3903 __ sll(t3, t3, kMantissaInHiWordShift);
3904 __ or_(t7, t7, t3);
3905 __ srl(t4, t4, kMantissaInLoWordShift);
3906 __ or_(t7, t7, t4);
3907 __ sll(t6, t6, kBinary32ExponentShift);
3908 __ or_(t3, t7, t6);
3909
3910 __ bind(&done);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003911 __ sll(t9, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003912 __ addu(t9, a2, t9);
3913 __ sw(t3, MemOperand(t9, 0));
3914
3915 // Entry registers are intact, a0 holds the value which is the return
3916 // value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003917 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003918 __ Ret();
3919
3920 __ bind(&nan_or_infinity_or_zero);
3921 __ And(t7, t3, Operand(HeapNumber::kSignMask));
3922 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3923 __ or_(t6, t6, t7);
3924 __ sll(t3, t3, kMantissaInHiWordShift);
3925 __ or_(t6, t6, t3);
3926 __ srl(t4, t4, kMantissaInLoWordShift);
3927 __ or_(t3, t6, t4);
3928 __ Branch(&done);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003929 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003930 __ sll(t8, t0, 3);
3931 __ addu(t8, a3, t8);
3932 // t8: effective address of destination element.
3933 __ sw(t4, MemOperand(t8, 0));
3934 __ sw(t3, MemOperand(t8, Register::kSizeInBytes));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003935 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003936 __ Ret();
3937 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003938 bool is_signed_type = IsElementTypeSigned(elements_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003939 int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
3940 int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
3941
3942 Label done, sign;
3943
3944 // Test for all special exponent values: zeros, subnormal numbers, NaNs
3945 // and infinities. All these should be converted to 0.
3946 __ li(t5, HeapNumber::kExponentMask);
3947 __ and_(t6, t3, t5);
3948 __ movz(t3, zero_reg, t6); // Only if t6 is equal to zero.
3949 __ Branch(&done, eq, t6, Operand(zero_reg));
3950
3951 __ xor_(t2, t6, t5);
3952 __ movz(t3, zero_reg, t2); // Only if t6 is equal to t5.
3953 __ Branch(&done, eq, t6, Operand(t5));
3954
3955 // Unbias exponent.
3956 __ srl(t6, t6, HeapNumber::kExponentShift);
3957 __ Subu(t6, t6, Operand(HeapNumber::kExponentBias));
3958 // If exponent is negative then result is 0.
3959 __ slt(t2, t6, zero_reg);
3960 __ movn(t3, zero_reg, t2); // Only if exponent is negative.
3961 __ Branch(&done, lt, t6, Operand(zero_reg));
3962
3963 // If exponent is too big then result is minimal value.
3964 __ slti(t1, t6, meaningfull_bits - 1);
3965 __ li(t2, min_value);
3966 __ movz(t3, t2, t1); // Only if t6 is ge meaningfull_bits - 1.
3967 __ Branch(&done, ge, t6, Operand(meaningfull_bits - 1));
3968
3969 __ And(t5, t3, Operand(HeapNumber::kSignMask));
3970 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3971 __ Or(t3, t3, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
3972
3973 __ li(t9, HeapNumber::kMantissaBitsInTopWord);
3974 __ subu(t6, t9, t6);
3975 __ slt(t1, t6, zero_reg);
3976 __ srlv(t2, t3, t6);
3977 __ movz(t3, t2, t1); // Only if t6 is positive.
3978 __ Branch(&sign, ge, t6, Operand(zero_reg));
3979
3980 __ subu(t6, zero_reg, t6);
3981 __ sllv(t3, t3, t6);
3982 __ li(t9, meaningfull_bits);
3983 __ subu(t6, t9, t6);
3984 __ srlv(t4, t4, t6);
3985 __ or_(t3, t3, t4);
3986
3987 __ bind(&sign);
3988 __ subu(t2, t3, zero_reg);
3989 __ movz(t3, t2, t5); // Only if t5 is zero.
3990
3991 __ bind(&done);
3992
3993 // Result is in t3.
3994 // This switch block should be exactly the same as above (FPU mode).
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003995 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003996 case EXTERNAL_BYTE_ELEMENTS:
3997 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003998 __ srl(t8, key, 1);
3999 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004000 __ sb(t3, MemOperand(t8, 0));
4001 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004002 case EXTERNAL_SHORT_ELEMENTS:
4003 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004004 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004005 __ sh(t3, MemOperand(t8, 0));
4006 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004007 case EXTERNAL_INT_ELEMENTS:
4008 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004009 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004010 __ addu(t8, a3, t8);
4011 __ sw(t3, MemOperand(t8, 0));
4012 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004013 case EXTERNAL_PIXEL_ELEMENTS:
4014 case EXTERNAL_FLOAT_ELEMENTS:
4015 case EXTERNAL_DOUBLE_ELEMENTS:
4016 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004017 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004018 case FAST_DOUBLE_ELEMENTS:
4019 case DICTIONARY_ELEMENTS:
4020 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004021 UNREACHABLE();
4022 break;
4023 }
4024 }
4025 }
4026 }
4027
danno@chromium.org40cb8782011-05-25 07:58:50 +00004028 // Slow case, key and receiver still in a0 and a1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004029 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004030 __ IncrementCounter(
4031 masm->isolate()->counters()->keyed_load_external_array_slow(),
4032 1, a2, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004033 // Entry registers are intact.
4034 // ---------- S t a t e --------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004035 // -- ra : return address
danno@chromium.org40cb8782011-05-25 07:58:50 +00004036 // -- a0 : key
4037 // -- a1 : receiver
4038 // -----------------------------------
4039 Handle<Code> slow_ic =
4040 masm->isolate()->builtins()->KeyedStoreIC_Slow();
4041 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4042
4043 // Miss case, call the runtime.
4044 __ bind(&miss_force_generic);
4045
4046 // ---------- S t a t e --------------
4047 // -- ra : return address
4048 // -- a0 : key
4049 // -- a1 : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004050 // -----------------------------------
4051
danno@chromium.org40cb8782011-05-25 07:58:50 +00004052 Handle<Code> miss_ic =
4053 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4054 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
4055}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004056
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004057
danno@chromium.org40cb8782011-05-25 07:58:50 +00004058void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
4059 // ----------- S t a t e -------------
4060 // -- ra : return address
4061 // -- a0 : key
4062 // -- a1 : receiver
4063 // -----------------------------------
4064 Label miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004065
danno@chromium.org40cb8782011-05-25 07:58:50 +00004066 // This stub is meant to be tail-jumped to, the receiver must already
4067 // have been verified by the caller to not be a smi.
4068
4069 // Check that the key is a smi.
4070 __ JumpIfNotSmi(a0, &miss_force_generic);
4071
4072 // Get the elements array.
4073 __ lw(a2, FieldMemOperand(a1, JSObject::kElementsOffset));
4074 __ AssertFastElements(a2);
4075
4076 // Check that the key is within bounds.
4077 __ lw(a3, FieldMemOperand(a2, FixedArray::kLengthOffset));
4078 __ Branch(&miss_force_generic, hs, a0, Operand(a3));
4079
4080 // Load the result and make sure it's not the hole.
4081 __ Addu(a3, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004082 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004083 __ sll(t0, a0, kPointerSizeLog2 - kSmiTagSize);
4084 __ Addu(t0, t0, a3);
4085 __ lw(t0, MemOperand(t0));
4086 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
4087 __ Branch(&miss_force_generic, eq, t0, Operand(t1));
4088 __ mov(v0, t0);
4089 __ Ret();
4090
4091 __ bind(&miss_force_generic);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004092 Handle<Code> stub =
4093 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4094 __ Jump(stub, RelocInfo::CODE_TARGET);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004095}
4096
4097
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004098void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
4099 MacroAssembler* masm) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004100 // ----------- S t a t e -------------
4101 // -- ra : return address
4102 // -- a0 : key
4103 // -- a1 : receiver
4104 // -----------------------------------
4105 Label miss_force_generic, slow_allocate_heapnumber;
4106
4107 Register key_reg = a0;
4108 Register receiver_reg = a1;
4109 Register elements_reg = a2;
4110 Register heap_number_reg = a2;
4111 Register indexed_double_offset = a3;
4112 Register scratch = t0;
4113 Register scratch2 = t1;
4114 Register scratch3 = t2;
4115 Register heap_number_map = t3;
4116
4117 // This stub is meant to be tail-jumped to, the receiver must already
4118 // have been verified by the caller to not be a smi.
4119
4120 // Check that the key is a smi.
4121 __ JumpIfNotSmi(key_reg, &miss_force_generic);
4122
4123 // Get the elements array.
4124 __ lw(elements_reg,
4125 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4126
4127 // Check that the key is within bounds.
4128 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4129 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4130
4131 // Load the upper word of the double in the fixed array and test for NaN.
4132 __ sll(scratch2, key_reg, kDoubleSizeLog2 - kSmiTagSize);
4133 __ Addu(indexed_double_offset, elements_reg, Operand(scratch2));
4134 uint32_t upper_32_offset = FixedArray::kHeaderSize + sizeof(kHoleNanLower32);
4135 __ lw(scratch, FieldMemOperand(indexed_double_offset, upper_32_offset));
4136 __ Branch(&miss_force_generic, eq, scratch, Operand(kHoleNanUpper32));
4137
4138 // Non-NaN. Allocate a new heap number and copy the double value into it.
4139 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
4140 __ AllocateHeapNumber(heap_number_reg, scratch2, scratch3,
4141 heap_number_map, &slow_allocate_heapnumber);
4142
4143 // Don't need to reload the upper 32 bits of the double, it's already in
4144 // scratch.
4145 __ sw(scratch, FieldMemOperand(heap_number_reg,
4146 HeapNumber::kExponentOffset));
4147 __ lw(scratch, FieldMemOperand(indexed_double_offset,
4148 FixedArray::kHeaderSize));
4149 __ sw(scratch, FieldMemOperand(heap_number_reg,
4150 HeapNumber::kMantissaOffset));
4151
4152 __ mov(v0, heap_number_reg);
4153 __ Ret();
4154
4155 __ bind(&slow_allocate_heapnumber);
4156 Handle<Code> slow_ic =
4157 masm->isolate()->builtins()->KeyedLoadIC_Slow();
4158 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4159
4160 __ bind(&miss_force_generic);
4161 Handle<Code> miss_ic =
4162 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4163 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004164}
4165
4166
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004167void KeyedStoreStubCompiler::GenerateStoreFastElement(
4168 MacroAssembler* masm,
4169 bool is_js_array,
4170 ElementsKind elements_kind) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00004171 // ----------- S t a t e -------------
4172 // -- a0 : value
4173 // -- a1 : key
4174 // -- a2 : receiver
4175 // -- ra : return address
4176 // -- a3 : scratch
4177 // -- a4 : scratch (elements)
4178 // -----------------------------------
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004179 Label miss_force_generic, transition_elements_kind;
danno@chromium.org40cb8782011-05-25 07:58:50 +00004180
4181 Register value_reg = a0;
4182 Register key_reg = a1;
4183 Register receiver_reg = a2;
4184 Register scratch = a3;
4185 Register elements_reg = t0;
4186 Register scratch2 = t1;
4187 Register scratch3 = t2;
4188
4189 // This stub is meant to be tail-jumped to, the receiver must already
4190 // have been verified by the caller to not be a smi.
4191
4192 // Check that the key is a smi.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00004193 __ JumpIfNotSmi(key_reg, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004194
4195 // Get the elements array and make sure it is a fast element array, not 'cow'.
4196 __ lw(elements_reg,
4197 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4198 __ CheckMap(elements_reg,
4199 scratch,
4200 Heap::kFixedArrayMapRootIndex,
4201 &miss_force_generic,
4202 DONT_DO_SMI_CHECK);
4203
4204 // Check that the key is within bounds.
4205 if (is_js_array) {
4206 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4207 } else {
4208 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4209 }
4210 // Compare smis.
4211 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4212
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004213 if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
4214 __ JumpIfNotSmi(value_reg, &transition_elements_kind);
4215 __ Addu(scratch,
4216 elements_reg,
4217 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4218 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4219 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4220 __ Addu(scratch, scratch, scratch2);
4221 __ sw(value_reg, MemOperand(scratch));
4222 } else {
4223 ASSERT(elements_kind == FAST_ELEMENTS);
4224 __ Addu(scratch,
4225 elements_reg,
4226 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4227 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4228 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4229 __ Addu(scratch, scratch, scratch2);
4230 __ sw(value_reg, MemOperand(scratch));
4231 __ mov(receiver_reg, value_reg);
4232 ASSERT(elements_kind == FAST_ELEMENTS);
4233 __ RecordWrite(elements_reg, // Object.
4234 scratch, // Address.
4235 receiver_reg, // Value.
4236 kRAHasNotBeenSaved,
4237 kDontSaveFPRegs);
4238 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004239 // value_reg (a0) is preserved.
4240 // Done.
4241 __ Ret();
4242
4243 __ bind(&miss_force_generic);
4244 Handle<Code> ic =
4245 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4246 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004247
4248 __ bind(&transition_elements_kind);
4249 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4250 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004251}
4252
4253
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004254void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
4255 MacroAssembler* masm,
4256 bool is_js_array) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004257 // ----------- S t a t e -------------
4258 // -- a0 : value
4259 // -- a1 : key
4260 // -- a2 : receiver
4261 // -- ra : return address
4262 // -- a3 : scratch
4263 // -- t0 : scratch (elements_reg)
4264 // -- t1 : scratch (mantissa_reg)
4265 // -- t2 : scratch (exponent_reg)
4266 // -- t3 : scratch4
4267 // -----------------------------------
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004268 Label miss_force_generic, transition_elements_kind;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004269
4270 Register value_reg = a0;
4271 Register key_reg = a1;
4272 Register receiver_reg = a2;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004273 Register elements_reg = a3;
4274 Register scratch1 = t0;
4275 Register scratch2 = t1;
4276 Register scratch3 = t2;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004277 Register scratch4 = t3;
4278
4279 // This stub is meant to be tail-jumped to, the receiver must already
4280 // have been verified by the caller to not be a smi.
4281 __ JumpIfNotSmi(key_reg, &miss_force_generic);
4282
4283 __ lw(elements_reg,
4284 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4285
4286 // Check that the key is within bounds.
4287 if (is_js_array) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004288 __ lw(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004289 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004290 __ lw(scratch1,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004291 FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4292 }
4293 // Compare smis, unsigned compare catches both negative and out-of-bound
4294 // indexes.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004295 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch1));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004296
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004297 __ StoreNumberToDoubleElements(value_reg,
4298 key_reg,
4299 receiver_reg,
4300 elements_reg,
4301 scratch1,
4302 scratch2,
4303 scratch3,
4304 scratch4,
4305 &transition_elements_kind);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004306
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004307 __ Ret(USE_DELAY_SLOT);
4308 __ mov(v0, value_reg); // In delay slot.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004309
4310 // Handle store cache miss, replacing the ic with the generic stub.
4311 __ bind(&miss_force_generic);
4312 Handle<Code> ic =
4313 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4314 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004315
4316 __ bind(&transition_elements_kind);
4317 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4318 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004319}
4320
4321
ager@chromium.org5c838252010-02-19 08:53:10 +00004322#undef __
4323
4324} } // namespace v8::internal
4325
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004326#endif // V8_TARGET_ARCH_MIPS