blob: c17a8e8a463aeae374856b6bc7b0534cc1fa8b01 [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.
102MUST_USE_RESULT static MaybeObject* GenerateDictionaryNegativeLookup(
103 MacroAssembler* masm,
104 Label* miss_label,
105 Register receiver,
106 String* name,
107 Register scratch0,
108 Register scratch1) {
109 ASSERT(name->IsSymbol());
110 Counters* counters = masm->isolate()->counters();
111 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
112 __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
113
114 Label done;
115
116 const int kInterceptorOrAccessCheckNeededMask =
117 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
118
119 // Bail out if the receiver has a named interceptor or requires access checks.
120 Register map = scratch1;
121 __ lw(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
122 __ lbu(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
123 __ And(at, scratch0, Operand(kInterceptorOrAccessCheckNeededMask));
124 __ Branch(miss_label, ne, at, Operand(zero_reg));
125
126
127 // Check that receiver is a JSObject.
128 __ lbu(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000129 __ Branch(miss_label, lt, scratch0, Operand(FIRST_SPEC_OBJECT_TYPE));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000130
131 // Load properties array.
132 Register properties = scratch0;
133 __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
134 // Check that the properties array is a dictionary.
135 __ lw(map, FieldMemOperand(properties, HeapObject::kMapOffset));
136 Register tmp = properties;
137 __ LoadRoot(tmp, Heap::kHashTableMapRootIndex);
138 __ Branch(miss_label, ne, map, Operand(tmp));
139
140 // Restore the temporarily used register.
141 __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
142
143 MaybeObject* result = StringDictionaryLookupStub::GenerateNegativeLookup(
144 masm,
145 miss_label,
146 &done,
147 receiver,
148 properties,
149 name,
150 scratch1);
151 if (result->IsFailure()) return result;
152
153 __ bind(&done);
154 __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
155
156 return result;
157}
158
159
ager@chromium.org5c838252010-02-19 08:53:10 +0000160void StubCache::GenerateProbe(MacroAssembler* masm,
161 Code::Flags flags,
162 Register receiver,
163 Register name,
164 Register scratch,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000165 Register extra,
166 Register extra2) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000167 Isolate* isolate = masm->isolate();
168 Label miss;
169
170 // Make sure that code is valid. The shifting code relies on the
171 // entry size being 8.
172 ASSERT(sizeof(Entry) == 8);
173
174 // Make sure the flags does not name a specific type.
175 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
176
177 // Make sure that there are no register conflicts.
178 ASSERT(!scratch.is(receiver));
179 ASSERT(!scratch.is(name));
180 ASSERT(!extra.is(receiver));
181 ASSERT(!extra.is(name));
182 ASSERT(!extra.is(scratch));
183 ASSERT(!extra2.is(receiver));
184 ASSERT(!extra2.is(name));
185 ASSERT(!extra2.is(scratch));
186 ASSERT(!extra2.is(extra));
187
188 // Check scratch, extra and extra2 registers are valid.
189 ASSERT(!scratch.is(no_reg));
190 ASSERT(!extra.is(no_reg));
191 ASSERT(!extra2.is(no_reg));
192
193 // Check that the receiver isn't a smi.
194 __ JumpIfSmi(receiver, &miss, t0);
195
196 // Get the map of the receiver and compute the hash.
197 __ lw(scratch, FieldMemOperand(name, String::kHashFieldOffset));
198 __ lw(t8, FieldMemOperand(receiver, HeapObject::kMapOffset));
199 __ Addu(scratch, scratch, Operand(t8));
200 __ Xor(scratch, scratch, Operand(flags));
201 __ And(scratch,
202 scratch,
203 Operand((kPrimaryTableSize - 1) << kHeapObjectTagSize));
204
205 // Probe the primary table.
206 ProbeTable(isolate, masm, flags, kPrimary, name, scratch, extra, extra2);
207
208 // Primary miss: Compute hash for secondary probe.
209 __ Subu(scratch, scratch, Operand(name));
210 __ Addu(scratch, scratch, Operand(flags));
211 __ And(scratch,
212 scratch,
213 Operand((kSecondaryTableSize - 1) << kHeapObjectTagSize));
214
215 // Probe the secondary table.
216 ProbeTable(isolate, masm, flags, kSecondary, name, scratch, extra, extra2);
217
218 // Cache miss: Fall-through and let caller handle the miss by
219 // entering the runtime system.
220 __ bind(&miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000221}
222
223
224void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
225 int index,
226 Register prototype) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000227 // Load the global or builtins object from the current context.
228 __ lw(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
229 // Load the global context from the global or builtins object.
230 __ lw(prototype,
231 FieldMemOperand(prototype, GlobalObject::kGlobalContextOffset));
232 // Load the function from the global context.
233 __ lw(prototype, MemOperand(prototype, Context::SlotOffset(index)));
234 // Load the initial map. The global functions all have initial maps.
235 __ lw(prototype,
236 FieldMemOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
237 // Load the prototype from the initial map.
238 __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000239}
240
241
lrn@chromium.org7516f052011-03-30 08:52:27 +0000242void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
243 MacroAssembler* masm, int index, Register prototype, Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000244 Isolate* isolate = masm->isolate();
245 // Check we're still in the same context.
246 __ lw(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
247 ASSERT(!prototype.is(at));
248 __ li(at, isolate->global());
249 __ Branch(miss, ne, prototype, Operand(at));
250 // Get the global function with the given index.
251 JSFunction* function =
252 JSFunction::cast(isolate->global_context()->get(index));
253 // Load its initial map. The global functions all have initial maps.
254 __ li(prototype, Handle<Map>(function->initial_map()));
255 // Load the prototype from the initial map.
256 __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000257}
258
259
ager@chromium.org5c838252010-02-19 08:53:10 +0000260// Load a fast property out of a holder object (src). In-object properties
261// are loaded directly otherwise the property is loaded from the properties
262// fixed array.
263void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
264 Register dst, Register src,
265 JSObject* holder, int index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000266 // Adjust for the number of properties stored in the holder.
267 index -= holder->map()->inobject_properties();
268 if (index < 0) {
269 // Get the property straight out of the holder.
270 int offset = holder->map()->instance_size() + (index * kPointerSize);
271 __ lw(dst, FieldMemOperand(src, offset));
272 } else {
273 // Calculate the offset into the properties array.
274 int offset = index * kPointerSize + FixedArray::kHeaderSize;
275 __ lw(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
276 __ lw(dst, FieldMemOperand(dst, offset));
277 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000278}
279
280
281void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
282 Register receiver,
283 Register scratch,
284 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000285 // Check that the receiver isn't a smi.
286 __ And(scratch, receiver, Operand(kSmiTagMask));
287 __ Branch(miss_label, eq, scratch, Operand(zero_reg));
288
289 // Check that the object is a JS array.
290 __ GetObjectType(receiver, scratch, scratch);
291 __ Branch(miss_label, ne, scratch, Operand(JS_ARRAY_TYPE));
292
293 // Load length directly from the JS array.
294 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
295 __ Ret();
296}
297
298
299// Generate code to check if an object is a string. If the object is a
300// heap object, its map's instance type is left in the scratch1 register.
301// If this is not needed, scratch1 and scratch2 may be the same register.
302static void GenerateStringCheck(MacroAssembler* masm,
303 Register receiver,
304 Register scratch1,
305 Register scratch2,
306 Label* smi,
307 Label* non_string_object) {
308 // Check that the receiver isn't a smi.
309 __ JumpIfSmi(receiver, smi, t0);
310
311 // Check that the object is a string.
312 __ lw(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
313 __ lbu(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
314 __ And(scratch2, scratch1, Operand(kIsNotStringMask));
315 // The cast is to resolve the overload for the argument of 0x0.
316 __ Branch(non_string_object,
317 ne,
318 scratch2,
319 Operand(static_cast<int32_t>(kStringTag)));
ager@chromium.org5c838252010-02-19 08:53:10 +0000320}
321
322
lrn@chromium.org7516f052011-03-30 08:52:27 +0000323// Generate code to load the length from a string object and return the length.
324// If the receiver object is not a string or a wrapped string object the
325// execution continues at the miss label. The register containing the
326// receiver is potentially clobbered.
327void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
328 Register receiver,
329 Register scratch1,
330 Register scratch2,
331 Label* miss,
332 bool support_wrappers) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000333 Label check_wrapper;
334
335 // Check if the object is a string leaving the instance type in the
336 // scratch1 register.
337 GenerateStringCheck(masm, receiver, scratch1, scratch2, miss,
338 support_wrappers ? &check_wrapper : miss);
339
340 // Load length directly from the string.
341 __ lw(v0, FieldMemOperand(receiver, String::kLengthOffset));
342 __ Ret();
343
344 if (support_wrappers) {
345 // Check if the object is a JSValue wrapper.
346 __ bind(&check_wrapper);
347 __ Branch(miss, ne, scratch1, Operand(JS_VALUE_TYPE));
348
349 // Unwrap the value and check if the wrapped value is a string.
350 __ lw(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
351 GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
352 __ lw(v0, FieldMemOperand(scratch1, String::kLengthOffset));
353 __ Ret();
354 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000355}
356
357
ager@chromium.org5c838252010-02-19 08:53:10 +0000358void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
359 Register receiver,
360 Register scratch1,
361 Register scratch2,
362 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000363 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
364 __ mov(v0, scratch1);
365 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000366}
367
368
lrn@chromium.org7516f052011-03-30 08:52:27 +0000369// Generate StoreField code, value is passed in a0 register.
ager@chromium.org5c838252010-02-19 08:53:10 +0000370// After executing generated code, the receiver_reg and name_reg
371// may be clobbered.
372void StubCompiler::GenerateStoreField(MacroAssembler* masm,
ager@chromium.org5c838252010-02-19 08:53:10 +0000373 JSObject* object,
374 int index,
375 Map* transition,
376 Register receiver_reg,
377 Register name_reg,
378 Register scratch,
379 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000380 // a0 : value.
381 Label exit;
382
383 // Check that the receiver isn't a smi.
384 __ JumpIfSmi(receiver_reg, miss_label, scratch);
385
386 // Check that the map of the receiver hasn't changed.
387 __ lw(scratch, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
388 __ Branch(miss_label, ne, scratch, Operand(Handle<Map>(object->map())));
389
390 // Perform global security token check if needed.
391 if (object->IsJSGlobalProxy()) {
392 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
393 }
394
395 // Stub never generated for non-global objects that require access
396 // checks.
397 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
398
399 // Perform map transition for the receiver if necessary.
400 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
401 // The properties must be extended before we can store the value.
402 // We jump to a runtime call that extends the properties array.
403 __ push(receiver_reg);
404 __ li(a2, Operand(Handle<Map>(transition)));
405 __ Push(a2, a0);
406 __ TailCallExternalReference(
407 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
408 masm->isolate()),
409 3, 1);
410 return;
411 }
412
413 if (transition != NULL) {
414 // Update the map of the object; no write barrier updating is
415 // needed because the map is never in new space.
416 __ li(t0, Operand(Handle<Map>(transition)));
417 __ sw(t0, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
418 }
419
420 // Adjust for the number of properties stored in the object. Even in the
421 // face of a transition we can use the old map here because the size of the
422 // object and the number of in-object properties is not going to change.
423 index -= object->map()->inobject_properties();
424
425 if (index < 0) {
426 // Set the property straight into the object.
427 int offset = object->map()->instance_size() + (index * kPointerSize);
428 __ sw(a0, FieldMemOperand(receiver_reg, offset));
429
430 // Skip updating write barrier if storing a smi.
431 __ JumpIfSmi(a0, &exit, scratch);
432
433 // Update the write barrier for the array address.
434 // Pass the now unused name_reg as a scratch register.
435 __ RecordWrite(receiver_reg, Operand(offset), name_reg, scratch);
436 } else {
437 // Write to the properties array.
438 int offset = index * kPointerSize + FixedArray::kHeaderSize;
439 // Get the properties array.
440 __ lw(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
441 __ sw(a0, FieldMemOperand(scratch, offset));
442
443 // Skip updating write barrier if storing a smi.
444 __ JumpIfSmi(a0, &exit);
445
446 // Update the write barrier for the array address.
447 // Ok to clobber receiver_reg and name_reg, since we return.
448 __ RecordWrite(scratch, Operand(offset), name_reg, receiver_reg);
449 }
450
451 // Return the value (register v0).
452 __ bind(&exit);
453 __ mov(v0, a0);
454 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000455}
456
457
458void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000459 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
460 Code* code = NULL;
461 if (kind == Code::LOAD_IC) {
462 code = masm->isolate()->builtins()->builtin(Builtins::kLoadIC_Miss);
463 } else {
464 code = masm->isolate()->builtins()->builtin(Builtins::kKeyedLoadIC_Miss);
465 }
466
467 Handle<Code> ic(code);
468 __ Jump(ic, RelocInfo::CODE_TARGET);
ager@chromium.org5c838252010-02-19 08:53:10 +0000469}
470
471
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000472static void GenerateCallFunction(MacroAssembler* masm,
473 Object* object,
474 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000475 Label* miss,
476 Code::ExtraICState extra_ic_state) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000477 // ----------- S t a t e -------------
478 // -- a0: receiver
479 // -- a1: function to call
480 // -----------------------------------
481 // Check that the function really is a function.
482 __ JumpIfSmi(a1, miss);
483 __ GetObjectType(a1, a3, a3);
484 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
485
486 // Patch the receiver on the stack with the global proxy if
487 // necessary.
488 if (object->IsGlobalObject()) {
489 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
490 __ sw(a3, MemOperand(sp, arguments.immediate() * kPointerSize));
491 }
492
493 // Invoke the function.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000494 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
495 ? CALL_AS_FUNCTION
496 : CALL_AS_METHOD;
497 __ InvokeFunction(a1, arguments, JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000498}
499
500
501static void PushInterceptorArguments(MacroAssembler* masm,
502 Register receiver,
503 Register holder,
504 Register name,
505 JSObject* holder_obj) {
506 __ push(name);
507 InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
508 ASSERT(!masm->isolate()->heap()->InNewSpace(interceptor));
509 Register scratch = name;
510 __ li(scratch, Operand(Handle<Object>(interceptor)));
511 __ Push(scratch, receiver, holder);
512 __ lw(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
513 __ push(scratch);
514}
515
516
517static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
518 Register receiver,
519 Register holder,
520 Register name,
521 JSObject* holder_obj) {
522 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
523
524 ExternalReference ref =
525 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
526 masm->isolate());
527 __ li(a0, Operand(5));
528 __ li(a1, Operand(ref));
529
530 CEntryStub stub(1);
531 __ CallStub(&stub);
532}
533
534
535static const int kFastApiCallArguments = 3;
536
537
538// Reserves space for the extra arguments to FastHandleApiCall in the
539// caller's frame.
540//
541// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
542static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
543 Register scratch) {
544 ASSERT(Smi::FromInt(0) == 0);
545 for (int i = 0; i < kFastApiCallArguments; i++) {
546 __ push(zero_reg);
547 }
548}
549
550
551// Undoes the effects of ReserveSpaceForFastApiCall.
552static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
553 __ Drop(kFastApiCallArguments);
554}
555
556
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000557static MaybeObject* GenerateFastApiDirectCall(
558 MacroAssembler* masm,
559 const CallOptimization& optimization,
560 int argc) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000561 // ----------- S t a t e -------------
562 // -- sp[0] : holder (set by CheckPrototypes)
563 // -- sp[4] : callee js function
564 // -- sp[8] : call data
565 // -- sp[12] : last js argument
566 // -- ...
567 // -- sp[(argc + 3) * 4] : first js argument
568 // -- sp[(argc + 4) * 4] : receiver
569 // -----------------------------------
570 // Get the function and setup the context.
571 JSFunction* function = optimization.constant_function();
572 __ li(t1, Operand(Handle<JSFunction>(function)));
573 __ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset));
574
575 // Pass the additional arguments FastHandleApiCall expects.
576 Object* call_data = optimization.api_call_info()->data();
577 Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info());
578 if (masm->isolate()->heap()->InNewSpace(call_data)) {
579 __ li(a0, api_call_info_handle);
580 __ lw(t2, FieldMemOperand(a0, CallHandlerInfo::kDataOffset));
581 } else {
582 __ li(t2, Operand(Handle<Object>(call_data)));
583 }
584
585 // Store js function and call data.
586 __ sw(t1, MemOperand(sp, 1 * kPointerSize));
587 __ sw(t2, MemOperand(sp, 2 * kPointerSize));
588
589 // a2 points to call data as expected by Arguments
590 // (refer to layout above).
591 __ Addu(a2, sp, Operand(2 * kPointerSize));
592
593 Object* callback = optimization.api_call_info()->callback();
594 Address api_function_address = v8::ToCData<Address>(callback);
595 ApiFunction fun(api_function_address);
596
597 const int kApiStackSpace = 4;
598
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000599 FrameScope frame_scope(masm, StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000600 __ EnterExitFrame(false, kApiStackSpace);
601
602 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
603 // struct from the function (which is currently the case). This means we pass
604 // the first argument in a1 instead of a0. TryCallApiFunctionAndReturn
605 // will handle setting up a0.
606
607 // a1 = v8::Arguments&
608 // Arguments is built at sp + 1 (sp is a reserved spot for ra).
609 __ Addu(a1, sp, kPointerSize);
610
611 // v8::Arguments::implicit_args = data
612 __ sw(a2, MemOperand(a1, 0 * kPointerSize));
613 // v8::Arguments::values = last argument
614 __ Addu(t0, a2, Operand(argc * kPointerSize));
615 __ sw(t0, MemOperand(a1, 1 * kPointerSize));
616 // v8::Arguments::length_ = argc
617 __ li(t0, Operand(argc));
618 __ sw(t0, MemOperand(a1, 2 * kPointerSize));
619 // v8::Arguments::is_construct_call = 0
620 __ sw(zero_reg, MemOperand(a1, 3 * kPointerSize));
621
622 // Emitting a stub call may try to allocate (if the code is not
623 // already generated). Do not allow the assembler to perform a
624 // garbage collection but instead return the allocation failure
625 // object.
626 const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
627 ExternalReference ref =
628 ExternalReference(&fun,
629 ExternalReference::DIRECT_API_CALL,
630 masm->isolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000631 AllowExternalCallThatCantCauseGC scope(masm);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000632 return masm->TryCallApiFunctionAndReturn(ref, kStackUnwindSpace);
633}
634
lrn@chromium.org7516f052011-03-30 08:52:27 +0000635class CallInterceptorCompiler BASE_EMBEDDED {
636 public:
637 CallInterceptorCompiler(StubCompiler* stub_compiler,
638 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000639 Register name,
640 Code::ExtraICState extra_ic_state)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000641 : stub_compiler_(stub_compiler),
642 arguments_(arguments),
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000643 name_(name),
644 extra_ic_state_(extra_ic_state) {}
lrn@chromium.org7516f052011-03-30 08:52:27 +0000645
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000646 MaybeObject* Compile(MacroAssembler* masm,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000647 JSObject* object,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000648 JSObject* holder,
649 String* name,
650 LookupResult* lookup,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000651 Register receiver,
652 Register scratch1,
653 Register scratch2,
654 Register scratch3,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000655 Label* miss) {
656 ASSERT(holder->HasNamedInterceptor());
657 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
658
659 // Check that the receiver isn't a smi.
660 __ JumpIfSmi(receiver, miss);
661
662 CallOptimization optimization(lookup);
663
664 if (optimization.is_constant_call()) {
665 return CompileCacheable(masm,
666 object,
667 receiver,
668 scratch1,
669 scratch2,
670 scratch3,
671 holder,
672 lookup,
673 name,
674 optimization,
675 miss);
676 } else {
677 CompileRegular(masm,
678 object,
679 receiver,
680 scratch1,
681 scratch2,
682 scratch3,
683 name,
684 holder,
685 miss);
686 return masm->isolate()->heap()->undefined_value();
687 }
688 }
689
690 private:
691 MaybeObject* CompileCacheable(MacroAssembler* masm,
692 JSObject* object,
693 Register receiver,
694 Register scratch1,
695 Register scratch2,
696 Register scratch3,
697 JSObject* interceptor_holder,
698 LookupResult* lookup,
699 String* name,
700 const CallOptimization& optimization,
701 Label* miss_label) {
702 ASSERT(optimization.is_constant_call());
703 ASSERT(!lookup->holder()->IsGlobalObject());
704
705 Counters* counters = masm->isolate()->counters();
706
707 int depth1 = kInvalidProtoDepth;
708 int depth2 = kInvalidProtoDepth;
709 bool can_do_fast_api_call = false;
710 if (optimization.is_simple_api_call() &&
711 !lookup->holder()->IsGlobalObject()) {
712 depth1 =
713 optimization.GetPrototypeDepthOfExpectedType(object,
714 interceptor_holder);
715 if (depth1 == kInvalidProtoDepth) {
716 depth2 =
717 optimization.GetPrototypeDepthOfExpectedType(interceptor_holder,
718 lookup->holder());
719 }
720 can_do_fast_api_call = (depth1 != kInvalidProtoDepth) ||
721 (depth2 != kInvalidProtoDepth);
722 }
723
724 __ IncrementCounter(counters->call_const_interceptor(), 1,
725 scratch1, scratch2);
726
727 if (can_do_fast_api_call) {
728 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
729 scratch1, scratch2);
730 ReserveSpaceForFastApiCall(masm, scratch1);
731 }
732
733 // Check that the maps from receiver to interceptor's holder
734 // haven't changed and thus we can invoke interceptor.
735 Label miss_cleanup;
736 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
737 Register holder =
738 stub_compiler_->CheckPrototypes(object, receiver,
739 interceptor_holder, scratch1,
740 scratch2, scratch3, name, depth1, miss);
741
742 // Invoke an interceptor and if it provides a value,
743 // branch to |regular_invoke|.
744 Label regular_invoke;
745 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
746 &regular_invoke);
747
748 // Interceptor returned nothing for this property. Try to use cached
749 // constant function.
750
751 // Check that the maps from interceptor's holder to constant function's
752 // holder haven't changed and thus we can use cached constant function.
753 if (interceptor_holder != lookup->holder()) {
754 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
755 lookup->holder(), scratch1,
756 scratch2, scratch3, name, depth2, miss);
757 } else {
758 // CheckPrototypes has a side effect of fetching a 'holder'
759 // for API (object which is instanceof for the signature). It's
760 // safe to omit it here, as if present, it should be fetched
761 // by the previous CheckPrototypes.
762 ASSERT(depth2 == kInvalidProtoDepth);
763 }
764
765 // Invoke function.
766 if (can_do_fast_api_call) {
767 MaybeObject* result = GenerateFastApiDirectCall(masm,
768 optimization,
769 arguments_.immediate());
770 if (result->IsFailure()) return result;
771 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000772 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
773 ? CALL_AS_FUNCTION
774 : CALL_AS_METHOD;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000775 __ InvokeFunction(optimization.constant_function(), arguments_,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000776 JUMP_FUNCTION, call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000777 }
778
779 // Deferred code for fast API call case---clean preallocated space.
780 if (can_do_fast_api_call) {
781 __ bind(&miss_cleanup);
782 FreeSpaceForFastApiCall(masm);
783 __ Branch(miss_label);
784 }
785
786 // Invoke a regular function.
787 __ bind(&regular_invoke);
788 if (can_do_fast_api_call) {
789 FreeSpaceForFastApiCall(masm);
790 }
791
792 return masm->isolate()->heap()->undefined_value();
lrn@chromium.org7516f052011-03-30 08:52:27 +0000793 }
794
795 void CompileRegular(MacroAssembler* masm,
796 JSObject* object,
797 Register receiver,
798 Register scratch1,
799 Register scratch2,
800 Register scratch3,
801 String* name,
802 JSObject* interceptor_holder,
803 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000804 Register holder =
805 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
806 scratch1, scratch2, scratch3, name,
807 miss_label);
808
809 // Call a runtime function to load the interceptor property.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000810 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000811 // Save the name_ register across the call.
812 __ push(name_);
813
814 PushInterceptorArguments(masm,
815 receiver,
816 holder,
817 name_,
818 interceptor_holder);
819
820 __ CallExternalReference(
821 ExternalReference(
822 IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
823 masm->isolate()),
824 5);
825
826 // Restore the name_ register.
827 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000828
829 // Leave the internal frame.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000830 }
831
832 void LoadWithInterceptor(MacroAssembler* masm,
833 Register receiver,
834 Register holder,
835 JSObject* holder_obj,
836 Register scratch,
837 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000838 {
839 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000840
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000841 __ Push(holder, name_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000842
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000843 CompileCallLoadPropertyWithInterceptor(masm,
844 receiver,
845 holder,
846 name_,
847 holder_obj);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000848
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000849 __ pop(name_); // Restore the name.
850 __ pop(receiver); // Restore the holder.
851 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000852
853 // If interceptor returns no-result sentinel, call the constant function.
854 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
855 __ Branch(interceptor_succeeded, ne, v0, Operand(scratch));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000856 }
857
858 StubCompiler* stub_compiler_;
859 const ParameterCount& arguments_;
860 Register name_;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000861 Code::ExtraICState extra_ic_state_;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000862};
863
864
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000865
866// Generate code to check that a global property cell is empty. Create
867// the property cell at compilation time if no cell exists for the
868// property.
869MUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCell(
870 MacroAssembler* masm,
871 GlobalObject* global,
872 String* name,
873 Register scratch,
874 Label* miss) {
875 Object* probe;
876 { MaybeObject* maybe_probe = global->EnsurePropertyCell(name);
877 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
878 }
879 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
880 ASSERT(cell->value()->IsTheHole());
881 __ li(scratch, Operand(Handle<Object>(cell)));
882 __ lw(scratch,
883 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
884 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
885 __ Branch(miss, ne, scratch, Operand(at));
886 return cell;
887}
888
889
890// Calls GenerateCheckPropertyCell for each global object in the prototype chain
891// from object to (but not including) holder.
892MUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCells(
893 MacroAssembler* masm,
894 JSObject* object,
895 JSObject* holder,
896 String* name,
897 Register scratch,
898 Label* miss) {
899 JSObject* current = object;
900 while (current != holder) {
901 if (current->IsGlobalObject()) {
902 // Returns a cell or a failure.
903 MaybeObject* result = GenerateCheckPropertyCell(
904 masm,
905 GlobalObject::cast(current),
906 name,
907 scratch,
908 miss);
909 if (result->IsFailure()) return result;
910 }
911 ASSERT(current->IsJSObject());
912 current = JSObject::cast(current->GetPrototype());
913 }
914 return NULL;
915}
916
917
918// Convert and store int passed in register ival to IEEE 754 single precision
919// floating point value at memory location (dst + 4 * wordoffset)
920// If FPU is available use it for conversion.
921static void StoreIntAsFloat(MacroAssembler* masm,
922 Register dst,
923 Register wordoffset,
924 Register ival,
925 Register fval,
926 Register scratch1,
927 Register scratch2) {
928 if (CpuFeatures::IsSupported(FPU)) {
929 CpuFeatures::Scope scope(FPU);
930 __ mtc1(ival, f0);
931 __ cvt_s_w(f0, f0);
932 __ sll(scratch1, wordoffset, 2);
933 __ addu(scratch1, dst, scratch1);
934 __ swc1(f0, MemOperand(scratch1, 0));
935 } else {
936 // FPU is not available, do manual conversions.
937
938 Label not_special, done;
939 // Move sign bit from source to destination. This works because the sign
940 // bit in the exponent word of the double has the same position and polarity
941 // as the 2's complement sign bit in a Smi.
942 ASSERT(kBinary32SignMask == 0x80000000u);
943
944 __ And(fval, ival, Operand(kBinary32SignMask));
945 // Negate value if it is negative.
946 __ subu(scratch1, zero_reg, ival);
947 __ movn(ival, scratch1, fval);
948
949 // We have -1, 0 or 1, which we treat specially. Register ival contains
950 // absolute value: it is either equal to 1 (special case of -1 and 1),
951 // greater than 1 (not a special case) or less than 1 (special case of 0).
952 __ Branch(&not_special, gt, ival, Operand(1));
953
954 // For 1 or -1 we need to or in the 0 exponent (biased).
955 static const uint32_t exponent_word_for_1 =
956 kBinary32ExponentBias << kBinary32ExponentShift;
957
958 __ Xor(scratch1, ival, Operand(1));
959 __ li(scratch2, exponent_word_for_1);
960 __ or_(scratch2, fval, scratch2);
961 __ movz(fval, scratch2, scratch1); // Only if ival is equal to 1.
962 __ Branch(&done);
963
964 __ bind(&not_special);
965 // Count leading zeros.
966 // Gets the wrong answer for 0, but we already checked for that case above.
967 Register zeros = scratch2;
968 __ clz(zeros, ival);
969
970 // Compute exponent and or it into the exponent register.
971 __ li(scratch1, (kBitsPerInt - 1) + kBinary32ExponentBias);
972 __ subu(scratch1, scratch1, zeros);
973
974 __ sll(scratch1, scratch1, kBinary32ExponentShift);
975 __ or_(fval, fval, scratch1);
976
977 // Shift up the source chopping the top bit off.
978 __ Addu(zeros, zeros, Operand(1));
979 // This wouldn't work for 1 and -1 as the shift would be 32 which means 0.
980 __ sllv(ival, ival, zeros);
981 // And the top (top 20 bits).
982 __ srl(scratch1, ival, kBitsPerInt - kBinary32MantissaBits);
983 __ or_(fval, fval, scratch1);
984
985 __ bind(&done);
986
987 __ sll(scratch1, wordoffset, 2);
988 __ addu(scratch1, dst, scratch1);
989 __ sw(fval, MemOperand(scratch1, 0));
990 }
991}
992
993
994// Convert unsigned integer with specified number of leading zeroes in binary
995// representation to IEEE 754 double.
996// Integer to convert is passed in register hiword.
997// Resulting double is returned in registers hiword:loword.
998// This functions does not work correctly for 0.
999static void GenerateUInt2Double(MacroAssembler* masm,
1000 Register hiword,
1001 Register loword,
1002 Register scratch,
1003 int leading_zeroes) {
1004 const int meaningful_bits = kBitsPerInt - leading_zeroes - 1;
1005 const int biased_exponent = HeapNumber::kExponentBias + meaningful_bits;
1006
1007 const int mantissa_shift_for_hi_word =
1008 meaningful_bits - HeapNumber::kMantissaBitsInTopWord;
1009
1010 const int mantissa_shift_for_lo_word =
1011 kBitsPerInt - mantissa_shift_for_hi_word;
1012
1013 __ li(scratch, biased_exponent << HeapNumber::kExponentShift);
1014 if (mantissa_shift_for_hi_word > 0) {
1015 __ sll(loword, hiword, mantissa_shift_for_lo_word);
1016 __ srl(hiword, hiword, mantissa_shift_for_hi_word);
1017 __ or_(hiword, scratch, hiword);
1018 } else {
1019 __ mov(loword, zero_reg);
1020 __ sll(hiword, hiword, mantissa_shift_for_hi_word);
1021 __ or_(hiword, scratch, hiword);
1022 }
1023
1024 // If least significant bit of biased exponent was not 1 it was corrupted
1025 // by most significant bit of mantissa so we should fix that.
1026 if (!(biased_exponent & 1)) {
1027 __ li(scratch, 1 << HeapNumber::kExponentShift);
1028 __ nor(scratch, scratch, scratch);
1029 __ and_(hiword, hiword, scratch);
1030 }
1031}
1032
1033
ager@chromium.org5c838252010-02-19 08:53:10 +00001034#undef __
1035#define __ ACCESS_MASM(masm())
1036
1037
lrn@chromium.org7516f052011-03-30 08:52:27 +00001038Register StubCompiler::CheckPrototypes(JSObject* object,
1039 Register object_reg,
1040 JSObject* holder,
1041 Register holder_reg,
1042 Register scratch1,
1043 Register scratch2,
1044 String* name,
1045 int save_at_depth,
1046 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001047 // Make sure there's no overlap between holder and object registers.
1048 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1049 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1050 && !scratch2.is(scratch1));
1051
1052 // Keep track of the current object in register reg.
1053 Register reg = object_reg;
1054 int depth = 0;
1055
1056 if (save_at_depth == depth) {
1057 __ sw(reg, MemOperand(sp));
1058 }
1059
1060 // Check the maps in the prototype chain.
1061 // Traverse the prototype chain from the object and do map checks.
1062 JSObject* current = object;
1063 while (current != holder) {
1064 depth++;
1065
1066 // Only global objects and objects that do not require access
1067 // checks are allowed in stubs.
1068 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1069
1070 ASSERT(current->GetPrototype()->IsJSObject());
1071 JSObject* prototype = JSObject::cast(current->GetPrototype());
1072 if (!current->HasFastProperties() &&
1073 !current->IsJSGlobalObject() &&
1074 !current->IsJSGlobalProxy()) {
1075 if (!name->IsSymbol()) {
1076 MaybeObject* maybe_lookup_result = heap()->LookupSymbol(name);
1077 Object* lookup_result = NULL; // Initialization to please compiler.
1078 if (!maybe_lookup_result->ToObject(&lookup_result)) {
1079 set_failure(Failure::cast(maybe_lookup_result));
1080 return reg;
1081 }
1082 name = String::cast(lookup_result);
1083 }
1084 ASSERT(current->property_dictionary()->FindEntry(name) ==
1085 StringDictionary::kNotFound);
1086
1087 MaybeObject* negative_lookup = GenerateDictionaryNegativeLookup(masm(),
1088 miss,
1089 reg,
1090 name,
1091 scratch1,
1092 scratch2);
1093 if (negative_lookup->IsFailure()) {
1094 set_failure(Failure::cast(negative_lookup));
1095 return reg;
1096 }
1097
1098 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1099 reg = holder_reg; // From now the object is in holder_reg.
1100 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1101 } else if (heap()->InNewSpace(prototype)) {
1102 // Get the map of the current object.
1103 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1104
1105 // Branch on the result of the map check.
1106 __ Branch(miss, ne, scratch1, Operand(Handle<Map>(current->map())));
1107
1108 // Check access rights to the global object. This has to happen
1109 // after the map check so that we know that the object is
1110 // actually a global object.
1111 if (current->IsJSGlobalProxy()) {
1112 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1113 // Restore scratch register to be the map of the object. In the
1114 // new space case below, we load the prototype from the map in
1115 // the scratch register.
1116 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1117 }
1118
1119 reg = holder_reg; // From now the object is in holder_reg.
1120 // The prototype is in new space; we cannot store a reference
1121 // to it in the code. Load it from the map.
1122 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1123 } else {
1124 // Check the map of the current object.
1125 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1126 // Branch on the result of the map check.
1127 __ Branch(miss, ne, scratch1, Operand(Handle<Map>(current->map())));
1128 // Check access rights to the global object. This has to happen
1129 // after the map check so that we know that the object is
1130 // actually a global object.
1131 if (current->IsJSGlobalProxy()) {
1132 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1133 }
1134 // The prototype is in old space; load it directly.
1135 reg = holder_reg; // From now the object is in holder_reg.
1136 __ li(reg, Operand(Handle<JSObject>(prototype)));
1137 }
1138
1139 if (save_at_depth == depth) {
1140 __ sw(reg, MemOperand(sp));
1141 }
1142
1143 // Go to the next object in the prototype chain.
1144 current = prototype;
1145 }
1146
1147 // Check the holder map.
1148 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1149 __ Branch(miss, ne, scratch1, Operand(Handle<Map>(current->map())));
1150
1151 // Log the check depth.
1152 LOG(masm()->isolate(), IntEvent("check-maps-depth", depth + 1));
1153 // Perform security check for access to the global object.
1154 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1155 if (holder->IsJSGlobalProxy()) {
1156 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1157 };
1158
1159 // If we've skipped any global objects, it's not enough to verify
1160 // that their maps haven't changed. We also need to check that the
1161 // property cell for the property is still empty.
1162
1163 MaybeObject* result = GenerateCheckPropertyCells(masm(),
1164 object,
1165 holder,
1166 name,
1167 scratch1,
1168 miss);
1169 if (result->IsFailure()) set_failure(Failure::cast(result));
1170
1171 // Return the register containing the holder.
1172 return reg;
lrn@chromium.org7516f052011-03-30 08:52:27 +00001173}
1174
1175
ager@chromium.org5c838252010-02-19 08:53:10 +00001176void StubCompiler::GenerateLoadField(JSObject* object,
1177 JSObject* holder,
1178 Register receiver,
1179 Register scratch1,
1180 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001181 Register scratch3,
ager@chromium.org5c838252010-02-19 08:53:10 +00001182 int index,
1183 String* name,
1184 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001185 // Check that the receiver isn't a smi.
1186 __ And(scratch1, receiver, Operand(kSmiTagMask));
1187 __ Branch(miss, eq, scratch1, Operand(zero_reg));
1188
1189 // Check that the maps haven't changed.
1190 Register reg =
1191 CheckPrototypes(object, receiver, holder, scratch1, scratch2, scratch3,
1192 name, miss);
1193 GenerateFastPropertyLoad(masm(), v0, reg, holder, index);
1194 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001195}
1196
1197
1198void StubCompiler::GenerateLoadConstant(JSObject* object,
1199 JSObject* holder,
1200 Register receiver,
1201 Register scratch1,
1202 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001203 Register scratch3,
ager@chromium.org5c838252010-02-19 08:53:10 +00001204 Object* value,
1205 String* name,
1206 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001207 // Check that the receiver isn't a smi.
1208 __ JumpIfSmi(receiver, miss, scratch1);
1209
1210 // Check that the maps haven't changed.
1211 Register reg =
1212 CheckPrototypes(object, receiver, holder,
1213 scratch1, scratch2, scratch3, name, miss);
1214
1215 // Return the constant value.
1216 __ li(v0, Operand(Handle<Object>(value)));
1217 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001218}
1219
1220
lrn@chromium.org7516f052011-03-30 08:52:27 +00001221MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object,
1222 JSObject* holder,
1223 Register receiver,
1224 Register name_reg,
1225 Register scratch1,
1226 Register scratch2,
1227 Register scratch3,
1228 AccessorInfo* callback,
1229 String* name,
1230 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001231 // Check that the receiver isn't a smi.
1232 __ JumpIfSmi(receiver, miss, scratch1);
1233
1234 // Check that the maps haven't changed.
1235 Register reg =
1236 CheckPrototypes(object, receiver, holder, scratch1, scratch2, scratch3,
1237 name, miss);
1238
1239 // Build AccessorInfo::args_ list on the stack and push property name below
1240 // the exit frame to make GC aware of them and store pointers to them.
1241 __ push(receiver);
1242 __ mov(scratch2, sp); // scratch2 = AccessorInfo::args_
1243 Handle<AccessorInfo> callback_handle(callback);
1244 if (heap()->InNewSpace(callback_handle->data())) {
1245 __ li(scratch3, callback_handle);
1246 __ lw(scratch3, FieldMemOperand(scratch3, AccessorInfo::kDataOffset));
1247 } else {
1248 __ li(scratch3, Handle<Object>(callback_handle->data()));
1249 }
1250 __ Push(reg, scratch3, name_reg);
1251 __ mov(a2, scratch2); // Saved in case scratch2 == a1.
1252 __ mov(a1, sp); // a1 (first argument - see note below) = Handle<String>
1253
1254 Address getter_address = v8::ToCData<Address>(callback->getter());
1255 ApiFunction fun(getter_address);
1256
1257 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
1258 // struct from the function (which is currently the case). This means we pass
1259 // the arguments in a1-a2 instead of a0-a1. TryCallApiFunctionAndReturn
1260 // will handle setting up a0.
1261
1262 const int kApiStackSpace = 1;
1263
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001264 FrameScope frame_scope(masm(), StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001265 __ EnterExitFrame(false, kApiStackSpace);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001266
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001267 // Create AccessorInfo instance on the stack above the exit frame with
1268 // scratch2 (internal::Object **args_) as the data.
1269 __ sw(a2, MemOperand(sp, kPointerSize));
1270 // a2 (second argument - see note above) = AccessorInfo&
1271 __ Addu(a2, sp, kPointerSize);
1272
1273 // Emitting a stub call may try to allocate (if the code is not
1274 // already generated). Do not allow the assembler to perform a
1275 // garbage collection but instead return the allocation failure
1276 // object.
1277 ExternalReference ref =
1278 ExternalReference(&fun,
1279 ExternalReference::DIRECT_GETTER_CALL,
1280 masm()->isolate());
1281 // 4 args - will be freed later by LeaveExitFrame.
1282 return masm()->TryCallApiFunctionAndReturn(ref, 4);
ager@chromium.org5c838252010-02-19 08:53:10 +00001283}
1284
1285
1286void StubCompiler::GenerateLoadInterceptor(JSObject* object,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001287 JSObject* interceptor_holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001288 LookupResult* lookup,
1289 Register receiver,
1290 Register name_reg,
1291 Register scratch1,
1292 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001293 Register scratch3,
ager@chromium.org5c838252010-02-19 08:53:10 +00001294 String* name,
1295 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001296 ASSERT(interceptor_holder->HasNamedInterceptor());
1297 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1298
1299 // Check that the receiver isn't a smi.
1300 __ JumpIfSmi(receiver, miss);
1301
1302 // So far the most popular follow ups for interceptor loads are FIELD
1303 // and CALLBACKS, so inline only them, other cases may be added
1304 // later.
1305 bool compile_followup_inline = false;
1306 if (lookup->IsProperty() && lookup->IsCacheable()) {
1307 if (lookup->type() == FIELD) {
1308 compile_followup_inline = true;
1309 } else if (lookup->type() == CALLBACKS &&
1310 lookup->GetCallbackObject()->IsAccessorInfo() &&
1311 AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) {
1312 compile_followup_inline = true;
1313 }
1314 }
1315
1316 if (compile_followup_inline) {
1317 // Compile the interceptor call, followed by inline code to load the
1318 // property from further up the prototype chain if the call fails.
1319 // Check that the maps haven't changed.
1320 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1321 scratch1, scratch2, scratch3,
1322 name, miss);
1323 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
1324
1325 // Save necessary data before invoking an interceptor.
1326 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001327 {
1328 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001329
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001330 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
1331 // CALLBACKS case needs a receiver to be passed into C++ callback.
1332 __ Push(receiver, holder_reg, name_reg);
1333 } else {
1334 __ Push(holder_reg, name_reg);
1335 }
1336
1337 // Invoke an interceptor. Note: map checks from receiver to
1338 // interceptor's holder has been compiled before (see a caller
1339 // of this method).
1340 CompileCallLoadPropertyWithInterceptor(masm(),
1341 receiver,
1342 holder_reg,
1343 name_reg,
1344 interceptor_holder);
1345
1346 // Check if interceptor provided a value for property. If it's
1347 // the case, return immediately.
1348 Label interceptor_failed;
1349 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
1350 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1));
1351 frame_scope.GenerateLeaveFrame();
1352 __ Ret();
1353
1354 __ bind(&interceptor_failed);
1355 __ pop(name_reg);
1356 __ pop(holder_reg);
1357 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
1358 __ pop(receiver);
1359 }
1360
1361 // Leave the internal frame.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001362 }
1363
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001364 // Check that the maps from interceptor's holder to lookup's holder
1365 // haven't changed. And load lookup's holder into |holder| register.
1366 if (interceptor_holder != lookup->holder()) {
1367 holder_reg = CheckPrototypes(interceptor_holder,
1368 holder_reg,
1369 lookup->holder(),
1370 scratch1,
1371 scratch2,
1372 scratch3,
1373 name,
1374 miss);
1375 }
1376
1377 if (lookup->type() == FIELD) {
1378 // We found FIELD property in prototype chain of interceptor's holder.
1379 // Retrieve a field from field's holder.
1380 GenerateFastPropertyLoad(masm(), v0, holder_reg,
1381 lookup->holder(), lookup->GetFieldIndex());
1382 __ Ret();
1383 } else {
1384 // We found CALLBACKS property in prototype chain of interceptor's
1385 // holder.
1386 ASSERT(lookup->type() == CALLBACKS);
1387 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
1388 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
1389 ASSERT(callback != NULL);
1390 ASSERT(callback->getter() != NULL);
1391
1392 // Tail call to runtime.
1393 // Important invariant in CALLBACKS case: the code above must be
1394 // structured to never clobber |receiver| register.
1395 __ li(scratch2, Handle<AccessorInfo>(callback));
1396 // holder_reg is either receiver or scratch1.
1397 if (!receiver.is(holder_reg)) {
1398 ASSERT(scratch1.is(holder_reg));
1399 __ Push(receiver, holder_reg);
1400 __ lw(scratch3,
1401 FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
1402 __ Push(scratch3, scratch2, name_reg);
1403 } else {
1404 __ push(receiver);
1405 __ lw(scratch3,
1406 FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
1407 __ Push(holder_reg, scratch3, scratch2, name_reg);
1408 }
1409
1410 ExternalReference ref =
1411 ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
1412 masm()->isolate());
1413 __ TailCallExternalReference(ref, 5, 1);
1414 }
1415 } else { // !compile_followup_inline
1416 // Call the runtime system to load the interceptor.
1417 // Check that the maps haven't changed.
1418 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1419 scratch1, scratch2, scratch3,
1420 name, miss);
1421 PushInterceptorArguments(masm(), receiver, holder_reg,
1422 name_reg, interceptor_holder);
1423
1424 ExternalReference ref = ExternalReference(
1425 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), masm()->isolate());
1426 __ TailCallExternalReference(ref, 5, 1);
1427 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001428}
1429
1430
lrn@chromium.org7516f052011-03-30 08:52:27 +00001431void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001432 if (kind_ == Code::KEYED_CALL_IC) {
1433 __ Branch(miss, ne, a2, Operand(Handle<String>(name)));
1434 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001435}
1436
1437
lrn@chromium.org7516f052011-03-30 08:52:27 +00001438void CallStubCompiler::GenerateGlobalReceiverCheck(JSObject* object,
1439 JSObject* holder,
1440 String* name,
1441 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001442 ASSERT(holder->IsGlobalObject());
1443
1444 // Get the number of arguments.
1445 const int argc = arguments().immediate();
1446
1447 // Get the receiver from the stack.
1448 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1449
1450 // If the object is the holder then we know that it's a global
1451 // object which can only happen for contextual calls. In this case,
1452 // the receiver cannot be a smi.
1453 if (object != holder) {
1454 __ JumpIfSmi(a0, miss);
1455 }
1456
1457 // Check that the maps haven't changed.
1458 CheckPrototypes(object, a0, holder, a3, a1, t0, name, miss);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001459}
1460
1461
lrn@chromium.org7516f052011-03-30 08:52:27 +00001462void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell,
1463 JSFunction* function,
1464 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001465 // Get the value from the cell.
1466 __ li(a3, Operand(Handle<JSGlobalPropertyCell>(cell)));
1467 __ lw(a1, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
1468
1469 // Check that the cell contains the same function.
1470 if (heap()->InNewSpace(function)) {
1471 // We can't embed a pointer to a function in new space so we have
1472 // to verify that the shared function info is unchanged. This has
1473 // the nice side effect that multiple closures based on the same
1474 // function can all use this call IC. Before we load through the
1475 // function, we have to verify that it still is a function.
1476 __ JumpIfSmi(a1, miss);
1477 __ GetObjectType(a1, a3, a3);
1478 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
1479
1480 // Check the shared function info. Make sure it hasn't changed.
1481 __ li(a3, Handle<SharedFunctionInfo>(function->shared()));
1482 __ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
1483 __ Branch(miss, ne, t0, Operand(a3));
1484 } else {
1485 __ Branch(miss, ne, a1, Operand(Handle<JSFunction>(function)));
1486 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001487}
1488
1489
lrn@chromium.org7516f052011-03-30 08:52:27 +00001490MaybeObject* CallStubCompiler::GenerateMissBranch() {
danno@chromium.org40cb8782011-05-25 07:58:50 +00001491 MaybeObject* maybe_obj =
1492 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1493 kind_,
1494 extra_ic_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001495 Object* obj;
1496 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1497 __ Jump(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET);
1498 return obj;
ager@chromium.org5c838252010-02-19 08:53:10 +00001499}
1500
1501
lrn@chromium.org7516f052011-03-30 08:52:27 +00001502MaybeObject* CallStubCompiler::CompileCallField(JSObject* object,
1503 JSObject* holder,
1504 int index,
ager@chromium.org5c838252010-02-19 08:53:10 +00001505 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001506 // ----------- S t a t e -------------
1507 // -- a2 : name
1508 // -- ra : return address
1509 // -----------------------------------
1510 Label miss;
1511
1512 GenerateNameCheck(name, &miss);
1513
1514 const int argc = arguments().immediate();
1515
1516 // Get the receiver of the function from the stack into a0.
1517 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1518 // Check that the receiver isn't a smi.
1519 __ JumpIfSmi(a0, &miss, t0);
1520
1521 // Do the right check and compute the holder register.
1522 Register reg = CheckPrototypes(object, a0, holder, a1, a3, t0, name, &miss);
1523 GenerateFastPropertyLoad(masm(), a1, reg, holder, index);
1524
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001525 GenerateCallFunction(masm(), object, arguments(), &miss, extra_ic_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001526
1527 // Handle call cache miss.
1528 __ bind(&miss);
1529 MaybeObject* maybe_result = GenerateMissBranch();
1530 if (maybe_result->IsFailure()) return maybe_result;
1531
1532 // Return the generated code.
1533 return GetCode(FIELD, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001534}
1535
1536
lrn@chromium.org7516f052011-03-30 08:52:27 +00001537MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
1538 JSObject* holder,
1539 JSGlobalPropertyCell* cell,
1540 JSFunction* function,
1541 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001542 // ----------- S t a t e -------------
1543 // -- a2 : name
1544 // -- ra : return address
1545 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1546 // -- ...
1547 // -- sp[argc * 4] : receiver
1548 // -----------------------------------
1549
1550 // If object is not an array, bail out to regular call.
1551 if (!object->IsJSArray() || cell != NULL) return heap()->undefined_value();
1552
1553 Label miss;
1554
1555 GenerateNameCheck(name, &miss);
1556
1557 Register receiver = a1;
1558
1559 // Get the receiver from the stack.
1560 const int argc = arguments().immediate();
1561 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1562
1563 // Check that the receiver isn't a smi.
1564 __ JumpIfSmi(receiver, &miss);
1565
1566 // Check that the maps haven't changed.
1567 CheckPrototypes(JSObject::cast(object), receiver,
1568 holder, a3, v0, t0, name, &miss);
1569
1570 if (argc == 0) {
1571 // Nothing to do, just return the length.
1572 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1573 __ Drop(argc + 1);
1574 __ Ret();
1575 } else {
1576 Label call_builtin;
1577
1578 Register elements = a3;
1579 Register end_elements = t1;
1580
1581 // Get the elements array of the object.
1582 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1583
1584 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001585 __ CheckMap(elements,
1586 v0,
1587 Heap::kFixedArrayMapRootIndex,
1588 &call_builtin,
1589 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001590
1591 if (argc == 1) { // Otherwise fall through to call the builtin.
1592 Label exit, with_write_barrier, attempt_to_grow_elements;
1593
1594 // Get the array's length into v0 and calculate new length.
1595 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1596 STATIC_ASSERT(kSmiTagSize == 1);
1597 STATIC_ASSERT(kSmiTag == 0);
1598 __ Addu(v0, v0, Operand(Smi::FromInt(argc)));
1599
1600 // Get the element's length.
1601 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1602
1603 // Check if we could survive without allocation.
1604 __ Branch(&attempt_to_grow_elements, gt, v0, Operand(t0));
1605
1606 // Save new length.
1607 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1608
1609 // Push the element.
1610 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1611 // We may need a register containing the address end_elements below,
1612 // so write back the value in end_elements.
1613 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1614 __ Addu(end_elements, elements, end_elements);
1615 const int kEndElementsOffset =
1616 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001617 __ Addu(end_elements, end_elements, kEndElementsOffset);
1618 __ sw(t0, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001619
1620 // Check for a smi.
1621 __ JumpIfNotSmi(t0, &with_write_barrier);
1622 __ bind(&exit);
1623 __ Drop(argc + 1);
1624 __ Ret();
1625
1626 __ bind(&with_write_barrier);
1627 __ InNewSpace(elements, t0, eq, &exit);
1628 __ RecordWriteHelper(elements, end_elements, t0);
1629 __ Drop(argc + 1);
1630 __ Ret();
1631
1632 __ bind(&attempt_to_grow_elements);
1633 // v0: array's length + 1.
1634 // t0: elements' length.
1635
1636 if (!FLAG_inline_new) {
1637 __ Branch(&call_builtin);
1638 }
1639
1640 ExternalReference new_space_allocation_top =
1641 ExternalReference::new_space_allocation_top_address(
1642 masm()->isolate());
1643 ExternalReference new_space_allocation_limit =
1644 ExternalReference::new_space_allocation_limit_address(
1645 masm()->isolate());
1646
1647 const int kAllocationDelta = 4;
1648 // Load top and check if it is the end of elements.
1649 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1650 __ Addu(end_elements, elements, end_elements);
1651 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset));
1652 __ li(t3, Operand(new_space_allocation_top));
1653 __ lw(t2, MemOperand(t3));
1654 __ Branch(&call_builtin, ne, end_elements, Operand(t2));
1655
1656 __ li(t5, Operand(new_space_allocation_limit));
1657 __ lw(t5, MemOperand(t5));
1658 __ Addu(t2, t2, Operand(kAllocationDelta * kPointerSize));
1659 __ Branch(&call_builtin, hi, t2, Operand(t5));
1660
1661 // We fit and could grow elements.
1662 // Update new_space_allocation_top.
1663 __ sw(t2, MemOperand(t3));
1664 // Push the argument.
1665 __ lw(t2, MemOperand(sp, (argc - 1) * kPointerSize));
1666 __ sw(t2, MemOperand(end_elements));
1667 // Fill the rest with holes.
1668 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1669 for (int i = 1; i < kAllocationDelta; i++) {
1670 __ sw(t2, MemOperand(end_elements, i * kPointerSize));
1671 }
1672
1673 // Update elements' and array's sizes.
1674 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1675 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta)));
1676 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1677
1678 // Elements are in new space, so write barrier is not required.
1679 __ Drop(argc + 1);
1680 __ Ret();
1681 }
1682 __ bind(&call_builtin);
1683 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
1684 masm()->isolate()),
1685 argc + 1,
1686 1);
1687 }
1688
1689 // Handle call cache miss.
1690 __ bind(&miss);
1691 MaybeObject* maybe_result = GenerateMissBranch();
1692 if (maybe_result->IsFailure()) return maybe_result;
1693
1694 // Return the generated code.
1695 return GetCode(function);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001696}
1697
1698
1699MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object,
1700 JSObject* holder,
1701 JSGlobalPropertyCell* cell,
1702 JSFunction* function,
ager@chromium.org5c838252010-02-19 08:53:10 +00001703 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001704 // ----------- S t a t e -------------
1705 // -- a2 : name
1706 // -- ra : return address
1707 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1708 // -- ...
1709 // -- sp[argc * 4] : receiver
1710 // -----------------------------------
1711
1712 // If object is not an array, bail out to regular call.
1713 if (!object->IsJSArray() || cell != NULL) return heap()->undefined_value();
1714
1715 Label miss, return_undefined, call_builtin;
1716
1717 Register receiver = a1;
1718 Register elements = a3;
1719
1720 GenerateNameCheck(name, &miss);
1721
1722 // Get the receiver from the stack.
1723 const int argc = arguments().immediate();
1724 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1725
1726 // Check that the receiver isn't a smi.
1727 __ JumpIfSmi(receiver, &miss);
1728
1729 // Check that the maps haven't changed.
1730 CheckPrototypes(JSObject::cast(object),
1731 receiver, holder, elements, t0, v0, name, &miss);
1732
1733 // Get the elements array of the object.
1734 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1735
1736 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001737 __ CheckMap(elements,
1738 v0,
1739 Heap::kFixedArrayMapRootIndex,
1740 &call_builtin,
1741 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001742
1743 // Get the array's length into t0 and calculate new length.
1744 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1745 __ Subu(t0, t0, Operand(Smi::FromInt(1)));
1746 __ Branch(&return_undefined, lt, t0, Operand(zero_reg));
1747
1748 // Get the last element.
1749 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1750 STATIC_ASSERT(kSmiTagSize == 1);
1751 STATIC_ASSERT(kSmiTag == 0);
1752 // We can't address the last element in one operation. Compute the more
1753 // expensive shift first, and use an offset later on.
1754 __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize);
1755 __ Addu(elements, elements, t1);
1756 __ lw(v0, MemOperand(elements, FixedArray::kHeaderSize - kHeapObjectTag));
1757 __ Branch(&call_builtin, eq, v0, Operand(t2));
1758
1759 // Set the array's length.
1760 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1761
1762 // Fill with the hole.
1763 __ sw(t2, MemOperand(elements, FixedArray::kHeaderSize - kHeapObjectTag));
1764 __ Drop(argc + 1);
1765 __ Ret();
1766
1767 __ bind(&return_undefined);
1768 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
1769 __ Drop(argc + 1);
1770 __ Ret();
1771
1772 __ bind(&call_builtin);
1773 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop,
1774 masm()->isolate()),
1775 argc + 1,
1776 1);
1777
1778 // Handle call cache miss.
1779 __ bind(&miss);
1780 MaybeObject* maybe_result = GenerateMissBranch();
1781 if (maybe_result->IsFailure()) return maybe_result;
1782
1783 // Return the generated code.
1784 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001785}
1786
1787
lrn@chromium.org7516f052011-03-30 08:52:27 +00001788MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
1789 Object* object,
1790 JSObject* holder,
1791 JSGlobalPropertyCell* cell,
1792 JSFunction* function,
1793 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001794 // ----------- S t a t e -------------
1795 // -- a2 : function name
1796 // -- ra : return address
1797 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1798 // -- ...
1799 // -- sp[argc * 4] : receiver
1800 // -----------------------------------
1801
1802 // If object is not a string, bail out to regular call.
1803 if (!object->IsString() || cell != NULL) return heap()->undefined_value();
1804
1805 const int argc = arguments().immediate();
1806
1807 Label miss;
1808 Label name_miss;
1809 Label index_out_of_range;
1810
1811 Label* index_out_of_range_label = &index_out_of_range;
1812
danno@chromium.org40cb8782011-05-25 07:58:50 +00001813 if (kind_ == Code::CALL_IC &&
1814 (CallICBase::StringStubState::decode(extra_ic_state_) ==
1815 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001816 index_out_of_range_label = &miss;
1817 }
1818
1819 GenerateNameCheck(name, &name_miss);
1820
1821 // Check that the maps starting from the prototype haven't changed.
1822 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1823 Context::STRING_FUNCTION_INDEX,
1824 v0,
1825 &miss);
1826 ASSERT(object != holder);
1827 CheckPrototypes(JSObject::cast(object->GetPrototype()), v0, holder,
1828 a1, a3, t0, name, &miss);
1829
1830 Register receiver = a1;
1831 Register index = t1;
1832 Register scratch = a3;
1833 Register result = v0;
1834 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1835 if (argc > 0) {
1836 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1837 } else {
1838 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1839 }
1840
1841 StringCharCodeAtGenerator char_code_at_generator(receiver,
1842 index,
1843 scratch,
1844 result,
1845 &miss, // When not a string.
1846 &miss, // When not a number.
1847 index_out_of_range_label,
1848 STRING_INDEX_IS_NUMBER);
1849 char_code_at_generator.GenerateFast(masm());
1850 __ Drop(argc + 1);
1851 __ Ret();
1852
1853 StubRuntimeCallHelper call_helper;
1854 char_code_at_generator.GenerateSlow(masm(), call_helper);
1855
1856 if (index_out_of_range.is_linked()) {
1857 __ bind(&index_out_of_range);
1858 __ LoadRoot(v0, Heap::kNanValueRootIndex);
1859 __ Drop(argc + 1);
1860 __ Ret();
1861 }
1862
1863 __ bind(&miss);
1864 // Restore function name in a2.
1865 __ li(a2, Handle<String>(name));
1866 __ bind(&name_miss);
1867 MaybeObject* maybe_result = GenerateMissBranch();
1868 if (maybe_result->IsFailure()) return maybe_result;
1869
1870 // Return the generated code.
1871 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001872}
1873
1874
lrn@chromium.org7516f052011-03-30 08:52:27 +00001875MaybeObject* CallStubCompiler::CompileStringCharAtCall(
1876 Object* object,
1877 JSObject* holder,
1878 JSGlobalPropertyCell* cell,
1879 JSFunction* function,
1880 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001881 // ----------- S t a t e -------------
1882 // -- a2 : function name
1883 // -- ra : return address
1884 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1885 // -- ...
1886 // -- sp[argc * 4] : receiver
1887 // -----------------------------------
1888
1889 // If object is not a string, bail out to regular call.
1890 if (!object->IsString() || cell != NULL) return heap()->undefined_value();
1891
1892 const int argc = arguments().immediate();
1893
1894 Label miss;
1895 Label name_miss;
1896 Label index_out_of_range;
1897 Label* index_out_of_range_label = &index_out_of_range;
1898
danno@chromium.org40cb8782011-05-25 07:58:50 +00001899 if (kind_ == Code::CALL_IC &&
1900 (CallICBase::StringStubState::decode(extra_ic_state_) ==
1901 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001902 index_out_of_range_label = &miss;
1903 }
1904
1905 GenerateNameCheck(name, &name_miss);
1906
1907 // Check that the maps starting from the prototype haven't changed.
1908 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1909 Context::STRING_FUNCTION_INDEX,
1910 v0,
1911 &miss);
1912 ASSERT(object != holder);
1913 CheckPrototypes(JSObject::cast(object->GetPrototype()), v0, holder,
1914 a1, a3, t0, name, &miss);
1915
1916 Register receiver = v0;
1917 Register index = t1;
1918 Register scratch1 = a1;
1919 Register scratch2 = a3;
1920 Register result = v0;
1921 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1922 if (argc > 0) {
1923 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1924 } else {
1925 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1926 }
1927
1928 StringCharAtGenerator char_at_generator(receiver,
1929 index,
1930 scratch1,
1931 scratch2,
1932 result,
1933 &miss, // When not a string.
1934 &miss, // When not a number.
1935 index_out_of_range_label,
1936 STRING_INDEX_IS_NUMBER);
1937 char_at_generator.GenerateFast(masm());
1938 __ Drop(argc + 1);
1939 __ Ret();
1940
1941 StubRuntimeCallHelper call_helper;
1942 char_at_generator.GenerateSlow(masm(), call_helper);
1943
1944 if (index_out_of_range.is_linked()) {
1945 __ bind(&index_out_of_range);
1946 __ LoadRoot(v0, Heap::kEmptyStringRootIndex);
1947 __ Drop(argc + 1);
1948 __ Ret();
1949 }
1950
1951 __ bind(&miss);
1952 // Restore function name in a2.
1953 __ li(a2, Handle<String>(name));
1954 __ bind(&name_miss);
1955 MaybeObject* maybe_result = GenerateMissBranch();
1956 if (maybe_result->IsFailure()) return maybe_result;
1957
1958 // Return the generated code.
1959 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001960}
1961
1962
lrn@chromium.org7516f052011-03-30 08:52:27 +00001963MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall(
1964 Object* object,
1965 JSObject* holder,
1966 JSGlobalPropertyCell* cell,
1967 JSFunction* function,
1968 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001969 // ----------- S t a t e -------------
1970 // -- a2 : function name
1971 // -- ra : return address
1972 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1973 // -- ...
1974 // -- sp[argc * 4] : receiver
1975 // -----------------------------------
1976
1977 const int argc = arguments().immediate();
1978
1979 // If the object is not a JSObject or we got an unexpected number of
1980 // arguments, bail out to the regular call.
1981 if (!object->IsJSObject() || argc != 1) return heap()->undefined_value();
1982
1983 Label miss;
1984 GenerateNameCheck(name, &miss);
1985
1986 if (cell == NULL) {
1987 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
1988
1989 STATIC_ASSERT(kSmiTag == 0);
1990 __ JumpIfSmi(a1, &miss);
1991
1992 CheckPrototypes(JSObject::cast(object), a1, holder, v0, a3, t0, name,
1993 &miss);
1994 } else {
1995 ASSERT(cell->value() == function);
1996 GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
1997 GenerateLoadFunctionFromCell(cell, function, &miss);
1998 }
1999
2000 // Load the char code argument.
2001 Register code = a1;
2002 __ lw(code, MemOperand(sp, 0 * kPointerSize));
2003
2004 // Check the code is a smi.
2005 Label slow;
2006 STATIC_ASSERT(kSmiTag == 0);
2007 __ JumpIfNotSmi(code, &slow);
2008
2009 // Convert the smi code to uint16.
2010 __ And(code, code, Operand(Smi::FromInt(0xffff)));
2011
2012 StringCharFromCodeGenerator char_from_code_generator(code, v0);
2013 char_from_code_generator.GenerateFast(masm());
2014 __ Drop(argc + 1);
2015 __ Ret();
2016
2017 StubRuntimeCallHelper call_helper;
2018 char_from_code_generator.GenerateSlow(masm(), call_helper);
2019
2020 // Tail call the full function. We do not have to patch the receiver
2021 // because the function makes no use of it.
2022 __ bind(&slow);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002023 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002024
2025 __ bind(&miss);
2026 // a2: function name.
2027 MaybeObject* maybe_result = GenerateMissBranch();
2028 if (maybe_result->IsFailure()) return maybe_result;
2029
2030 // Return the generated code.
2031 return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002032}
2033
2034
lrn@chromium.org7516f052011-03-30 08:52:27 +00002035MaybeObject* CallStubCompiler::CompileMathFloorCall(Object* object,
2036 JSObject* holder,
2037 JSGlobalPropertyCell* cell,
2038 JSFunction* function,
2039 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002040 // ----------- S t a t e -------------
2041 // -- a2 : function name
2042 // -- ra : return address
2043 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2044 // -- ...
2045 // -- sp[argc * 4] : receiver
2046 // -----------------------------------
2047
2048 if (!CpuFeatures::IsSupported(FPU))
2049 return heap()->undefined_value();
2050 CpuFeatures::Scope scope_fpu(FPU);
2051
2052 const int argc = arguments().immediate();
2053
2054 // If the object is not a JSObject or we got an unexpected number of
2055 // arguments, bail out to the regular call.
2056 if (!object->IsJSObject() || argc != 1) return heap()->undefined_value();
2057
2058 Label miss, slow;
2059 GenerateNameCheck(name, &miss);
2060
2061 if (cell == NULL) {
2062 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
2063
2064 STATIC_ASSERT(kSmiTag == 0);
2065 __ JumpIfSmi(a1, &miss);
2066
2067 CheckPrototypes(JSObject::cast(object), a1, holder, a0, a3, t0, name,
2068 &miss);
2069 } else {
2070 ASSERT(cell->value() == function);
2071 GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
2072 GenerateLoadFunctionFromCell(cell, function, &miss);
2073 }
2074
2075 // Load the (only) argument into v0.
2076 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2077
2078 // If the argument is a smi, just return.
2079 STATIC_ASSERT(kSmiTag == 0);
2080 __ And(t0, v0, Operand(kSmiTagMask));
2081 __ Drop(argc + 1, eq, t0, Operand(zero_reg));
2082 __ Ret(eq, t0, Operand(zero_reg));
2083
danno@chromium.org40cb8782011-05-25 07:58:50 +00002084 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002085
2086 Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return;
2087
2088 // If fpu is enabled, we use the floor instruction.
2089
2090 // Load the HeapNumber value.
2091 __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2092
2093 // Backup FCSR.
2094 __ cfc1(a3, FCSR);
2095 // Clearing FCSR clears the exception mask with no side-effects.
2096 __ ctc1(zero_reg, FCSR);
2097 // Convert the argument to an integer.
2098 __ floor_w_d(f0, f0);
2099
2100 // Start checking for special cases.
2101 // Get the argument exponent and clear the sign bit.
2102 __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize));
2103 __ And(t2, t1, Operand(~HeapNumber::kSignMask));
2104 __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord);
2105
2106 // Retrieve FCSR and check for fpu errors.
2107 __ cfc1(t5, FCSR);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002108 __ And(t5, t5, Operand(kFCSRExceptionFlagMask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002109 __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));
2110
2111 // Check for NaN, Infinity, and -Infinity.
2112 // They are invariant through a Math.Floor call, so just
2113 // return the original argument.
2114 __ Subu(t3, t2, Operand(HeapNumber::kExponentMask
2115 >> HeapNumber::kMantissaBitsInTopWord));
2116 __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg));
2117 // We had an overflow or underflow in the conversion. Check if we
2118 // have a big exponent.
2119 // If greater or equal, the argument is already round and in v0.
2120 __ Branch(&restore_fcsr_and_return, ge, t3,
2121 Operand(HeapNumber::kMantissaBits));
2122 __ Branch(&wont_fit_smi);
2123
2124 __ bind(&no_fpu_error);
2125 // Move the result back to v0.
2126 __ mfc1(v0, f0);
2127 // Check if the result fits into a smi.
2128 __ Addu(a1, v0, Operand(0x40000000));
2129 __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg));
2130 // Tag the result.
2131 STATIC_ASSERT(kSmiTag == 0);
2132 __ sll(v0, v0, kSmiTagSize);
2133
2134 // Check for -0.
2135 __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg));
2136 // t1 already holds the HeapNumber exponent.
2137 __ And(t0, t1, Operand(HeapNumber::kSignMask));
2138 // If our HeapNumber is negative it was -0, so load its address and return.
2139 // Else v0 is loaded with 0, so we can also just return.
2140 __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg));
2141 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2142
2143 __ bind(&restore_fcsr_and_return);
2144 // Restore FCSR and return.
2145 __ ctc1(a3, FCSR);
2146
2147 __ Drop(argc + 1);
2148 __ Ret();
2149
2150 __ bind(&wont_fit_smi);
2151 // Restore FCSR and fall to slow case.
2152 __ ctc1(a3, FCSR);
2153
2154 __ bind(&slow);
2155 // Tail call the full function. We do not have to patch the receiver
2156 // because the function makes no use of it.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002157 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002158
2159 __ bind(&miss);
2160 // a2: function name.
2161 MaybeObject* obj = GenerateMissBranch();
2162 if (obj->IsFailure()) return obj;
2163
2164 // Return the generated code.
2165 return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002166}
2167
2168
lrn@chromium.org7516f052011-03-30 08:52:27 +00002169MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object,
2170 JSObject* holder,
2171 JSGlobalPropertyCell* cell,
2172 JSFunction* function,
2173 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002174 // ----------- S t a t e -------------
2175 // -- a2 : function name
2176 // -- ra : return address
2177 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2178 // -- ...
2179 // -- sp[argc * 4] : receiver
2180 // -----------------------------------
2181
2182 const int argc = arguments().immediate();
2183
2184 // If the object is not a JSObject or we got an unexpected number of
2185 // arguments, bail out to the regular call.
2186 if (!object->IsJSObject() || argc != 1) return heap()->undefined_value();
2187
2188 Label miss;
2189 GenerateNameCheck(name, &miss);
2190
2191 if (cell == NULL) {
2192 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
2193
2194 STATIC_ASSERT(kSmiTag == 0);
2195 __ JumpIfSmi(a1, &miss);
2196
2197 CheckPrototypes(JSObject::cast(object), a1, holder, v0, a3, t0, name,
2198 &miss);
2199 } else {
2200 ASSERT(cell->value() == function);
2201 GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
2202 GenerateLoadFunctionFromCell(cell, function, &miss);
2203 }
2204
2205 // Load the (only) argument into v0.
2206 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2207
2208 // Check if the argument is a smi.
2209 Label not_smi;
2210 STATIC_ASSERT(kSmiTag == 0);
2211 __ JumpIfNotSmi(v0, &not_smi);
2212
2213 // Do bitwise not or do nothing depending on the sign of the
2214 // argument.
2215 __ sra(t0, v0, kBitsPerInt - 1);
2216 __ Xor(a1, v0, t0);
2217
2218 // Add 1 or do nothing depending on the sign of the argument.
2219 __ Subu(v0, a1, t0);
2220
2221 // If the result is still negative, go to the slow case.
2222 // This only happens for the most negative smi.
2223 Label slow;
2224 __ Branch(&slow, lt, v0, Operand(zero_reg));
2225
2226 // Smi case done.
2227 __ Drop(argc + 1);
2228 __ Ret();
2229
2230 // Check if the argument is a heap number and load its exponent and
2231 // sign.
2232 __ bind(&not_smi);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002233 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002234 __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2235
2236 // Check the sign of the argument. If the argument is positive,
2237 // just return it.
2238 Label negative_sign;
2239 __ And(t0, a1, Operand(HeapNumber::kSignMask));
2240 __ Branch(&negative_sign, ne, t0, Operand(zero_reg));
2241 __ Drop(argc + 1);
2242 __ Ret();
2243
2244 // If the argument is negative, clear the sign, and return a new
2245 // number.
2246 __ bind(&negative_sign);
2247 __ Xor(a1, a1, Operand(HeapNumber::kSignMask));
2248 __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2249 __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
2250 __ AllocateHeapNumber(v0, t0, t1, t2, &slow);
2251 __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2252 __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2253 __ Drop(argc + 1);
2254 __ Ret();
2255
2256 // Tail call the full function. We do not have to patch the receiver
2257 // because the function makes no use of it.
2258 __ bind(&slow);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002259 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002260
2261 __ bind(&miss);
2262 // a2: function name.
2263 MaybeObject* maybe_result = GenerateMissBranch();
2264 if (maybe_result->IsFailure()) return maybe_result;
2265
2266 // Return the generated code.
2267 return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002268}
2269
2270
lrn@chromium.org7516f052011-03-30 08:52:27 +00002271MaybeObject* CallStubCompiler::CompileFastApiCall(
2272 const CallOptimization& optimization,
2273 Object* object,
2274 JSObject* holder,
2275 JSGlobalPropertyCell* cell,
2276 JSFunction* function,
2277 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002278
danno@chromium.org40cb8782011-05-25 07:58:50 +00002279 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002280
2281 ASSERT(optimization.is_simple_api_call());
2282 // Bail out if object is a global object as we don't want to
2283 // repatch it to global receiver.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002284 if (object->IsGlobalObject()) return heap()->undefined_value();
2285 if (cell != NULL) return heap()->undefined_value();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002286 if (!object->IsJSObject()) return heap()->undefined_value();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002287 int depth = optimization.GetPrototypeDepthOfExpectedType(
2288 JSObject::cast(object), holder);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002289 if (depth == kInvalidProtoDepth) return heap()->undefined_value();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002290
2291 Label miss, miss_before_stack_reserved;
2292
2293 GenerateNameCheck(name, &miss_before_stack_reserved);
2294
2295 // Get the receiver from the stack.
2296 const int argc = arguments().immediate();
2297 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2298
2299 // Check that the receiver isn't a smi.
2300 __ JumpIfSmi(a1, &miss_before_stack_reserved);
2301
2302 __ IncrementCounter(counters->call_const(), 1, a0, a3);
2303 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2304
2305 ReserveSpaceForFastApiCall(masm(), a0);
2306
2307 // Check that the maps haven't changed and find a Holder as a side effect.
2308 CheckPrototypes(JSObject::cast(object), a1, holder, a0, a3, t0, name,
2309 depth, &miss);
2310
2311 MaybeObject* result = GenerateFastApiDirectCall(masm(), optimization, argc);
2312 if (result->IsFailure()) return result;
2313
2314 __ bind(&miss);
2315 FreeSpaceForFastApiCall(masm());
2316
2317 __ bind(&miss_before_stack_reserved);
2318 MaybeObject* maybe_result = GenerateMissBranch();
2319 if (maybe_result->IsFailure()) return maybe_result;
2320
2321 // Return the generated code.
2322 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002323}
2324
2325
lrn@chromium.org7516f052011-03-30 08:52:27 +00002326MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
ager@chromium.org5c838252010-02-19 08:53:10 +00002327 JSObject* holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002328 JSFunction* function,
2329 String* name,
2330 CheckType check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002331 // ----------- S t a t e -------------
2332 // -- a2 : name
2333 // -- ra : return address
2334 // -----------------------------------
2335 if (HasCustomCallGenerator(function)) {
2336 MaybeObject* maybe_result = CompileCustomCall(
2337 object, holder, NULL, function, name);
2338 Object* result;
2339 if (!maybe_result->ToObject(&result)) return maybe_result;
2340 // Undefined means bail out to regular compiler.
2341 if (!result->IsUndefined()) return result;
2342 }
2343
2344 Label miss;
2345
2346 GenerateNameCheck(name, &miss);
2347
2348 // Get the receiver from the stack.
2349 const int argc = arguments().immediate();
2350 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2351
2352 // Check that the receiver isn't a smi.
2353 if (check != NUMBER_CHECK) {
2354 __ And(t1, a1, Operand(kSmiTagMask));
2355 __ Branch(&miss, eq, t1, Operand(zero_reg));
2356 }
2357
2358 // Make sure that it's okay not to patch the on stack receiver
2359 // unless we're doing a receiver map check.
2360 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
2361
2362 SharedFunctionInfo* function_info = function->shared();
2363 switch (check) {
2364 case RECEIVER_MAP_CHECK:
2365 __ IncrementCounter(masm()->isolate()->counters()->call_const(),
2366 1, a0, a3);
2367
2368 // Check that the maps haven't changed.
2369 CheckPrototypes(JSObject::cast(object), a1, holder, a0, a3, t0, name,
2370 &miss);
2371
2372 // Patch the receiver on the stack with the global proxy if
2373 // necessary.
2374 if (object->IsGlobalObject()) {
2375 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2376 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2377 }
2378 break;
2379
2380 case STRING_CHECK:
2381 if (!function->IsBuiltin() && !function_info->strict_mode()) {
2382 // Calling non-strict non-builtins with a value as the receiver
2383 // requires boxing.
2384 __ jmp(&miss);
2385 } else {
2386 // Check that the object is a two-byte string or a symbol.
2387 __ GetObjectType(a1, a3, a3);
2388 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2389 // Check that the maps starting from the prototype haven't changed.
2390 GenerateDirectLoadGlobalFunctionPrototype(
2391 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
2392 CheckPrototypes(JSObject::cast(object->GetPrototype()), a0, holder, a3,
2393 a1, t0, name, &miss);
2394 }
2395 break;
2396
2397 case NUMBER_CHECK: {
2398 if (!function->IsBuiltin() && !function_info->strict_mode()) {
2399 // Calling non-strict non-builtins with a value as the receiver
2400 // requires boxing.
2401 __ jmp(&miss);
2402 } else {
2403 Label fast;
2404 // Check that the object is a smi or a heap number.
2405 __ And(t1, a1, Operand(kSmiTagMask));
2406 __ Branch(&fast, eq, t1, Operand(zero_reg));
2407 __ GetObjectType(a1, a0, a0);
2408 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
2409 __ bind(&fast);
2410 // Check that the maps starting from the prototype haven't changed.
2411 GenerateDirectLoadGlobalFunctionPrototype(
2412 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
2413 CheckPrototypes(JSObject::cast(object->GetPrototype()), a0, holder, a3,
2414 a1, t0, name, &miss);
2415 }
2416 break;
2417 }
2418
2419 case BOOLEAN_CHECK: {
2420 if (!function->IsBuiltin() && !function_info->strict_mode()) {
2421 // Calling non-strict non-builtins with a value as the receiver
2422 // requires boxing.
2423 __ jmp(&miss);
2424 } else {
2425 Label fast;
2426 // Check that the object is a boolean.
2427 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
2428 __ Branch(&fast, eq, a1, Operand(t0));
2429 __ LoadRoot(t0, Heap::kFalseValueRootIndex);
2430 __ Branch(&miss, ne, a1, Operand(t0));
2431 __ bind(&fast);
2432 // Check that the maps starting from the prototype haven't changed.
2433 GenerateDirectLoadGlobalFunctionPrototype(
2434 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
2435 CheckPrototypes(JSObject::cast(object->GetPrototype()), a0, holder, a3,
2436 a1, t0, name, &miss);
2437 }
2438 break;
2439 }
2440
2441 default:
2442 UNREACHABLE();
2443 }
2444
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002445 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
2446 ? CALL_AS_FUNCTION
2447 : CALL_AS_METHOD;
2448 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002449
2450 // Handle call cache miss.
2451 __ bind(&miss);
2452
2453 MaybeObject* maybe_result = GenerateMissBranch();
2454 if (maybe_result->IsFailure()) return maybe_result;
2455
2456 // Return the generated code.
2457 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002458}
2459
2460
lrn@chromium.org7516f052011-03-30 08:52:27 +00002461MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
ager@chromium.org5c838252010-02-19 08:53:10 +00002462 JSObject* holder,
2463 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002464 // ----------- S t a t e -------------
2465 // -- a2 : name
2466 // -- ra : return address
2467 // -----------------------------------
2468
2469 Label miss;
2470
2471 GenerateNameCheck(name, &miss);
2472
2473 // Get the number of arguments.
2474 const int argc = arguments().immediate();
2475
2476 LookupResult lookup;
2477 LookupPostInterceptor(holder, name, &lookup);
2478
2479 // Get the receiver from the stack.
2480 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2481
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002482 CallInterceptorCompiler compiler(this, arguments(), a2, extra_ic_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002483 MaybeObject* result = compiler.Compile(masm(),
2484 object,
2485 holder,
2486 name,
2487 &lookup,
2488 a1,
2489 a3,
2490 t0,
2491 a0,
2492 &miss);
2493 if (result->IsFailure()) {
2494 return result;
2495 }
2496
2497 // Move returned value, the function to call, to a1.
2498 __ mov(a1, v0);
2499 // Restore receiver.
2500 __ lw(a0, MemOperand(sp, argc * kPointerSize));
2501
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002502 GenerateCallFunction(masm(), object, arguments(), &miss, extra_ic_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002503
2504 // Handle call cache miss.
2505 __ bind(&miss);
2506 MaybeObject* maybe_result = GenerateMissBranch();
2507 if (maybe_result->IsFailure()) return maybe_result;
2508
2509 // Return the generated code.
2510 return GetCode(INTERCEPTOR, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002511}
2512
2513
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002514MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
2515 GlobalObject* holder,
2516 JSGlobalPropertyCell* cell,
2517 JSFunction* function,
2518 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002519 // ----------- S t a t e -------------
2520 // -- a2 : name
2521 // -- ra : return address
2522 // -----------------------------------
2523
2524 if (HasCustomCallGenerator(function)) {
2525 MaybeObject* maybe_result = CompileCustomCall(
2526 object, holder, cell, function, name);
2527 Object* result;
2528 if (!maybe_result->ToObject(&result)) return maybe_result;
2529 // Undefined means bail out to regular compiler.
2530 if (!result->IsUndefined()) return result;
2531 }
2532
2533 Label miss;
2534
2535 GenerateNameCheck(name, &miss);
2536
2537 // Get the number of arguments.
2538 const int argc = arguments().immediate();
2539
2540 GenerateGlobalReceiverCheck(object, holder, name, &miss);
2541 GenerateLoadFunctionFromCell(cell, function, &miss);
2542
2543 // Patch the receiver on the stack with the global proxy if
2544 // necessary.
2545 if (object->IsGlobalObject()) {
2546 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
2547 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2548 }
2549
2550 // Setup the context (function already in r1).
2551 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
2552
2553 // Jump to the cached code (tail call).
2554 Counters* counters = masm()->isolate()->counters();
2555 __ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
2556 ASSERT(function->is_compiled());
2557 Handle<Code> code(function->code());
2558 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002559 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002560 ? CALL_AS_FUNCTION
2561 : CALL_AS_METHOD;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002562 if (V8::UseCrankshaft()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002563 // TODO(kasperl): For now, we always call indirectly through the
2564 // code field in the function to allow recompilation to take effect
2565 // without changing any of the call sites.
2566 __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
2567 __ InvokeCode(a3, expected, arguments(), JUMP_FUNCTION,
2568 NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002569 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00002570 __ InvokeCode(code, expected, arguments(), RelocInfo::CODE_TARGET,
2571 JUMP_FUNCTION, call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002572 }
2573
2574 // Handle call cache miss.
2575 __ bind(&miss);
2576 __ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
2577 MaybeObject* maybe_result = GenerateMissBranch();
2578 if (maybe_result->IsFailure()) return maybe_result;
2579
2580 // Return the generated code.
2581 return GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002582}
2583
2584
lrn@chromium.org7516f052011-03-30 08:52:27 +00002585MaybeObject* StoreStubCompiler::CompileStoreField(JSObject* object,
ager@chromium.org5c838252010-02-19 08:53:10 +00002586 int index,
2587 Map* transition,
2588 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002589 // ----------- S t a t e -------------
2590 // -- a0 : value
2591 // -- a1 : receiver
2592 // -- a2 : name
2593 // -- ra : return address
2594 // -----------------------------------
2595 Label miss;
2596
2597 // Name register might be clobbered.
2598 GenerateStoreField(masm(),
2599 object,
2600 index,
2601 transition,
2602 a1, a2, a3,
2603 &miss);
2604 __ bind(&miss);
2605 __ li(a2, Operand(Handle<String>(name))); // Restore name.
2606 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2607 __ Jump(ic, RelocInfo::CODE_TARGET);
2608
2609 // Return the generated code.
2610 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002611}
2612
2613
lrn@chromium.org7516f052011-03-30 08:52:27 +00002614MaybeObject* StoreStubCompiler::CompileStoreCallback(JSObject* object,
2615 AccessorInfo* callback,
2616 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002617 // ----------- S t a t e -------------
2618 // -- a0 : value
2619 // -- a1 : receiver
2620 // -- a2 : name
2621 // -- ra : return address
2622 // -----------------------------------
2623 Label miss;
2624
2625 // Check that the object isn't a smi.
2626 __ JumpIfSmi(a1, &miss);
2627
2628 // Check that the map of the object hasn't changed.
2629 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2630 __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map())));
2631
2632 // Perform global security token check if needed.
2633 if (object->IsJSGlobalProxy()) {
2634 __ CheckAccessGlobalProxy(a1, a3, &miss);
2635 }
2636
2637 // Stub never generated for non-global objects that require access
2638 // checks.
2639 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
2640
2641 __ push(a1); // Receiver.
2642 __ li(a3, Operand(Handle<AccessorInfo>(callback))); // Callback info.
2643 __ Push(a3, a2, a0);
2644
2645 // Do tail-call to the runtime system.
2646 ExternalReference store_callback_property =
2647 ExternalReference(IC_Utility(IC::kStoreCallbackProperty),
2648 masm()->isolate());
2649 __ TailCallExternalReference(store_callback_property, 4, 1);
2650
2651 // Handle store cache miss.
2652 __ bind(&miss);
2653 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2654 __ Jump(ic, RelocInfo::CODE_TARGET);
2655
2656 // Return the generated code.
2657 return GetCode(CALLBACKS, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002658}
2659
2660
lrn@chromium.org7516f052011-03-30 08:52:27 +00002661MaybeObject* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
2662 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002663 // ----------- S t a t e -------------
2664 // -- a0 : value
2665 // -- a1 : receiver
2666 // -- a2 : name
2667 // -- ra : return address
2668 // -----------------------------------
2669 Label miss;
2670
2671 // Check that the object isn't a smi.
2672 __ JumpIfSmi(a1, &miss);
2673
2674 // Check that the map of the object hasn't changed.
2675 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2676 __ Branch(&miss, ne, a3, Operand(Handle<Map>(receiver->map())));
2677
2678 // Perform global security token check if needed.
2679 if (receiver->IsJSGlobalProxy()) {
2680 __ CheckAccessGlobalProxy(a1, a3, &miss);
2681 }
2682
2683 // Stub is never generated for non-global objects that require access
2684 // checks.
2685 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2686
2687 __ Push(a1, a2, a0); // Receiver, name, value.
2688
2689 __ li(a0, Operand(Smi::FromInt(strict_mode_)));
2690 __ push(a0); // Strict mode.
2691
2692 // Do tail-call to the runtime system.
2693 ExternalReference store_ic_property =
2694 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty),
2695 masm()->isolate());
2696 __ TailCallExternalReference(store_ic_property, 4, 1);
2697
2698 // Handle store cache miss.
2699 __ bind(&miss);
2700 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2701 __ Jump(ic, RelocInfo::CODE_TARGET);
2702
2703 // Return the generated code.
2704 return GetCode(INTERCEPTOR, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002705}
2706
2707
lrn@chromium.org7516f052011-03-30 08:52:27 +00002708MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
2709 JSGlobalPropertyCell* cell,
2710 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002711 // ----------- S t a t e -------------
2712 // -- a0 : value
2713 // -- a1 : receiver
2714 // -- a2 : name
2715 // -- ra : return address
2716 // -----------------------------------
2717 Label miss;
2718
2719 // Check that the map of the global has not changed.
2720 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2721 __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map())));
2722
2723 // Check that the value in the cell is not the hole. If it is, this
2724 // cell could have been deleted and reintroducing the global needs
2725 // to update the property details in the property dictionary of the
2726 // global object. We bail out to the runtime system to do that.
2727 __ li(t0, Operand(Handle<JSGlobalPropertyCell>(cell)));
2728 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
2729 __ lw(t2, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2730 __ Branch(&miss, eq, t1, Operand(t2));
2731
2732 // Store the value in the cell.
2733 __ sw(a0, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2734 __ mov(v0, a0); // Stored value must be returned in v0.
2735 Counters* counters = masm()->isolate()->counters();
2736 __ IncrementCounter(counters->named_store_global_inline(), 1, a1, a3);
2737 __ Ret();
2738
2739 // Handle store cache miss.
2740 __ bind(&miss);
2741 __ IncrementCounter(counters->named_store_global_inline_miss(), 1, a1, a3);
2742 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2743 __ Jump(ic, RelocInfo::CODE_TARGET);
2744
2745 // Return the generated code.
2746 return GetCode(NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002747}
2748
2749
2750MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name,
2751 JSObject* object,
2752 JSObject* last) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002753 // ----------- S t a t e -------------
2754 // -- a0 : receiver
2755 // -- ra : return address
2756 // -----------------------------------
2757 Label miss;
2758
2759 // Check that the receiver is not a smi.
2760 __ JumpIfSmi(a0, &miss);
2761
2762 // Check the maps of the full prototype chain.
2763 CheckPrototypes(object, a0, last, a3, a1, t0, name, &miss);
2764
2765 // If the last object in the prototype chain is a global object,
2766 // check that the global property cell is empty.
2767 if (last->IsGlobalObject()) {
2768 MaybeObject* cell = GenerateCheckPropertyCell(masm(),
2769 GlobalObject::cast(last),
2770 name,
2771 a1,
2772 &miss);
2773 if (cell->IsFailure()) {
2774 miss.Unuse();
2775 return cell;
2776 }
2777 }
2778
2779 // Return undefined if maps of the full prototype chain is still the same.
2780 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2781 __ Ret();
2782
2783 __ bind(&miss);
2784 GenerateLoadMiss(masm(), Code::LOAD_IC);
2785
2786 // Return the generated code.
2787 return GetCode(NONEXISTENT, heap()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00002788}
2789
2790
2791MaybeObject* LoadStubCompiler::CompileLoadField(JSObject* object,
2792 JSObject* holder,
2793 int index,
2794 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002795 // ----------- S t a t e -------------
2796 // -- a0 : receiver
2797 // -- a2 : name
2798 // -- ra : return address
2799 // -----------------------------------
2800 Label miss;
2801
2802 __ mov(v0, a0);
2803
2804 GenerateLoadField(object, holder, v0, a3, a1, t0, index, name, &miss);
2805 __ bind(&miss);
2806 GenerateLoadMiss(masm(), Code::LOAD_IC);
2807
2808 // Return the generated code.
2809 return GetCode(FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002810}
2811
2812
2813MaybeObject* LoadStubCompiler::CompileLoadCallback(String* name,
2814 JSObject* object,
2815 JSObject* holder,
2816 AccessorInfo* callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002817 // ----------- S t a t e -------------
2818 // -- a0 : receiver
2819 // -- a2 : name
2820 // -- ra : return address
2821 // -----------------------------------
2822 Label miss;
2823
2824 MaybeObject* result = GenerateLoadCallback(object, holder, a0, a2, a3, a1, t0,
2825 callback, name, &miss);
2826 if (result->IsFailure()) {
2827 miss.Unuse();
2828 return result;
2829 }
2830
2831 __ bind(&miss);
2832 GenerateLoadMiss(masm(), Code::LOAD_IC);
2833
2834 // Return the generated code.
2835 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002836}
2837
2838
2839MaybeObject* LoadStubCompiler::CompileLoadConstant(JSObject* object,
2840 JSObject* holder,
2841 Object* value,
2842 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002843 // ----------- S t a t e -------------
2844 // -- a0 : receiver
2845 // -- a2 : name
2846 // -- ra : return address
2847 // -----------------------------------
2848 Label miss;
2849
2850 GenerateLoadConstant(object, holder, a0, a3, a1, t0, value, name, &miss);
2851 __ bind(&miss);
2852 GenerateLoadMiss(masm(), Code::LOAD_IC);
2853
2854 // Return the generated code.
2855 return GetCode(CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002856}
2857
2858
2859MaybeObject* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
2860 JSObject* holder,
2861 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002862 // ----------- S t a t e -------------
2863 // -- a0 : receiver
2864 // -- a2 : name
2865 // -- ra : return address
2866 // -- [sp] : receiver
2867 // -----------------------------------
2868 Label miss;
2869
2870 LookupResult lookup;
2871 LookupPostInterceptor(holder, name, &lookup);
2872 GenerateLoadInterceptor(object,
2873 holder,
2874 &lookup,
2875 a0,
2876 a2,
2877 a3,
2878 a1,
2879 t0,
2880 name,
2881 &miss);
2882 __ bind(&miss);
2883 GenerateLoadMiss(masm(), Code::LOAD_IC);
2884
2885 // Return the generated code.
2886 return GetCode(INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002887}
2888
2889
2890MaybeObject* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
2891 GlobalObject* holder,
2892 JSGlobalPropertyCell* cell,
2893 String* name,
2894 bool is_dont_delete) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002895 // ----------- S t a t e -------------
2896 // -- a0 : receiver
2897 // -- a2 : name
2898 // -- ra : return address
2899 // -----------------------------------
2900 Label miss;
2901
2902 // If the object is the holder then we know that it's a global
2903 // object which can only happen for contextual calls. In this case,
2904 // the receiver cannot be a smi.
2905 if (object != holder) {
2906 __ And(t0, a0, Operand(kSmiTagMask));
2907 __ Branch(&miss, eq, t0, Operand(zero_reg));
2908 }
2909
2910 // Check that the map of the global has not changed.
2911 CheckPrototypes(object, a0, holder, a3, t0, a1, name, &miss);
2912
2913 // Get the value from the cell.
2914 __ li(a3, Operand(Handle<JSGlobalPropertyCell>(cell)));
2915 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
2916
2917 // Check for deleted property if property can actually be deleted.
2918 if (!is_dont_delete) {
2919 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
2920 __ Branch(&miss, eq, t0, Operand(at));
2921 }
2922
2923 __ mov(v0, t0);
2924 Counters* counters = masm()->isolate()->counters();
2925 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
2926 __ Ret();
2927
2928 __ bind(&miss);
2929 __ IncrementCounter(counters->named_load_global_stub_miss(), 1, a1, a3);
2930 GenerateLoadMiss(masm(), Code::LOAD_IC);
2931
2932 // Return the generated code.
2933 return GetCode(NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002934}
2935
2936
2937MaybeObject* KeyedLoadStubCompiler::CompileLoadField(String* name,
2938 JSObject* receiver,
2939 JSObject* holder,
2940 int index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002941 // ----------- S t a t e -------------
2942 // -- ra : return address
2943 // -- a0 : key
2944 // -- a1 : receiver
2945 // -----------------------------------
2946 Label miss;
2947
2948 // Check the key is the cached one.
2949 __ Branch(&miss, ne, a0, Operand(Handle<String>(name)));
2950
2951 GenerateLoadField(receiver, holder, a1, a2, a3, t0, index, name, &miss);
2952 __ bind(&miss);
2953 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2954
2955 return GetCode(FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002956}
2957
2958
2959MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback(
2960 String* name,
2961 JSObject* receiver,
2962 JSObject* holder,
2963 AccessorInfo* callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002964 // ----------- S t a t e -------------
2965 // -- ra : return address
2966 // -- a0 : key
2967 // -- a1 : receiver
2968 // -----------------------------------
2969 Label miss;
2970
2971 // Check the key is the cached one.
2972 __ Branch(&miss, ne, a0, Operand(Handle<String>(name)));
2973
2974 MaybeObject* result = GenerateLoadCallback(receiver, holder, a1, a0, a2, a3,
2975 t0, callback, name, &miss);
2976 if (result->IsFailure()) {
2977 miss.Unuse();
2978 return result;
2979 }
2980
2981 __ bind(&miss);
2982 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2983
2984 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002985}
2986
2987
2988MaybeObject* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
2989 JSObject* receiver,
2990 JSObject* holder,
2991 Object* value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002992 // ----------- S t a t e -------------
2993 // -- ra : return address
2994 // -- a0 : key
2995 // -- a1 : receiver
2996 // -----------------------------------
2997 Label miss;
2998
2999 // Check the key is the cached one.
3000 __ Branch(&miss, ne, a0, Operand(Handle<String>(name)));
3001
3002 GenerateLoadConstant(receiver, holder, a1, a2, a3, t0, value, name, &miss);
3003 __ bind(&miss);
3004 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3005
3006 // Return the generated code.
3007 return GetCode(CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003008}
3009
3010
3011MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
3012 JSObject* holder,
3013 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003014 // ----------- S t a t e -------------
3015 // -- ra : return address
3016 // -- a0 : key
3017 // -- a1 : receiver
3018 // -----------------------------------
3019 Label miss;
3020
3021 // Check the key is the cached one.
3022 __ Branch(&miss, ne, a0, Operand(Handle<String>(name)));
3023
3024 LookupResult lookup;
3025 LookupPostInterceptor(holder, name, &lookup);
3026 GenerateLoadInterceptor(receiver,
3027 holder,
3028 &lookup,
3029 a1,
3030 a0,
3031 a2,
3032 a3,
3033 t0,
3034 name,
3035 &miss);
3036 __ bind(&miss);
3037 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3038
3039 return GetCode(INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003040}
3041
3042
3043MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003044 // ----------- S t a t e -------------
3045 // -- ra : return address
3046 // -- a0 : key
3047 // -- a1 : receiver
3048 // -----------------------------------
3049 Label miss;
3050
3051 // Check the key is the cached one.
3052 __ Branch(&miss, ne, a0, Operand(Handle<String>(name)));
3053
3054 GenerateLoadArrayLength(masm(), a1, a2, &miss);
3055 __ bind(&miss);
3056 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3057
3058 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003059}
3060
3061
3062MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003063 // ----------- S t a t e -------------
3064 // -- ra : return address
3065 // -- a0 : key
3066 // -- a1 : receiver
3067 // -----------------------------------
3068 Label miss;
3069
3070 Counters* counters = masm()->isolate()->counters();
3071 __ IncrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
3072
3073 // Check the key is the cached one.
3074 __ Branch(&miss, ne, a0, Operand(Handle<String>(name)));
3075
3076 GenerateLoadStringLength(masm(), a1, a2, a3, &miss, true);
3077 __ bind(&miss);
3078 __ DecrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
3079
3080 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3081
3082 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003083}
3084
3085
3086MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003087 // ----------- S t a t e -------------
3088 // -- ra : return address
3089 // -- a0 : key
3090 // -- a1 : receiver
3091 // -----------------------------------
3092 Label miss;
3093
3094 Counters* counters = masm()->isolate()->counters();
3095 __ IncrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
3096
3097 // Check the name hasn't changed.
3098 __ Branch(&miss, ne, a0, Operand(Handle<String>(name)));
3099
3100 GenerateLoadFunctionPrototype(masm(), a1, a2, a3, &miss);
3101 __ bind(&miss);
3102 __ DecrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
3103 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3104
3105 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003106}
3107
3108
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003109MaybeObject* KeyedLoadStubCompiler::CompileLoadElement(Map* receiver_map) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003110 // ----------- S t a t e -------------
3111 // -- ra : return address
3112 // -- a0 : key
3113 // -- a1 : receiver
3114 // -----------------------------------
danno@chromium.org40cb8782011-05-25 07:58:50 +00003115 Code* stub;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003116 ElementsKind elements_kind = receiver_map->elements_kind();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003117 MaybeObject* maybe_stub = KeyedLoadElementStub(elements_kind).TryGetCode();
danno@chromium.org40cb8782011-05-25 07:58:50 +00003118 if (!maybe_stub->To(&stub)) return maybe_stub;
3119 __ DispatchMap(a1,
3120 a2,
3121 Handle<Map>(receiver_map),
3122 Handle<Code>(stub),
3123 DO_SMI_CHECK);
3124
3125 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
3126 __ Jump(ic, RelocInfo::CODE_TARGET);
3127
3128 // Return the generated code.
3129 return GetCode(NORMAL, NULL);
3130}
3131
3132
3133MaybeObject* KeyedLoadStubCompiler::CompileLoadMegamorphic(
3134 MapList* receiver_maps,
3135 CodeList* handler_ics) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003136 // ----------- S t a t e -------------
3137 // -- ra : return address
3138 // -- a0 : key
3139 // -- a1 : receiver
3140 // -----------------------------------
3141 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003142 __ JumpIfSmi(a1, &miss);
3143
danno@chromium.org40cb8782011-05-25 07:58:50 +00003144 int receiver_count = receiver_maps->length();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003145 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003146 for (int current = 0; current < receiver_count; ++current) {
3147 Handle<Map> map(receiver_maps->at(current));
3148 Handle<Code> code(handler_ics->at(current));
3149 __ Jump(code, RelocInfo::CODE_TARGET, eq, a2, Operand(map));
3150 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003151
3152 __ bind(&miss);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003153 Handle<Code> miss_ic = isolate()->builtins()->KeyedLoadIC_Miss();
3154 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003155
3156 // Return the generated code.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003157 return GetCode(NORMAL, NULL, MEGAMORPHIC);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003158}
3159
3160
3161MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
3162 int index,
3163 Map* transition,
3164 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003165 // ----------- S t a t e -------------
3166 // -- a0 : value
3167 // -- a1 : key
3168 // -- a2 : receiver
3169 // -- ra : return address
3170 // -----------------------------------
3171
3172 Label miss;
3173
3174 Counters* counters = masm()->isolate()->counters();
3175 __ IncrementCounter(counters->keyed_store_field(), 1, a3, t0);
3176
3177 // Check that the name has not changed.
3178 __ Branch(&miss, ne, a1, Operand(Handle<String>(name)));
3179
3180 // a3 is used as scratch register. a1 and a2 keep their values if a jump to
3181 // the miss label is generated.
3182 GenerateStoreField(masm(),
3183 object,
3184 index,
3185 transition,
3186 a2, a1, a3,
3187 &miss);
3188 __ bind(&miss);
3189
3190 __ DecrementCounter(counters->keyed_store_field(), 1, a3, t0);
3191 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss();
3192 __ Jump(ic, RelocInfo::CODE_TARGET);
3193
3194 // Return the generated code.
3195 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003196}
3197
3198
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003199MaybeObject* KeyedStoreStubCompiler::CompileStoreElement(Map* receiver_map) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003200 // ----------- S t a t e -------------
3201 // -- a0 : value
3202 // -- a1 : key
3203 // -- a2 : receiver
3204 // -- ra : return address
3205 // -- a3 : scratch
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003206 // -----------------------------------
danno@chromium.org40cb8782011-05-25 07:58:50 +00003207 Code* stub;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003208 ElementsKind elements_kind = receiver_map->elements_kind();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003209 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
3210 MaybeObject* maybe_stub =
3211 KeyedStoreElementStub(is_js_array, elements_kind).TryGetCode();
danno@chromium.org40cb8782011-05-25 07:58:50 +00003212 if (!maybe_stub->To(&stub)) return maybe_stub;
3213 __ DispatchMap(a2,
3214 a3,
3215 Handle<Map>(receiver_map),
3216 Handle<Code>(stub),
3217 DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003218
danno@chromium.org40cb8782011-05-25 07:58:50 +00003219 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003220 __ Jump(ic, RelocInfo::CODE_TARGET);
3221
3222 // Return the generated code.
3223 return GetCode(NORMAL, NULL);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003224}
3225
3226
danno@chromium.org40cb8782011-05-25 07:58:50 +00003227MaybeObject* KeyedStoreStubCompiler::CompileStoreMegamorphic(
3228 MapList* receiver_maps,
3229 CodeList* handler_ics) {
3230 // ----------- S t a t e -------------
3231 // -- a0 : value
3232 // -- a1 : key
3233 // -- a2 : receiver
3234 // -- ra : return address
3235 // -- a3 : scratch
3236 // -----------------------------------
3237 Label miss;
3238 __ JumpIfSmi(a2, &miss);
3239
3240 int receiver_count = receiver_maps->length();
3241 __ lw(a3, FieldMemOperand(a2, HeapObject::kMapOffset));
3242 for (int current = 0; current < receiver_count; ++current) {
3243 Handle<Map> map(receiver_maps->at(current));
3244 Handle<Code> code(handler_ics->at(current));
3245 __ Jump(code, RelocInfo::CODE_TARGET, eq, a3, Operand(map));
3246 }
3247
3248 __ bind(&miss);
3249 Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
3250 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3251
3252 // Return the generated code.
3253 return GetCode(NORMAL, NULL, MEGAMORPHIC);
3254}
3255
3256
lrn@chromium.org7516f052011-03-30 08:52:27 +00003257MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003258 // a0 : argc
3259 // a1 : constructor
3260 // ra : return address
3261 // [sp] : last argument
3262 Label generic_stub_call;
3263
3264 // Use t7 for holding undefined which is used in several places below.
3265 __ LoadRoot(t7, Heap::kUndefinedValueRootIndex);
3266
3267#ifdef ENABLE_DEBUGGER_SUPPORT
3268 // Check to see whether there are any break points in the function code. If
3269 // there are jump to the generic constructor stub which calls the actual
3270 // code for the function thereby hitting the break points.
3271 __ lw(t5, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3272 __ lw(a2, FieldMemOperand(t5, SharedFunctionInfo::kDebugInfoOffset));
3273 __ Branch(&generic_stub_call, ne, a2, Operand(t7));
3274#endif
3275
3276 // Load the initial map and verify that it is in fact a map.
3277 // a1: constructor function
3278 // t7: undefined
3279 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
3280 __ And(t0, a2, Operand(kSmiTagMask));
3281 __ Branch(&generic_stub_call, eq, t0, Operand(zero_reg));
3282 __ GetObjectType(a2, a3, t0);
3283 __ Branch(&generic_stub_call, ne, t0, Operand(MAP_TYPE));
3284
3285#ifdef DEBUG
3286 // Cannot construct functions this way.
3287 // a0: argc
3288 // a1: constructor function
3289 // a2: initial map
3290 // t7: undefined
3291 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
3292 __ Check(ne, "Function constructed by construct stub.",
3293 a3, Operand(JS_FUNCTION_TYPE));
3294#endif
3295
3296 // Now allocate the JSObject in new space.
3297 // a0: argc
3298 // a1: constructor function
3299 // a2: initial map
3300 // t7: undefined
3301 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
3302 __ AllocateInNewSpace(a3,
3303 t4,
3304 t5,
3305 t6,
3306 &generic_stub_call,
3307 SIZE_IN_WORDS);
3308
3309 // Allocated the JSObject, now initialize the fields. Map is set to initial
3310 // map and properties and elements are set to empty fixed array.
3311 // a0: argc
3312 // a1: constructor function
3313 // a2: initial map
3314 // a3: object size (in words)
3315 // t4: JSObject (not tagged)
3316 // t7: undefined
3317 __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex);
3318 __ mov(t5, t4);
3319 __ sw(a2, MemOperand(t5, JSObject::kMapOffset));
3320 __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset));
3321 __ sw(t6, MemOperand(t5, JSObject::kElementsOffset));
3322 __ Addu(t5, t5, Operand(3 * kPointerSize));
3323 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
3324 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
3325 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
3326
3327
3328 // Calculate the location of the first argument. The stack contains only the
3329 // argc arguments.
3330 __ sll(a1, a0, kPointerSizeLog2);
3331 __ Addu(a1, a1, sp);
3332
3333 // Fill all the in-object properties with undefined.
3334 // a0: argc
3335 // a1: first argument
3336 // a3: object size (in words)
3337 // t4: JSObject (not tagged)
3338 // t5: First in-object property of JSObject (not tagged)
3339 // t7: undefined
3340 // Fill the initialized properties with a constant value or a passed argument
3341 // depending on the this.x = ...; assignment in the function.
3342 SharedFunctionInfo* shared = function->shared();
3343 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3344 if (shared->IsThisPropertyAssignmentArgument(i)) {
3345 Label not_passed, next;
3346 // Check if the argument assigned to the property is actually passed.
3347 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3348 __ Branch(&not_passed, less_equal, a0, Operand(arg_number));
3349 // Argument passed - find it on the stack.
3350 __ lw(a2, MemOperand(a1, (arg_number + 1) * -kPointerSize));
3351 __ sw(a2, MemOperand(t5));
3352 __ Addu(t5, t5, kPointerSize);
3353 __ jmp(&next);
3354 __ bind(&not_passed);
3355 // Set the property to undefined.
3356 __ sw(t7, MemOperand(t5));
3357 __ Addu(t5, t5, Operand(kPointerSize));
3358 __ bind(&next);
3359 } else {
3360 // Set the property to the constant value.
3361 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
3362 __ li(a2, Operand(constant));
3363 __ sw(a2, MemOperand(t5));
3364 __ Addu(t5, t5, kPointerSize);
3365 }
3366 }
3367
3368 // Fill the unused in-object property fields with undefined.
3369 ASSERT(function->has_initial_map());
3370 for (int i = shared->this_property_assignments_count();
3371 i < function->initial_map()->inobject_properties();
3372 i++) {
3373 __ sw(t7, MemOperand(t5));
3374 __ Addu(t5, t5, kPointerSize);
3375 }
3376
3377 // a0: argc
3378 // t4: JSObject (not tagged)
3379 // Move argc to a1 and the JSObject to return to v0 and tag it.
3380 __ mov(a1, a0);
3381 __ mov(v0, t4);
3382 __ Or(v0, v0, Operand(kHeapObjectTag));
3383
3384 // v0: JSObject
3385 // a1: argc
3386 // Remove caller arguments and receiver from the stack and return.
3387 __ sll(t0, a1, kPointerSizeLog2);
3388 __ Addu(sp, sp, t0);
3389 __ Addu(sp, sp, Operand(kPointerSize));
3390 Counters* counters = masm()->isolate()->counters();
3391 __ IncrementCounter(counters->constructed_objects(), 1, a1, a2);
3392 __ IncrementCounter(counters->constructed_objects_stub(), 1, a1, a2);
3393 __ Ret();
3394
3395 // Jump to the generic stub in case the specialized code cannot handle the
3396 // construction.
3397 __ bind(&generic_stub_call);
3398 Handle<Code> generic_construct_stub =
3399 masm()->isolate()->builtins()->JSConstructStubGeneric();
3400 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
3401
3402 // Return the generated code.
3403 return GetCode();
3404}
3405
3406
danno@chromium.org40cb8782011-05-25 07:58:50 +00003407#undef __
3408#define __ ACCESS_MASM(masm)
3409
3410
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003411void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3412 MacroAssembler* masm) {
3413 // ---------- S t a t e --------------
3414 // -- ra : return address
3415 // -- a0 : key
3416 // -- a1 : receiver
3417 // -----------------------------------
3418 Label slow, miss_force_generic;
3419
3420 Register key = a0;
3421 Register receiver = a1;
3422
3423 __ JumpIfNotSmi(key, &miss_force_generic);
3424 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
3425 __ sra(a2, a0, kSmiTagSize);
3426 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
3427 __ Ret();
3428
3429 // Slow case, key and receiver still in a0 and a1.
3430 __ bind(&slow);
3431 __ IncrementCounter(
3432 masm->isolate()->counters()->keyed_load_external_array_slow(),
3433 1, a2, a3);
3434 // Entry registers are intact.
3435 // ---------- S t a t e --------------
3436 // -- ra : return address
3437 // -- a0 : key
3438 // -- a1 : receiver
3439 // -----------------------------------
3440 Handle<Code> slow_ic =
3441 masm->isolate()->builtins()->KeyedLoadIC_Slow();
3442 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
3443
3444 // Miss case, call the runtime.
3445 __ bind(&miss_force_generic);
3446
3447 // ---------- S t a t e --------------
3448 // -- ra : return address
3449 // -- a0 : key
3450 // -- a1 : receiver
3451 // -----------------------------------
3452
3453 Handle<Code> miss_ic =
3454 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3455 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3456}
3457
3458
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003459static bool IsElementTypeSigned(ElementsKind elements_kind) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003460 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003461 case EXTERNAL_BYTE_ELEMENTS:
3462 case EXTERNAL_SHORT_ELEMENTS:
3463 case EXTERNAL_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003464 return true;
3465
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003466 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3467 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3468 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3469 case EXTERNAL_PIXEL_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003470 return false;
3471
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003472 case EXTERNAL_FLOAT_ELEMENTS:
3473 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003474 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003475 case FAST_ELEMENTS:
3476 case FAST_DOUBLE_ELEMENTS:
3477 case DICTIONARY_ELEMENTS:
3478 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003479 UNREACHABLE();
3480 return false;
3481 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003482 return false;
lrn@chromium.org7516f052011-03-30 08:52:27 +00003483}
3484
3485
danno@chromium.org40cb8782011-05-25 07:58:50 +00003486void KeyedLoadStubCompiler::GenerateLoadExternalArray(
3487 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003488 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003489 // ---------- S t a t e --------------
3490 // -- ra : return address
3491 // -- a0 : key
3492 // -- a1 : receiver
3493 // -----------------------------------
danno@chromium.org40cb8782011-05-25 07:58:50 +00003494 Label miss_force_generic, slow, failed_allocation;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003495
3496 Register key = a0;
3497 Register receiver = a1;
3498
danno@chromium.org40cb8782011-05-25 07:58:50 +00003499 // This stub is meant to be tail-jumped to, the receiver must already
3500 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003501
3502 // Check that the key is a smi.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003503 __ JumpIfNotSmi(key, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003504
3505 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3506 // a3: elements array
3507
3508 // Check that the index is in range.
3509 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3510 __ sra(t2, key, kSmiTagSize);
3511 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003512 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003513
3514 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3515 // a3: base pointer of external storage
3516
3517 // We are not untagging smi key and instead work with it
3518 // as if it was premultiplied by 2.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003519 STATIC_ASSERT((kSmiTag == 0) && (kSmiTagSize == 1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003520
3521 Register value = a2;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003522 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003523 case EXTERNAL_BYTE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003524 __ srl(t2, key, 1);
3525 __ addu(t3, a3, t2);
3526 __ lb(value, MemOperand(t3, 0));
3527 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003528 case EXTERNAL_PIXEL_ELEMENTS:
3529 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003530 __ srl(t2, key, 1);
3531 __ addu(t3, a3, t2);
3532 __ lbu(value, MemOperand(t3, 0));
3533 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003534 case EXTERNAL_SHORT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003535 __ addu(t3, a3, key);
3536 __ lh(value, MemOperand(t3, 0));
3537 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003538 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003539 __ addu(t3, a3, key);
3540 __ lhu(value, MemOperand(t3, 0));
3541 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003542 case EXTERNAL_INT_ELEMENTS:
3543 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003544 __ sll(t2, key, 1);
3545 __ addu(t3, a3, t2);
3546 __ lw(value, MemOperand(t3, 0));
3547 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003548 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003549 __ sll(t3, t2, 2);
3550 __ addu(t3, a3, t3);
3551 if (CpuFeatures::IsSupported(FPU)) {
3552 CpuFeatures::Scope scope(FPU);
3553 __ lwc1(f0, MemOperand(t3, 0));
3554 } else {
3555 __ lw(value, MemOperand(t3, 0));
3556 }
3557 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003558 case EXTERNAL_DOUBLE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003559 __ sll(t2, key, 2);
3560 __ addu(t3, a3, t2);
3561 if (CpuFeatures::IsSupported(FPU)) {
3562 CpuFeatures::Scope scope(FPU);
3563 __ ldc1(f0, MemOperand(t3, 0));
3564 } else {
3565 // t3: pointer to the beginning of the double we want to load.
3566 __ lw(a2, MemOperand(t3, 0));
3567 __ lw(a3, MemOperand(t3, Register::kSizeInBytes));
3568 }
3569 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003570 case FAST_ELEMENTS:
3571 case FAST_DOUBLE_ELEMENTS:
3572 case DICTIONARY_ELEMENTS:
3573 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003574 UNREACHABLE();
3575 break;
3576 }
3577
3578 // For integer array types:
3579 // a2: value
3580 // For float array type:
3581 // f0: value (if FPU is supported)
3582 // a2: value (if FPU is not supported)
3583 // For double array type:
3584 // f0: value (if FPU is supported)
3585 // a2/a3: value (if FPU is not supported)
3586
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003587 if (elements_kind == EXTERNAL_INT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003588 // For the Int and UnsignedInt array types, we need to see whether
3589 // the value can be represented in a Smi. If not, we need to convert
3590 // it to a HeapNumber.
3591 Label box_int;
3592 __ Subu(t3, value, Operand(0xC0000000)); // Non-smi value gives neg result.
3593 __ Branch(&box_int, lt, t3, Operand(zero_reg));
3594 // Tag integer as smi and return it.
3595 __ sll(v0, value, kSmiTagSize);
3596 __ Ret();
3597
3598 __ bind(&box_int);
3599 // Allocate a HeapNumber for the result and perform int-to-double
3600 // conversion.
3601 // The arm version uses a temporary here to save r0, but we don't need to
3602 // (a0 is not modified).
3603 __ LoadRoot(t1, Heap::kHeapNumberMapRootIndex);
3604 __ AllocateHeapNumber(v0, a3, t0, t1, &slow);
3605
3606 if (CpuFeatures::IsSupported(FPU)) {
3607 CpuFeatures::Scope scope(FPU);
3608 __ mtc1(value, f0);
3609 __ cvt_d_w(f0, f0);
3610 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag));
3611 __ Ret();
3612 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003613 Register dst1 = t2;
3614 Register dst2 = t3;
3615 FloatingPointHelper::Destination dest =
3616 FloatingPointHelper::kCoreRegisters;
3617 FloatingPointHelper::ConvertIntToDouble(masm,
3618 value,
3619 dest,
3620 f0,
3621 dst1,
3622 dst2,
3623 t1,
3624 f2);
3625 __ sw(dst1, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3626 __ sw(dst2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3627 __ Ret();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003628 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003629 } else if (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003630 // The test is different for unsigned int values. Since we need
3631 // the value to be in the range of a positive smi, we can't
3632 // handle either of the top two bits being set in the value.
3633 if (CpuFeatures::IsSupported(FPU)) {
3634 CpuFeatures::Scope scope(FPU);
3635 Label pl_box_int;
3636 __ And(t2, value, Operand(0xC0000000));
3637 __ Branch(&pl_box_int, ne, t2, Operand(zero_reg));
3638
3639 // It can fit in an Smi.
3640 // Tag integer as smi and return it.
3641 __ sll(v0, value, kSmiTagSize);
3642 __ Ret();
3643
3644 __ bind(&pl_box_int);
3645 // Allocate a HeapNumber for the result and perform int-to-double
3646 // conversion. Don't use a0 and a1 as AllocateHeapNumber clobbers all
3647 // registers - also when jumping due to exhausted young space.
3648 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3649 __ AllocateHeapNumber(v0, t2, t3, t6, &slow);
3650
3651 // This is replaced by a macro:
3652 // __ mtc1(value, f0); // LS 32-bits.
3653 // __ mtc1(zero_reg, f1); // MS 32-bits are all zero.
3654 // __ cvt_d_l(f0, f0); // Use 64 bit conv to get correct unsigned 32-bit.
3655
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003656 __ Cvt_d_uw(f0, value, f22);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003657
3658 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag));
3659
3660 __ Ret();
3661 } else {
3662 // Check whether unsigned integer fits into smi.
3663 Label box_int_0, box_int_1, done;
3664 __ And(t2, value, Operand(0x80000000));
3665 __ Branch(&box_int_0, ne, t2, Operand(zero_reg));
3666 __ And(t2, value, Operand(0x40000000));
3667 __ Branch(&box_int_1, ne, t2, Operand(zero_reg));
3668
3669 // Tag integer as smi and return it.
3670 __ sll(v0, value, kSmiTagSize);
3671 __ Ret();
3672
3673 Register hiword = value; // a2.
3674 Register loword = a3;
3675
3676 __ bind(&box_int_0);
3677 // Integer does not have leading zeros.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003678 GenerateUInt2Double(masm, hiword, loword, t0, 0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003679 __ Branch(&done);
3680
3681 __ bind(&box_int_1);
3682 // Integer has one leading zero.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003683 GenerateUInt2Double(masm, hiword, loword, t0, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003684
3685
3686 __ bind(&done);
3687 // Integer was converted to double in registers hiword:loword.
3688 // Wrap it into a HeapNumber. Don't use a0 and a1 as AllocateHeapNumber
3689 // clobbers all registers - also when jumping due to exhausted young
3690 // space.
3691 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3692 __ AllocateHeapNumber(t2, t3, t5, t6, &slow);
3693
3694 __ sw(hiword, FieldMemOperand(t2, HeapNumber::kExponentOffset));
3695 __ sw(loword, FieldMemOperand(t2, HeapNumber::kMantissaOffset));
3696
3697 __ mov(v0, t2);
3698 __ Ret();
3699 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003700 } else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003701 // For the floating-point array type, we need to always allocate a
3702 // HeapNumber.
3703 if (CpuFeatures::IsSupported(FPU)) {
3704 CpuFeatures::Scope scope(FPU);
3705 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3706 // AllocateHeapNumber clobbers all registers - also when jumping due to
3707 // exhausted young space.
3708 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3709 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3710 // The float (single) value is already in fpu reg f0 (if we use float).
3711 __ cvt_d_s(f0, f0);
3712 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag));
3713 __ Ret();
3714 } else {
3715 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3716 // AllocateHeapNumber clobbers all registers - also when jumping due to
3717 // exhausted young space.
3718 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3719 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3720 // FPU is not available, do manual single to double conversion.
3721
3722 // a2: floating point value (binary32).
3723 // v0: heap number for result
3724
3725 // Extract mantissa to t4.
3726 __ And(t4, value, Operand(kBinary32MantissaMask));
3727
3728 // Extract exponent to t5.
3729 __ srl(t5, value, kBinary32MantissaBits);
3730 __ And(t5, t5, Operand(kBinary32ExponentMask >> kBinary32MantissaBits));
3731
3732 Label exponent_rebiased;
3733 __ Branch(&exponent_rebiased, eq, t5, Operand(zero_reg));
3734
3735 __ li(t0, 0x7ff);
3736 __ Xor(t1, t5, Operand(0xFF));
3737 __ movz(t5, t0, t1); // Set t5 to 0x7ff only if t5 is equal to 0xff.
3738 __ Branch(&exponent_rebiased, eq, t0, Operand(0xff));
3739
3740 // Rebias exponent.
3741 __ Addu(t5,
3742 t5,
3743 Operand(-kBinary32ExponentBias + HeapNumber::kExponentBias));
3744
3745 __ bind(&exponent_rebiased);
3746 __ And(a2, value, Operand(kBinary32SignMask));
3747 value = no_reg;
3748 __ sll(t0, t5, HeapNumber::kMantissaBitsInTopWord);
3749 __ or_(a2, a2, t0);
3750
3751 // Shift mantissa.
3752 static const int kMantissaShiftForHiWord =
3753 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3754
3755 static const int kMantissaShiftForLoWord =
3756 kBitsPerInt - kMantissaShiftForHiWord;
3757
3758 __ srl(t0, t4, kMantissaShiftForHiWord);
3759 __ or_(a2, a2, t0);
3760 __ sll(a0, t4, kMantissaShiftForLoWord);
3761
3762 __ sw(a2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3763 __ sw(a0, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3764 __ Ret();
3765 }
3766
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003767 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003768 if (CpuFeatures::IsSupported(FPU)) {
3769 CpuFeatures::Scope scope(FPU);
3770 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3771 // AllocateHeapNumber clobbers all registers - also when jumping due to
3772 // exhausted young space.
3773 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3774 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3775 // The double value is already in f0
3776 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
3777 __ Ret();
3778 } else {
3779 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3780 // AllocateHeapNumber clobbers all registers - also when jumping due to
3781 // exhausted young space.
3782 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3783 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3784
3785 __ sw(a2, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3786 __ sw(a3, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3787 __ Ret();
3788 }
3789
3790 } else {
3791 // Tag integer as smi and return it.
3792 __ sll(v0, value, kSmiTagSize);
3793 __ Ret();
3794 }
3795
3796 // Slow case, key and receiver still in a0 and a1.
3797 __ bind(&slow);
3798 __ IncrementCounter(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003799 masm->isolate()->counters()->keyed_load_external_array_slow(),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003800 1, a2, a3);
3801
3802 // ---------- S t a t e --------------
3803 // -- ra : return address
3804 // -- a0 : key
3805 // -- a1 : receiver
3806 // -----------------------------------
3807
3808 __ Push(a1, a0);
3809
3810 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
3811
danno@chromium.org40cb8782011-05-25 07:58:50 +00003812 __ bind(&miss_force_generic);
3813 Code* stub = masm->isolate()->builtins()->builtin(
3814 Builtins::kKeyedLoadIC_MissForceGeneric);
3815 __ Jump(Handle<Code>(stub), RelocInfo::CODE_TARGET);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003816}
3817
3818
danno@chromium.org40cb8782011-05-25 07:58:50 +00003819void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3820 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003821 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003822 // ---------- S t a t e --------------
3823 // -- a0 : value
3824 // -- a1 : key
3825 // -- a2 : receiver
3826 // -- ra : return address
3827 // -----------------------------------
3828
danno@chromium.org40cb8782011-05-25 07:58:50 +00003829 Label slow, check_heap_number, miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003830
3831 // Register usage.
3832 Register value = a0;
3833 Register key = a1;
3834 Register receiver = a2;
3835 // a3 mostly holds the elements array or the destination external array.
3836
danno@chromium.org40cb8782011-05-25 07:58:50 +00003837 // This stub is meant to be tail-jumped to, the receiver must already
3838 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003839
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003840 // Check that the key is a smi.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003841 __ JumpIfNotSmi(key, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003842
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003843 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3844
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003845 // Check that the index is in range.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003846 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3847 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003848 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003849
3850 // Handle both smis and HeapNumbers in the fast path. Go to the
3851 // runtime for all other kinds of values.
3852 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003853
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003854 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003855 // Double to pixel conversion is only implemented in the runtime for now.
3856 __ JumpIfNotSmi(value, &slow);
3857 } else {
3858 __ JumpIfNotSmi(value, &check_heap_number);
3859 }
3860 __ SmiUntag(t1, value);
3861 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3862
3863 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003864 // t1: value (integer).
3865
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003866 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003867 case EXTERNAL_PIXEL_ELEMENTS: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003868 // Clamp the value to [0..255].
3869 // v0 is used as a scratch register here.
3870 Label done;
3871 __ li(v0, Operand(255));
3872 // Normal branch: nop in delay slot.
3873 __ Branch(&done, gt, t1, Operand(v0));
3874 // Use delay slot in this branch.
3875 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg));
3876 __ mov(v0, zero_reg); // In delay slot.
3877 __ mov(v0, t1); // Value is in range 0..255.
3878 __ bind(&done);
3879 __ mov(t1, v0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003880
3881 __ srl(t8, key, 1);
3882 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003883 __ sb(t1, MemOperand(t8, 0));
3884 }
3885 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003886 case EXTERNAL_BYTE_ELEMENTS:
3887 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003888 __ srl(t8, key, 1);
3889 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003890 __ sb(t1, MemOperand(t8, 0));
3891 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003892 case EXTERNAL_SHORT_ELEMENTS:
3893 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003894 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003895 __ sh(t1, MemOperand(t8, 0));
3896 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003897 case EXTERNAL_INT_ELEMENTS:
3898 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003899 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003900 __ addu(t8, a3, t8);
3901 __ sw(t1, MemOperand(t8, 0));
3902 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003903 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003904 // Perform int-to-float conversion and store to memory.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003905 __ SmiUntag(t0, key);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003906 StoreIntAsFloat(masm, a3, t0, t1, t2, t3, t4);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003907 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003908 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003909 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003910 __ addu(a3, a3, t8);
3911 // a3: effective address of the double element
3912 FloatingPointHelper::Destination destination;
3913 if (CpuFeatures::IsSupported(FPU)) {
3914 destination = FloatingPointHelper::kFPURegisters;
3915 } else {
3916 destination = FloatingPointHelper::kCoreRegisters;
3917 }
3918 FloatingPointHelper::ConvertIntToDouble(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003919 masm, t1, destination,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003920 f0, t2, t3, // These are: double_dst, dst1, dst2.
3921 t0, f2); // These are: scratch2, single_scratch.
3922 if (destination == FloatingPointHelper::kFPURegisters) {
3923 CpuFeatures::Scope scope(FPU);
3924 __ sdc1(f0, MemOperand(a3, 0));
3925 } else {
3926 __ sw(t2, MemOperand(a3, 0));
3927 __ sw(t3, MemOperand(a3, Register::kSizeInBytes));
3928 }
3929 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003930 case FAST_ELEMENTS:
3931 case FAST_DOUBLE_ELEMENTS:
3932 case DICTIONARY_ELEMENTS:
3933 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003934 UNREACHABLE();
3935 break;
3936 }
3937
3938 // Entry registers are intact, a0 holds the value which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003939 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003940 __ Ret();
3941
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003942 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003943 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003944 __ bind(&check_heap_number);
3945 __ GetObjectType(value, t1, t2);
3946 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE));
3947
3948 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3949
3950 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003951
3952 // The WebGL specification leaves the behavior of storing NaN and
3953 // +/-Infinity into integer arrays basically undefined. For more
3954 // reproducible behavior, convert these to zero.
3955
3956 if (CpuFeatures::IsSupported(FPU)) {
3957 CpuFeatures::Scope scope(FPU);
3958
3959 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
3960
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003961 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003962 __ cvt_s_d(f0, f0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003963 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003964 __ addu(t8, a3, t8);
3965 __ swc1(f0, MemOperand(t8, 0));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003966 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003967 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003968 __ addu(t8, a3, t8);
3969 __ sdc1(f0, MemOperand(t8, 0));
3970 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003971 __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003972
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003973 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003974 case EXTERNAL_BYTE_ELEMENTS:
3975 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003976 __ srl(t8, key, 1);
3977 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003978 __ sb(t3, MemOperand(t8, 0));
3979 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003980 case EXTERNAL_SHORT_ELEMENTS:
3981 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003982 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003983 __ sh(t3, MemOperand(t8, 0));
3984 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003985 case EXTERNAL_INT_ELEMENTS:
3986 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003987 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003988 __ addu(t8, a3, t8);
3989 __ sw(t3, MemOperand(t8, 0));
3990 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003991 case EXTERNAL_PIXEL_ELEMENTS:
3992 case EXTERNAL_FLOAT_ELEMENTS:
3993 case EXTERNAL_DOUBLE_ELEMENTS:
3994 case FAST_ELEMENTS:
3995 case FAST_DOUBLE_ELEMENTS:
3996 case DICTIONARY_ELEMENTS:
3997 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003998 UNREACHABLE();
3999 break;
4000 }
4001 }
4002
4003 // Entry registers are intact, a0 holds the value
4004 // which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004005 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004006 __ Ret();
4007 } else {
4008 // FPU is not available, do manual conversions.
4009
4010 __ lw(t3, FieldMemOperand(value, HeapNumber::kExponentOffset));
4011 __ lw(t4, FieldMemOperand(value, HeapNumber::kMantissaOffset));
4012
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004013 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004014 Label done, nan_or_infinity_or_zero;
4015 static const int kMantissaInHiWordShift =
4016 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
4017
4018 static const int kMantissaInLoWordShift =
4019 kBitsPerInt - kMantissaInHiWordShift;
4020
4021 // Test for all special exponent values: zeros, subnormal numbers, NaNs
4022 // and infinities. All these should be converted to 0.
4023 __ li(t5, HeapNumber::kExponentMask);
4024 __ and_(t6, t3, t5);
4025 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(zero_reg));
4026
4027 __ xor_(t1, t6, t5);
4028 __ li(t2, kBinary32ExponentMask);
4029 __ movz(t6, t2, t1); // Only if t6 is equal to t5.
4030 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(t5));
4031
4032 // Rebias exponent.
4033 __ srl(t6, t6, HeapNumber::kExponentShift);
4034 __ Addu(t6,
4035 t6,
4036 Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
4037
4038 __ li(t1, Operand(kBinary32MaxExponent));
4039 __ Slt(t1, t1, t6);
4040 __ And(t2, t3, Operand(HeapNumber::kSignMask));
4041 __ Or(t2, t2, Operand(kBinary32ExponentMask));
4042 __ movn(t3, t2, t1); // Only if t6 is gt kBinary32MaxExponent.
4043 __ Branch(&done, gt, t6, Operand(kBinary32MaxExponent));
4044
4045 __ Slt(t1, t6, Operand(kBinary32MinExponent));
4046 __ And(t2, t3, Operand(HeapNumber::kSignMask));
4047 __ movn(t3, t2, t1); // Only if t6 is lt kBinary32MinExponent.
4048 __ Branch(&done, lt, t6, Operand(kBinary32MinExponent));
4049
4050 __ And(t7, t3, Operand(HeapNumber::kSignMask));
4051 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4052 __ sll(t3, t3, kMantissaInHiWordShift);
4053 __ or_(t7, t7, t3);
4054 __ srl(t4, t4, kMantissaInLoWordShift);
4055 __ or_(t7, t7, t4);
4056 __ sll(t6, t6, kBinary32ExponentShift);
4057 __ or_(t3, t7, t6);
4058
4059 __ bind(&done);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004060 __ sll(t9, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004061 __ addu(t9, a2, t9);
4062 __ sw(t3, MemOperand(t9, 0));
4063
4064 // Entry registers are intact, a0 holds the value which is the return
4065 // value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004066 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004067 __ Ret();
4068
4069 __ bind(&nan_or_infinity_or_zero);
4070 __ And(t7, t3, Operand(HeapNumber::kSignMask));
4071 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4072 __ or_(t6, t6, t7);
4073 __ sll(t3, t3, kMantissaInHiWordShift);
4074 __ or_(t6, t6, t3);
4075 __ srl(t4, t4, kMantissaInLoWordShift);
4076 __ or_(t3, t6, t4);
4077 __ Branch(&done);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004078 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004079 __ sll(t8, t0, 3);
4080 __ addu(t8, a3, t8);
4081 // t8: effective address of destination element.
4082 __ sw(t4, MemOperand(t8, 0));
4083 __ sw(t3, MemOperand(t8, Register::kSizeInBytes));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004084 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004085 __ Ret();
4086 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004087 bool is_signed_type = IsElementTypeSigned(elements_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004088 int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
4089 int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
4090
4091 Label done, sign;
4092
4093 // Test for all special exponent values: zeros, subnormal numbers, NaNs
4094 // and infinities. All these should be converted to 0.
4095 __ li(t5, HeapNumber::kExponentMask);
4096 __ and_(t6, t3, t5);
4097 __ movz(t3, zero_reg, t6); // Only if t6 is equal to zero.
4098 __ Branch(&done, eq, t6, Operand(zero_reg));
4099
4100 __ xor_(t2, t6, t5);
4101 __ movz(t3, zero_reg, t2); // Only if t6 is equal to t5.
4102 __ Branch(&done, eq, t6, Operand(t5));
4103
4104 // Unbias exponent.
4105 __ srl(t6, t6, HeapNumber::kExponentShift);
4106 __ Subu(t6, t6, Operand(HeapNumber::kExponentBias));
4107 // If exponent is negative then result is 0.
4108 __ slt(t2, t6, zero_reg);
4109 __ movn(t3, zero_reg, t2); // Only if exponent is negative.
4110 __ Branch(&done, lt, t6, Operand(zero_reg));
4111
4112 // If exponent is too big then result is minimal value.
4113 __ slti(t1, t6, meaningfull_bits - 1);
4114 __ li(t2, min_value);
4115 __ movz(t3, t2, t1); // Only if t6 is ge meaningfull_bits - 1.
4116 __ Branch(&done, ge, t6, Operand(meaningfull_bits - 1));
4117
4118 __ And(t5, t3, Operand(HeapNumber::kSignMask));
4119 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4120 __ Or(t3, t3, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
4121
4122 __ li(t9, HeapNumber::kMantissaBitsInTopWord);
4123 __ subu(t6, t9, t6);
4124 __ slt(t1, t6, zero_reg);
4125 __ srlv(t2, t3, t6);
4126 __ movz(t3, t2, t1); // Only if t6 is positive.
4127 __ Branch(&sign, ge, t6, Operand(zero_reg));
4128
4129 __ subu(t6, zero_reg, t6);
4130 __ sllv(t3, t3, t6);
4131 __ li(t9, meaningfull_bits);
4132 __ subu(t6, t9, t6);
4133 __ srlv(t4, t4, t6);
4134 __ or_(t3, t3, t4);
4135
4136 __ bind(&sign);
4137 __ subu(t2, t3, zero_reg);
4138 __ movz(t3, t2, t5); // Only if t5 is zero.
4139
4140 __ bind(&done);
4141
4142 // Result is in t3.
4143 // This switch block should be exactly the same as above (FPU mode).
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004144 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004145 case EXTERNAL_BYTE_ELEMENTS:
4146 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004147 __ srl(t8, key, 1);
4148 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004149 __ sb(t3, MemOperand(t8, 0));
4150 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004151 case EXTERNAL_SHORT_ELEMENTS:
4152 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004153 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004154 __ sh(t3, MemOperand(t8, 0));
4155 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004156 case EXTERNAL_INT_ELEMENTS:
4157 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004158 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004159 __ addu(t8, a3, t8);
4160 __ sw(t3, MemOperand(t8, 0));
4161 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004162 case EXTERNAL_PIXEL_ELEMENTS:
4163 case EXTERNAL_FLOAT_ELEMENTS:
4164 case EXTERNAL_DOUBLE_ELEMENTS:
4165 case FAST_ELEMENTS:
4166 case FAST_DOUBLE_ELEMENTS:
4167 case DICTIONARY_ELEMENTS:
4168 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004169 UNREACHABLE();
4170 break;
4171 }
4172 }
4173 }
4174 }
4175
danno@chromium.org40cb8782011-05-25 07:58:50 +00004176 // Slow case, key and receiver still in a0 and a1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004177 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004178 __ IncrementCounter(
4179 masm->isolate()->counters()->keyed_load_external_array_slow(),
4180 1, a2, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004181 // Entry registers are intact.
4182 // ---------- S t a t e --------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004183 // -- ra : return address
danno@chromium.org40cb8782011-05-25 07:58:50 +00004184 // -- a0 : key
4185 // -- a1 : receiver
4186 // -----------------------------------
4187 Handle<Code> slow_ic =
4188 masm->isolate()->builtins()->KeyedStoreIC_Slow();
4189 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4190
4191 // Miss case, call the runtime.
4192 __ bind(&miss_force_generic);
4193
4194 // ---------- S t a t e --------------
4195 // -- ra : return address
4196 // -- a0 : key
4197 // -- a1 : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004198 // -----------------------------------
4199
danno@chromium.org40cb8782011-05-25 07:58:50 +00004200 Handle<Code> miss_ic =
4201 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4202 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
4203}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004204
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004205
danno@chromium.org40cb8782011-05-25 07:58:50 +00004206void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
4207 // ----------- S t a t e -------------
4208 // -- ra : return address
4209 // -- a0 : key
4210 // -- a1 : receiver
4211 // -----------------------------------
4212 Label miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004213
danno@chromium.org40cb8782011-05-25 07:58:50 +00004214 // This stub is meant to be tail-jumped to, the receiver must already
4215 // have been verified by the caller to not be a smi.
4216
4217 // Check that the key is a smi.
4218 __ JumpIfNotSmi(a0, &miss_force_generic);
4219
4220 // Get the elements array.
4221 __ lw(a2, FieldMemOperand(a1, JSObject::kElementsOffset));
4222 __ AssertFastElements(a2);
4223
4224 // Check that the key is within bounds.
4225 __ lw(a3, FieldMemOperand(a2, FixedArray::kLengthOffset));
4226 __ Branch(&miss_force_generic, hs, a0, Operand(a3));
4227
4228 // Load the result and make sure it's not the hole.
4229 __ Addu(a3, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004230 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004231 __ sll(t0, a0, kPointerSizeLog2 - kSmiTagSize);
4232 __ Addu(t0, t0, a3);
4233 __ lw(t0, MemOperand(t0));
4234 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
4235 __ Branch(&miss_force_generic, eq, t0, Operand(t1));
4236 __ mov(v0, t0);
4237 __ Ret();
4238
4239 __ bind(&miss_force_generic);
4240 Code* stub = masm->isolate()->builtins()->builtin(
4241 Builtins::kKeyedLoadIC_MissForceGeneric);
4242 __ Jump(Handle<Code>(stub), RelocInfo::CODE_TARGET);
4243}
4244
4245
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004246void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
4247 MacroAssembler* masm) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004248 // ----------- S t a t e -------------
4249 // -- ra : return address
4250 // -- a0 : key
4251 // -- a1 : receiver
4252 // -----------------------------------
4253 Label miss_force_generic, slow_allocate_heapnumber;
4254
4255 Register key_reg = a0;
4256 Register receiver_reg = a1;
4257 Register elements_reg = a2;
4258 Register heap_number_reg = a2;
4259 Register indexed_double_offset = a3;
4260 Register scratch = t0;
4261 Register scratch2 = t1;
4262 Register scratch3 = t2;
4263 Register heap_number_map = t3;
4264
4265 // This stub is meant to be tail-jumped to, the receiver must already
4266 // have been verified by the caller to not be a smi.
4267
4268 // Check that the key is a smi.
4269 __ JumpIfNotSmi(key_reg, &miss_force_generic);
4270
4271 // Get the elements array.
4272 __ lw(elements_reg,
4273 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4274
4275 // Check that the key is within bounds.
4276 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4277 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4278
4279 // Load the upper word of the double in the fixed array and test for NaN.
4280 __ sll(scratch2, key_reg, kDoubleSizeLog2 - kSmiTagSize);
4281 __ Addu(indexed_double_offset, elements_reg, Operand(scratch2));
4282 uint32_t upper_32_offset = FixedArray::kHeaderSize + sizeof(kHoleNanLower32);
4283 __ lw(scratch, FieldMemOperand(indexed_double_offset, upper_32_offset));
4284 __ Branch(&miss_force_generic, eq, scratch, Operand(kHoleNanUpper32));
4285
4286 // Non-NaN. Allocate a new heap number and copy the double value into it.
4287 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
4288 __ AllocateHeapNumber(heap_number_reg, scratch2, scratch3,
4289 heap_number_map, &slow_allocate_heapnumber);
4290
4291 // Don't need to reload the upper 32 bits of the double, it's already in
4292 // scratch.
4293 __ sw(scratch, FieldMemOperand(heap_number_reg,
4294 HeapNumber::kExponentOffset));
4295 __ lw(scratch, FieldMemOperand(indexed_double_offset,
4296 FixedArray::kHeaderSize));
4297 __ sw(scratch, FieldMemOperand(heap_number_reg,
4298 HeapNumber::kMantissaOffset));
4299
4300 __ mov(v0, heap_number_reg);
4301 __ Ret();
4302
4303 __ bind(&slow_allocate_heapnumber);
4304 Handle<Code> slow_ic =
4305 masm->isolate()->builtins()->KeyedLoadIC_Slow();
4306 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4307
4308 __ bind(&miss_force_generic);
4309 Handle<Code> miss_ic =
4310 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4311 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004312}
4313
4314
danno@chromium.org40cb8782011-05-25 07:58:50 +00004315void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm,
4316 bool is_js_array) {
4317 // ----------- S t a t e -------------
4318 // -- a0 : value
4319 // -- a1 : key
4320 // -- a2 : receiver
4321 // -- ra : return address
4322 // -- a3 : scratch
4323 // -- a4 : scratch (elements)
4324 // -----------------------------------
4325 Label miss_force_generic;
4326
4327 Register value_reg = a0;
4328 Register key_reg = a1;
4329 Register receiver_reg = a2;
4330 Register scratch = a3;
4331 Register elements_reg = t0;
4332 Register scratch2 = t1;
4333 Register scratch3 = t2;
4334
4335 // This stub is meant to be tail-jumped to, the receiver must already
4336 // have been verified by the caller to not be a smi.
4337
4338 // Check that the key is a smi.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00004339 __ JumpIfNotSmi(key_reg, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004340
4341 // Get the elements array and make sure it is a fast element array, not 'cow'.
4342 __ lw(elements_reg,
4343 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4344 __ CheckMap(elements_reg,
4345 scratch,
4346 Heap::kFixedArrayMapRootIndex,
4347 &miss_force_generic,
4348 DONT_DO_SMI_CHECK);
4349
4350 // Check that the key is within bounds.
4351 if (is_js_array) {
4352 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4353 } else {
4354 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4355 }
4356 // Compare smis.
4357 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4358
4359 __ Addu(scratch,
4360 elements_reg, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004361 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004362 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4363 __ Addu(scratch3, scratch2, scratch);
4364 __ sw(value_reg, MemOperand(scratch3));
4365 __ RecordWrite(scratch, Operand(scratch2), receiver_reg , elements_reg);
4366
4367 // value_reg (a0) is preserved.
4368 // Done.
4369 __ Ret();
4370
4371 __ bind(&miss_force_generic);
4372 Handle<Code> ic =
4373 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4374 __ Jump(ic, RelocInfo::CODE_TARGET);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004375}
4376
4377
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004378void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
4379 MacroAssembler* masm,
4380 bool is_js_array) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004381 // ----------- S t a t e -------------
4382 // -- a0 : value
4383 // -- a1 : key
4384 // -- a2 : receiver
4385 // -- ra : return address
4386 // -- a3 : scratch
4387 // -- t0 : scratch (elements_reg)
4388 // -- t1 : scratch (mantissa_reg)
4389 // -- t2 : scratch (exponent_reg)
4390 // -- t3 : scratch4
4391 // -----------------------------------
4392 Label miss_force_generic, smi_value, is_nan, maybe_nan, have_double_value;
4393
4394 Register value_reg = a0;
4395 Register key_reg = a1;
4396 Register receiver_reg = a2;
4397 Register scratch = a3;
4398 Register elements_reg = t0;
4399 Register mantissa_reg = t1;
4400 Register exponent_reg = t2;
4401 Register scratch4 = t3;
4402
4403 // This stub is meant to be tail-jumped to, the receiver must already
4404 // have been verified by the caller to not be a smi.
4405 __ JumpIfNotSmi(key_reg, &miss_force_generic);
4406
4407 __ lw(elements_reg,
4408 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4409
4410 // Check that the key is within bounds.
4411 if (is_js_array) {
4412 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4413 } else {
4414 __ lw(scratch,
4415 FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4416 }
4417 // Compare smis, unsigned compare catches both negative and out-of-bound
4418 // indexes.
4419 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4420
4421 // Handle smi values specially.
4422 __ JumpIfSmi(value_reg, &smi_value);
4423
4424 // Ensure that the object is a heap number
4425 __ CheckMap(value_reg,
4426 scratch,
4427 masm->isolate()->factory()->heap_number_map(),
4428 &miss_force_generic,
4429 DONT_DO_SMI_CHECK);
4430
4431 // Check for nan: all NaN values have a value greater (signed) than 0x7ff00000
4432 // in the exponent.
4433 __ li(scratch, Operand(kNaNOrInfinityLowerBoundUpper32));
4434 __ lw(exponent_reg, FieldMemOperand(value_reg, HeapNumber::kExponentOffset));
4435 __ Branch(&maybe_nan, ge, exponent_reg, Operand(scratch));
4436
4437 __ lw(mantissa_reg, FieldMemOperand(value_reg, HeapNumber::kMantissaOffset));
4438
4439 __ bind(&have_double_value);
4440 __ sll(scratch4, key_reg, kDoubleSizeLog2 - kSmiTagSize);
4441 __ Addu(scratch, elements_reg, Operand(scratch4));
4442 __ sw(mantissa_reg, FieldMemOperand(scratch, FixedDoubleArray::kHeaderSize));
4443 uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
4444 __ sw(exponent_reg, FieldMemOperand(scratch, offset));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004445 __ Ret(USE_DELAY_SLOT);
4446 __ mov(v0, value_reg); // In delay slot.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004447
4448 __ bind(&maybe_nan);
4449 // Could be NaN or Infinity. If fraction is not zero, it's NaN, otherwise
4450 // it's an Infinity, and the non-NaN code path applies.
4451 __ li(scratch, Operand(kNaNOrInfinityLowerBoundUpper32));
4452 __ Branch(&is_nan, gt, exponent_reg, Operand(scratch));
4453 __ lw(mantissa_reg, FieldMemOperand(value_reg, HeapNumber::kMantissaOffset));
4454 __ Branch(&have_double_value, eq, mantissa_reg, Operand(zero_reg));
4455
4456 __ bind(&is_nan);
4457 // Load canonical NaN for storing into the double array.
4458 uint64_t nan_int64 = BitCast<uint64_t>(
4459 FixedDoubleArray::canonical_not_the_hole_nan_as_double());
4460 __ li(mantissa_reg, Operand(static_cast<uint32_t>(nan_int64)));
4461 __ li(exponent_reg, Operand(static_cast<uint32_t>(nan_int64 >> 32)));
4462 __ jmp(&have_double_value);
4463
4464 __ bind(&smi_value);
4465 __ Addu(scratch, elements_reg,
4466 Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag));
4467 __ sll(scratch4, key_reg, kDoubleSizeLog2 - kSmiTagSize);
4468 __ Addu(scratch, scratch, scratch4);
4469 // scratch is now effective address of the double element
4470
4471 FloatingPointHelper::Destination destination;
4472 if (CpuFeatures::IsSupported(FPU)) {
4473 destination = FloatingPointHelper::kFPURegisters;
4474 } else {
4475 destination = FloatingPointHelper::kCoreRegisters;
4476 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00004477
4478 Register untagged_value = receiver_reg;
4479 __ SmiUntag(untagged_value, value_reg);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004480 FloatingPointHelper::ConvertIntToDouble(
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00004481 masm,
4482 untagged_value,
4483 destination,
4484 f0,
4485 mantissa_reg,
4486 exponent_reg,
4487 scratch4,
4488 f2);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004489 if (destination == FloatingPointHelper::kFPURegisters) {
4490 CpuFeatures::Scope scope(FPU);
4491 __ sdc1(f0, MemOperand(scratch, 0));
4492 } else {
4493 __ sw(mantissa_reg, MemOperand(scratch, 0));
4494 __ sw(exponent_reg, MemOperand(scratch, Register::kSizeInBytes));
4495 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004496 __ Ret(USE_DELAY_SLOT);
4497 __ mov(v0, value_reg); // In delay slot.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004498
4499 // Handle store cache miss, replacing the ic with the generic stub.
4500 __ bind(&miss_force_generic);
4501 Handle<Code> ic =
4502 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4503 __ Jump(ic, RelocInfo::CODE_TARGET);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004504}
4505
4506
ager@chromium.org5c838252010-02-19 08:53:10 +00004507#undef __
4508
4509} } // namespace v8::internal
4510
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004511#endif // V8_TARGET_ARCH_MIPS