blob: 45df93a340d79074acfa52e963335b9523e88e47 [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));
129 __ Branch(miss_label, lt, scratch0, Operand(FIRST_JS_OBJECT_TYPE));
130
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,
475 Label* miss) {
476 // ----------- S t a t e -------------
477 // -- a0: receiver
478 // -- a1: function to call
479 // -----------------------------------
480 // Check that the function really is a function.
481 __ JumpIfSmi(a1, miss);
482 __ GetObjectType(a1, a3, a3);
483 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
484
485 // Patch the receiver on the stack with the global proxy if
486 // necessary.
487 if (object->IsGlobalObject()) {
488 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
489 __ sw(a3, MemOperand(sp, arguments.immediate() * kPointerSize));
490 }
491
492 // Invoke the function.
493 __ InvokeFunction(a1, arguments, JUMP_FUNCTION);
494}
495
496
497static void PushInterceptorArguments(MacroAssembler* masm,
498 Register receiver,
499 Register holder,
500 Register name,
501 JSObject* holder_obj) {
502 __ push(name);
503 InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
504 ASSERT(!masm->isolate()->heap()->InNewSpace(interceptor));
505 Register scratch = name;
506 __ li(scratch, Operand(Handle<Object>(interceptor)));
507 __ Push(scratch, receiver, holder);
508 __ lw(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
509 __ push(scratch);
510}
511
512
513static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
514 Register receiver,
515 Register holder,
516 Register name,
517 JSObject* holder_obj) {
518 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
519
520 ExternalReference ref =
521 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
522 masm->isolate());
523 __ li(a0, Operand(5));
524 __ li(a1, Operand(ref));
525
526 CEntryStub stub(1);
527 __ CallStub(&stub);
528}
529
530
531static const int kFastApiCallArguments = 3;
532
533
534// Reserves space for the extra arguments to FastHandleApiCall in the
535// caller's frame.
536//
537// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
538static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
539 Register scratch) {
540 ASSERT(Smi::FromInt(0) == 0);
541 for (int i = 0; i < kFastApiCallArguments; i++) {
542 __ push(zero_reg);
543 }
544}
545
546
547// Undoes the effects of ReserveSpaceForFastApiCall.
548static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
549 __ Drop(kFastApiCallArguments);
550}
551
552
553static MaybeObject* GenerateFastApiDirectCall(MacroAssembler* masm,
554 const CallOptimization& optimization,
555 int argc) {
556 // ----------- S t a t e -------------
557 // -- sp[0] : holder (set by CheckPrototypes)
558 // -- sp[4] : callee js function
559 // -- sp[8] : call data
560 // -- sp[12] : last js argument
561 // -- ...
562 // -- sp[(argc + 3) * 4] : first js argument
563 // -- sp[(argc + 4) * 4] : receiver
564 // -----------------------------------
565 // Get the function and setup the context.
566 JSFunction* function = optimization.constant_function();
567 __ li(t1, Operand(Handle<JSFunction>(function)));
568 __ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset));
569
570 // Pass the additional arguments FastHandleApiCall expects.
571 Object* call_data = optimization.api_call_info()->data();
572 Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info());
573 if (masm->isolate()->heap()->InNewSpace(call_data)) {
574 __ li(a0, api_call_info_handle);
575 __ lw(t2, FieldMemOperand(a0, CallHandlerInfo::kDataOffset));
576 } else {
577 __ li(t2, Operand(Handle<Object>(call_data)));
578 }
579
580 // Store js function and call data.
581 __ sw(t1, MemOperand(sp, 1 * kPointerSize));
582 __ sw(t2, MemOperand(sp, 2 * kPointerSize));
583
584 // a2 points to call data as expected by Arguments
585 // (refer to layout above).
586 __ Addu(a2, sp, Operand(2 * kPointerSize));
587
588 Object* callback = optimization.api_call_info()->callback();
589 Address api_function_address = v8::ToCData<Address>(callback);
590 ApiFunction fun(api_function_address);
591
592 const int kApiStackSpace = 4;
593
594 __ EnterExitFrame(false, kApiStackSpace);
595
596 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
597 // struct from the function (which is currently the case). This means we pass
598 // the first argument in a1 instead of a0. TryCallApiFunctionAndReturn
599 // will handle setting up a0.
600
601 // a1 = v8::Arguments&
602 // Arguments is built at sp + 1 (sp is a reserved spot for ra).
603 __ Addu(a1, sp, kPointerSize);
604
605 // v8::Arguments::implicit_args = data
606 __ sw(a2, MemOperand(a1, 0 * kPointerSize));
607 // v8::Arguments::values = last argument
608 __ Addu(t0, a2, Operand(argc * kPointerSize));
609 __ sw(t0, MemOperand(a1, 1 * kPointerSize));
610 // v8::Arguments::length_ = argc
611 __ li(t0, Operand(argc));
612 __ sw(t0, MemOperand(a1, 2 * kPointerSize));
613 // v8::Arguments::is_construct_call = 0
614 __ sw(zero_reg, MemOperand(a1, 3 * kPointerSize));
615
616 // Emitting a stub call may try to allocate (if the code is not
617 // already generated). Do not allow the assembler to perform a
618 // garbage collection but instead return the allocation failure
619 // object.
620 const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
621 ExternalReference ref =
622 ExternalReference(&fun,
623 ExternalReference::DIRECT_API_CALL,
624 masm->isolate());
625 return masm->TryCallApiFunctionAndReturn(ref, kStackUnwindSpace);
626}
627
lrn@chromium.org7516f052011-03-30 08:52:27 +0000628class CallInterceptorCompiler BASE_EMBEDDED {
629 public:
630 CallInterceptorCompiler(StubCompiler* stub_compiler,
631 const ParameterCount& arguments,
632 Register name)
633 : stub_compiler_(stub_compiler),
634 arguments_(arguments),
635 name_(name) {}
636
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000637 MaybeObject* Compile(MacroAssembler* masm,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000638 JSObject* object,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000639 JSObject* holder,
640 String* name,
641 LookupResult* lookup,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000642 Register receiver,
643 Register scratch1,
644 Register scratch2,
645 Register scratch3,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000646 Label* miss) {
647 ASSERT(holder->HasNamedInterceptor());
648 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
649
650 // Check that the receiver isn't a smi.
651 __ JumpIfSmi(receiver, miss);
652
653 CallOptimization optimization(lookup);
654
655 if (optimization.is_constant_call()) {
656 return CompileCacheable(masm,
657 object,
658 receiver,
659 scratch1,
660 scratch2,
661 scratch3,
662 holder,
663 lookup,
664 name,
665 optimization,
666 miss);
667 } else {
668 CompileRegular(masm,
669 object,
670 receiver,
671 scratch1,
672 scratch2,
673 scratch3,
674 name,
675 holder,
676 miss);
677 return masm->isolate()->heap()->undefined_value();
678 }
679 }
680
681 private:
682 MaybeObject* CompileCacheable(MacroAssembler* masm,
683 JSObject* object,
684 Register receiver,
685 Register scratch1,
686 Register scratch2,
687 Register scratch3,
688 JSObject* interceptor_holder,
689 LookupResult* lookup,
690 String* name,
691 const CallOptimization& optimization,
692 Label* miss_label) {
693 ASSERT(optimization.is_constant_call());
694 ASSERT(!lookup->holder()->IsGlobalObject());
695
696 Counters* counters = masm->isolate()->counters();
697
698 int depth1 = kInvalidProtoDepth;
699 int depth2 = kInvalidProtoDepth;
700 bool can_do_fast_api_call = false;
701 if (optimization.is_simple_api_call() &&
702 !lookup->holder()->IsGlobalObject()) {
703 depth1 =
704 optimization.GetPrototypeDepthOfExpectedType(object,
705 interceptor_holder);
706 if (depth1 == kInvalidProtoDepth) {
707 depth2 =
708 optimization.GetPrototypeDepthOfExpectedType(interceptor_holder,
709 lookup->holder());
710 }
711 can_do_fast_api_call = (depth1 != kInvalidProtoDepth) ||
712 (depth2 != kInvalidProtoDepth);
713 }
714
715 __ IncrementCounter(counters->call_const_interceptor(), 1,
716 scratch1, scratch2);
717
718 if (can_do_fast_api_call) {
719 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
720 scratch1, scratch2);
721 ReserveSpaceForFastApiCall(masm, scratch1);
722 }
723
724 // Check that the maps from receiver to interceptor's holder
725 // haven't changed and thus we can invoke interceptor.
726 Label miss_cleanup;
727 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
728 Register holder =
729 stub_compiler_->CheckPrototypes(object, receiver,
730 interceptor_holder, scratch1,
731 scratch2, scratch3, name, depth1, miss);
732
733 // Invoke an interceptor and if it provides a value,
734 // branch to |regular_invoke|.
735 Label regular_invoke;
736 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
737 &regular_invoke);
738
739 // Interceptor returned nothing for this property. Try to use cached
740 // constant function.
741
742 // Check that the maps from interceptor's holder to constant function's
743 // holder haven't changed and thus we can use cached constant function.
744 if (interceptor_holder != lookup->holder()) {
745 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
746 lookup->holder(), scratch1,
747 scratch2, scratch3, name, depth2, miss);
748 } else {
749 // CheckPrototypes has a side effect of fetching a 'holder'
750 // for API (object which is instanceof for the signature). It's
751 // safe to omit it here, as if present, it should be fetched
752 // by the previous CheckPrototypes.
753 ASSERT(depth2 == kInvalidProtoDepth);
754 }
755
756 // Invoke function.
757 if (can_do_fast_api_call) {
758 MaybeObject* result = GenerateFastApiDirectCall(masm,
759 optimization,
760 arguments_.immediate());
761 if (result->IsFailure()) return result;
762 } else {
763 __ InvokeFunction(optimization.constant_function(), arguments_,
764 JUMP_FUNCTION);
765 }
766
767 // Deferred code for fast API call case---clean preallocated space.
768 if (can_do_fast_api_call) {
769 __ bind(&miss_cleanup);
770 FreeSpaceForFastApiCall(masm);
771 __ Branch(miss_label);
772 }
773
774 // Invoke a regular function.
775 __ bind(&regular_invoke);
776 if (can_do_fast_api_call) {
777 FreeSpaceForFastApiCall(masm);
778 }
779
780 return masm->isolate()->heap()->undefined_value();
lrn@chromium.org7516f052011-03-30 08:52:27 +0000781 }
782
783 void CompileRegular(MacroAssembler* masm,
784 JSObject* object,
785 Register receiver,
786 Register scratch1,
787 Register scratch2,
788 Register scratch3,
789 String* name,
790 JSObject* interceptor_holder,
791 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000792 Register holder =
793 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
794 scratch1, scratch2, scratch3, name,
795 miss_label);
796
797 // Call a runtime function to load the interceptor property.
798 __ EnterInternalFrame();
799 // Save the name_ register across the call.
800 __ push(name_);
801
802 PushInterceptorArguments(masm,
803 receiver,
804 holder,
805 name_,
806 interceptor_holder);
807
808 __ CallExternalReference(
809 ExternalReference(
810 IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
811 masm->isolate()),
812 5);
813
814 // Restore the name_ register.
815 __ pop(name_);
816 __ LeaveInternalFrame();
lrn@chromium.org7516f052011-03-30 08:52:27 +0000817 }
818
819 void LoadWithInterceptor(MacroAssembler* masm,
820 Register receiver,
821 Register holder,
822 JSObject* holder_obj,
823 Register scratch,
824 Label* interceptor_succeeded) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000825 __ EnterInternalFrame();
826
827 __ Push(holder, name_);
828
829 CompileCallLoadPropertyWithInterceptor(masm,
830 receiver,
831 holder,
832 name_,
833 holder_obj);
834
835 __ pop(name_); // Restore the name.
836 __ pop(receiver); // Restore the holder.
837 __ LeaveInternalFrame();
838
839 // If interceptor returns no-result sentinel, call the constant function.
840 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
841 __ Branch(interceptor_succeeded, ne, v0, Operand(scratch));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000842 }
843
844 StubCompiler* stub_compiler_;
845 const ParameterCount& arguments_;
846 Register name_;
847};
848
849
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000850
851// Generate code to check that a global property cell is empty. Create
852// the property cell at compilation time if no cell exists for the
853// property.
854MUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCell(
855 MacroAssembler* masm,
856 GlobalObject* global,
857 String* name,
858 Register scratch,
859 Label* miss) {
860 Object* probe;
861 { MaybeObject* maybe_probe = global->EnsurePropertyCell(name);
862 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
863 }
864 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
865 ASSERT(cell->value()->IsTheHole());
866 __ li(scratch, Operand(Handle<Object>(cell)));
867 __ lw(scratch,
868 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
869 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
870 __ Branch(miss, ne, scratch, Operand(at));
871 return cell;
872}
873
874
875// Calls GenerateCheckPropertyCell for each global object in the prototype chain
876// from object to (but not including) holder.
877MUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCells(
878 MacroAssembler* masm,
879 JSObject* object,
880 JSObject* holder,
881 String* name,
882 Register scratch,
883 Label* miss) {
884 JSObject* current = object;
885 while (current != holder) {
886 if (current->IsGlobalObject()) {
887 // Returns a cell or a failure.
888 MaybeObject* result = GenerateCheckPropertyCell(
889 masm,
890 GlobalObject::cast(current),
891 name,
892 scratch,
893 miss);
894 if (result->IsFailure()) return result;
895 }
896 ASSERT(current->IsJSObject());
897 current = JSObject::cast(current->GetPrototype());
898 }
899 return NULL;
900}
901
902
903// Convert and store int passed in register ival to IEEE 754 single precision
904// floating point value at memory location (dst + 4 * wordoffset)
905// If FPU is available use it for conversion.
906static void StoreIntAsFloat(MacroAssembler* masm,
907 Register dst,
908 Register wordoffset,
909 Register ival,
910 Register fval,
911 Register scratch1,
912 Register scratch2) {
913 if (CpuFeatures::IsSupported(FPU)) {
914 CpuFeatures::Scope scope(FPU);
915 __ mtc1(ival, f0);
916 __ cvt_s_w(f0, f0);
917 __ sll(scratch1, wordoffset, 2);
918 __ addu(scratch1, dst, scratch1);
919 __ swc1(f0, MemOperand(scratch1, 0));
920 } else {
921 // FPU is not available, do manual conversions.
922
923 Label not_special, done;
924 // Move sign bit from source to destination. This works because the sign
925 // bit in the exponent word of the double has the same position and polarity
926 // as the 2's complement sign bit in a Smi.
927 ASSERT(kBinary32SignMask == 0x80000000u);
928
929 __ And(fval, ival, Operand(kBinary32SignMask));
930 // Negate value if it is negative.
931 __ subu(scratch1, zero_reg, ival);
932 __ movn(ival, scratch1, fval);
933
934 // We have -1, 0 or 1, which we treat specially. Register ival contains
935 // absolute value: it is either equal to 1 (special case of -1 and 1),
936 // greater than 1 (not a special case) or less than 1 (special case of 0).
937 __ Branch(&not_special, gt, ival, Operand(1));
938
939 // For 1 or -1 we need to or in the 0 exponent (biased).
940 static const uint32_t exponent_word_for_1 =
941 kBinary32ExponentBias << kBinary32ExponentShift;
942
943 __ Xor(scratch1, ival, Operand(1));
944 __ li(scratch2, exponent_word_for_1);
945 __ or_(scratch2, fval, scratch2);
946 __ movz(fval, scratch2, scratch1); // Only if ival is equal to 1.
947 __ Branch(&done);
948
949 __ bind(&not_special);
950 // Count leading zeros.
951 // Gets the wrong answer for 0, but we already checked for that case above.
952 Register zeros = scratch2;
953 __ clz(zeros, ival);
954
955 // Compute exponent and or it into the exponent register.
956 __ li(scratch1, (kBitsPerInt - 1) + kBinary32ExponentBias);
957 __ subu(scratch1, scratch1, zeros);
958
959 __ sll(scratch1, scratch1, kBinary32ExponentShift);
960 __ or_(fval, fval, scratch1);
961
962 // Shift up the source chopping the top bit off.
963 __ Addu(zeros, zeros, Operand(1));
964 // This wouldn't work for 1 and -1 as the shift would be 32 which means 0.
965 __ sllv(ival, ival, zeros);
966 // And the top (top 20 bits).
967 __ srl(scratch1, ival, kBitsPerInt - kBinary32MantissaBits);
968 __ or_(fval, fval, scratch1);
969
970 __ bind(&done);
971
972 __ sll(scratch1, wordoffset, 2);
973 __ addu(scratch1, dst, scratch1);
974 __ sw(fval, MemOperand(scratch1, 0));
975 }
976}
977
978
979// Convert unsigned integer with specified number of leading zeroes in binary
980// representation to IEEE 754 double.
981// Integer to convert is passed in register hiword.
982// Resulting double is returned in registers hiword:loword.
983// This functions does not work correctly for 0.
984static void GenerateUInt2Double(MacroAssembler* masm,
985 Register hiword,
986 Register loword,
987 Register scratch,
988 int leading_zeroes) {
989 const int meaningful_bits = kBitsPerInt - leading_zeroes - 1;
990 const int biased_exponent = HeapNumber::kExponentBias + meaningful_bits;
991
992 const int mantissa_shift_for_hi_word =
993 meaningful_bits - HeapNumber::kMantissaBitsInTopWord;
994
995 const int mantissa_shift_for_lo_word =
996 kBitsPerInt - mantissa_shift_for_hi_word;
997
998 __ li(scratch, biased_exponent << HeapNumber::kExponentShift);
999 if (mantissa_shift_for_hi_word > 0) {
1000 __ sll(loword, hiword, mantissa_shift_for_lo_word);
1001 __ srl(hiword, hiword, mantissa_shift_for_hi_word);
1002 __ or_(hiword, scratch, hiword);
1003 } else {
1004 __ mov(loword, zero_reg);
1005 __ sll(hiword, hiword, mantissa_shift_for_hi_word);
1006 __ or_(hiword, scratch, hiword);
1007 }
1008
1009 // If least significant bit of biased exponent was not 1 it was corrupted
1010 // by most significant bit of mantissa so we should fix that.
1011 if (!(biased_exponent & 1)) {
1012 __ li(scratch, 1 << HeapNumber::kExponentShift);
1013 __ nor(scratch, scratch, scratch);
1014 __ and_(hiword, hiword, scratch);
1015 }
1016}
1017
1018
ager@chromium.org5c838252010-02-19 08:53:10 +00001019#undef __
1020#define __ ACCESS_MASM(masm())
1021
1022
lrn@chromium.org7516f052011-03-30 08:52:27 +00001023Register StubCompiler::CheckPrototypes(JSObject* object,
1024 Register object_reg,
1025 JSObject* holder,
1026 Register holder_reg,
1027 Register scratch1,
1028 Register scratch2,
1029 String* name,
1030 int save_at_depth,
1031 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001032 // Make sure there's no overlap between holder and object registers.
1033 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1034 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1035 && !scratch2.is(scratch1));
1036
1037 // Keep track of the current object in register reg.
1038 Register reg = object_reg;
1039 int depth = 0;
1040
1041 if (save_at_depth == depth) {
1042 __ sw(reg, MemOperand(sp));
1043 }
1044
1045 // Check the maps in the prototype chain.
1046 // Traverse the prototype chain from the object and do map checks.
1047 JSObject* current = object;
1048 while (current != holder) {
1049 depth++;
1050
1051 // Only global objects and objects that do not require access
1052 // checks are allowed in stubs.
1053 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1054
1055 ASSERT(current->GetPrototype()->IsJSObject());
1056 JSObject* prototype = JSObject::cast(current->GetPrototype());
1057 if (!current->HasFastProperties() &&
1058 !current->IsJSGlobalObject() &&
1059 !current->IsJSGlobalProxy()) {
1060 if (!name->IsSymbol()) {
1061 MaybeObject* maybe_lookup_result = heap()->LookupSymbol(name);
1062 Object* lookup_result = NULL; // Initialization to please compiler.
1063 if (!maybe_lookup_result->ToObject(&lookup_result)) {
1064 set_failure(Failure::cast(maybe_lookup_result));
1065 return reg;
1066 }
1067 name = String::cast(lookup_result);
1068 }
1069 ASSERT(current->property_dictionary()->FindEntry(name) ==
1070 StringDictionary::kNotFound);
1071
1072 MaybeObject* negative_lookup = GenerateDictionaryNegativeLookup(masm(),
1073 miss,
1074 reg,
1075 name,
1076 scratch1,
1077 scratch2);
1078 if (negative_lookup->IsFailure()) {
1079 set_failure(Failure::cast(negative_lookup));
1080 return reg;
1081 }
1082
1083 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1084 reg = holder_reg; // From now the object is in holder_reg.
1085 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1086 } else if (heap()->InNewSpace(prototype)) {
1087 // Get the map of the current object.
1088 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1089
1090 // Branch on the result of the map check.
1091 __ Branch(miss, ne, scratch1, Operand(Handle<Map>(current->map())));
1092
1093 // Check access rights to the global object. This has to happen
1094 // after the map check so that we know that the object is
1095 // actually a global object.
1096 if (current->IsJSGlobalProxy()) {
1097 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1098 // Restore scratch register to be the map of the object. In the
1099 // new space case below, we load the prototype from the map in
1100 // the scratch register.
1101 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1102 }
1103
1104 reg = holder_reg; // From now the object is in holder_reg.
1105 // The prototype is in new space; we cannot store a reference
1106 // to it in the code. Load it from the map.
1107 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1108 } else {
1109 // Check the map of the current object.
1110 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1111 // Branch on the result of the map check.
1112 __ Branch(miss, ne, scratch1, Operand(Handle<Map>(current->map())));
1113 // Check access rights to the global object. This has to happen
1114 // after the map check so that we know that the object is
1115 // actually a global object.
1116 if (current->IsJSGlobalProxy()) {
1117 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1118 }
1119 // The prototype is in old space; load it directly.
1120 reg = holder_reg; // From now the object is in holder_reg.
1121 __ li(reg, Operand(Handle<JSObject>(prototype)));
1122 }
1123
1124 if (save_at_depth == depth) {
1125 __ sw(reg, MemOperand(sp));
1126 }
1127
1128 // Go to the next object in the prototype chain.
1129 current = prototype;
1130 }
1131
1132 // Check the holder map.
1133 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1134 __ Branch(miss, ne, scratch1, Operand(Handle<Map>(current->map())));
1135
1136 // Log the check depth.
1137 LOG(masm()->isolate(), IntEvent("check-maps-depth", depth + 1));
1138 // Perform security check for access to the global object.
1139 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1140 if (holder->IsJSGlobalProxy()) {
1141 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1142 };
1143
1144 // If we've skipped any global objects, it's not enough to verify
1145 // that their maps haven't changed. We also need to check that the
1146 // property cell for the property is still empty.
1147
1148 MaybeObject* result = GenerateCheckPropertyCells(masm(),
1149 object,
1150 holder,
1151 name,
1152 scratch1,
1153 miss);
1154 if (result->IsFailure()) set_failure(Failure::cast(result));
1155
1156 // Return the register containing the holder.
1157 return reg;
lrn@chromium.org7516f052011-03-30 08:52:27 +00001158}
1159
1160
ager@chromium.org5c838252010-02-19 08:53:10 +00001161void StubCompiler::GenerateLoadField(JSObject* object,
1162 JSObject* holder,
1163 Register receiver,
1164 Register scratch1,
1165 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001166 Register scratch3,
ager@chromium.org5c838252010-02-19 08:53:10 +00001167 int index,
1168 String* name,
1169 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001170 // Check that the receiver isn't a smi.
1171 __ And(scratch1, receiver, Operand(kSmiTagMask));
1172 __ Branch(miss, eq, scratch1, Operand(zero_reg));
1173
1174 // Check that the maps haven't changed.
1175 Register reg =
1176 CheckPrototypes(object, receiver, holder, scratch1, scratch2, scratch3,
1177 name, miss);
1178 GenerateFastPropertyLoad(masm(), v0, reg, holder, index);
1179 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001180}
1181
1182
1183void StubCompiler::GenerateLoadConstant(JSObject* object,
1184 JSObject* holder,
1185 Register receiver,
1186 Register scratch1,
1187 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001188 Register scratch3,
ager@chromium.org5c838252010-02-19 08:53:10 +00001189 Object* value,
1190 String* name,
1191 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001192 // Check that the receiver isn't a smi.
1193 __ JumpIfSmi(receiver, miss, scratch1);
1194
1195 // Check that the maps haven't changed.
1196 Register reg =
1197 CheckPrototypes(object, receiver, holder,
1198 scratch1, scratch2, scratch3, name, miss);
1199
1200 // Return the constant value.
1201 __ li(v0, Operand(Handle<Object>(value)));
1202 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001203}
1204
1205
lrn@chromium.org7516f052011-03-30 08:52:27 +00001206MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object,
1207 JSObject* holder,
1208 Register receiver,
1209 Register name_reg,
1210 Register scratch1,
1211 Register scratch2,
1212 Register scratch3,
1213 AccessorInfo* callback,
1214 String* name,
1215 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001216 // Check that the receiver isn't a smi.
1217 __ JumpIfSmi(receiver, miss, scratch1);
1218
1219 // Check that the maps haven't changed.
1220 Register reg =
1221 CheckPrototypes(object, receiver, holder, scratch1, scratch2, scratch3,
1222 name, miss);
1223
1224 // Build AccessorInfo::args_ list on the stack and push property name below
1225 // the exit frame to make GC aware of them and store pointers to them.
1226 __ push(receiver);
1227 __ mov(scratch2, sp); // scratch2 = AccessorInfo::args_
1228 Handle<AccessorInfo> callback_handle(callback);
1229 if (heap()->InNewSpace(callback_handle->data())) {
1230 __ li(scratch3, callback_handle);
1231 __ lw(scratch3, FieldMemOperand(scratch3, AccessorInfo::kDataOffset));
1232 } else {
1233 __ li(scratch3, Handle<Object>(callback_handle->data()));
1234 }
1235 __ Push(reg, scratch3, name_reg);
1236 __ mov(a2, scratch2); // Saved in case scratch2 == a1.
1237 __ mov(a1, sp); // a1 (first argument - see note below) = Handle<String>
1238
1239 Address getter_address = v8::ToCData<Address>(callback->getter());
1240 ApiFunction fun(getter_address);
1241
1242 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
1243 // struct from the function (which is currently the case). This means we pass
1244 // the arguments in a1-a2 instead of a0-a1. TryCallApiFunctionAndReturn
1245 // will handle setting up a0.
1246
1247 const int kApiStackSpace = 1;
1248
1249 __ EnterExitFrame(false, kApiStackSpace);
1250 // Create AccessorInfo instance on the stack above the exit frame with
1251 // scratch2 (internal::Object **args_) as the data.
1252 __ sw(a2, MemOperand(sp, kPointerSize));
1253 // a2 (second argument - see note above) = AccessorInfo&
1254 __ Addu(a2, sp, kPointerSize);
1255
1256 // Emitting a stub call may try to allocate (if the code is not
1257 // already generated). Do not allow the assembler to perform a
1258 // garbage collection but instead return the allocation failure
1259 // object.
1260 ExternalReference ref =
1261 ExternalReference(&fun,
1262 ExternalReference::DIRECT_GETTER_CALL,
1263 masm()->isolate());
1264 // 4 args - will be freed later by LeaveExitFrame.
1265 return masm()->TryCallApiFunctionAndReturn(ref, 4);
ager@chromium.org5c838252010-02-19 08:53:10 +00001266}
1267
1268
1269void StubCompiler::GenerateLoadInterceptor(JSObject* object,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001270 JSObject* interceptor_holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001271 LookupResult* lookup,
1272 Register receiver,
1273 Register name_reg,
1274 Register scratch1,
1275 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001276 Register scratch3,
ager@chromium.org5c838252010-02-19 08:53:10 +00001277 String* name,
1278 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001279 ASSERT(interceptor_holder->HasNamedInterceptor());
1280 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1281
1282 // Check that the receiver isn't a smi.
1283 __ JumpIfSmi(receiver, miss);
1284
1285 // So far the most popular follow ups for interceptor loads are FIELD
1286 // and CALLBACKS, so inline only them, other cases may be added
1287 // later.
1288 bool compile_followup_inline = false;
1289 if (lookup->IsProperty() && lookup->IsCacheable()) {
1290 if (lookup->type() == FIELD) {
1291 compile_followup_inline = true;
1292 } else if (lookup->type() == CALLBACKS &&
1293 lookup->GetCallbackObject()->IsAccessorInfo() &&
1294 AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) {
1295 compile_followup_inline = true;
1296 }
1297 }
1298
1299 if (compile_followup_inline) {
1300 // Compile the interceptor call, followed by inline code to load the
1301 // property from further up the prototype chain if the call fails.
1302 // Check that the maps haven't changed.
1303 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1304 scratch1, scratch2, scratch3,
1305 name, miss);
1306 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
1307
1308 // Save necessary data before invoking an interceptor.
1309 // Requires a frame to make GC aware of pushed pointers.
1310 __ EnterInternalFrame();
1311
1312 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
1313 // CALLBACKS case needs a receiver to be passed into C++ callback.
1314 __ Push(receiver, holder_reg, name_reg);
1315 } else {
1316 __ Push(holder_reg, name_reg);
1317 }
1318
1319 // Invoke an interceptor. Note: map checks from receiver to
1320 // interceptor's holder has been compiled before (see a caller
1321 // of this method).
1322 CompileCallLoadPropertyWithInterceptor(masm(),
1323 receiver,
1324 holder_reg,
1325 name_reg,
1326 interceptor_holder);
1327
1328 // Check if interceptor provided a value for property. If it's
1329 // the case, return immediately.
1330 Label interceptor_failed;
1331 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
1332 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1));
1333 __ LeaveInternalFrame();
1334 __ Ret();
1335
1336 __ bind(&interceptor_failed);
1337 __ pop(name_reg);
1338 __ pop(holder_reg);
1339 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
1340 __ pop(receiver);
1341 }
1342
1343 __ LeaveInternalFrame();
1344
1345 // Check that the maps from interceptor's holder to lookup's holder
1346 // haven't changed. And load lookup's holder into |holder| register.
1347 if (interceptor_holder != lookup->holder()) {
1348 holder_reg = CheckPrototypes(interceptor_holder,
1349 holder_reg,
1350 lookup->holder(),
1351 scratch1,
1352 scratch2,
1353 scratch3,
1354 name,
1355 miss);
1356 }
1357
1358 if (lookup->type() == FIELD) {
1359 // We found FIELD property in prototype chain of interceptor's holder.
1360 // Retrieve a field from field's holder.
1361 GenerateFastPropertyLoad(masm(), v0, holder_reg,
1362 lookup->holder(), lookup->GetFieldIndex());
1363 __ Ret();
1364 } else {
1365 // We found CALLBACKS property in prototype chain of interceptor's
1366 // holder.
1367 ASSERT(lookup->type() == CALLBACKS);
1368 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
1369 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
1370 ASSERT(callback != NULL);
1371 ASSERT(callback->getter() != NULL);
1372
1373 // Tail call to runtime.
1374 // Important invariant in CALLBACKS case: the code above must be
1375 // structured to never clobber |receiver| register.
1376 __ li(scratch2, Handle<AccessorInfo>(callback));
1377 // holder_reg is either receiver or scratch1.
1378 if (!receiver.is(holder_reg)) {
1379 ASSERT(scratch1.is(holder_reg));
1380 __ Push(receiver, holder_reg);
1381 __ lw(scratch3,
1382 FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
1383 __ Push(scratch3, scratch2, name_reg);
1384 } else {
1385 __ push(receiver);
1386 __ lw(scratch3,
1387 FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
1388 __ Push(holder_reg, scratch3, scratch2, name_reg);
1389 }
1390
1391 ExternalReference ref =
1392 ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
1393 masm()->isolate());
1394 __ TailCallExternalReference(ref, 5, 1);
1395 }
1396 } else { // !compile_followup_inline
1397 // Call the runtime system to load the interceptor.
1398 // Check that the maps haven't changed.
1399 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1400 scratch1, scratch2, scratch3,
1401 name, miss);
1402 PushInterceptorArguments(masm(), receiver, holder_reg,
1403 name_reg, interceptor_holder);
1404
1405 ExternalReference ref = ExternalReference(
1406 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), masm()->isolate());
1407 __ TailCallExternalReference(ref, 5, 1);
1408 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001409}
1410
1411
lrn@chromium.org7516f052011-03-30 08:52:27 +00001412void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001413 if (kind_ == Code::KEYED_CALL_IC) {
1414 __ Branch(miss, ne, a2, Operand(Handle<String>(name)));
1415 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001416}
1417
1418
lrn@chromium.org7516f052011-03-30 08:52:27 +00001419void CallStubCompiler::GenerateGlobalReceiverCheck(JSObject* object,
1420 JSObject* holder,
1421 String* name,
1422 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001423 ASSERT(holder->IsGlobalObject());
1424
1425 // Get the number of arguments.
1426 const int argc = arguments().immediate();
1427
1428 // Get the receiver from the stack.
1429 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1430
1431 // If the object is the holder then we know that it's a global
1432 // object which can only happen for contextual calls. In this case,
1433 // the receiver cannot be a smi.
1434 if (object != holder) {
1435 __ JumpIfSmi(a0, miss);
1436 }
1437
1438 // Check that the maps haven't changed.
1439 CheckPrototypes(object, a0, holder, a3, a1, t0, name, miss);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001440}
1441
1442
lrn@chromium.org7516f052011-03-30 08:52:27 +00001443void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell,
1444 JSFunction* function,
1445 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001446 // Get the value from the cell.
1447 __ li(a3, Operand(Handle<JSGlobalPropertyCell>(cell)));
1448 __ lw(a1, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
1449
1450 // Check that the cell contains the same function.
1451 if (heap()->InNewSpace(function)) {
1452 // We can't embed a pointer to a function in new space so we have
1453 // to verify that the shared function info is unchanged. This has
1454 // the nice side effect that multiple closures based on the same
1455 // function can all use this call IC. Before we load through the
1456 // function, we have to verify that it still is a function.
1457 __ JumpIfSmi(a1, miss);
1458 __ GetObjectType(a1, a3, a3);
1459 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
1460
1461 // Check the shared function info. Make sure it hasn't changed.
1462 __ li(a3, Handle<SharedFunctionInfo>(function->shared()));
1463 __ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
1464 __ Branch(miss, ne, t0, Operand(a3));
1465 } else {
1466 __ Branch(miss, ne, a1, Operand(Handle<JSFunction>(function)));
1467 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001468}
1469
1470
lrn@chromium.org7516f052011-03-30 08:52:27 +00001471MaybeObject* CallStubCompiler::GenerateMissBranch() {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001472 MaybeObject* maybe_obj = masm()->isolate()->stub_cache()->ComputeCallMiss(
1473 arguments().immediate(), kind_);
1474 Object* obj;
1475 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1476 __ Jump(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET);
1477 return obj;
ager@chromium.org5c838252010-02-19 08:53:10 +00001478}
1479
1480
lrn@chromium.org7516f052011-03-30 08:52:27 +00001481MaybeObject* CallStubCompiler::CompileCallField(JSObject* object,
1482 JSObject* holder,
1483 int index,
ager@chromium.org5c838252010-02-19 08:53:10 +00001484 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001485 // ----------- S t a t e -------------
1486 // -- a2 : name
1487 // -- ra : return address
1488 // -----------------------------------
1489 Label miss;
1490
1491 GenerateNameCheck(name, &miss);
1492
1493 const int argc = arguments().immediate();
1494
1495 // Get the receiver of the function from the stack into a0.
1496 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1497 // Check that the receiver isn't a smi.
1498 __ JumpIfSmi(a0, &miss, t0);
1499
1500 // Do the right check and compute the holder register.
1501 Register reg = CheckPrototypes(object, a0, holder, a1, a3, t0, name, &miss);
1502 GenerateFastPropertyLoad(masm(), a1, reg, holder, index);
1503
1504 GenerateCallFunction(masm(), object, arguments(), &miss);
1505
1506 // Handle call cache miss.
1507 __ bind(&miss);
1508 MaybeObject* maybe_result = GenerateMissBranch();
1509 if (maybe_result->IsFailure()) return maybe_result;
1510
1511 // Return the generated code.
1512 return GetCode(FIELD, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001513}
1514
1515
lrn@chromium.org7516f052011-03-30 08:52:27 +00001516MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
1517 JSObject* holder,
1518 JSGlobalPropertyCell* cell,
1519 JSFunction* function,
1520 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001521 // ----------- S t a t e -------------
1522 // -- a2 : name
1523 // -- ra : return address
1524 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1525 // -- ...
1526 // -- sp[argc * 4] : receiver
1527 // -----------------------------------
1528
1529 // If object is not an array, bail out to regular call.
1530 if (!object->IsJSArray() || cell != NULL) return heap()->undefined_value();
1531
1532 Label miss;
1533
1534 GenerateNameCheck(name, &miss);
1535
1536 Register receiver = a1;
1537
1538 // Get the receiver from the stack.
1539 const int argc = arguments().immediate();
1540 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1541
1542 // Check that the receiver isn't a smi.
1543 __ JumpIfSmi(receiver, &miss);
1544
1545 // Check that the maps haven't changed.
1546 CheckPrototypes(JSObject::cast(object), receiver,
1547 holder, a3, v0, t0, name, &miss);
1548
1549 if (argc == 0) {
1550 // Nothing to do, just return the length.
1551 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1552 __ Drop(argc + 1);
1553 __ Ret();
1554 } else {
1555 Label call_builtin;
1556
1557 Register elements = a3;
1558 Register end_elements = t1;
1559
1560 // Get the elements array of the object.
1561 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1562
1563 // Check that the elements are in fast mode and writable.
1564 __ CheckMap(elements, v0,
1565 Heap::kFixedArrayMapRootIndex, &call_builtin, true);
1566
1567 if (argc == 1) { // Otherwise fall through to call the builtin.
1568 Label exit, with_write_barrier, attempt_to_grow_elements;
1569
1570 // Get the array's length into v0 and calculate new length.
1571 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1572 STATIC_ASSERT(kSmiTagSize == 1);
1573 STATIC_ASSERT(kSmiTag == 0);
1574 __ Addu(v0, v0, Operand(Smi::FromInt(argc)));
1575
1576 // Get the element's length.
1577 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1578
1579 // Check if we could survive without allocation.
1580 __ Branch(&attempt_to_grow_elements, gt, v0, Operand(t0));
1581
1582 // Save new length.
1583 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1584
1585 // Push the element.
1586 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1587 // We may need a register containing the address end_elements below,
1588 // so write back the value in end_elements.
1589 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1590 __ Addu(end_elements, elements, end_elements);
1591 const int kEndElementsOffset =
1592 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
1593 __ sw(t0, MemOperand(end_elements, kEndElementsOffset));
1594 __ Addu(end_elements, end_elements, kPointerSize);
1595
1596 // Check for a smi.
1597 __ JumpIfNotSmi(t0, &with_write_barrier);
1598 __ bind(&exit);
1599 __ Drop(argc + 1);
1600 __ Ret();
1601
1602 __ bind(&with_write_barrier);
1603 __ InNewSpace(elements, t0, eq, &exit);
1604 __ RecordWriteHelper(elements, end_elements, t0);
1605 __ Drop(argc + 1);
1606 __ Ret();
1607
1608 __ bind(&attempt_to_grow_elements);
1609 // v0: array's length + 1.
1610 // t0: elements' length.
1611
1612 if (!FLAG_inline_new) {
1613 __ Branch(&call_builtin);
1614 }
1615
1616 ExternalReference new_space_allocation_top =
1617 ExternalReference::new_space_allocation_top_address(
1618 masm()->isolate());
1619 ExternalReference new_space_allocation_limit =
1620 ExternalReference::new_space_allocation_limit_address(
1621 masm()->isolate());
1622
1623 const int kAllocationDelta = 4;
1624 // Load top and check if it is the end of elements.
1625 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1626 __ Addu(end_elements, elements, end_elements);
1627 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset));
1628 __ li(t3, Operand(new_space_allocation_top));
1629 __ lw(t2, MemOperand(t3));
1630 __ Branch(&call_builtin, ne, end_elements, Operand(t2));
1631
1632 __ li(t5, Operand(new_space_allocation_limit));
1633 __ lw(t5, MemOperand(t5));
1634 __ Addu(t2, t2, Operand(kAllocationDelta * kPointerSize));
1635 __ Branch(&call_builtin, hi, t2, Operand(t5));
1636
1637 // We fit and could grow elements.
1638 // Update new_space_allocation_top.
1639 __ sw(t2, MemOperand(t3));
1640 // Push the argument.
1641 __ lw(t2, MemOperand(sp, (argc - 1) * kPointerSize));
1642 __ sw(t2, MemOperand(end_elements));
1643 // Fill the rest with holes.
1644 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1645 for (int i = 1; i < kAllocationDelta; i++) {
1646 __ sw(t2, MemOperand(end_elements, i * kPointerSize));
1647 }
1648
1649 // Update elements' and array's sizes.
1650 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1651 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta)));
1652 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1653
1654 // Elements are in new space, so write barrier is not required.
1655 __ Drop(argc + 1);
1656 __ Ret();
1657 }
1658 __ bind(&call_builtin);
1659 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
1660 masm()->isolate()),
1661 argc + 1,
1662 1);
1663 }
1664
1665 // Handle call cache miss.
1666 __ bind(&miss);
1667 MaybeObject* maybe_result = GenerateMissBranch();
1668 if (maybe_result->IsFailure()) return maybe_result;
1669
1670 // Return the generated code.
1671 return GetCode(function);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001672}
1673
1674
1675MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object,
1676 JSObject* holder,
1677 JSGlobalPropertyCell* cell,
1678 JSFunction* function,
ager@chromium.org5c838252010-02-19 08:53:10 +00001679 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001680 // ----------- S t a t e -------------
1681 // -- a2 : name
1682 // -- ra : return address
1683 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1684 // -- ...
1685 // -- sp[argc * 4] : receiver
1686 // -----------------------------------
1687
1688 // If object is not an array, bail out to regular call.
1689 if (!object->IsJSArray() || cell != NULL) return heap()->undefined_value();
1690
1691 Label miss, return_undefined, call_builtin;
1692
1693 Register receiver = a1;
1694 Register elements = a3;
1695
1696 GenerateNameCheck(name, &miss);
1697
1698 // Get the receiver from the stack.
1699 const int argc = arguments().immediate();
1700 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1701
1702 // Check that the receiver isn't a smi.
1703 __ JumpIfSmi(receiver, &miss);
1704
1705 // Check that the maps haven't changed.
1706 CheckPrototypes(JSObject::cast(object),
1707 receiver, holder, elements, t0, v0, name, &miss);
1708
1709 // Get the elements array of the object.
1710 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1711
1712 // Check that the elements are in fast mode and writable.
1713 __ CheckMap(elements, v0, Heap::kFixedArrayMapRootIndex, &call_builtin, true);
1714
1715 // Get the array's length into t0 and calculate new length.
1716 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1717 __ Subu(t0, t0, Operand(Smi::FromInt(1)));
1718 __ Branch(&return_undefined, lt, t0, Operand(zero_reg));
1719
1720 // Get the last element.
1721 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1722 STATIC_ASSERT(kSmiTagSize == 1);
1723 STATIC_ASSERT(kSmiTag == 0);
1724 // We can't address the last element in one operation. Compute the more
1725 // expensive shift first, and use an offset later on.
1726 __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize);
1727 __ Addu(elements, elements, t1);
1728 __ lw(v0, MemOperand(elements, FixedArray::kHeaderSize - kHeapObjectTag));
1729 __ Branch(&call_builtin, eq, v0, Operand(t2));
1730
1731 // Set the array's length.
1732 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1733
1734 // Fill with the hole.
1735 __ sw(t2, MemOperand(elements, FixedArray::kHeaderSize - kHeapObjectTag));
1736 __ Drop(argc + 1);
1737 __ Ret();
1738
1739 __ bind(&return_undefined);
1740 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
1741 __ Drop(argc + 1);
1742 __ Ret();
1743
1744 __ bind(&call_builtin);
1745 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop,
1746 masm()->isolate()),
1747 argc + 1,
1748 1);
1749
1750 // Handle call cache miss.
1751 __ bind(&miss);
1752 MaybeObject* maybe_result = GenerateMissBranch();
1753 if (maybe_result->IsFailure()) return maybe_result;
1754
1755 // Return the generated code.
1756 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001757}
1758
1759
lrn@chromium.org7516f052011-03-30 08:52:27 +00001760MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
1761 Object* object,
1762 JSObject* holder,
1763 JSGlobalPropertyCell* cell,
1764 JSFunction* function,
1765 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001766 // ----------- S t a t e -------------
1767 // -- a2 : function name
1768 // -- ra : return address
1769 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1770 // -- ...
1771 // -- sp[argc * 4] : receiver
1772 // -----------------------------------
1773
1774 // If object is not a string, bail out to regular call.
1775 if (!object->IsString() || cell != NULL) return heap()->undefined_value();
1776
1777 const int argc = arguments().immediate();
1778
1779 Label miss;
1780 Label name_miss;
1781 Label index_out_of_range;
1782
1783 Label* index_out_of_range_label = &index_out_of_range;
1784
1785 if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) {
1786 index_out_of_range_label = &miss;
1787 }
1788
1789 GenerateNameCheck(name, &name_miss);
1790
1791 // Check that the maps starting from the prototype haven't changed.
1792 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1793 Context::STRING_FUNCTION_INDEX,
1794 v0,
1795 &miss);
1796 ASSERT(object != holder);
1797 CheckPrototypes(JSObject::cast(object->GetPrototype()), v0, holder,
1798 a1, a3, t0, name, &miss);
1799
1800 Register receiver = a1;
1801 Register index = t1;
1802 Register scratch = a3;
1803 Register result = v0;
1804 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1805 if (argc > 0) {
1806 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1807 } else {
1808 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1809 }
1810
1811 StringCharCodeAtGenerator char_code_at_generator(receiver,
1812 index,
1813 scratch,
1814 result,
1815 &miss, // When not a string.
1816 &miss, // When not a number.
1817 index_out_of_range_label,
1818 STRING_INDEX_IS_NUMBER);
1819 char_code_at_generator.GenerateFast(masm());
1820 __ Drop(argc + 1);
1821 __ Ret();
1822
1823 StubRuntimeCallHelper call_helper;
1824 char_code_at_generator.GenerateSlow(masm(), call_helper);
1825
1826 if (index_out_of_range.is_linked()) {
1827 __ bind(&index_out_of_range);
1828 __ LoadRoot(v0, Heap::kNanValueRootIndex);
1829 __ Drop(argc + 1);
1830 __ Ret();
1831 }
1832
1833 __ bind(&miss);
1834 // Restore function name in a2.
1835 __ li(a2, Handle<String>(name));
1836 __ bind(&name_miss);
1837 MaybeObject* maybe_result = GenerateMissBranch();
1838 if (maybe_result->IsFailure()) return maybe_result;
1839
1840 // Return the generated code.
1841 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001842}
1843
1844
lrn@chromium.org7516f052011-03-30 08:52:27 +00001845MaybeObject* CallStubCompiler::CompileStringCharAtCall(
1846 Object* object,
1847 JSObject* holder,
1848 JSGlobalPropertyCell* cell,
1849 JSFunction* function,
1850 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001851 // ----------- S t a t e -------------
1852 // -- a2 : function name
1853 // -- ra : return address
1854 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1855 // -- ...
1856 // -- sp[argc * 4] : receiver
1857 // -----------------------------------
1858
1859 // If object is not a string, bail out to regular call.
1860 if (!object->IsString() || cell != NULL) return heap()->undefined_value();
1861
1862 const int argc = arguments().immediate();
1863
1864 Label miss;
1865 Label name_miss;
1866 Label index_out_of_range;
1867 Label* index_out_of_range_label = &index_out_of_range;
1868
1869 if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) {
1870 index_out_of_range_label = &miss;
1871 }
1872
1873 GenerateNameCheck(name, &name_miss);
1874
1875 // Check that the maps starting from the prototype haven't changed.
1876 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1877 Context::STRING_FUNCTION_INDEX,
1878 v0,
1879 &miss);
1880 ASSERT(object != holder);
1881 CheckPrototypes(JSObject::cast(object->GetPrototype()), v0, holder,
1882 a1, a3, t0, name, &miss);
1883
1884 Register receiver = v0;
1885 Register index = t1;
1886 Register scratch1 = a1;
1887 Register scratch2 = a3;
1888 Register result = v0;
1889 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1890 if (argc > 0) {
1891 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1892 } else {
1893 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1894 }
1895
1896 StringCharAtGenerator char_at_generator(receiver,
1897 index,
1898 scratch1,
1899 scratch2,
1900 result,
1901 &miss, // When not a string.
1902 &miss, // When not a number.
1903 index_out_of_range_label,
1904 STRING_INDEX_IS_NUMBER);
1905 char_at_generator.GenerateFast(masm());
1906 __ Drop(argc + 1);
1907 __ Ret();
1908
1909 StubRuntimeCallHelper call_helper;
1910 char_at_generator.GenerateSlow(masm(), call_helper);
1911
1912 if (index_out_of_range.is_linked()) {
1913 __ bind(&index_out_of_range);
1914 __ LoadRoot(v0, Heap::kEmptyStringRootIndex);
1915 __ Drop(argc + 1);
1916 __ Ret();
1917 }
1918
1919 __ bind(&miss);
1920 // Restore function name in a2.
1921 __ li(a2, Handle<String>(name));
1922 __ bind(&name_miss);
1923 MaybeObject* maybe_result = GenerateMissBranch();
1924 if (maybe_result->IsFailure()) return maybe_result;
1925
1926 // Return the generated code.
1927 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001928}
1929
1930
lrn@chromium.org7516f052011-03-30 08:52:27 +00001931MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall(
1932 Object* object,
1933 JSObject* holder,
1934 JSGlobalPropertyCell* cell,
1935 JSFunction* function,
1936 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001937 // ----------- S t a t e -------------
1938 // -- a2 : function name
1939 // -- ra : return address
1940 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1941 // -- ...
1942 // -- sp[argc * 4] : receiver
1943 // -----------------------------------
1944
1945 const int argc = arguments().immediate();
1946
1947 // If the object is not a JSObject or we got an unexpected number of
1948 // arguments, bail out to the regular call.
1949 if (!object->IsJSObject() || argc != 1) return heap()->undefined_value();
1950
1951 Label miss;
1952 GenerateNameCheck(name, &miss);
1953
1954 if (cell == NULL) {
1955 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
1956
1957 STATIC_ASSERT(kSmiTag == 0);
1958 __ JumpIfSmi(a1, &miss);
1959
1960 CheckPrototypes(JSObject::cast(object), a1, holder, v0, a3, t0, name,
1961 &miss);
1962 } else {
1963 ASSERT(cell->value() == function);
1964 GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
1965 GenerateLoadFunctionFromCell(cell, function, &miss);
1966 }
1967
1968 // Load the char code argument.
1969 Register code = a1;
1970 __ lw(code, MemOperand(sp, 0 * kPointerSize));
1971
1972 // Check the code is a smi.
1973 Label slow;
1974 STATIC_ASSERT(kSmiTag == 0);
1975 __ JumpIfNotSmi(code, &slow);
1976
1977 // Convert the smi code to uint16.
1978 __ And(code, code, Operand(Smi::FromInt(0xffff)));
1979
1980 StringCharFromCodeGenerator char_from_code_generator(code, v0);
1981 char_from_code_generator.GenerateFast(masm());
1982 __ Drop(argc + 1);
1983 __ Ret();
1984
1985 StubRuntimeCallHelper call_helper;
1986 char_from_code_generator.GenerateSlow(masm(), call_helper);
1987
1988 // Tail call the full function. We do not have to patch the receiver
1989 // because the function makes no use of it.
1990 __ bind(&slow);
1991 __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
1992
1993 __ bind(&miss);
1994 // a2: function name.
1995 MaybeObject* maybe_result = GenerateMissBranch();
1996 if (maybe_result->IsFailure()) return maybe_result;
1997
1998 // Return the generated code.
1999 return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002000}
2001
2002
lrn@chromium.org7516f052011-03-30 08:52:27 +00002003MaybeObject* CallStubCompiler::CompileMathFloorCall(Object* object,
2004 JSObject* holder,
2005 JSGlobalPropertyCell* cell,
2006 JSFunction* function,
2007 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002008 // ----------- S t a t e -------------
2009 // -- a2 : function name
2010 // -- ra : return address
2011 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2012 // -- ...
2013 // -- sp[argc * 4] : receiver
2014 // -----------------------------------
2015
2016 if (!CpuFeatures::IsSupported(FPU))
2017 return heap()->undefined_value();
2018 CpuFeatures::Scope scope_fpu(FPU);
2019
2020 const int argc = arguments().immediate();
2021
2022 // If the object is not a JSObject or we got an unexpected number of
2023 // arguments, bail out to the regular call.
2024 if (!object->IsJSObject() || argc != 1) return heap()->undefined_value();
2025
2026 Label miss, slow;
2027 GenerateNameCheck(name, &miss);
2028
2029 if (cell == NULL) {
2030 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
2031
2032 STATIC_ASSERT(kSmiTag == 0);
2033 __ JumpIfSmi(a1, &miss);
2034
2035 CheckPrototypes(JSObject::cast(object), a1, holder, a0, a3, t0, name,
2036 &miss);
2037 } else {
2038 ASSERT(cell->value() == function);
2039 GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
2040 GenerateLoadFunctionFromCell(cell, function, &miss);
2041 }
2042
2043 // Load the (only) argument into v0.
2044 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2045
2046 // If the argument is a smi, just return.
2047 STATIC_ASSERT(kSmiTag == 0);
2048 __ And(t0, v0, Operand(kSmiTagMask));
2049 __ Drop(argc + 1, eq, t0, Operand(zero_reg));
2050 __ Ret(eq, t0, Operand(zero_reg));
2051
2052 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, true);
2053
2054 Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return;
2055
2056 // If fpu is enabled, we use the floor instruction.
2057
2058 // Load the HeapNumber value.
2059 __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2060
2061 // Backup FCSR.
2062 __ cfc1(a3, FCSR);
2063 // Clearing FCSR clears the exception mask with no side-effects.
2064 __ ctc1(zero_reg, FCSR);
2065 // Convert the argument to an integer.
2066 __ floor_w_d(f0, f0);
2067
2068 // Start checking for special cases.
2069 // Get the argument exponent and clear the sign bit.
2070 __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize));
2071 __ And(t2, t1, Operand(~HeapNumber::kSignMask));
2072 __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord);
2073
2074 // Retrieve FCSR and check for fpu errors.
2075 __ cfc1(t5, FCSR);
2076 __ srl(t5, t5, kFCSRFlagShift);
2077 // Flag 1 marks an inaccurate but still good result so we ignore it.
2078 __ And(t5, t5, Operand(kFCSRFlagMask ^ 1));
2079 __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));
2080
2081 // Check for NaN, Infinity, and -Infinity.
2082 // They are invariant through a Math.Floor call, so just
2083 // return the original argument.
2084 __ Subu(t3, t2, Operand(HeapNumber::kExponentMask
2085 >> HeapNumber::kMantissaBitsInTopWord));
2086 __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg));
2087 // We had an overflow or underflow in the conversion. Check if we
2088 // have a big exponent.
2089 // If greater or equal, the argument is already round and in v0.
2090 __ Branch(&restore_fcsr_and_return, ge, t3,
2091 Operand(HeapNumber::kMantissaBits));
2092 __ Branch(&wont_fit_smi);
2093
2094 __ bind(&no_fpu_error);
2095 // Move the result back to v0.
2096 __ mfc1(v0, f0);
2097 // Check if the result fits into a smi.
2098 __ Addu(a1, v0, Operand(0x40000000));
2099 __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg));
2100 // Tag the result.
2101 STATIC_ASSERT(kSmiTag == 0);
2102 __ sll(v0, v0, kSmiTagSize);
2103
2104 // Check for -0.
2105 __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg));
2106 // t1 already holds the HeapNumber exponent.
2107 __ And(t0, t1, Operand(HeapNumber::kSignMask));
2108 // If our HeapNumber is negative it was -0, so load its address and return.
2109 // Else v0 is loaded with 0, so we can also just return.
2110 __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg));
2111 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2112
2113 __ bind(&restore_fcsr_and_return);
2114 // Restore FCSR and return.
2115 __ ctc1(a3, FCSR);
2116
2117 __ Drop(argc + 1);
2118 __ Ret();
2119
2120 __ bind(&wont_fit_smi);
2121 // Restore FCSR and fall to slow case.
2122 __ ctc1(a3, FCSR);
2123
2124 __ bind(&slow);
2125 // Tail call the full function. We do not have to patch the receiver
2126 // because the function makes no use of it.
2127 __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
2128
2129 __ bind(&miss);
2130 // a2: function name.
2131 MaybeObject* obj = GenerateMissBranch();
2132 if (obj->IsFailure()) return obj;
2133
2134 // Return the generated code.
2135 return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002136}
2137
2138
lrn@chromium.org7516f052011-03-30 08:52:27 +00002139MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object,
2140 JSObject* holder,
2141 JSGlobalPropertyCell* cell,
2142 JSFunction* function,
2143 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002144 // ----------- S t a t e -------------
2145 // -- a2 : function name
2146 // -- ra : return address
2147 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2148 // -- ...
2149 // -- sp[argc * 4] : receiver
2150 // -----------------------------------
2151
2152 const int argc = arguments().immediate();
2153
2154 // If the object is not a JSObject or we got an unexpected number of
2155 // arguments, bail out to the regular call.
2156 if (!object->IsJSObject() || argc != 1) return heap()->undefined_value();
2157
2158 Label miss;
2159 GenerateNameCheck(name, &miss);
2160
2161 if (cell == NULL) {
2162 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
2163
2164 STATIC_ASSERT(kSmiTag == 0);
2165 __ JumpIfSmi(a1, &miss);
2166
2167 CheckPrototypes(JSObject::cast(object), a1, holder, v0, a3, t0, name,
2168 &miss);
2169 } else {
2170 ASSERT(cell->value() == function);
2171 GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
2172 GenerateLoadFunctionFromCell(cell, function, &miss);
2173 }
2174
2175 // Load the (only) argument into v0.
2176 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2177
2178 // Check if the argument is a smi.
2179 Label not_smi;
2180 STATIC_ASSERT(kSmiTag == 0);
2181 __ JumpIfNotSmi(v0, &not_smi);
2182
2183 // Do bitwise not or do nothing depending on the sign of the
2184 // argument.
2185 __ sra(t0, v0, kBitsPerInt - 1);
2186 __ Xor(a1, v0, t0);
2187
2188 // Add 1 or do nothing depending on the sign of the argument.
2189 __ Subu(v0, a1, t0);
2190
2191 // If the result is still negative, go to the slow case.
2192 // This only happens for the most negative smi.
2193 Label slow;
2194 __ Branch(&slow, lt, v0, Operand(zero_reg));
2195
2196 // Smi case done.
2197 __ Drop(argc + 1);
2198 __ Ret();
2199
2200 // Check if the argument is a heap number and load its exponent and
2201 // sign.
2202 __ bind(&not_smi);
2203 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, true);
2204 __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2205
2206 // Check the sign of the argument. If the argument is positive,
2207 // just return it.
2208 Label negative_sign;
2209 __ And(t0, a1, Operand(HeapNumber::kSignMask));
2210 __ Branch(&negative_sign, ne, t0, Operand(zero_reg));
2211 __ Drop(argc + 1);
2212 __ Ret();
2213
2214 // If the argument is negative, clear the sign, and return a new
2215 // number.
2216 __ bind(&negative_sign);
2217 __ Xor(a1, a1, Operand(HeapNumber::kSignMask));
2218 __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2219 __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
2220 __ AllocateHeapNumber(v0, t0, t1, t2, &slow);
2221 __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2222 __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2223 __ Drop(argc + 1);
2224 __ Ret();
2225
2226 // Tail call the full function. We do not have to patch the receiver
2227 // because the function makes no use of it.
2228 __ bind(&slow);
2229 __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
2230
2231 __ bind(&miss);
2232 // a2: function name.
2233 MaybeObject* maybe_result = GenerateMissBranch();
2234 if (maybe_result->IsFailure()) return maybe_result;
2235
2236 // Return the generated code.
2237 return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002238}
2239
2240
lrn@chromium.org7516f052011-03-30 08:52:27 +00002241MaybeObject* CallStubCompiler::CompileFastApiCall(
2242 const CallOptimization& optimization,
2243 Object* object,
2244 JSObject* holder,
2245 JSGlobalPropertyCell* cell,
2246 JSFunction* function,
2247 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002248
2249 Isolate* isolate = masm()->isolate();
2250 Heap* heap = isolate->heap();
2251 Counters* counters = isolate->counters();
2252
2253 ASSERT(optimization.is_simple_api_call());
2254 // Bail out if object is a global object as we don't want to
2255 // repatch it to global receiver.
2256 if (object->IsGlobalObject()) return heap->undefined_value();
2257 if (cell != NULL) return heap->undefined_value();
2258 int depth = optimization.GetPrototypeDepthOfExpectedType(
2259 JSObject::cast(object), holder);
2260 if (depth == kInvalidProtoDepth) return heap->undefined_value();
2261
2262 Label miss, miss_before_stack_reserved;
2263
2264 GenerateNameCheck(name, &miss_before_stack_reserved);
2265
2266 // Get the receiver from the stack.
2267 const int argc = arguments().immediate();
2268 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2269
2270 // Check that the receiver isn't a smi.
2271 __ JumpIfSmi(a1, &miss_before_stack_reserved);
2272
2273 __ IncrementCounter(counters->call_const(), 1, a0, a3);
2274 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2275
2276 ReserveSpaceForFastApiCall(masm(), a0);
2277
2278 // Check that the maps haven't changed and find a Holder as a side effect.
2279 CheckPrototypes(JSObject::cast(object), a1, holder, a0, a3, t0, name,
2280 depth, &miss);
2281
2282 MaybeObject* result = GenerateFastApiDirectCall(masm(), optimization, argc);
2283 if (result->IsFailure()) return result;
2284
2285 __ bind(&miss);
2286 FreeSpaceForFastApiCall(masm());
2287
2288 __ bind(&miss_before_stack_reserved);
2289 MaybeObject* maybe_result = GenerateMissBranch();
2290 if (maybe_result->IsFailure()) return maybe_result;
2291
2292 // Return the generated code.
2293 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002294}
2295
2296
lrn@chromium.org7516f052011-03-30 08:52:27 +00002297MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
ager@chromium.org5c838252010-02-19 08:53:10 +00002298 JSObject* holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002299 JSFunction* function,
2300 String* name,
2301 CheckType check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002302 // ----------- S t a t e -------------
2303 // -- a2 : name
2304 // -- ra : return address
2305 // -----------------------------------
2306 if (HasCustomCallGenerator(function)) {
2307 MaybeObject* maybe_result = CompileCustomCall(
2308 object, holder, NULL, function, name);
2309 Object* result;
2310 if (!maybe_result->ToObject(&result)) return maybe_result;
2311 // Undefined means bail out to regular compiler.
2312 if (!result->IsUndefined()) return result;
2313 }
2314
2315 Label miss;
2316
2317 GenerateNameCheck(name, &miss);
2318
2319 // Get the receiver from the stack.
2320 const int argc = arguments().immediate();
2321 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2322
2323 // Check that the receiver isn't a smi.
2324 if (check != NUMBER_CHECK) {
2325 __ And(t1, a1, Operand(kSmiTagMask));
2326 __ Branch(&miss, eq, t1, Operand(zero_reg));
2327 }
2328
2329 // Make sure that it's okay not to patch the on stack receiver
2330 // unless we're doing a receiver map check.
2331 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
2332
2333 SharedFunctionInfo* function_info = function->shared();
2334 switch (check) {
2335 case RECEIVER_MAP_CHECK:
2336 __ IncrementCounter(masm()->isolate()->counters()->call_const(),
2337 1, a0, a3);
2338
2339 // Check that the maps haven't changed.
2340 CheckPrototypes(JSObject::cast(object), a1, holder, a0, a3, t0, name,
2341 &miss);
2342
2343 // Patch the receiver on the stack with the global proxy if
2344 // necessary.
2345 if (object->IsGlobalObject()) {
2346 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2347 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2348 }
2349 break;
2350
2351 case STRING_CHECK:
2352 if (!function->IsBuiltin() && !function_info->strict_mode()) {
2353 // Calling non-strict non-builtins with a value as the receiver
2354 // requires boxing.
2355 __ jmp(&miss);
2356 } else {
2357 // Check that the object is a two-byte string or a symbol.
2358 __ GetObjectType(a1, a3, a3);
2359 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2360 // Check that the maps starting from the prototype haven't changed.
2361 GenerateDirectLoadGlobalFunctionPrototype(
2362 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
2363 CheckPrototypes(JSObject::cast(object->GetPrototype()), a0, holder, a3,
2364 a1, t0, name, &miss);
2365 }
2366 break;
2367
2368 case NUMBER_CHECK: {
2369 if (!function->IsBuiltin() && !function_info->strict_mode()) {
2370 // Calling non-strict non-builtins with a value as the receiver
2371 // requires boxing.
2372 __ jmp(&miss);
2373 } else {
2374 Label fast;
2375 // Check that the object is a smi or a heap number.
2376 __ And(t1, a1, Operand(kSmiTagMask));
2377 __ Branch(&fast, eq, t1, Operand(zero_reg));
2378 __ GetObjectType(a1, a0, a0);
2379 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
2380 __ bind(&fast);
2381 // Check that the maps starting from the prototype haven't changed.
2382 GenerateDirectLoadGlobalFunctionPrototype(
2383 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
2384 CheckPrototypes(JSObject::cast(object->GetPrototype()), a0, holder, a3,
2385 a1, t0, name, &miss);
2386 }
2387 break;
2388 }
2389
2390 case BOOLEAN_CHECK: {
2391 if (!function->IsBuiltin() && !function_info->strict_mode()) {
2392 // Calling non-strict non-builtins with a value as the receiver
2393 // requires boxing.
2394 __ jmp(&miss);
2395 } else {
2396 Label fast;
2397 // Check that the object is a boolean.
2398 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
2399 __ Branch(&fast, eq, a1, Operand(t0));
2400 __ LoadRoot(t0, Heap::kFalseValueRootIndex);
2401 __ Branch(&miss, ne, a1, Operand(t0));
2402 __ bind(&fast);
2403 // Check that the maps starting from the prototype haven't changed.
2404 GenerateDirectLoadGlobalFunctionPrototype(
2405 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
2406 CheckPrototypes(JSObject::cast(object->GetPrototype()), a0, holder, a3,
2407 a1, t0, name, &miss);
2408 }
2409 break;
2410 }
2411
2412 default:
2413 UNREACHABLE();
2414 }
2415
2416 __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
2417
2418 // Handle call cache miss.
2419 __ bind(&miss);
2420
2421 MaybeObject* maybe_result = GenerateMissBranch();
2422 if (maybe_result->IsFailure()) return maybe_result;
2423
2424 // Return the generated code.
2425 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002426}
2427
2428
lrn@chromium.org7516f052011-03-30 08:52:27 +00002429MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
ager@chromium.org5c838252010-02-19 08:53:10 +00002430 JSObject* holder,
2431 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002432 // ----------- S t a t e -------------
2433 // -- a2 : name
2434 // -- ra : return address
2435 // -----------------------------------
2436
2437 Label miss;
2438
2439 GenerateNameCheck(name, &miss);
2440
2441 // Get the number of arguments.
2442 const int argc = arguments().immediate();
2443
2444 LookupResult lookup;
2445 LookupPostInterceptor(holder, name, &lookup);
2446
2447 // Get the receiver from the stack.
2448 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2449
2450 CallInterceptorCompiler compiler(this, arguments(), a2);
2451 MaybeObject* result = compiler.Compile(masm(),
2452 object,
2453 holder,
2454 name,
2455 &lookup,
2456 a1,
2457 a3,
2458 t0,
2459 a0,
2460 &miss);
2461 if (result->IsFailure()) {
2462 return result;
2463 }
2464
2465 // Move returned value, the function to call, to a1.
2466 __ mov(a1, v0);
2467 // Restore receiver.
2468 __ lw(a0, MemOperand(sp, argc * kPointerSize));
2469
2470 GenerateCallFunction(masm(), object, arguments(), &miss);
2471
2472 // Handle call cache miss.
2473 __ bind(&miss);
2474 MaybeObject* maybe_result = GenerateMissBranch();
2475 if (maybe_result->IsFailure()) return maybe_result;
2476
2477 // Return the generated code.
2478 return GetCode(INTERCEPTOR, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002479}
2480
2481
lrn@chromium.org7516f052011-03-30 08:52:27 +00002482MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
2483 GlobalObject* holder,
2484 JSGlobalPropertyCell* cell,
2485 JSFunction* function,
2486 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002487 // ----------- S t a t e -------------
2488 // -- a2 : name
2489 // -- ra : return address
2490 // -----------------------------------
2491
2492 if (HasCustomCallGenerator(function)) {
2493 MaybeObject* maybe_result = CompileCustomCall(
2494 object, holder, cell, function, name);
2495 Object* result;
2496 if (!maybe_result->ToObject(&result)) return maybe_result;
2497 // Undefined means bail out to regular compiler.
2498 if (!result->IsUndefined()) return result;
2499 }
2500
2501 Label miss;
2502
2503 GenerateNameCheck(name, &miss);
2504
2505 // Get the number of arguments.
2506 const int argc = arguments().immediate();
2507
2508 GenerateGlobalReceiverCheck(object, holder, name, &miss);
2509 GenerateLoadFunctionFromCell(cell, function, &miss);
2510
2511 // Patch the receiver on the stack with the global proxy if
2512 // necessary.
2513 if (object->IsGlobalObject()) {
2514 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
2515 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2516 }
2517
2518 // Setup the context (function already in r1).
2519 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
2520
2521 // Jump to the cached code (tail call).
2522 Counters* counters = masm()->isolate()->counters();
2523 __ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
2524 ASSERT(function->is_compiled());
2525 Handle<Code> code(function->code());
2526 ParameterCount expected(function->shared()->formal_parameter_count());
2527 if (V8::UseCrankshaft()) {
2528 UNIMPLEMENTED_MIPS();
2529 } else {
2530 __ InvokeCode(code, expected, arguments(),
2531 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
2532 }
2533
2534 // Handle call cache miss.
2535 __ bind(&miss);
2536 __ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
2537 MaybeObject* maybe_result = GenerateMissBranch();
2538 if (maybe_result->IsFailure()) return maybe_result;
2539
2540 // Return the generated code.
2541 return GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002542}
2543
2544
lrn@chromium.org7516f052011-03-30 08:52:27 +00002545MaybeObject* StoreStubCompiler::CompileStoreField(JSObject* object,
ager@chromium.org5c838252010-02-19 08:53:10 +00002546 int index,
2547 Map* transition,
2548 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002549 // ----------- S t a t e -------------
2550 // -- a0 : value
2551 // -- a1 : receiver
2552 // -- a2 : name
2553 // -- ra : return address
2554 // -----------------------------------
2555 Label miss;
2556
2557 // Name register might be clobbered.
2558 GenerateStoreField(masm(),
2559 object,
2560 index,
2561 transition,
2562 a1, a2, a3,
2563 &miss);
2564 __ bind(&miss);
2565 __ li(a2, Operand(Handle<String>(name))); // Restore name.
2566 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2567 __ Jump(ic, RelocInfo::CODE_TARGET);
2568
2569 // Return the generated code.
2570 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002571}
2572
2573
lrn@chromium.org7516f052011-03-30 08:52:27 +00002574MaybeObject* StoreStubCompiler::CompileStoreCallback(JSObject* object,
2575 AccessorInfo* callback,
2576 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002577 // ----------- S t a t e -------------
2578 // -- a0 : value
2579 // -- a1 : receiver
2580 // -- a2 : name
2581 // -- ra : return address
2582 // -----------------------------------
2583 Label miss;
2584
2585 // Check that the object isn't a smi.
2586 __ JumpIfSmi(a1, &miss);
2587
2588 // Check that the map of the object hasn't changed.
2589 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2590 __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map())));
2591
2592 // Perform global security token check if needed.
2593 if (object->IsJSGlobalProxy()) {
2594 __ CheckAccessGlobalProxy(a1, a3, &miss);
2595 }
2596
2597 // Stub never generated for non-global objects that require access
2598 // checks.
2599 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
2600
2601 __ push(a1); // Receiver.
2602 __ li(a3, Operand(Handle<AccessorInfo>(callback))); // Callback info.
2603 __ Push(a3, a2, a0);
2604
2605 // Do tail-call to the runtime system.
2606 ExternalReference store_callback_property =
2607 ExternalReference(IC_Utility(IC::kStoreCallbackProperty),
2608 masm()->isolate());
2609 __ TailCallExternalReference(store_callback_property, 4, 1);
2610
2611 // Handle store cache miss.
2612 __ bind(&miss);
2613 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2614 __ Jump(ic, RelocInfo::CODE_TARGET);
2615
2616 // Return the generated code.
2617 return GetCode(CALLBACKS, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002618}
2619
2620
lrn@chromium.org7516f052011-03-30 08:52:27 +00002621MaybeObject* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
2622 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002623 // ----------- S t a t e -------------
2624 // -- a0 : value
2625 // -- a1 : receiver
2626 // -- a2 : name
2627 // -- ra : return address
2628 // -----------------------------------
2629 Label miss;
2630
2631 // Check that the object isn't a smi.
2632 __ JumpIfSmi(a1, &miss);
2633
2634 // Check that the map of the object hasn't changed.
2635 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2636 __ Branch(&miss, ne, a3, Operand(Handle<Map>(receiver->map())));
2637
2638 // Perform global security token check if needed.
2639 if (receiver->IsJSGlobalProxy()) {
2640 __ CheckAccessGlobalProxy(a1, a3, &miss);
2641 }
2642
2643 // Stub is never generated for non-global objects that require access
2644 // checks.
2645 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2646
2647 __ Push(a1, a2, a0); // Receiver, name, value.
2648
2649 __ li(a0, Operand(Smi::FromInt(strict_mode_)));
2650 __ push(a0); // Strict mode.
2651
2652 // Do tail-call to the runtime system.
2653 ExternalReference store_ic_property =
2654 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty),
2655 masm()->isolate());
2656 __ TailCallExternalReference(store_ic_property, 4, 1);
2657
2658 // Handle store cache miss.
2659 __ bind(&miss);
2660 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2661 __ Jump(ic, RelocInfo::CODE_TARGET);
2662
2663 // Return the generated code.
2664 return GetCode(INTERCEPTOR, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002665}
2666
2667
lrn@chromium.org7516f052011-03-30 08:52:27 +00002668MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
2669 JSGlobalPropertyCell* cell,
2670 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002671 // ----------- S t a t e -------------
2672 // -- a0 : value
2673 // -- a1 : receiver
2674 // -- a2 : name
2675 // -- ra : return address
2676 // -----------------------------------
2677 Label miss;
2678
2679 // Check that the map of the global has not changed.
2680 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2681 __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map())));
2682
2683 // Check that the value in the cell is not the hole. If it is, this
2684 // cell could have been deleted and reintroducing the global needs
2685 // to update the property details in the property dictionary of the
2686 // global object. We bail out to the runtime system to do that.
2687 __ li(t0, Operand(Handle<JSGlobalPropertyCell>(cell)));
2688 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
2689 __ lw(t2, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2690 __ Branch(&miss, eq, t1, Operand(t2));
2691
2692 // Store the value in the cell.
2693 __ sw(a0, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2694 __ mov(v0, a0); // Stored value must be returned in v0.
2695 Counters* counters = masm()->isolate()->counters();
2696 __ IncrementCounter(counters->named_store_global_inline(), 1, a1, a3);
2697 __ Ret();
2698
2699 // Handle store cache miss.
2700 __ bind(&miss);
2701 __ IncrementCounter(counters->named_store_global_inline_miss(), 1, a1, a3);
2702 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2703 __ Jump(ic, RelocInfo::CODE_TARGET);
2704
2705 // Return the generated code.
2706 return GetCode(NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002707}
2708
2709
2710MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name,
2711 JSObject* object,
2712 JSObject* last) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002713 // ----------- S t a t e -------------
2714 // -- a0 : receiver
2715 // -- ra : return address
2716 // -----------------------------------
2717 Label miss;
2718
2719 // Check that the receiver is not a smi.
2720 __ JumpIfSmi(a0, &miss);
2721
2722 // Check the maps of the full prototype chain.
2723 CheckPrototypes(object, a0, last, a3, a1, t0, name, &miss);
2724
2725 // If the last object in the prototype chain is a global object,
2726 // check that the global property cell is empty.
2727 if (last->IsGlobalObject()) {
2728 MaybeObject* cell = GenerateCheckPropertyCell(masm(),
2729 GlobalObject::cast(last),
2730 name,
2731 a1,
2732 &miss);
2733 if (cell->IsFailure()) {
2734 miss.Unuse();
2735 return cell;
2736 }
2737 }
2738
2739 // Return undefined if maps of the full prototype chain is still the same.
2740 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2741 __ Ret();
2742
2743 __ bind(&miss);
2744 GenerateLoadMiss(masm(), Code::LOAD_IC);
2745
2746 // Return the generated code.
2747 return GetCode(NONEXISTENT, heap()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00002748}
2749
2750
2751MaybeObject* LoadStubCompiler::CompileLoadField(JSObject* object,
2752 JSObject* holder,
2753 int index,
2754 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002755 // ----------- S t a t e -------------
2756 // -- a0 : receiver
2757 // -- a2 : name
2758 // -- ra : return address
2759 // -----------------------------------
2760 Label miss;
2761
2762 __ mov(v0, a0);
2763
2764 GenerateLoadField(object, holder, v0, a3, a1, t0, index, name, &miss);
2765 __ bind(&miss);
2766 GenerateLoadMiss(masm(), Code::LOAD_IC);
2767
2768 // Return the generated code.
2769 return GetCode(FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002770}
2771
2772
2773MaybeObject* LoadStubCompiler::CompileLoadCallback(String* name,
2774 JSObject* object,
2775 JSObject* holder,
2776 AccessorInfo* callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002777 // ----------- S t a t e -------------
2778 // -- a0 : receiver
2779 // -- a2 : name
2780 // -- ra : return address
2781 // -----------------------------------
2782 Label miss;
2783
2784 MaybeObject* result = GenerateLoadCallback(object, holder, a0, a2, a3, a1, t0,
2785 callback, name, &miss);
2786 if (result->IsFailure()) {
2787 miss.Unuse();
2788 return result;
2789 }
2790
2791 __ bind(&miss);
2792 GenerateLoadMiss(masm(), Code::LOAD_IC);
2793
2794 // Return the generated code.
2795 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002796}
2797
2798
2799MaybeObject* LoadStubCompiler::CompileLoadConstant(JSObject* object,
2800 JSObject* holder,
2801 Object* value,
2802 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002803 // ----------- S t a t e -------------
2804 // -- a0 : receiver
2805 // -- a2 : name
2806 // -- ra : return address
2807 // -----------------------------------
2808 Label miss;
2809
2810 GenerateLoadConstant(object, holder, a0, a3, a1, t0, value, name, &miss);
2811 __ bind(&miss);
2812 GenerateLoadMiss(masm(), Code::LOAD_IC);
2813
2814 // Return the generated code.
2815 return GetCode(CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002816}
2817
2818
2819MaybeObject* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
2820 JSObject* holder,
2821 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002822 // ----------- S t a t e -------------
2823 // -- a0 : receiver
2824 // -- a2 : name
2825 // -- ra : return address
2826 // -- [sp] : receiver
2827 // -----------------------------------
2828 Label miss;
2829
2830 LookupResult lookup;
2831 LookupPostInterceptor(holder, name, &lookup);
2832 GenerateLoadInterceptor(object,
2833 holder,
2834 &lookup,
2835 a0,
2836 a2,
2837 a3,
2838 a1,
2839 t0,
2840 name,
2841 &miss);
2842 __ bind(&miss);
2843 GenerateLoadMiss(masm(), Code::LOAD_IC);
2844
2845 // Return the generated code.
2846 return GetCode(INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002847}
2848
2849
2850MaybeObject* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
2851 GlobalObject* holder,
2852 JSGlobalPropertyCell* cell,
2853 String* name,
2854 bool is_dont_delete) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002855 // ----------- S t a t e -------------
2856 // -- a0 : receiver
2857 // -- a2 : name
2858 // -- ra : return address
2859 // -----------------------------------
2860 Label miss;
2861
2862 // If the object is the holder then we know that it's a global
2863 // object which can only happen for contextual calls. In this case,
2864 // the receiver cannot be a smi.
2865 if (object != holder) {
2866 __ And(t0, a0, Operand(kSmiTagMask));
2867 __ Branch(&miss, eq, t0, Operand(zero_reg));
2868 }
2869
2870 // Check that the map of the global has not changed.
2871 CheckPrototypes(object, a0, holder, a3, t0, a1, name, &miss);
2872
2873 // Get the value from the cell.
2874 __ li(a3, Operand(Handle<JSGlobalPropertyCell>(cell)));
2875 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
2876
2877 // Check for deleted property if property can actually be deleted.
2878 if (!is_dont_delete) {
2879 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
2880 __ Branch(&miss, eq, t0, Operand(at));
2881 }
2882
2883 __ mov(v0, t0);
2884 Counters* counters = masm()->isolate()->counters();
2885 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
2886 __ Ret();
2887
2888 __ bind(&miss);
2889 __ IncrementCounter(counters->named_load_global_stub_miss(), 1, a1, a3);
2890 GenerateLoadMiss(masm(), Code::LOAD_IC);
2891
2892 // Return the generated code.
2893 return GetCode(NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002894}
2895
2896
2897MaybeObject* KeyedLoadStubCompiler::CompileLoadField(String* name,
2898 JSObject* receiver,
2899 JSObject* holder,
2900 int index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002901 // ----------- S t a t e -------------
2902 // -- ra : return address
2903 // -- a0 : key
2904 // -- a1 : receiver
2905 // -----------------------------------
2906 Label miss;
2907
2908 // Check the key is the cached one.
2909 __ Branch(&miss, ne, a0, Operand(Handle<String>(name)));
2910
2911 GenerateLoadField(receiver, holder, a1, a2, a3, t0, index, name, &miss);
2912 __ bind(&miss);
2913 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2914
2915 return GetCode(FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002916}
2917
2918
2919MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback(
2920 String* name,
2921 JSObject* receiver,
2922 JSObject* holder,
2923 AccessorInfo* callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002924 // ----------- S t a t e -------------
2925 // -- ra : return address
2926 // -- a0 : key
2927 // -- a1 : receiver
2928 // -----------------------------------
2929 Label miss;
2930
2931 // Check the key is the cached one.
2932 __ Branch(&miss, ne, a0, Operand(Handle<String>(name)));
2933
2934 MaybeObject* result = GenerateLoadCallback(receiver, holder, a1, a0, a2, a3,
2935 t0, callback, name, &miss);
2936 if (result->IsFailure()) {
2937 miss.Unuse();
2938 return result;
2939 }
2940
2941 __ bind(&miss);
2942 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2943
2944 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002945}
2946
2947
2948MaybeObject* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
2949 JSObject* receiver,
2950 JSObject* holder,
2951 Object* value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002952 // ----------- S t a t e -------------
2953 // -- ra : return address
2954 // -- a0 : key
2955 // -- a1 : receiver
2956 // -----------------------------------
2957 Label miss;
2958
2959 // Check the key is the cached one.
2960 __ Branch(&miss, ne, a0, Operand(Handle<String>(name)));
2961
2962 GenerateLoadConstant(receiver, holder, a1, a2, a3, t0, value, name, &miss);
2963 __ bind(&miss);
2964 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2965
2966 // Return the generated code.
2967 return GetCode(CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002968}
2969
2970
2971MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
2972 JSObject* holder,
2973 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002974 // ----------- S t a t e -------------
2975 // -- ra : return address
2976 // -- a0 : key
2977 // -- a1 : receiver
2978 // -----------------------------------
2979 Label miss;
2980
2981 // Check the key is the cached one.
2982 __ Branch(&miss, ne, a0, Operand(Handle<String>(name)));
2983
2984 LookupResult lookup;
2985 LookupPostInterceptor(holder, name, &lookup);
2986 GenerateLoadInterceptor(receiver,
2987 holder,
2988 &lookup,
2989 a1,
2990 a0,
2991 a2,
2992 a3,
2993 t0,
2994 name,
2995 &miss);
2996 __ bind(&miss);
2997 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2998
2999 return GetCode(INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003000}
3001
3002
3003MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003004 // ----------- S t a t e -------------
3005 // -- ra : return address
3006 // -- a0 : key
3007 // -- a1 : receiver
3008 // -----------------------------------
3009 Label miss;
3010
3011 // Check the key is the cached one.
3012 __ Branch(&miss, ne, a0, Operand(Handle<String>(name)));
3013
3014 GenerateLoadArrayLength(masm(), a1, a2, &miss);
3015 __ bind(&miss);
3016 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3017
3018 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003019}
3020
3021
3022MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003023 // ----------- S t a t e -------------
3024 // -- ra : return address
3025 // -- a0 : key
3026 // -- a1 : receiver
3027 // -----------------------------------
3028 Label miss;
3029
3030 Counters* counters = masm()->isolate()->counters();
3031 __ IncrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
3032
3033 // Check the key is the cached one.
3034 __ Branch(&miss, ne, a0, Operand(Handle<String>(name)));
3035
3036 GenerateLoadStringLength(masm(), a1, a2, a3, &miss, true);
3037 __ bind(&miss);
3038 __ DecrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
3039
3040 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3041
3042 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003043}
3044
3045
3046MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003047 // ----------- S t a t e -------------
3048 // -- ra : return address
3049 // -- a0 : key
3050 // -- a1 : receiver
3051 // -----------------------------------
3052 Label miss;
3053
3054 Counters* counters = masm()->isolate()->counters();
3055 __ IncrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
3056
3057 // Check the name hasn't changed.
3058 __ Branch(&miss, ne, a0, Operand(Handle<String>(name)));
3059
3060 GenerateLoadFunctionPrototype(masm(), a1, a2, a3, &miss);
3061 __ bind(&miss);
3062 __ DecrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
3063 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3064
3065 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003066}
3067
3068
3069MaybeObject* KeyedLoadStubCompiler::CompileLoadSpecialized(JSObject* receiver) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003070 // ----------- S t a t e -------------
3071 // -- ra : return address
3072 // -- a0 : key
3073 // -- a1 : receiver
3074 // -----------------------------------
3075 Label miss;
3076
3077 // Check that the receiver isn't a smi.
3078 __ JumpIfSmi(a1, &miss);
3079
3080 // Check that the map matches.
3081 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
3082 __ Branch(&miss, ne, a2, Operand(Handle<Map>(receiver->map())));
3083
3084 // Check that the key is a smi.
3085 __ JumpIfNotSmi(a0, &miss);
3086
3087 // Get the elements array.
3088 __ lw(a2, FieldMemOperand(a1, JSObject::kElementsOffset));
3089 __ AssertFastElements(a2);
3090
3091 // Check that the key is within bounds.
3092 __ lw(a3, FieldMemOperand(a2, FixedArray::kLengthOffset));
3093 __ Branch(&miss, hs, a0, Operand(a3));
3094
3095 // Load the result and make sure it's not the hole.
3096 __ Addu(a3, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3097 ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
3098 __ sll(t1, a0, kPointerSizeLog2 - kSmiTagSize);
3099 __ Addu(t1, t1, a3);
3100 __ lw(t0, MemOperand(t1));
3101 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
3102 __ Branch(&miss, eq, t0, Operand(t1));
3103 __ mov(v0, t0);
3104 __ Ret();
3105
3106 __ bind(&miss);
3107 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3108
3109 // Return the generated code.
3110 return GetCode(NORMAL, NULL);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003111}
3112
3113
3114MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
3115 int index,
3116 Map* transition,
3117 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003118 // ----------- S t a t e -------------
3119 // -- a0 : value
3120 // -- a1 : key
3121 // -- a2 : receiver
3122 // -- ra : return address
3123 // -----------------------------------
3124
3125 Label miss;
3126
3127 Counters* counters = masm()->isolate()->counters();
3128 __ IncrementCounter(counters->keyed_store_field(), 1, a3, t0);
3129
3130 // Check that the name has not changed.
3131 __ Branch(&miss, ne, a1, Operand(Handle<String>(name)));
3132
3133 // a3 is used as scratch register. a1 and a2 keep their values if a jump to
3134 // the miss label is generated.
3135 GenerateStoreField(masm(),
3136 object,
3137 index,
3138 transition,
3139 a2, a1, a3,
3140 &miss);
3141 __ bind(&miss);
3142
3143 __ DecrementCounter(counters->keyed_store_field(), 1, a3, t0);
3144 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss();
3145 __ Jump(ic, RelocInfo::CODE_TARGET);
3146
3147 // Return the generated code.
3148 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003149}
3150
3151
3152MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized(
3153 JSObject* receiver) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003154 // ----------- S t a t e -------------
3155 // -- a0 : value
3156 // -- a1 : key
3157 // -- a2 : receiver
3158 // -- ra : return address
3159 // -- a3 : scratch
3160 // -- t0 : scratch (elements)
3161 // -----------------------------------
3162 Label miss;
3163 Register value_reg = a0;
3164 Register key_reg = a1;
3165 Register receiver_reg = a2;
3166 Register scratch = a3;
3167 Register elements_reg = t0;
3168
3169 // Check that the receiver isn't a smi.
3170 __ JumpIfSmi(receiver_reg, &miss);
3171
3172 // Check that the map matches.
3173 __ lw(scratch, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
3174 __ Branch(&miss, ne, scratch, Operand(Handle<Map>(receiver->map())));
3175
3176 // Check that the key is a smi.
3177 __ JumpIfNotSmi(key_reg, &miss);
3178
3179 // Get the elements array and make sure it is a fast element array, not 'cow'.
3180 __ lw(elements_reg,
3181 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
3182 __ lw(scratch, FieldMemOperand(elements_reg, HeapObject::kMapOffset));
3183 __ Branch(&miss, ne, scratch,
3184 Operand(Handle<Map>(FACTORY->fixed_array_map())));
3185
3186 // Check that the key is within bounds.
3187 if (receiver->IsJSArray()) {
3188 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3189 } else {
3190 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3191 }
3192 // Compare smis.
3193 __ Branch(&miss, hs, key_reg, Operand(scratch));
3194 __ Addu(scratch,
3195 elements_reg, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3196 ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
3197 __ sll(key_reg, key_reg, kPointerSizeLog2 - kSmiTagSize);
3198 __ Addu(v0, scratch, key_reg);
3199 __ sw(value_reg, MemOperand(v0));
3200 __ RecordWrite(scratch, Operand(key_reg), receiver_reg , elements_reg);
3201
3202 // value_reg (a0) is preserved.
3203 // Done.
3204 __ mov(v0, value_reg);
3205 __ Ret();
3206
3207 __ bind(&miss);
3208 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss();
3209 __ Jump(ic, RelocInfo::CODE_TARGET);
3210
3211 // Return the generated code.
3212 return GetCode(NORMAL, NULL);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003213}
3214
3215
3216MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003217 // a0 : argc
3218 // a1 : constructor
3219 // ra : return address
3220 // [sp] : last argument
3221 Label generic_stub_call;
3222
3223 // Use t7 for holding undefined which is used in several places below.
3224 __ LoadRoot(t7, Heap::kUndefinedValueRootIndex);
3225
3226#ifdef ENABLE_DEBUGGER_SUPPORT
3227 // Check to see whether there are any break points in the function code. If
3228 // there are jump to the generic constructor stub which calls the actual
3229 // code for the function thereby hitting the break points.
3230 __ lw(t5, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3231 __ lw(a2, FieldMemOperand(t5, SharedFunctionInfo::kDebugInfoOffset));
3232 __ Branch(&generic_stub_call, ne, a2, Operand(t7));
3233#endif
3234
3235 // Load the initial map and verify that it is in fact a map.
3236 // a1: constructor function
3237 // t7: undefined
3238 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
3239 __ And(t0, a2, Operand(kSmiTagMask));
3240 __ Branch(&generic_stub_call, eq, t0, Operand(zero_reg));
3241 __ GetObjectType(a2, a3, t0);
3242 __ Branch(&generic_stub_call, ne, t0, Operand(MAP_TYPE));
3243
3244#ifdef DEBUG
3245 // Cannot construct functions this way.
3246 // a0: argc
3247 // a1: constructor function
3248 // a2: initial map
3249 // t7: undefined
3250 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
3251 __ Check(ne, "Function constructed by construct stub.",
3252 a3, Operand(JS_FUNCTION_TYPE));
3253#endif
3254
3255 // Now allocate the JSObject in new space.
3256 // a0: argc
3257 // a1: constructor function
3258 // a2: initial map
3259 // t7: undefined
3260 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
3261 __ AllocateInNewSpace(a3,
3262 t4,
3263 t5,
3264 t6,
3265 &generic_stub_call,
3266 SIZE_IN_WORDS);
3267
3268 // Allocated the JSObject, now initialize the fields. Map is set to initial
3269 // map and properties and elements are set to empty fixed array.
3270 // a0: argc
3271 // a1: constructor function
3272 // a2: initial map
3273 // a3: object size (in words)
3274 // t4: JSObject (not tagged)
3275 // t7: undefined
3276 __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex);
3277 __ mov(t5, t4);
3278 __ sw(a2, MemOperand(t5, JSObject::kMapOffset));
3279 __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset));
3280 __ sw(t6, MemOperand(t5, JSObject::kElementsOffset));
3281 __ Addu(t5, t5, Operand(3 * kPointerSize));
3282 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
3283 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
3284 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
3285
3286
3287 // Calculate the location of the first argument. The stack contains only the
3288 // argc arguments.
3289 __ sll(a1, a0, kPointerSizeLog2);
3290 __ Addu(a1, a1, sp);
3291
3292 // Fill all the in-object properties with undefined.
3293 // a0: argc
3294 // a1: first argument
3295 // a3: object size (in words)
3296 // t4: JSObject (not tagged)
3297 // t5: First in-object property of JSObject (not tagged)
3298 // t7: undefined
3299 // Fill the initialized properties with a constant value or a passed argument
3300 // depending on the this.x = ...; assignment in the function.
3301 SharedFunctionInfo* shared = function->shared();
3302 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3303 if (shared->IsThisPropertyAssignmentArgument(i)) {
3304 Label not_passed, next;
3305 // Check if the argument assigned to the property is actually passed.
3306 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3307 __ Branch(&not_passed, less_equal, a0, Operand(arg_number));
3308 // Argument passed - find it on the stack.
3309 __ lw(a2, MemOperand(a1, (arg_number + 1) * -kPointerSize));
3310 __ sw(a2, MemOperand(t5));
3311 __ Addu(t5, t5, kPointerSize);
3312 __ jmp(&next);
3313 __ bind(&not_passed);
3314 // Set the property to undefined.
3315 __ sw(t7, MemOperand(t5));
3316 __ Addu(t5, t5, Operand(kPointerSize));
3317 __ bind(&next);
3318 } else {
3319 // Set the property to the constant value.
3320 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
3321 __ li(a2, Operand(constant));
3322 __ sw(a2, MemOperand(t5));
3323 __ Addu(t5, t5, kPointerSize);
3324 }
3325 }
3326
3327 // Fill the unused in-object property fields with undefined.
3328 ASSERT(function->has_initial_map());
3329 for (int i = shared->this_property_assignments_count();
3330 i < function->initial_map()->inobject_properties();
3331 i++) {
3332 __ sw(t7, MemOperand(t5));
3333 __ Addu(t5, t5, kPointerSize);
3334 }
3335
3336 // a0: argc
3337 // t4: JSObject (not tagged)
3338 // Move argc to a1 and the JSObject to return to v0 and tag it.
3339 __ mov(a1, a0);
3340 __ mov(v0, t4);
3341 __ Or(v0, v0, Operand(kHeapObjectTag));
3342
3343 // v0: JSObject
3344 // a1: argc
3345 // Remove caller arguments and receiver from the stack and return.
3346 __ sll(t0, a1, kPointerSizeLog2);
3347 __ Addu(sp, sp, t0);
3348 __ Addu(sp, sp, Operand(kPointerSize));
3349 Counters* counters = masm()->isolate()->counters();
3350 __ IncrementCounter(counters->constructed_objects(), 1, a1, a2);
3351 __ IncrementCounter(counters->constructed_objects_stub(), 1, a1, a2);
3352 __ Ret();
3353
3354 // Jump to the generic stub in case the specialized code cannot handle the
3355 // construction.
3356 __ bind(&generic_stub_call);
3357 Handle<Code> generic_construct_stub =
3358 masm()->isolate()->builtins()->JSConstructStubGeneric();
3359 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
3360
3361 // Return the generated code.
3362 return GetCode();
3363}
3364
3365
3366static bool IsElementTypeSigned(ExternalArrayType array_type) {
3367 switch (array_type) {
3368 case kExternalByteArray:
3369 case kExternalShortArray:
3370 case kExternalIntArray:
3371 return true;
3372
3373 case kExternalUnsignedByteArray:
3374 case kExternalUnsignedShortArray:
3375 case kExternalUnsignedIntArray:
3376 return false;
3377
3378 default:
3379 UNREACHABLE();
3380 return false;
3381 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00003382}
3383
3384
3385MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
3386 JSObject* receiver_object,
3387 ExternalArrayType array_type,
3388 Code::Flags flags) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003389 // ---------- S t a t e --------------
3390 // -- ra : return address
3391 // -- a0 : key
3392 // -- a1 : receiver
3393 // -----------------------------------
3394 Label slow, failed_allocation;
3395
3396 Register key = a0;
3397 Register receiver = a1;
3398
3399 // Check that the object isn't a smi.
3400 __ JumpIfSmi(receiver, &slow);
3401
3402 // Check that the key is a smi.
3403 __ JumpIfNotSmi(key, &slow);
3404
3405 // Make sure that we've got the right map.
3406 __ lw(a2, FieldMemOperand(receiver, HeapObject::kMapOffset));
3407 __ Branch(&slow, ne, a2, Operand(Handle<Map>(receiver_object->map())));
3408
3409 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3410 // a3: elements array
3411
3412 // Check that the index is in range.
3413 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3414 __ sra(t2, key, kSmiTagSize);
3415 // Unsigned comparison catches both negative and too-large values.
3416 __ Branch(&slow, Uless, t1, Operand(t2));
3417
3418
3419 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3420 // a3: base pointer of external storage
3421
3422 // We are not untagging smi key and instead work with it
3423 // as if it was premultiplied by 2.
3424 ASSERT((kSmiTag == 0) && (kSmiTagSize == 1));
3425
3426 Register value = a2;
3427 switch (array_type) {
3428 case kExternalByteArray:
3429 __ srl(t2, key, 1);
3430 __ addu(t3, a3, t2);
3431 __ lb(value, MemOperand(t3, 0));
3432 break;
3433 case kExternalPixelArray:
3434 case kExternalUnsignedByteArray:
3435 __ srl(t2, key, 1);
3436 __ addu(t3, a3, t2);
3437 __ lbu(value, MemOperand(t3, 0));
3438 break;
3439 case kExternalShortArray:
3440 __ addu(t3, a3, key);
3441 __ lh(value, MemOperand(t3, 0));
3442 break;
3443 case kExternalUnsignedShortArray:
3444 __ addu(t3, a3, key);
3445 __ lhu(value, MemOperand(t3, 0));
3446 break;
3447 case kExternalIntArray:
3448 case kExternalUnsignedIntArray:
3449 __ sll(t2, key, 1);
3450 __ addu(t3, a3, t2);
3451 __ lw(value, MemOperand(t3, 0));
3452 break;
3453 case kExternalFloatArray:
3454 __ sll(t3, t2, 2);
3455 __ addu(t3, a3, t3);
3456 if (CpuFeatures::IsSupported(FPU)) {
3457 CpuFeatures::Scope scope(FPU);
3458 __ lwc1(f0, MemOperand(t3, 0));
3459 } else {
3460 __ lw(value, MemOperand(t3, 0));
3461 }
3462 break;
3463 case kExternalDoubleArray:
3464 __ sll(t2, key, 2);
3465 __ addu(t3, a3, t2);
3466 if (CpuFeatures::IsSupported(FPU)) {
3467 CpuFeatures::Scope scope(FPU);
3468 __ ldc1(f0, MemOperand(t3, 0));
3469 } else {
3470 // t3: pointer to the beginning of the double we want to load.
3471 __ lw(a2, MemOperand(t3, 0));
3472 __ lw(a3, MemOperand(t3, Register::kSizeInBytes));
3473 }
3474 break;
3475 default:
3476 UNREACHABLE();
3477 break;
3478 }
3479
3480 // For integer array types:
3481 // a2: value
3482 // For float array type:
3483 // f0: value (if FPU is supported)
3484 // a2: value (if FPU is not supported)
3485 // For double array type:
3486 // f0: value (if FPU is supported)
3487 // a2/a3: value (if FPU is not supported)
3488
3489 if (array_type == kExternalIntArray) {
3490 // For the Int and UnsignedInt array types, we need to see whether
3491 // the value can be represented in a Smi. If not, we need to convert
3492 // it to a HeapNumber.
3493 Label box_int;
3494 __ Subu(t3, value, Operand(0xC0000000)); // Non-smi value gives neg result.
3495 __ Branch(&box_int, lt, t3, Operand(zero_reg));
3496 // Tag integer as smi and return it.
3497 __ sll(v0, value, kSmiTagSize);
3498 __ Ret();
3499
3500 __ bind(&box_int);
3501 // Allocate a HeapNumber for the result and perform int-to-double
3502 // conversion.
3503 // The arm version uses a temporary here to save r0, but we don't need to
3504 // (a0 is not modified).
3505 __ LoadRoot(t1, Heap::kHeapNumberMapRootIndex);
3506 __ AllocateHeapNumber(v0, a3, t0, t1, &slow);
3507
3508 if (CpuFeatures::IsSupported(FPU)) {
3509 CpuFeatures::Scope scope(FPU);
3510 __ mtc1(value, f0);
3511 __ cvt_d_w(f0, f0);
3512 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag));
3513 __ Ret();
3514 } else {
3515 WriteInt32ToHeapNumberStub stub(value, v0, t2, t3);
3516 __ TailCallStub(&stub);
3517 }
3518 } else if (array_type == kExternalUnsignedIntArray) {
3519 // The test is different for unsigned int values. Since we need
3520 // the value to be in the range of a positive smi, we can't
3521 // handle either of the top two bits being set in the value.
3522 if (CpuFeatures::IsSupported(FPU)) {
3523 CpuFeatures::Scope scope(FPU);
3524 Label pl_box_int;
3525 __ And(t2, value, Operand(0xC0000000));
3526 __ Branch(&pl_box_int, ne, t2, Operand(zero_reg));
3527
3528 // It can fit in an Smi.
3529 // Tag integer as smi and return it.
3530 __ sll(v0, value, kSmiTagSize);
3531 __ Ret();
3532
3533 __ bind(&pl_box_int);
3534 // Allocate a HeapNumber for the result and perform int-to-double
3535 // conversion. Don't use a0 and a1 as AllocateHeapNumber clobbers all
3536 // registers - also when jumping due to exhausted young space.
3537 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3538 __ AllocateHeapNumber(v0, t2, t3, t6, &slow);
3539
3540 // This is replaced by a macro:
3541 // __ mtc1(value, f0); // LS 32-bits.
3542 // __ mtc1(zero_reg, f1); // MS 32-bits are all zero.
3543 // __ cvt_d_l(f0, f0); // Use 64 bit conv to get correct unsigned 32-bit.
3544
3545 __ Cvt_d_uw(f0, value);
3546
3547 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag));
3548
3549 __ Ret();
3550 } else {
3551 // Check whether unsigned integer fits into smi.
3552 Label box_int_0, box_int_1, done;
3553 __ And(t2, value, Operand(0x80000000));
3554 __ Branch(&box_int_0, ne, t2, Operand(zero_reg));
3555 __ And(t2, value, Operand(0x40000000));
3556 __ Branch(&box_int_1, ne, t2, Operand(zero_reg));
3557
3558 // Tag integer as smi and return it.
3559 __ sll(v0, value, kSmiTagSize);
3560 __ Ret();
3561
3562 Register hiword = value; // a2.
3563 Register loword = a3;
3564
3565 __ bind(&box_int_0);
3566 // Integer does not have leading zeros.
3567 GenerateUInt2Double(masm(), hiword, loword, t0, 0);
3568 __ Branch(&done);
3569
3570 __ bind(&box_int_1);
3571 // Integer has one leading zero.
3572 GenerateUInt2Double(masm(), hiword, loword, t0, 1);
3573
3574
3575 __ bind(&done);
3576 // Integer was converted to double in registers hiword:loword.
3577 // Wrap it into a HeapNumber. Don't use a0 and a1 as AllocateHeapNumber
3578 // clobbers all registers - also when jumping due to exhausted young
3579 // space.
3580 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3581 __ AllocateHeapNumber(t2, t3, t5, t6, &slow);
3582
3583 __ sw(hiword, FieldMemOperand(t2, HeapNumber::kExponentOffset));
3584 __ sw(loword, FieldMemOperand(t2, HeapNumber::kMantissaOffset));
3585
3586 __ mov(v0, t2);
3587 __ Ret();
3588 }
3589 } else if (array_type == kExternalFloatArray) {
3590 // For the floating-point array type, we need to always allocate a
3591 // HeapNumber.
3592 if (CpuFeatures::IsSupported(FPU)) {
3593 CpuFeatures::Scope scope(FPU);
3594 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3595 // AllocateHeapNumber clobbers all registers - also when jumping due to
3596 // exhausted young space.
3597 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3598 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3599 // The float (single) value is already in fpu reg f0 (if we use float).
3600 __ cvt_d_s(f0, f0);
3601 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag));
3602 __ Ret();
3603 } else {
3604 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3605 // AllocateHeapNumber clobbers all registers - also when jumping due to
3606 // exhausted young space.
3607 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3608 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3609 // FPU is not available, do manual single to double conversion.
3610
3611 // a2: floating point value (binary32).
3612 // v0: heap number for result
3613
3614 // Extract mantissa to t4.
3615 __ And(t4, value, Operand(kBinary32MantissaMask));
3616
3617 // Extract exponent to t5.
3618 __ srl(t5, value, kBinary32MantissaBits);
3619 __ And(t5, t5, Operand(kBinary32ExponentMask >> kBinary32MantissaBits));
3620
3621 Label exponent_rebiased;
3622 __ Branch(&exponent_rebiased, eq, t5, Operand(zero_reg));
3623
3624 __ li(t0, 0x7ff);
3625 __ Xor(t1, t5, Operand(0xFF));
3626 __ movz(t5, t0, t1); // Set t5 to 0x7ff only if t5 is equal to 0xff.
3627 __ Branch(&exponent_rebiased, eq, t0, Operand(0xff));
3628
3629 // Rebias exponent.
3630 __ Addu(t5,
3631 t5,
3632 Operand(-kBinary32ExponentBias + HeapNumber::kExponentBias));
3633
3634 __ bind(&exponent_rebiased);
3635 __ And(a2, value, Operand(kBinary32SignMask));
3636 value = no_reg;
3637 __ sll(t0, t5, HeapNumber::kMantissaBitsInTopWord);
3638 __ or_(a2, a2, t0);
3639
3640 // Shift mantissa.
3641 static const int kMantissaShiftForHiWord =
3642 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3643
3644 static const int kMantissaShiftForLoWord =
3645 kBitsPerInt - kMantissaShiftForHiWord;
3646
3647 __ srl(t0, t4, kMantissaShiftForHiWord);
3648 __ or_(a2, a2, t0);
3649 __ sll(a0, t4, kMantissaShiftForLoWord);
3650
3651 __ sw(a2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3652 __ sw(a0, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3653 __ Ret();
3654 }
3655
3656 } else if (array_type == kExternalDoubleArray) {
3657 if (CpuFeatures::IsSupported(FPU)) {
3658 CpuFeatures::Scope scope(FPU);
3659 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3660 // AllocateHeapNumber clobbers all registers - also when jumping due to
3661 // exhausted young space.
3662 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3663 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3664 // The double value is already in f0
3665 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
3666 __ Ret();
3667 } else {
3668 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3669 // AllocateHeapNumber clobbers all registers - also when jumping due to
3670 // exhausted young space.
3671 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3672 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3673
3674 __ sw(a2, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3675 __ sw(a3, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3676 __ Ret();
3677 }
3678
3679 } else {
3680 // Tag integer as smi and return it.
3681 __ sll(v0, value, kSmiTagSize);
3682 __ Ret();
3683 }
3684
3685 // Slow case, key and receiver still in a0 and a1.
3686 __ bind(&slow);
3687 __ IncrementCounter(
3688 masm()->isolate()->counters()->keyed_load_external_array_slow(),
3689 1, a2, a3);
3690
3691 // ---------- S t a t e --------------
3692 // -- ra : return address
3693 // -- a0 : key
3694 // -- a1 : receiver
3695 // -----------------------------------
3696
3697 __ Push(a1, a0);
3698
3699 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
3700
3701 return GetCode(flags);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003702}
3703
3704
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003705
3706
lrn@chromium.org7516f052011-03-30 08:52:27 +00003707MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
3708 JSObject* receiver_object,
3709 ExternalArrayType array_type,
3710 Code::Flags flags) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003711 // ---------- S t a t e --------------
3712 // -- a0 : value
3713 // -- a1 : key
3714 // -- a2 : receiver
3715 // -- ra : return address
3716 // -----------------------------------
3717
3718 Label slow, check_heap_number;
3719
3720 // Register usage.
3721 Register value = a0;
3722 Register key = a1;
3723 Register receiver = a2;
3724 // a3 mostly holds the elements array or the destination external array.
3725
3726 // Check that the object isn't a smi.
3727 __ JumpIfSmi(receiver, &slow);
3728
3729 // Make sure that we've got the right map.
3730 __ lw(a3, FieldMemOperand(receiver, HeapObject::kMapOffset));
3731 __ Branch(&slow, ne, a3, Operand(Handle<Map>(receiver_object->map())));
3732
3733 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3734
3735 // Check that the key is a smi.
3736 __ JumpIfNotSmi(key, &slow);
3737
3738 // Check that the index is in range.
3739 __ SmiUntag(t0, key);
3740 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3741 // Unsigned comparison catches both negative and too-large values.
3742 __ Branch(&slow, Ugreater_equal, t0, Operand(t1));
3743
3744 // Handle both smis and HeapNumbers in the fast path. Go to the
3745 // runtime for all other kinds of values.
3746 // a3: external array.
3747 // t0: key (integer).
3748
3749 if (array_type == kExternalPixelArray) {
3750 // Double to pixel conversion is only implemented in the runtime for now.
3751 __ JumpIfNotSmi(value, &slow);
3752 } else {
3753 __ JumpIfNotSmi(value, &check_heap_number);
3754 }
3755 __ SmiUntag(t1, value);
3756 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3757
3758 // a3: base pointer of external storage.
3759 // t0: key (integer).
3760 // t1: value (integer).
3761
3762 switch (array_type) {
3763 case kExternalPixelArray: {
3764 // Clamp the value to [0..255].
3765 // v0 is used as a scratch register here.
3766 Label done;
3767 __ li(v0, Operand(255));
3768 // Normal branch: nop in delay slot.
3769 __ Branch(&done, gt, t1, Operand(v0));
3770 // Use delay slot in this branch.
3771 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg));
3772 __ mov(v0, zero_reg); // In delay slot.
3773 __ mov(v0, t1); // Value is in range 0..255.
3774 __ bind(&done);
3775 __ mov(t1, v0);
3776 __ addu(t8, a3, t0);
3777 __ sb(t1, MemOperand(t8, 0));
3778 }
3779 break;
3780 case kExternalByteArray:
3781 case kExternalUnsignedByteArray:
3782 __ addu(t8, a3, t0);
3783 __ sb(t1, MemOperand(t8, 0));
3784 break;
3785 case kExternalShortArray:
3786 case kExternalUnsignedShortArray:
3787 __ sll(t8, t0, 1);
3788 __ addu(t8, a3, t8);
3789 __ sh(t1, MemOperand(t8, 0));
3790 break;
3791 case kExternalIntArray:
3792 case kExternalUnsignedIntArray:
3793 __ sll(t8, t0, 2);
3794 __ addu(t8, a3, t8);
3795 __ sw(t1, MemOperand(t8, 0));
3796 break;
3797 case kExternalFloatArray:
3798 // Perform int-to-float conversion and store to memory.
3799 StoreIntAsFloat(masm(), a3, t0, t1, t2, t3, t4);
3800 break;
3801 case kExternalDoubleArray:
3802 __ sll(t8, t0, 3);
3803 __ addu(a3, a3, t8);
3804 // a3: effective address of the double element
3805 FloatingPointHelper::Destination destination;
3806 if (CpuFeatures::IsSupported(FPU)) {
3807 destination = FloatingPointHelper::kFPURegisters;
3808 } else {
3809 destination = FloatingPointHelper::kCoreRegisters;
3810 }
3811 FloatingPointHelper::ConvertIntToDouble(
3812 masm(), t1, destination,
3813 f0, t2, t3, // These are: double_dst, dst1, dst2.
3814 t0, f2); // These are: scratch2, single_scratch.
3815 if (destination == FloatingPointHelper::kFPURegisters) {
3816 CpuFeatures::Scope scope(FPU);
3817 __ sdc1(f0, MemOperand(a3, 0));
3818 } else {
3819 __ sw(t2, MemOperand(a3, 0));
3820 __ sw(t3, MemOperand(a3, Register::kSizeInBytes));
3821 }
3822 break;
3823 default:
3824 UNREACHABLE();
3825 break;
3826 }
3827
3828 // Entry registers are intact, a0 holds the value which is the return value.
3829 __ mov(v0, value);
3830 __ Ret();
3831
3832 if (array_type != kExternalPixelArray) {
3833 // a3: external array.
3834 // t0: index (integer).
3835 __ bind(&check_heap_number);
3836 __ GetObjectType(value, t1, t2);
3837 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE));
3838
3839 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3840
3841 // a3: base pointer of external storage.
3842 // t0: key (integer).
3843
3844 // The WebGL specification leaves the behavior of storing NaN and
3845 // +/-Infinity into integer arrays basically undefined. For more
3846 // reproducible behavior, convert these to zero.
3847
3848 if (CpuFeatures::IsSupported(FPU)) {
3849 CpuFeatures::Scope scope(FPU);
3850
3851 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
3852
3853 if (array_type == kExternalFloatArray) {
3854 __ cvt_s_d(f0, f0);
3855 __ sll(t8, t0, 2);
3856 __ addu(t8, a3, t8);
3857 __ swc1(f0, MemOperand(t8, 0));
3858 } else if (array_type == kExternalDoubleArray) {
3859 __ sll(t8, t0, 3);
3860 __ addu(t8, a3, t8);
3861 __ sdc1(f0, MemOperand(t8, 0));
3862 } else {
3863 Label done;
3864
3865 // Need to perform float-to-int conversion.
3866 // Test whether exponent equal to 0x7FF (infinity or NaN).
3867
3868 __ mfc1(t3, f1); // Move exponent word of double to t3 (as raw bits).
3869 __ li(t1, Operand(0x7FF00000));
3870 __ And(t3, t3, Operand(t1));
3871 __ Branch(USE_DELAY_SLOT, &done, eq, t3, Operand(t1));
3872 __ mov(t3, zero_reg); // In delay slot.
3873
3874 // Not infinity or NaN simply convert to int.
3875 if (IsElementTypeSigned(array_type)) {
3876 __ trunc_w_d(f0, f0);
3877 __ mfc1(t3, f0);
3878 } else {
3879 __ Trunc_uw_d(f0, t3);
3880 }
3881
3882 // t3: HeapNumber converted to integer
3883 __ bind(&done);
3884 switch (array_type) {
3885 case kExternalByteArray:
3886 case kExternalUnsignedByteArray:
3887 __ addu(t8, a3, t0);
3888 __ sb(t3, MemOperand(t8, 0));
3889 break;
3890 case kExternalShortArray:
3891 case kExternalUnsignedShortArray:
3892 __ sll(t8, t0, 1);
3893 __ addu(t8, a3, t8);
3894 __ sh(t3, MemOperand(t8, 0));
3895 break;
3896 case kExternalIntArray:
3897 case kExternalUnsignedIntArray:
3898 __ sll(t8, t0, 2);
3899 __ addu(t8, a3, t8);
3900 __ sw(t3, MemOperand(t8, 0));
3901 break;
3902 default:
3903 UNREACHABLE();
3904 break;
3905 }
3906 }
3907
3908 // Entry registers are intact, a0 holds the value
3909 // which is the return value.
3910 __ mov(v0, value);
3911 __ Ret();
3912 } else {
3913 // FPU is not available, do manual conversions.
3914
3915 __ lw(t3, FieldMemOperand(value, HeapNumber::kExponentOffset));
3916 __ lw(t4, FieldMemOperand(value, HeapNumber::kMantissaOffset));
3917
3918 if (array_type == kExternalFloatArray) {
3919 Label done, nan_or_infinity_or_zero;
3920 static const int kMantissaInHiWordShift =
3921 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3922
3923 static const int kMantissaInLoWordShift =
3924 kBitsPerInt - kMantissaInHiWordShift;
3925
3926 // Test for all special exponent values: zeros, subnormal numbers, NaNs
3927 // and infinities. All these should be converted to 0.
3928 __ li(t5, HeapNumber::kExponentMask);
3929 __ and_(t6, t3, t5);
3930 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(zero_reg));
3931
3932 __ xor_(t1, t6, t5);
3933 __ li(t2, kBinary32ExponentMask);
3934 __ movz(t6, t2, t1); // Only if t6 is equal to t5.
3935 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(t5));
3936
3937 // Rebias exponent.
3938 __ srl(t6, t6, HeapNumber::kExponentShift);
3939 __ Addu(t6,
3940 t6,
3941 Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
3942
3943 __ li(t1, Operand(kBinary32MaxExponent));
3944 __ Slt(t1, t1, t6);
3945 __ And(t2, t3, Operand(HeapNumber::kSignMask));
3946 __ Or(t2, t2, Operand(kBinary32ExponentMask));
3947 __ movn(t3, t2, t1); // Only if t6 is gt kBinary32MaxExponent.
3948 __ Branch(&done, gt, t6, Operand(kBinary32MaxExponent));
3949
3950 __ Slt(t1, t6, Operand(kBinary32MinExponent));
3951 __ And(t2, t3, Operand(HeapNumber::kSignMask));
3952 __ movn(t3, t2, t1); // Only if t6 is lt kBinary32MinExponent.
3953 __ Branch(&done, lt, t6, Operand(kBinary32MinExponent));
3954
3955 __ And(t7, t3, Operand(HeapNumber::kSignMask));
3956 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3957 __ sll(t3, t3, kMantissaInHiWordShift);
3958 __ or_(t7, t7, t3);
3959 __ srl(t4, t4, kMantissaInLoWordShift);
3960 __ or_(t7, t7, t4);
3961 __ sll(t6, t6, kBinary32ExponentShift);
3962 __ or_(t3, t7, t6);
3963
3964 __ bind(&done);
3965 __ sll(t9, a1, 2);
3966 __ addu(t9, a2, t9);
3967 __ sw(t3, MemOperand(t9, 0));
3968
3969 // Entry registers are intact, a0 holds the value which is the return
3970 // value.
3971 __ mov(v0, value);
3972 __ Ret();
3973
3974 __ bind(&nan_or_infinity_or_zero);
3975 __ And(t7, t3, Operand(HeapNumber::kSignMask));
3976 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3977 __ or_(t6, t6, t7);
3978 __ sll(t3, t3, kMantissaInHiWordShift);
3979 __ or_(t6, t6, t3);
3980 __ srl(t4, t4, kMantissaInLoWordShift);
3981 __ or_(t3, t6, t4);
3982 __ Branch(&done);
3983 } else if (array_type == kExternalDoubleArray) {
3984 __ sll(t8, t0, 3);
3985 __ addu(t8, a3, t8);
3986 // t8: effective address of destination element.
3987 __ sw(t4, MemOperand(t8, 0));
3988 __ sw(t3, MemOperand(t8, Register::kSizeInBytes));
3989 __ Ret();
3990 } else {
3991 bool is_signed_type = IsElementTypeSigned(array_type);
3992 int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
3993 int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
3994
3995 Label done, sign;
3996
3997 // Test for all special exponent values: zeros, subnormal numbers, NaNs
3998 // and infinities. All these should be converted to 0.
3999 __ li(t5, HeapNumber::kExponentMask);
4000 __ and_(t6, t3, t5);
4001 __ movz(t3, zero_reg, t6); // Only if t6 is equal to zero.
4002 __ Branch(&done, eq, t6, Operand(zero_reg));
4003
4004 __ xor_(t2, t6, t5);
4005 __ movz(t3, zero_reg, t2); // Only if t6 is equal to t5.
4006 __ Branch(&done, eq, t6, Operand(t5));
4007
4008 // Unbias exponent.
4009 __ srl(t6, t6, HeapNumber::kExponentShift);
4010 __ Subu(t6, t6, Operand(HeapNumber::kExponentBias));
4011 // If exponent is negative then result is 0.
4012 __ slt(t2, t6, zero_reg);
4013 __ movn(t3, zero_reg, t2); // Only if exponent is negative.
4014 __ Branch(&done, lt, t6, Operand(zero_reg));
4015
4016 // If exponent is too big then result is minimal value.
4017 __ slti(t1, t6, meaningfull_bits - 1);
4018 __ li(t2, min_value);
4019 __ movz(t3, t2, t1); // Only if t6 is ge meaningfull_bits - 1.
4020 __ Branch(&done, ge, t6, Operand(meaningfull_bits - 1));
4021
4022 __ And(t5, t3, Operand(HeapNumber::kSignMask));
4023 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4024 __ Or(t3, t3, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
4025
4026 __ li(t9, HeapNumber::kMantissaBitsInTopWord);
4027 __ subu(t6, t9, t6);
4028 __ slt(t1, t6, zero_reg);
4029 __ srlv(t2, t3, t6);
4030 __ movz(t3, t2, t1); // Only if t6 is positive.
4031 __ Branch(&sign, ge, t6, Operand(zero_reg));
4032
4033 __ subu(t6, zero_reg, t6);
4034 __ sllv(t3, t3, t6);
4035 __ li(t9, meaningfull_bits);
4036 __ subu(t6, t9, t6);
4037 __ srlv(t4, t4, t6);
4038 __ or_(t3, t3, t4);
4039
4040 __ bind(&sign);
4041 __ subu(t2, t3, zero_reg);
4042 __ movz(t3, t2, t5); // Only if t5 is zero.
4043
4044 __ bind(&done);
4045
4046 // Result is in t3.
4047 // This switch block should be exactly the same as above (FPU mode).
4048 switch (array_type) {
4049 case kExternalByteArray:
4050 case kExternalUnsignedByteArray:
4051 __ addu(t8, a3, t0);
4052 __ sb(t3, MemOperand(t8, 0));
4053 break;
4054 case kExternalShortArray:
4055 case kExternalUnsignedShortArray:
4056 __ sll(t8, t0, 1);
4057 __ addu(t8, a3, t8);
4058 __ sh(t3, MemOperand(t8, 0));
4059 break;
4060 case kExternalIntArray:
4061 case kExternalUnsignedIntArray:
4062 __ sll(t8, t0, 2);
4063 __ addu(t8, a3, t8);
4064 __ sw(t3, MemOperand(t8, 0));
4065 break;
4066 default:
4067 UNREACHABLE();
4068 break;
4069 }
4070 }
4071 }
4072 }
4073
4074 // Slow case: call runtime.
4075 __ bind(&slow);
4076 // Entry registers are intact.
4077 // ---------- S t a t e --------------
4078 // -- a0 : value
4079 // -- a1 : key
4080 // -- a2 : receiver
4081 // -- ra : return address
4082 // -----------------------------------
4083
4084 // Push receiver, key and value for runtime call.
4085 __ Push(a2, a1, a0);
4086
4087 __ li(a1, Operand(Smi::FromInt(NONE))); // PropertyAttributes.
4088 __ li(a0, Operand(Smi::FromInt(
4089 Code::ExtractExtraICStateFromFlags(flags) & kStrictMode)));
4090 __ Push(a1, a0);
4091
4092 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
4093
4094 return GetCode(flags);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004095}
4096
4097
ager@chromium.org5c838252010-02-19 08:53:10 +00004098#undef __
4099
4100} } // namespace v8::internal
4101
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004102#endif // V8_TARGET_ARCH_MIPS