blob: 4bad0a2ccda04930c7fc5c3bcb748c93f93f449d [file] [log] [blame]
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001// Copyright 2011 the V8 project authors. All rights reserved.
ager@chromium.org5c838252010-02-19 08:53:10 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000030#if defined(V8_TARGET_ARCH_MIPS)
31
ager@chromium.org5c838252010-02-19 08:53:10 +000032#include "ic-inl.h"
karlklose@chromium.org83a47282011-05-11 11:54:09 +000033#include "codegen.h"
ager@chromium.org5c838252010-02-19 08:53:10 +000034#include "stub-cache.h"
35
36namespace v8 {
37namespace internal {
38
39#define __ ACCESS_MASM(masm)
40
41
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000042static void ProbeTable(Isolate* isolate,
43 MacroAssembler* masm,
44 Code::Flags flags,
45 StubCache::Table table,
46 Register name,
47 Register offset,
48 Register scratch,
49 Register scratch2) {
50 ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
51 ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
52
53 uint32_t key_off_addr = reinterpret_cast<uint32_t>(key_offset.address());
54 uint32_t value_off_addr = reinterpret_cast<uint32_t>(value_offset.address());
55
56 // Check the relative positions of the address fields.
57 ASSERT(value_off_addr > key_off_addr);
58 ASSERT((value_off_addr - key_off_addr) % 4 == 0);
59 ASSERT((value_off_addr - key_off_addr) < (256 * 4));
60
61 Label miss;
62 Register offsets_base_addr = scratch;
63
64 // Check that the key in the entry matches the name.
65 __ li(offsets_base_addr, Operand(key_offset));
66 __ sll(scratch2, offset, 1);
67 __ addu(scratch2, offsets_base_addr, scratch2);
68 __ lw(scratch2, MemOperand(scratch2));
69 __ Branch(&miss, ne, name, Operand(scratch2));
70
71 // Get the code entry from the cache.
72 __ Addu(offsets_base_addr, offsets_base_addr,
73 Operand(value_off_addr - key_off_addr));
74 __ sll(scratch2, offset, 1);
75 __ addu(scratch2, offsets_base_addr, scratch2);
76 __ lw(scratch2, MemOperand(scratch2));
77
78 // Check that the flags match what we're looking for.
79 __ lw(scratch2, FieldMemOperand(scratch2, Code::kFlagsOffset));
80 __ And(scratch2, scratch2, Operand(~Code::kFlagsNotUsedInLookup));
81 __ Branch(&miss, ne, scratch2, Operand(flags));
82
83 // Re-load code entry from cache.
84 __ sll(offset, offset, 1);
85 __ addu(offset, offset, offsets_base_addr);
86 __ lw(offset, MemOperand(offset));
87
88 // Jump to the first instruction in the code stub.
89 __ Addu(offset, offset, Operand(Code::kHeaderSize - kHeapObjectTag));
90 __ Jump(offset);
91
92 // Miss: fall through.
93 __ bind(&miss);
94}
95
96
97// Helper function used to check that the dictionary doesn't contain
98// the property. This function may return false negatives, so miss_label
99// must always call a backup property check that is complete.
100// This function is safe to call if the receiver has fast properties.
101// Name must be a symbol and receiver must be a heap object.
102MUST_USE_RESULT static MaybeObject* GenerateDictionaryNegativeLookup(
103 MacroAssembler* masm,
104 Label* miss_label,
105 Register receiver,
106 String* name,
107 Register scratch0,
108 Register scratch1) {
109 ASSERT(name->IsSymbol());
110 Counters* counters = masm->isolate()->counters();
111 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
112 __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
113
114 Label done;
115
116 const int kInterceptorOrAccessCheckNeededMask =
117 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
118
119 // Bail out if the receiver has a named interceptor or requires access checks.
120 Register map = scratch1;
121 __ lw(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
122 __ lbu(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
123 __ And(at, scratch0, Operand(kInterceptorOrAccessCheckNeededMask));
124 __ Branch(miss_label, ne, at, Operand(zero_reg));
125
126
127 // Check that receiver is a JSObject.
128 __ lbu(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000129 __ Branch(miss_label, lt, scratch0, Operand(FIRST_SPEC_OBJECT_TYPE));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000130
131 // Load properties array.
132 Register properties = scratch0;
133 __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
134 // Check that the properties array is a dictionary.
135 __ lw(map, FieldMemOperand(properties, HeapObject::kMapOffset));
136 Register tmp = properties;
137 __ LoadRoot(tmp, Heap::kHashTableMapRootIndex);
138 __ Branch(miss_label, ne, map, Operand(tmp));
139
140 // Restore the temporarily used register.
141 __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
142
143 MaybeObject* result = StringDictionaryLookupStub::GenerateNegativeLookup(
144 masm,
145 miss_label,
146 &done,
147 receiver,
148 properties,
149 name,
150 scratch1);
151 if (result->IsFailure()) return result;
152
153 __ bind(&done);
154 __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
155
156 return result;
157}
158
159
ager@chromium.org5c838252010-02-19 08:53:10 +0000160void StubCache::GenerateProbe(MacroAssembler* masm,
161 Code::Flags flags,
162 Register receiver,
163 Register name,
164 Register scratch,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000165 Register extra,
166 Register extra2) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000167 Isolate* isolate = masm->isolate();
168 Label miss;
169
170 // Make sure that code is valid. The shifting code relies on the
171 // entry size being 8.
172 ASSERT(sizeof(Entry) == 8);
173
174 // Make sure the flags does not name a specific type.
175 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
176
177 // Make sure that there are no register conflicts.
178 ASSERT(!scratch.is(receiver));
179 ASSERT(!scratch.is(name));
180 ASSERT(!extra.is(receiver));
181 ASSERT(!extra.is(name));
182 ASSERT(!extra.is(scratch));
183 ASSERT(!extra2.is(receiver));
184 ASSERT(!extra2.is(name));
185 ASSERT(!extra2.is(scratch));
186 ASSERT(!extra2.is(extra));
187
188 // Check scratch, extra and extra2 registers are valid.
189 ASSERT(!scratch.is(no_reg));
190 ASSERT(!extra.is(no_reg));
191 ASSERT(!extra2.is(no_reg));
192
193 // Check that the receiver isn't a smi.
194 __ JumpIfSmi(receiver, &miss, t0);
195
196 // Get the map of the receiver and compute the hash.
197 __ lw(scratch, FieldMemOperand(name, String::kHashFieldOffset));
198 __ lw(t8, FieldMemOperand(receiver, HeapObject::kMapOffset));
199 __ Addu(scratch, scratch, Operand(t8));
200 __ Xor(scratch, scratch, Operand(flags));
201 __ And(scratch,
202 scratch,
203 Operand((kPrimaryTableSize - 1) << kHeapObjectTagSize));
204
205 // Probe the primary table.
206 ProbeTable(isolate, masm, flags, kPrimary, name, scratch, extra, extra2);
207
208 // Primary miss: Compute hash for secondary probe.
209 __ Subu(scratch, scratch, Operand(name));
210 __ Addu(scratch, scratch, Operand(flags));
211 __ And(scratch,
212 scratch,
213 Operand((kSecondaryTableSize - 1) << kHeapObjectTagSize));
214
215 // Probe the secondary table.
216 ProbeTable(isolate, masm, flags, kSecondary, name, scratch, extra, extra2);
217
218 // Cache miss: Fall-through and let caller handle the miss by
219 // entering the runtime system.
220 __ bind(&miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000221}
222
223
224void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
225 int index,
226 Register prototype) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000227 // Load the global or builtins object from the current context.
228 __ lw(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
229 // Load the global context from the global or builtins object.
230 __ lw(prototype,
231 FieldMemOperand(prototype, GlobalObject::kGlobalContextOffset));
232 // Load the function from the global context.
233 __ lw(prototype, MemOperand(prototype, Context::SlotOffset(index)));
234 // Load the initial map. The global functions all have initial maps.
235 __ lw(prototype,
236 FieldMemOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
237 // Load the prototype from the initial map.
238 __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000239}
240
241
lrn@chromium.org7516f052011-03-30 08:52:27 +0000242void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
243 MacroAssembler* masm, int index, Register prototype, Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000244 Isolate* isolate = masm->isolate();
245 // Check we're still in the same context.
246 __ lw(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
247 ASSERT(!prototype.is(at));
248 __ li(at, isolate->global());
249 __ Branch(miss, ne, prototype, Operand(at));
250 // Get the global function with the given index.
251 JSFunction* function =
252 JSFunction::cast(isolate->global_context()->get(index));
253 // Load its initial map. The global functions all have initial maps.
254 __ li(prototype, Handle<Map>(function->initial_map()));
255 // Load the prototype from the initial map.
256 __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000257}
258
259
ager@chromium.org5c838252010-02-19 08:53:10 +0000260// Load a fast property out of a holder object (src). In-object properties
261// are loaded directly otherwise the property is loaded from the properties
262// fixed array.
263void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
264 Register dst, Register src,
265 JSObject* holder, int index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000266 // Adjust for the number of properties stored in the holder.
267 index -= holder->map()->inobject_properties();
268 if (index < 0) {
269 // Get the property straight out of the holder.
270 int offset = holder->map()->instance_size() + (index * kPointerSize);
271 __ lw(dst, FieldMemOperand(src, offset));
272 } else {
273 // Calculate the offset into the properties array.
274 int offset = index * kPointerSize + FixedArray::kHeaderSize;
275 __ lw(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
276 __ lw(dst, FieldMemOperand(dst, offset));
277 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000278}
279
280
281void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
282 Register receiver,
283 Register scratch,
284 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000285 // Check that the receiver isn't a smi.
286 __ And(scratch, receiver, Operand(kSmiTagMask));
287 __ Branch(miss_label, eq, scratch, Operand(zero_reg));
288
289 // Check that the object is a JS array.
290 __ GetObjectType(receiver, scratch, scratch);
291 __ Branch(miss_label, ne, scratch, Operand(JS_ARRAY_TYPE));
292
293 // Load length directly from the JS array.
294 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
295 __ Ret();
296}
297
298
299// Generate code to check if an object is a string. If the object is a
300// heap object, its map's instance type is left in the scratch1 register.
301// If this is not needed, scratch1 and scratch2 may be the same register.
302static void GenerateStringCheck(MacroAssembler* masm,
303 Register receiver,
304 Register scratch1,
305 Register scratch2,
306 Label* smi,
307 Label* non_string_object) {
308 // Check that the receiver isn't a smi.
309 __ JumpIfSmi(receiver, smi, t0);
310
311 // Check that the object is a string.
312 __ lw(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
313 __ lbu(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
314 __ And(scratch2, scratch1, Operand(kIsNotStringMask));
315 // The cast is to resolve the overload for the argument of 0x0.
316 __ Branch(non_string_object,
317 ne,
318 scratch2,
319 Operand(static_cast<int32_t>(kStringTag)));
ager@chromium.org5c838252010-02-19 08:53:10 +0000320}
321
322
lrn@chromium.org7516f052011-03-30 08:52:27 +0000323// Generate code to load the length from a string object and return the length.
324// If the receiver object is not a string or a wrapped string object the
325// execution continues at the miss label. The register containing the
326// receiver is potentially clobbered.
327void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
328 Register receiver,
329 Register scratch1,
330 Register scratch2,
331 Label* miss,
332 bool support_wrappers) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000333 Label check_wrapper;
334
335 // Check if the object is a string leaving the instance type in the
336 // scratch1 register.
337 GenerateStringCheck(masm, receiver, scratch1, scratch2, miss,
338 support_wrappers ? &check_wrapper : miss);
339
340 // Load length directly from the string.
341 __ lw(v0, FieldMemOperand(receiver, String::kLengthOffset));
342 __ Ret();
343
344 if (support_wrappers) {
345 // Check if the object is a JSValue wrapper.
346 __ bind(&check_wrapper);
347 __ Branch(miss, ne, scratch1, Operand(JS_VALUE_TYPE));
348
349 // Unwrap the value and check if the wrapped value is a string.
350 __ lw(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
351 GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
352 __ lw(v0, FieldMemOperand(scratch1, String::kLengthOffset));
353 __ Ret();
354 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000355}
356
357
ager@chromium.org5c838252010-02-19 08:53:10 +0000358void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
359 Register receiver,
360 Register scratch1,
361 Register scratch2,
362 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000363 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
364 __ mov(v0, scratch1);
365 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000366}
367
368
lrn@chromium.org7516f052011-03-30 08:52:27 +0000369// Generate StoreField code, value is passed in a0 register.
ager@chromium.org5c838252010-02-19 08:53:10 +0000370// After executing generated code, the receiver_reg and name_reg
371// may be clobbered.
372void StubCompiler::GenerateStoreField(MacroAssembler* masm,
ager@chromium.org5c838252010-02-19 08:53:10 +0000373 JSObject* object,
374 int index,
375 Map* transition,
376 Register receiver_reg,
377 Register name_reg,
378 Register scratch,
379 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000380 // a0 : value.
381 Label exit;
382
383 // Check that the receiver isn't a smi.
384 __ JumpIfSmi(receiver_reg, miss_label, scratch);
385
386 // Check that the map of the receiver hasn't changed.
387 __ lw(scratch, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
388 __ Branch(miss_label, ne, scratch, Operand(Handle<Map>(object->map())));
389
390 // Perform global security token check if needed.
391 if (object->IsJSGlobalProxy()) {
392 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
393 }
394
395 // Stub never generated for non-global objects that require access
396 // checks.
397 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
398
399 // Perform map transition for the receiver if necessary.
400 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
401 // The properties must be extended before we can store the value.
402 // We jump to a runtime call that extends the properties array.
403 __ push(receiver_reg);
404 __ li(a2, Operand(Handle<Map>(transition)));
405 __ Push(a2, a0);
406 __ TailCallExternalReference(
407 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
408 masm->isolate()),
409 3, 1);
410 return;
411 }
412
413 if (transition != NULL) {
414 // Update the map of the object; no write barrier updating is
415 // needed because the map is never in new space.
416 __ li(t0, Operand(Handle<Map>(transition)));
417 __ sw(t0, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
418 }
419
420 // Adjust for the number of properties stored in the object. Even in the
421 // face of a transition we can use the old map here because the size of the
422 // object and the number of in-object properties is not going to change.
423 index -= object->map()->inobject_properties();
424
425 if (index < 0) {
426 // Set the property straight into the object.
427 int offset = object->map()->instance_size() + (index * kPointerSize);
428 __ sw(a0, FieldMemOperand(receiver_reg, offset));
429
430 // Skip updating write barrier if storing a smi.
431 __ JumpIfSmi(a0, &exit, scratch);
432
433 // Update the write barrier for the array address.
434 // Pass the now unused name_reg as a scratch register.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000435 __ mov(name_reg, a0);
436 __ RecordWriteField(receiver_reg,
437 offset,
438 name_reg,
439 scratch,
440 kRAHasNotBeenSaved,
441 kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000442 } else {
443 // Write to the properties array.
444 int offset = index * kPointerSize + FixedArray::kHeaderSize;
445 // Get the properties array.
446 __ lw(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
447 __ sw(a0, FieldMemOperand(scratch, offset));
448
449 // Skip updating write barrier if storing a smi.
450 __ JumpIfSmi(a0, &exit);
451
452 // Update the write barrier for the array address.
453 // Ok to clobber receiver_reg and name_reg, since we return.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000454 __ mov(name_reg, a0);
455 __ RecordWriteField(scratch,
456 offset,
457 name_reg,
458 receiver_reg,
459 kRAHasNotBeenSaved,
460 kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000461 }
462
463 // Return the value (register v0).
464 __ bind(&exit);
465 __ mov(v0, a0);
466 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000467}
468
469
470void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000471 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
472 Code* code = NULL;
473 if (kind == Code::LOAD_IC) {
474 code = masm->isolate()->builtins()->builtin(Builtins::kLoadIC_Miss);
475 } else {
476 code = masm->isolate()->builtins()->builtin(Builtins::kKeyedLoadIC_Miss);
477 }
478
479 Handle<Code> ic(code);
480 __ Jump(ic, RelocInfo::CODE_TARGET);
ager@chromium.org5c838252010-02-19 08:53:10 +0000481}
482
483
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000484static void GenerateCallFunction(MacroAssembler* masm,
485 Object* object,
486 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000487 Label* miss,
488 Code::ExtraICState extra_ic_state) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000489 // ----------- S t a t e -------------
490 // -- a0: receiver
491 // -- a1: function to call
492 // -----------------------------------
493 // Check that the function really is a function.
494 __ JumpIfSmi(a1, miss);
495 __ GetObjectType(a1, a3, a3);
496 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
497
498 // Patch the receiver on the stack with the global proxy if
499 // necessary.
500 if (object->IsGlobalObject()) {
501 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
502 __ sw(a3, MemOperand(sp, arguments.immediate() * kPointerSize));
503 }
504
505 // Invoke the function.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000506 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
507 ? CALL_AS_FUNCTION
508 : CALL_AS_METHOD;
509 __ InvokeFunction(a1, arguments, JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000510}
511
512
513static void PushInterceptorArguments(MacroAssembler* masm,
514 Register receiver,
515 Register holder,
516 Register name,
517 JSObject* holder_obj) {
518 __ push(name);
519 InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
520 ASSERT(!masm->isolate()->heap()->InNewSpace(interceptor));
521 Register scratch = name;
522 __ li(scratch, Operand(Handle<Object>(interceptor)));
523 __ Push(scratch, receiver, holder);
524 __ lw(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
525 __ push(scratch);
526}
527
528
529static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
530 Register receiver,
531 Register holder,
532 Register name,
533 JSObject* holder_obj) {
534 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
535
536 ExternalReference ref =
537 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
538 masm->isolate());
539 __ li(a0, Operand(5));
540 __ li(a1, Operand(ref));
541
542 CEntryStub stub(1);
543 __ CallStub(&stub);
544}
545
546
547static const int kFastApiCallArguments = 3;
548
549
550// Reserves space for the extra arguments to FastHandleApiCall in the
551// caller's frame.
552//
553// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
554static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
555 Register scratch) {
556 ASSERT(Smi::FromInt(0) == 0);
557 for (int i = 0; i < kFastApiCallArguments; i++) {
558 __ push(zero_reg);
559 }
560}
561
562
563// Undoes the effects of ReserveSpaceForFastApiCall.
564static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
565 __ Drop(kFastApiCallArguments);
566}
567
568
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000569static MaybeObject* GenerateFastApiDirectCall(
570 MacroAssembler* masm,
571 const CallOptimization& optimization,
572 int argc) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000573 // ----------- S t a t e -------------
574 // -- sp[0] : holder (set by CheckPrototypes)
575 // -- sp[4] : callee js function
576 // -- sp[8] : call data
577 // -- sp[12] : last js argument
578 // -- ...
579 // -- sp[(argc + 3) * 4] : first js argument
580 // -- sp[(argc + 4) * 4] : receiver
581 // -----------------------------------
582 // Get the function and setup the context.
583 JSFunction* function = optimization.constant_function();
584 __ li(t1, Operand(Handle<JSFunction>(function)));
585 __ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset));
586
587 // Pass the additional arguments FastHandleApiCall expects.
588 Object* call_data = optimization.api_call_info()->data();
589 Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info());
590 if (masm->isolate()->heap()->InNewSpace(call_data)) {
591 __ li(a0, api_call_info_handle);
592 __ lw(t2, FieldMemOperand(a0, CallHandlerInfo::kDataOffset));
593 } else {
594 __ li(t2, Operand(Handle<Object>(call_data)));
595 }
596
597 // Store js function and call data.
598 __ sw(t1, MemOperand(sp, 1 * kPointerSize));
599 __ sw(t2, MemOperand(sp, 2 * kPointerSize));
600
601 // a2 points to call data as expected by Arguments
602 // (refer to layout above).
603 __ Addu(a2, sp, Operand(2 * kPointerSize));
604
605 Object* callback = optimization.api_call_info()->callback();
606 Address api_function_address = v8::ToCData<Address>(callback);
607 ApiFunction fun(api_function_address);
608
609 const int kApiStackSpace = 4;
610
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000611 FrameScope frame_scope(masm, StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000612 __ EnterExitFrame(false, kApiStackSpace);
613
614 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
615 // struct from the function (which is currently the case). This means we pass
616 // the first argument in a1 instead of a0. TryCallApiFunctionAndReturn
617 // will handle setting up a0.
618
619 // a1 = v8::Arguments&
620 // Arguments is built at sp + 1 (sp is a reserved spot for ra).
621 __ Addu(a1, sp, kPointerSize);
622
623 // v8::Arguments::implicit_args = data
624 __ sw(a2, MemOperand(a1, 0 * kPointerSize));
625 // v8::Arguments::values = last argument
626 __ Addu(t0, a2, Operand(argc * kPointerSize));
627 __ sw(t0, MemOperand(a1, 1 * kPointerSize));
628 // v8::Arguments::length_ = argc
629 __ li(t0, Operand(argc));
630 __ sw(t0, MemOperand(a1, 2 * kPointerSize));
631 // v8::Arguments::is_construct_call = 0
632 __ sw(zero_reg, MemOperand(a1, 3 * kPointerSize));
633
634 // Emitting a stub call may try to allocate (if the code is not
635 // already generated). Do not allow the assembler to perform a
636 // garbage collection but instead return the allocation failure
637 // object.
638 const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
639 ExternalReference ref =
640 ExternalReference(&fun,
641 ExternalReference::DIRECT_API_CALL,
642 masm->isolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000643 AllowExternalCallThatCantCauseGC scope(masm);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000644 return masm->TryCallApiFunctionAndReturn(ref, kStackUnwindSpace);
645}
646
lrn@chromium.org7516f052011-03-30 08:52:27 +0000647class CallInterceptorCompiler BASE_EMBEDDED {
648 public:
649 CallInterceptorCompiler(StubCompiler* stub_compiler,
650 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000651 Register name,
652 Code::ExtraICState extra_ic_state)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000653 : stub_compiler_(stub_compiler),
654 arguments_(arguments),
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000655 name_(name),
656 extra_ic_state_(extra_ic_state) {}
lrn@chromium.org7516f052011-03-30 08:52:27 +0000657
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000658 MaybeObject* Compile(MacroAssembler* masm,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000659 JSObject* object,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000660 JSObject* holder,
661 String* name,
662 LookupResult* lookup,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000663 Register receiver,
664 Register scratch1,
665 Register scratch2,
666 Register scratch3,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000667 Label* miss) {
668 ASSERT(holder->HasNamedInterceptor());
669 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
670
671 // Check that the receiver isn't a smi.
672 __ JumpIfSmi(receiver, miss);
673
674 CallOptimization optimization(lookup);
675
676 if (optimization.is_constant_call()) {
677 return CompileCacheable(masm,
678 object,
679 receiver,
680 scratch1,
681 scratch2,
682 scratch3,
683 holder,
684 lookup,
685 name,
686 optimization,
687 miss);
688 } else {
689 CompileRegular(masm,
690 object,
691 receiver,
692 scratch1,
693 scratch2,
694 scratch3,
695 name,
696 holder,
697 miss);
698 return masm->isolate()->heap()->undefined_value();
699 }
700 }
701
702 private:
703 MaybeObject* CompileCacheable(MacroAssembler* masm,
704 JSObject* object,
705 Register receiver,
706 Register scratch1,
707 Register scratch2,
708 Register scratch3,
709 JSObject* interceptor_holder,
710 LookupResult* lookup,
711 String* name,
712 const CallOptimization& optimization,
713 Label* miss_label) {
714 ASSERT(optimization.is_constant_call());
715 ASSERT(!lookup->holder()->IsGlobalObject());
716
717 Counters* counters = masm->isolate()->counters();
718
719 int depth1 = kInvalidProtoDepth;
720 int depth2 = kInvalidProtoDepth;
721 bool can_do_fast_api_call = false;
722 if (optimization.is_simple_api_call() &&
723 !lookup->holder()->IsGlobalObject()) {
724 depth1 =
725 optimization.GetPrototypeDepthOfExpectedType(object,
726 interceptor_holder);
727 if (depth1 == kInvalidProtoDepth) {
728 depth2 =
729 optimization.GetPrototypeDepthOfExpectedType(interceptor_holder,
730 lookup->holder());
731 }
732 can_do_fast_api_call = (depth1 != kInvalidProtoDepth) ||
733 (depth2 != kInvalidProtoDepth);
734 }
735
736 __ IncrementCounter(counters->call_const_interceptor(), 1,
737 scratch1, scratch2);
738
739 if (can_do_fast_api_call) {
740 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
741 scratch1, scratch2);
742 ReserveSpaceForFastApiCall(masm, scratch1);
743 }
744
745 // Check that the maps from receiver to interceptor's holder
746 // haven't changed and thus we can invoke interceptor.
747 Label miss_cleanup;
748 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
749 Register holder =
750 stub_compiler_->CheckPrototypes(object, receiver,
751 interceptor_holder, scratch1,
752 scratch2, scratch3, name, depth1, miss);
753
754 // Invoke an interceptor and if it provides a value,
755 // branch to |regular_invoke|.
756 Label regular_invoke;
757 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
758 &regular_invoke);
759
760 // Interceptor returned nothing for this property. Try to use cached
761 // constant function.
762
763 // Check that the maps from interceptor's holder to constant function's
764 // holder haven't changed and thus we can use cached constant function.
765 if (interceptor_holder != lookup->holder()) {
766 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
767 lookup->holder(), scratch1,
768 scratch2, scratch3, name, depth2, miss);
769 } else {
770 // CheckPrototypes has a side effect of fetching a 'holder'
771 // for API (object which is instanceof for the signature). It's
772 // safe to omit it here, as if present, it should be fetched
773 // by the previous CheckPrototypes.
774 ASSERT(depth2 == kInvalidProtoDepth);
775 }
776
777 // Invoke function.
778 if (can_do_fast_api_call) {
779 MaybeObject* result = GenerateFastApiDirectCall(masm,
780 optimization,
781 arguments_.immediate());
782 if (result->IsFailure()) return result;
783 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000784 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
785 ? CALL_AS_FUNCTION
786 : CALL_AS_METHOD;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000787 __ InvokeFunction(optimization.constant_function(), arguments_,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000788 JUMP_FUNCTION, call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000789 }
790
791 // Deferred code for fast API call case---clean preallocated space.
792 if (can_do_fast_api_call) {
793 __ bind(&miss_cleanup);
794 FreeSpaceForFastApiCall(masm);
795 __ Branch(miss_label);
796 }
797
798 // Invoke a regular function.
799 __ bind(&regular_invoke);
800 if (can_do_fast_api_call) {
801 FreeSpaceForFastApiCall(masm);
802 }
803
804 return masm->isolate()->heap()->undefined_value();
lrn@chromium.org7516f052011-03-30 08:52:27 +0000805 }
806
807 void CompileRegular(MacroAssembler* masm,
808 JSObject* object,
809 Register receiver,
810 Register scratch1,
811 Register scratch2,
812 Register scratch3,
813 String* name,
814 JSObject* interceptor_holder,
815 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000816 Register holder =
817 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
818 scratch1, scratch2, scratch3, name,
819 miss_label);
820
821 // Call a runtime function to load the interceptor property.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000822 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000823 // Save the name_ register across the call.
824 __ push(name_);
825
826 PushInterceptorArguments(masm,
827 receiver,
828 holder,
829 name_,
830 interceptor_holder);
831
832 __ CallExternalReference(
833 ExternalReference(
834 IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
835 masm->isolate()),
836 5);
837
838 // Restore the name_ register.
839 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000840
841 // Leave the internal frame.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000842 }
843
844 void LoadWithInterceptor(MacroAssembler* masm,
845 Register receiver,
846 Register holder,
847 JSObject* holder_obj,
848 Register scratch,
849 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000850 {
851 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000852
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000853 __ Push(holder, name_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000854
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000855 CompileCallLoadPropertyWithInterceptor(masm,
856 receiver,
857 holder,
858 name_,
859 holder_obj);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000860
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000861 __ pop(name_); // Restore the name.
862 __ pop(receiver); // Restore the holder.
863 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000864
865 // If interceptor returns no-result sentinel, call the constant function.
866 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
867 __ Branch(interceptor_succeeded, ne, v0, Operand(scratch));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000868 }
869
870 StubCompiler* stub_compiler_;
871 const ParameterCount& arguments_;
872 Register name_;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000873 Code::ExtraICState extra_ic_state_;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000874};
875
876
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000877
878// Generate code to check that a global property cell is empty. Create
879// the property cell at compilation time if no cell exists for the
880// property.
881MUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCell(
882 MacroAssembler* masm,
883 GlobalObject* global,
884 String* name,
885 Register scratch,
886 Label* miss) {
887 Object* probe;
888 { MaybeObject* maybe_probe = global->EnsurePropertyCell(name);
889 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
890 }
891 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
892 ASSERT(cell->value()->IsTheHole());
893 __ li(scratch, Operand(Handle<Object>(cell)));
894 __ lw(scratch,
895 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
896 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
897 __ Branch(miss, ne, scratch, Operand(at));
898 return cell;
899}
900
901
902// Calls GenerateCheckPropertyCell for each global object in the prototype chain
903// from object to (but not including) holder.
904MUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCells(
905 MacroAssembler* masm,
906 JSObject* object,
907 JSObject* holder,
908 String* name,
909 Register scratch,
910 Label* miss) {
911 JSObject* current = object;
912 while (current != holder) {
913 if (current->IsGlobalObject()) {
914 // Returns a cell or a failure.
915 MaybeObject* result = GenerateCheckPropertyCell(
916 masm,
917 GlobalObject::cast(current),
918 name,
919 scratch,
920 miss);
921 if (result->IsFailure()) return result;
922 }
923 ASSERT(current->IsJSObject());
924 current = JSObject::cast(current->GetPrototype());
925 }
926 return NULL;
927}
928
929
930// Convert and store int passed in register ival to IEEE 754 single precision
931// floating point value at memory location (dst + 4 * wordoffset)
932// If FPU is available use it for conversion.
933static void StoreIntAsFloat(MacroAssembler* masm,
934 Register dst,
935 Register wordoffset,
936 Register ival,
937 Register fval,
938 Register scratch1,
939 Register scratch2) {
940 if (CpuFeatures::IsSupported(FPU)) {
941 CpuFeatures::Scope scope(FPU);
942 __ mtc1(ival, f0);
943 __ cvt_s_w(f0, f0);
944 __ sll(scratch1, wordoffset, 2);
945 __ addu(scratch1, dst, scratch1);
946 __ swc1(f0, MemOperand(scratch1, 0));
947 } else {
948 // FPU is not available, do manual conversions.
949
950 Label not_special, done;
951 // Move sign bit from source to destination. This works because the sign
952 // bit in the exponent word of the double has the same position and polarity
953 // as the 2's complement sign bit in a Smi.
954 ASSERT(kBinary32SignMask == 0x80000000u);
955
956 __ And(fval, ival, Operand(kBinary32SignMask));
957 // Negate value if it is negative.
958 __ subu(scratch1, zero_reg, ival);
959 __ movn(ival, scratch1, fval);
960
961 // We have -1, 0 or 1, which we treat specially. Register ival contains
962 // absolute value: it is either equal to 1 (special case of -1 and 1),
963 // greater than 1 (not a special case) or less than 1 (special case of 0).
964 __ Branch(&not_special, gt, ival, Operand(1));
965
966 // For 1 or -1 we need to or in the 0 exponent (biased).
967 static const uint32_t exponent_word_for_1 =
968 kBinary32ExponentBias << kBinary32ExponentShift;
969
970 __ Xor(scratch1, ival, Operand(1));
971 __ li(scratch2, exponent_word_for_1);
972 __ or_(scratch2, fval, scratch2);
973 __ movz(fval, scratch2, scratch1); // Only if ival is equal to 1.
974 __ Branch(&done);
975
976 __ bind(&not_special);
977 // Count leading zeros.
978 // Gets the wrong answer for 0, but we already checked for that case above.
979 Register zeros = scratch2;
980 __ clz(zeros, ival);
981
982 // Compute exponent and or it into the exponent register.
983 __ li(scratch1, (kBitsPerInt - 1) + kBinary32ExponentBias);
984 __ subu(scratch1, scratch1, zeros);
985
986 __ sll(scratch1, scratch1, kBinary32ExponentShift);
987 __ or_(fval, fval, scratch1);
988
989 // Shift up the source chopping the top bit off.
990 __ Addu(zeros, zeros, Operand(1));
991 // This wouldn't work for 1 and -1 as the shift would be 32 which means 0.
992 __ sllv(ival, ival, zeros);
993 // And the top (top 20 bits).
994 __ srl(scratch1, ival, kBitsPerInt - kBinary32MantissaBits);
995 __ or_(fval, fval, scratch1);
996
997 __ bind(&done);
998
999 __ sll(scratch1, wordoffset, 2);
1000 __ addu(scratch1, dst, scratch1);
1001 __ sw(fval, MemOperand(scratch1, 0));
1002 }
1003}
1004
1005
1006// Convert unsigned integer with specified number of leading zeroes in binary
1007// representation to IEEE 754 double.
1008// Integer to convert is passed in register hiword.
1009// Resulting double is returned in registers hiword:loword.
1010// This functions does not work correctly for 0.
1011static void GenerateUInt2Double(MacroAssembler* masm,
1012 Register hiword,
1013 Register loword,
1014 Register scratch,
1015 int leading_zeroes) {
1016 const int meaningful_bits = kBitsPerInt - leading_zeroes - 1;
1017 const int biased_exponent = HeapNumber::kExponentBias + meaningful_bits;
1018
1019 const int mantissa_shift_for_hi_word =
1020 meaningful_bits - HeapNumber::kMantissaBitsInTopWord;
1021
1022 const int mantissa_shift_for_lo_word =
1023 kBitsPerInt - mantissa_shift_for_hi_word;
1024
1025 __ li(scratch, biased_exponent << HeapNumber::kExponentShift);
1026 if (mantissa_shift_for_hi_word > 0) {
1027 __ sll(loword, hiword, mantissa_shift_for_lo_word);
1028 __ srl(hiword, hiword, mantissa_shift_for_hi_word);
1029 __ or_(hiword, scratch, hiword);
1030 } else {
1031 __ mov(loword, zero_reg);
1032 __ sll(hiword, hiword, mantissa_shift_for_hi_word);
1033 __ or_(hiword, scratch, hiword);
1034 }
1035
1036 // If least significant bit of biased exponent was not 1 it was corrupted
1037 // by most significant bit of mantissa so we should fix that.
1038 if (!(biased_exponent & 1)) {
1039 __ li(scratch, 1 << HeapNumber::kExponentShift);
1040 __ nor(scratch, scratch, scratch);
1041 __ and_(hiword, hiword, scratch);
1042 }
1043}
1044
1045
ager@chromium.org5c838252010-02-19 08:53:10 +00001046#undef __
1047#define __ ACCESS_MASM(masm())
1048
1049
lrn@chromium.org7516f052011-03-30 08:52:27 +00001050Register StubCompiler::CheckPrototypes(JSObject* object,
1051 Register object_reg,
1052 JSObject* holder,
1053 Register holder_reg,
1054 Register scratch1,
1055 Register scratch2,
1056 String* name,
1057 int save_at_depth,
1058 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001059 // Make sure there's no overlap between holder and object registers.
1060 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1061 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1062 && !scratch2.is(scratch1));
1063
1064 // Keep track of the current object in register reg.
1065 Register reg = object_reg;
1066 int depth = 0;
1067
1068 if (save_at_depth == depth) {
1069 __ sw(reg, MemOperand(sp));
1070 }
1071
1072 // Check the maps in the prototype chain.
1073 // Traverse the prototype chain from the object and do map checks.
1074 JSObject* current = object;
1075 while (current != holder) {
1076 depth++;
1077
1078 // Only global objects and objects that do not require access
1079 // checks are allowed in stubs.
1080 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1081
1082 ASSERT(current->GetPrototype()->IsJSObject());
1083 JSObject* prototype = JSObject::cast(current->GetPrototype());
1084 if (!current->HasFastProperties() &&
1085 !current->IsJSGlobalObject() &&
1086 !current->IsJSGlobalProxy()) {
1087 if (!name->IsSymbol()) {
1088 MaybeObject* maybe_lookup_result = heap()->LookupSymbol(name);
1089 Object* lookup_result = NULL; // Initialization to please compiler.
1090 if (!maybe_lookup_result->ToObject(&lookup_result)) {
1091 set_failure(Failure::cast(maybe_lookup_result));
1092 return reg;
1093 }
1094 name = String::cast(lookup_result);
1095 }
1096 ASSERT(current->property_dictionary()->FindEntry(name) ==
1097 StringDictionary::kNotFound);
1098
1099 MaybeObject* negative_lookup = GenerateDictionaryNegativeLookup(masm(),
1100 miss,
1101 reg,
1102 name,
1103 scratch1,
1104 scratch2);
1105 if (negative_lookup->IsFailure()) {
1106 set_failure(Failure::cast(negative_lookup));
1107 return reg;
1108 }
1109
1110 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1111 reg = holder_reg; // From now the object is in holder_reg.
1112 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1113 } else if (heap()->InNewSpace(prototype)) {
1114 // Get the map of the current object.
1115 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1116
1117 // Branch on the result of the map check.
1118 __ Branch(miss, ne, scratch1, Operand(Handle<Map>(current->map())));
1119
1120 // Check access rights to the global object. This has to happen
1121 // after the map check so that we know that the object is
1122 // actually a global object.
1123 if (current->IsJSGlobalProxy()) {
1124 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1125 // Restore scratch register to be the map of the object. In the
1126 // new space case below, we load the prototype from the map in
1127 // the scratch register.
1128 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1129 }
1130
1131 reg = holder_reg; // From now the object is in holder_reg.
1132 // The prototype is in new space; we cannot store a reference
1133 // to it in the code. Load it from the map.
1134 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1135 } else {
1136 // Check the map of the current object.
1137 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1138 // Branch on the result of the map check.
1139 __ Branch(miss, ne, scratch1, Operand(Handle<Map>(current->map())));
1140 // Check access rights to the global object. This has to happen
1141 // after the map check so that we know that the object is
1142 // actually a global object.
1143 if (current->IsJSGlobalProxy()) {
1144 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1145 }
1146 // The prototype is in old space; load it directly.
1147 reg = holder_reg; // From now the object is in holder_reg.
1148 __ li(reg, Operand(Handle<JSObject>(prototype)));
1149 }
1150
1151 if (save_at_depth == depth) {
1152 __ sw(reg, MemOperand(sp));
1153 }
1154
1155 // Go to the next object in the prototype chain.
1156 current = prototype;
1157 }
1158
1159 // Check the holder map.
1160 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1161 __ Branch(miss, ne, scratch1, Operand(Handle<Map>(current->map())));
1162
1163 // Log the check depth.
1164 LOG(masm()->isolate(), IntEvent("check-maps-depth", depth + 1));
1165 // Perform security check for access to the global object.
1166 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1167 if (holder->IsJSGlobalProxy()) {
1168 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1169 };
1170
1171 // If we've skipped any global objects, it's not enough to verify
1172 // that their maps haven't changed. We also need to check that the
1173 // property cell for the property is still empty.
1174
1175 MaybeObject* result = GenerateCheckPropertyCells(masm(),
1176 object,
1177 holder,
1178 name,
1179 scratch1,
1180 miss);
1181 if (result->IsFailure()) set_failure(Failure::cast(result));
1182
1183 // Return the register containing the holder.
1184 return reg;
lrn@chromium.org7516f052011-03-30 08:52:27 +00001185}
1186
1187
ager@chromium.org5c838252010-02-19 08:53:10 +00001188void StubCompiler::GenerateLoadField(JSObject* object,
1189 JSObject* holder,
1190 Register receiver,
1191 Register scratch1,
1192 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001193 Register scratch3,
ager@chromium.org5c838252010-02-19 08:53:10 +00001194 int index,
1195 String* name,
1196 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001197 // Check that the receiver isn't a smi.
1198 __ And(scratch1, receiver, Operand(kSmiTagMask));
1199 __ Branch(miss, eq, scratch1, Operand(zero_reg));
1200
1201 // Check that the maps haven't changed.
1202 Register reg =
1203 CheckPrototypes(object, receiver, holder, scratch1, scratch2, scratch3,
1204 name, miss);
1205 GenerateFastPropertyLoad(masm(), v0, reg, holder, index);
1206 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001207}
1208
1209
1210void StubCompiler::GenerateLoadConstant(JSObject* object,
1211 JSObject* holder,
1212 Register receiver,
1213 Register scratch1,
1214 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001215 Register scratch3,
ager@chromium.org5c838252010-02-19 08:53:10 +00001216 Object* value,
1217 String* name,
1218 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001219 // Check that the receiver isn't a smi.
1220 __ JumpIfSmi(receiver, miss, scratch1);
1221
1222 // Check that the maps haven't changed.
1223 Register reg =
1224 CheckPrototypes(object, receiver, holder,
1225 scratch1, scratch2, scratch3, name, miss);
1226
1227 // Return the constant value.
1228 __ li(v0, Operand(Handle<Object>(value)));
1229 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001230}
1231
1232
lrn@chromium.org7516f052011-03-30 08:52:27 +00001233MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object,
1234 JSObject* holder,
1235 Register receiver,
1236 Register name_reg,
1237 Register scratch1,
1238 Register scratch2,
1239 Register scratch3,
1240 AccessorInfo* callback,
1241 String* name,
1242 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001243 // Check that the receiver isn't a smi.
1244 __ JumpIfSmi(receiver, miss, scratch1);
1245
1246 // Check that the maps haven't changed.
1247 Register reg =
1248 CheckPrototypes(object, receiver, holder, scratch1, scratch2, scratch3,
1249 name, miss);
1250
1251 // Build AccessorInfo::args_ list on the stack and push property name below
1252 // the exit frame to make GC aware of them and store pointers to them.
1253 __ push(receiver);
1254 __ mov(scratch2, sp); // scratch2 = AccessorInfo::args_
1255 Handle<AccessorInfo> callback_handle(callback);
1256 if (heap()->InNewSpace(callback_handle->data())) {
1257 __ li(scratch3, callback_handle);
1258 __ lw(scratch3, FieldMemOperand(scratch3, AccessorInfo::kDataOffset));
1259 } else {
1260 __ li(scratch3, Handle<Object>(callback_handle->data()));
1261 }
1262 __ Push(reg, scratch3, name_reg);
1263 __ mov(a2, scratch2); // Saved in case scratch2 == a1.
1264 __ mov(a1, sp); // a1 (first argument - see note below) = Handle<String>
1265
1266 Address getter_address = v8::ToCData<Address>(callback->getter());
1267 ApiFunction fun(getter_address);
1268
1269 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
1270 // struct from the function (which is currently the case). This means we pass
1271 // the arguments in a1-a2 instead of a0-a1. TryCallApiFunctionAndReturn
1272 // will handle setting up a0.
1273
1274 const int kApiStackSpace = 1;
1275
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001276 FrameScope frame_scope(masm(), StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001277 __ EnterExitFrame(false, kApiStackSpace);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001278
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001279 // Create AccessorInfo instance on the stack above the exit frame with
1280 // scratch2 (internal::Object **args_) as the data.
1281 __ sw(a2, MemOperand(sp, kPointerSize));
1282 // a2 (second argument - see note above) = AccessorInfo&
1283 __ Addu(a2, sp, kPointerSize);
1284
1285 // Emitting a stub call may try to allocate (if the code is not
1286 // already generated). Do not allow the assembler to perform a
1287 // garbage collection but instead return the allocation failure
1288 // object.
1289 ExternalReference ref =
1290 ExternalReference(&fun,
1291 ExternalReference::DIRECT_GETTER_CALL,
1292 masm()->isolate());
1293 // 4 args - will be freed later by LeaveExitFrame.
1294 return masm()->TryCallApiFunctionAndReturn(ref, 4);
ager@chromium.org5c838252010-02-19 08:53:10 +00001295}
1296
1297
1298void StubCompiler::GenerateLoadInterceptor(JSObject* object,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001299 JSObject* interceptor_holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001300 LookupResult* lookup,
1301 Register receiver,
1302 Register name_reg,
1303 Register scratch1,
1304 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001305 Register scratch3,
ager@chromium.org5c838252010-02-19 08:53:10 +00001306 String* name,
1307 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001308 ASSERT(interceptor_holder->HasNamedInterceptor());
1309 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1310
1311 // Check that the receiver isn't a smi.
1312 __ JumpIfSmi(receiver, miss);
1313
1314 // So far the most popular follow ups for interceptor loads are FIELD
1315 // and CALLBACKS, so inline only them, other cases may be added
1316 // later.
1317 bool compile_followup_inline = false;
1318 if (lookup->IsProperty() && lookup->IsCacheable()) {
1319 if (lookup->type() == FIELD) {
1320 compile_followup_inline = true;
1321 } else if (lookup->type() == CALLBACKS &&
1322 lookup->GetCallbackObject()->IsAccessorInfo() &&
1323 AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) {
1324 compile_followup_inline = true;
1325 }
1326 }
1327
1328 if (compile_followup_inline) {
1329 // Compile the interceptor call, followed by inline code to load the
1330 // property from further up the prototype chain if the call fails.
1331 // Check that the maps haven't changed.
1332 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1333 scratch1, scratch2, scratch3,
1334 name, miss);
1335 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
1336
1337 // Save necessary data before invoking an interceptor.
1338 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001339 {
1340 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001341
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001342 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
1343 // CALLBACKS case needs a receiver to be passed into C++ callback.
1344 __ Push(receiver, holder_reg, name_reg);
1345 } else {
1346 __ Push(holder_reg, name_reg);
1347 }
1348
1349 // Invoke an interceptor. Note: map checks from receiver to
1350 // interceptor's holder has been compiled before (see a caller
1351 // of this method).
1352 CompileCallLoadPropertyWithInterceptor(masm(),
1353 receiver,
1354 holder_reg,
1355 name_reg,
1356 interceptor_holder);
1357
1358 // Check if interceptor provided a value for property. If it's
1359 // the case, return immediately.
1360 Label interceptor_failed;
1361 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
1362 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1));
1363 frame_scope.GenerateLeaveFrame();
1364 __ Ret();
1365
1366 __ bind(&interceptor_failed);
1367 __ pop(name_reg);
1368 __ pop(holder_reg);
1369 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
1370 __ pop(receiver);
1371 }
1372
1373 // Leave the internal frame.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001374 }
1375
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001376 // Check that the maps from interceptor's holder to lookup's holder
1377 // haven't changed. And load lookup's holder into |holder| register.
1378 if (interceptor_holder != lookup->holder()) {
1379 holder_reg = CheckPrototypes(interceptor_holder,
1380 holder_reg,
1381 lookup->holder(),
1382 scratch1,
1383 scratch2,
1384 scratch3,
1385 name,
1386 miss);
1387 }
1388
1389 if (lookup->type() == FIELD) {
1390 // We found FIELD property in prototype chain of interceptor's holder.
1391 // Retrieve a field from field's holder.
1392 GenerateFastPropertyLoad(masm(), v0, holder_reg,
1393 lookup->holder(), lookup->GetFieldIndex());
1394 __ Ret();
1395 } else {
1396 // We found CALLBACKS property in prototype chain of interceptor's
1397 // holder.
1398 ASSERT(lookup->type() == CALLBACKS);
1399 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
1400 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
1401 ASSERT(callback != NULL);
1402 ASSERT(callback->getter() != NULL);
1403
1404 // Tail call to runtime.
1405 // Important invariant in CALLBACKS case: the code above must be
1406 // structured to never clobber |receiver| register.
1407 __ li(scratch2, Handle<AccessorInfo>(callback));
1408 // holder_reg is either receiver or scratch1.
1409 if (!receiver.is(holder_reg)) {
1410 ASSERT(scratch1.is(holder_reg));
1411 __ Push(receiver, holder_reg);
1412 __ lw(scratch3,
1413 FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
1414 __ Push(scratch3, scratch2, name_reg);
1415 } else {
1416 __ push(receiver);
1417 __ lw(scratch3,
1418 FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
1419 __ Push(holder_reg, scratch3, scratch2, name_reg);
1420 }
1421
1422 ExternalReference ref =
1423 ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
1424 masm()->isolate());
1425 __ TailCallExternalReference(ref, 5, 1);
1426 }
1427 } else { // !compile_followup_inline
1428 // Call the runtime system to load the interceptor.
1429 // Check that the maps haven't changed.
1430 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1431 scratch1, scratch2, scratch3,
1432 name, miss);
1433 PushInterceptorArguments(masm(), receiver, holder_reg,
1434 name_reg, interceptor_holder);
1435
1436 ExternalReference ref = ExternalReference(
1437 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), masm()->isolate());
1438 __ TailCallExternalReference(ref, 5, 1);
1439 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001440}
1441
1442
lrn@chromium.org7516f052011-03-30 08:52:27 +00001443void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001444 if (kind_ == Code::KEYED_CALL_IC) {
1445 __ Branch(miss, ne, a2, Operand(Handle<String>(name)));
1446 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001447}
1448
1449
lrn@chromium.org7516f052011-03-30 08:52:27 +00001450void CallStubCompiler::GenerateGlobalReceiverCheck(JSObject* object,
1451 JSObject* holder,
1452 String* name,
1453 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001454 ASSERT(holder->IsGlobalObject());
1455
1456 // Get the number of arguments.
1457 const int argc = arguments().immediate();
1458
1459 // Get the receiver from the stack.
1460 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1461
1462 // If the object is the holder then we know that it's a global
1463 // object which can only happen for contextual calls. In this case,
1464 // the receiver cannot be a smi.
1465 if (object != holder) {
1466 __ JumpIfSmi(a0, miss);
1467 }
1468
1469 // Check that the maps haven't changed.
1470 CheckPrototypes(object, a0, holder, a3, a1, t0, name, miss);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001471}
1472
1473
lrn@chromium.org7516f052011-03-30 08:52:27 +00001474void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell,
1475 JSFunction* function,
1476 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001477 // Get the value from the cell.
1478 __ li(a3, Operand(Handle<JSGlobalPropertyCell>(cell)));
1479 __ lw(a1, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
1480
1481 // Check that the cell contains the same function.
1482 if (heap()->InNewSpace(function)) {
1483 // We can't embed a pointer to a function in new space so we have
1484 // to verify that the shared function info is unchanged. This has
1485 // the nice side effect that multiple closures based on the same
1486 // function can all use this call IC. Before we load through the
1487 // function, we have to verify that it still is a function.
1488 __ JumpIfSmi(a1, miss);
1489 __ GetObjectType(a1, a3, a3);
1490 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
1491
1492 // Check the shared function info. Make sure it hasn't changed.
1493 __ li(a3, Handle<SharedFunctionInfo>(function->shared()));
1494 __ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
1495 __ Branch(miss, ne, t0, Operand(a3));
1496 } else {
1497 __ Branch(miss, ne, a1, Operand(Handle<JSFunction>(function)));
1498 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001499}
1500
1501
lrn@chromium.org7516f052011-03-30 08:52:27 +00001502MaybeObject* CallStubCompiler::GenerateMissBranch() {
danno@chromium.org40cb8782011-05-25 07:58:50 +00001503 MaybeObject* maybe_obj =
1504 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1505 kind_,
1506 extra_ic_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001507 Object* obj;
1508 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1509 __ Jump(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET);
1510 return obj;
ager@chromium.org5c838252010-02-19 08:53:10 +00001511}
1512
1513
lrn@chromium.org7516f052011-03-30 08:52:27 +00001514MaybeObject* CallStubCompiler::CompileCallField(JSObject* object,
1515 JSObject* holder,
1516 int index,
ager@chromium.org5c838252010-02-19 08:53:10 +00001517 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001518 // ----------- S t a t e -------------
1519 // -- a2 : name
1520 // -- ra : return address
1521 // -----------------------------------
1522 Label miss;
1523
1524 GenerateNameCheck(name, &miss);
1525
1526 const int argc = arguments().immediate();
1527
1528 // Get the receiver of the function from the stack into a0.
1529 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1530 // Check that the receiver isn't a smi.
1531 __ JumpIfSmi(a0, &miss, t0);
1532
1533 // Do the right check and compute the holder register.
1534 Register reg = CheckPrototypes(object, a0, holder, a1, a3, t0, name, &miss);
1535 GenerateFastPropertyLoad(masm(), a1, reg, holder, index);
1536
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001537 GenerateCallFunction(masm(), object, arguments(), &miss, extra_ic_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001538
1539 // Handle call cache miss.
1540 __ bind(&miss);
1541 MaybeObject* maybe_result = GenerateMissBranch();
1542 if (maybe_result->IsFailure()) return maybe_result;
1543
1544 // Return the generated code.
1545 return GetCode(FIELD, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001546}
1547
1548
lrn@chromium.org7516f052011-03-30 08:52:27 +00001549MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
1550 JSObject* holder,
1551 JSGlobalPropertyCell* cell,
1552 JSFunction* function,
1553 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001554 // ----------- S t a t e -------------
1555 // -- a2 : name
1556 // -- ra : return address
1557 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1558 // -- ...
1559 // -- sp[argc * 4] : receiver
1560 // -----------------------------------
1561
1562 // If object is not an array, bail out to regular call.
1563 if (!object->IsJSArray() || cell != NULL) return heap()->undefined_value();
1564
1565 Label miss;
1566
1567 GenerateNameCheck(name, &miss);
1568
1569 Register receiver = a1;
1570
1571 // Get the receiver from the stack.
1572 const int argc = arguments().immediate();
1573 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1574
1575 // Check that the receiver isn't a smi.
1576 __ JumpIfSmi(receiver, &miss);
1577
1578 // Check that the maps haven't changed.
1579 CheckPrototypes(JSObject::cast(object), receiver,
1580 holder, a3, v0, t0, name, &miss);
1581
1582 if (argc == 0) {
1583 // Nothing to do, just return the length.
1584 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1585 __ Drop(argc + 1);
1586 __ Ret();
1587 } else {
1588 Label call_builtin;
1589
1590 Register elements = a3;
1591 Register end_elements = t1;
1592
1593 // Get the elements array of the object.
1594 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1595
1596 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001597 __ CheckMap(elements,
1598 v0,
1599 Heap::kFixedArrayMapRootIndex,
1600 &call_builtin,
1601 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001602
1603 if (argc == 1) { // Otherwise fall through to call the builtin.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001604 Label attempt_to_grow_elements;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001605
1606 // Get the array's length into v0 and calculate new length.
1607 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1608 STATIC_ASSERT(kSmiTagSize == 1);
1609 STATIC_ASSERT(kSmiTag == 0);
1610 __ Addu(v0, v0, Operand(Smi::FromInt(argc)));
1611
1612 // Get the element's length.
1613 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1614
1615 // Check if we could survive without allocation.
1616 __ Branch(&attempt_to_grow_elements, gt, v0, Operand(t0));
1617
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001618 // Check if value is a smi.
1619 Label with_write_barrier;
1620 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1621 __ JumpIfNotSmi(t0, &with_write_barrier);
1622
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001623 // Save new length.
1624 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1625
1626 // Push the element.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001627 // We may need a register containing the address end_elements below,
1628 // so write back the value in end_elements.
1629 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1630 __ Addu(end_elements, elements, end_elements);
1631 const int kEndElementsOffset =
1632 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001633 __ Addu(end_elements, end_elements, kEndElementsOffset);
1634 __ sw(t0, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001635
1636 // Check for a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001637 __ Drop(argc + 1);
1638 __ Ret();
1639
1640 __ bind(&with_write_barrier);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001641
1642 __ lw(t2, FieldMemOperand(receiver, HeapObject::kMapOffset));
1643 __ CheckFastSmiOnlyElements(t2, t2, &call_builtin);
1644
1645 // Save new length.
1646 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1647
1648 // Push the element.
1649 // We may need a register containing the address end_elements below,
1650 // so write back the value in end_elements.
1651 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1652 __ Addu(end_elements, elements, end_elements);
1653 __ Addu(end_elements, end_elements, kEndElementsOffset);
1654 __ sw(t0, MemOperand(end_elements));
1655
1656 __ RecordWrite(elements,
1657 end_elements,
1658 t0,
1659 kRAHasNotBeenSaved,
1660 kDontSaveFPRegs,
1661 EMIT_REMEMBERED_SET,
1662 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001663 __ Drop(argc + 1);
1664 __ Ret();
1665
1666 __ bind(&attempt_to_grow_elements);
1667 // v0: array's length + 1.
1668 // t0: elements' length.
1669
1670 if (!FLAG_inline_new) {
1671 __ Branch(&call_builtin);
1672 }
1673
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001674 __ lw(a2, MemOperand(sp, (argc - 1) * kPointerSize));
1675 // Growing elements that are SMI-only requires special handling in case
1676 // the new element is non-Smi. For now, delegate to the builtin.
1677 Label no_fast_elements_check;
1678 __ JumpIfSmi(a2, &no_fast_elements_check);
1679 __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1680 __ CheckFastObjectElements(t3, t3, &call_builtin);
1681 __ bind(&no_fast_elements_check);
1682
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001683 ExternalReference new_space_allocation_top =
1684 ExternalReference::new_space_allocation_top_address(
1685 masm()->isolate());
1686 ExternalReference new_space_allocation_limit =
1687 ExternalReference::new_space_allocation_limit_address(
1688 masm()->isolate());
1689
1690 const int kAllocationDelta = 4;
1691 // Load top and check if it is the end of elements.
1692 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1693 __ Addu(end_elements, elements, end_elements);
1694 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset));
1695 __ li(t3, Operand(new_space_allocation_top));
1696 __ lw(t2, MemOperand(t3));
1697 __ Branch(&call_builtin, ne, end_elements, Operand(t2));
1698
1699 __ li(t5, Operand(new_space_allocation_limit));
1700 __ lw(t5, MemOperand(t5));
1701 __ Addu(t2, t2, Operand(kAllocationDelta * kPointerSize));
1702 __ Branch(&call_builtin, hi, t2, Operand(t5));
1703
1704 // We fit and could grow elements.
1705 // Update new_space_allocation_top.
1706 __ sw(t2, MemOperand(t3));
1707 // Push the argument.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001708 __ sw(a2, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001709 // Fill the rest with holes.
1710 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1711 for (int i = 1; i < kAllocationDelta; i++) {
1712 __ sw(t2, MemOperand(end_elements, i * kPointerSize));
1713 }
1714
1715 // Update elements' and array's sizes.
1716 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1717 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta)));
1718 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1719
1720 // Elements are in new space, so write barrier is not required.
1721 __ Drop(argc + 1);
1722 __ Ret();
1723 }
1724 __ bind(&call_builtin);
1725 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
1726 masm()->isolate()),
1727 argc + 1,
1728 1);
1729 }
1730
1731 // Handle call cache miss.
1732 __ bind(&miss);
1733 MaybeObject* maybe_result = GenerateMissBranch();
1734 if (maybe_result->IsFailure()) return maybe_result;
1735
1736 // Return the generated code.
1737 return GetCode(function);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001738}
1739
1740
1741MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object,
1742 JSObject* holder,
1743 JSGlobalPropertyCell* cell,
1744 JSFunction* function,
ager@chromium.org5c838252010-02-19 08:53:10 +00001745 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001746 // ----------- S t a t e -------------
1747 // -- a2 : name
1748 // -- ra : return address
1749 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1750 // -- ...
1751 // -- sp[argc * 4] : receiver
1752 // -----------------------------------
1753
1754 // If object is not an array, bail out to regular call.
1755 if (!object->IsJSArray() || cell != NULL) return heap()->undefined_value();
1756
1757 Label miss, return_undefined, call_builtin;
1758
1759 Register receiver = a1;
1760 Register elements = a3;
1761
1762 GenerateNameCheck(name, &miss);
1763
1764 // Get the receiver from the stack.
1765 const int argc = arguments().immediate();
1766 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1767
1768 // Check that the receiver isn't a smi.
1769 __ JumpIfSmi(receiver, &miss);
1770
1771 // Check that the maps haven't changed.
1772 CheckPrototypes(JSObject::cast(object),
1773 receiver, holder, elements, t0, v0, name, &miss);
1774
1775 // Get the elements array of the object.
1776 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1777
1778 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001779 __ CheckMap(elements,
1780 v0,
1781 Heap::kFixedArrayMapRootIndex,
1782 &call_builtin,
1783 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001784
1785 // Get the array's length into t0 and calculate new length.
1786 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1787 __ Subu(t0, t0, Operand(Smi::FromInt(1)));
1788 __ Branch(&return_undefined, lt, t0, Operand(zero_reg));
1789
1790 // Get the last element.
1791 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1792 STATIC_ASSERT(kSmiTagSize == 1);
1793 STATIC_ASSERT(kSmiTag == 0);
1794 // We can't address the last element in one operation. Compute the more
1795 // expensive shift first, and use an offset later on.
1796 __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize);
1797 __ Addu(elements, elements, t1);
1798 __ lw(v0, MemOperand(elements, FixedArray::kHeaderSize - kHeapObjectTag));
1799 __ Branch(&call_builtin, eq, v0, Operand(t2));
1800
1801 // Set the array's length.
1802 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1803
1804 // Fill with the hole.
1805 __ sw(t2, MemOperand(elements, FixedArray::kHeaderSize - kHeapObjectTag));
1806 __ Drop(argc + 1);
1807 __ Ret();
1808
1809 __ bind(&return_undefined);
1810 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
1811 __ Drop(argc + 1);
1812 __ Ret();
1813
1814 __ bind(&call_builtin);
1815 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop,
1816 masm()->isolate()),
1817 argc + 1,
1818 1);
1819
1820 // Handle call cache miss.
1821 __ bind(&miss);
1822 MaybeObject* maybe_result = GenerateMissBranch();
1823 if (maybe_result->IsFailure()) return maybe_result;
1824
1825 // Return the generated code.
1826 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001827}
1828
1829
lrn@chromium.org7516f052011-03-30 08:52:27 +00001830MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
1831 Object* object,
1832 JSObject* holder,
1833 JSGlobalPropertyCell* cell,
1834 JSFunction* function,
1835 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001836 // ----------- S t a t e -------------
1837 // -- a2 : function name
1838 // -- ra : return address
1839 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1840 // -- ...
1841 // -- sp[argc * 4] : receiver
1842 // -----------------------------------
1843
1844 // If object is not a string, bail out to regular call.
1845 if (!object->IsString() || cell != NULL) return heap()->undefined_value();
1846
1847 const int argc = arguments().immediate();
1848
1849 Label miss;
1850 Label name_miss;
1851 Label index_out_of_range;
1852
1853 Label* index_out_of_range_label = &index_out_of_range;
1854
danno@chromium.org40cb8782011-05-25 07:58:50 +00001855 if (kind_ == Code::CALL_IC &&
1856 (CallICBase::StringStubState::decode(extra_ic_state_) ==
1857 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001858 index_out_of_range_label = &miss;
1859 }
1860
1861 GenerateNameCheck(name, &name_miss);
1862
1863 // Check that the maps starting from the prototype haven't changed.
1864 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1865 Context::STRING_FUNCTION_INDEX,
1866 v0,
1867 &miss);
1868 ASSERT(object != holder);
1869 CheckPrototypes(JSObject::cast(object->GetPrototype()), v0, holder,
1870 a1, a3, t0, name, &miss);
1871
1872 Register receiver = a1;
1873 Register index = t1;
1874 Register scratch = a3;
1875 Register result = v0;
1876 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1877 if (argc > 0) {
1878 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1879 } else {
1880 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1881 }
1882
1883 StringCharCodeAtGenerator char_code_at_generator(receiver,
1884 index,
1885 scratch,
1886 result,
1887 &miss, // When not a string.
1888 &miss, // When not a number.
1889 index_out_of_range_label,
1890 STRING_INDEX_IS_NUMBER);
1891 char_code_at_generator.GenerateFast(masm());
1892 __ Drop(argc + 1);
1893 __ Ret();
1894
1895 StubRuntimeCallHelper call_helper;
1896 char_code_at_generator.GenerateSlow(masm(), call_helper);
1897
1898 if (index_out_of_range.is_linked()) {
1899 __ bind(&index_out_of_range);
1900 __ LoadRoot(v0, Heap::kNanValueRootIndex);
1901 __ Drop(argc + 1);
1902 __ Ret();
1903 }
1904
1905 __ bind(&miss);
1906 // Restore function name in a2.
1907 __ li(a2, Handle<String>(name));
1908 __ bind(&name_miss);
1909 MaybeObject* maybe_result = GenerateMissBranch();
1910 if (maybe_result->IsFailure()) return maybe_result;
1911
1912 // Return the generated code.
1913 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001914}
1915
1916
lrn@chromium.org7516f052011-03-30 08:52:27 +00001917MaybeObject* CallStubCompiler::CompileStringCharAtCall(
1918 Object* object,
1919 JSObject* holder,
1920 JSGlobalPropertyCell* cell,
1921 JSFunction* function,
1922 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001923 // ----------- S t a t e -------------
1924 // -- a2 : function name
1925 // -- ra : return address
1926 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1927 // -- ...
1928 // -- sp[argc * 4] : receiver
1929 // -----------------------------------
1930
1931 // If object is not a string, bail out to regular call.
1932 if (!object->IsString() || cell != NULL) return heap()->undefined_value();
1933
1934 const int argc = arguments().immediate();
1935
1936 Label miss;
1937 Label name_miss;
1938 Label index_out_of_range;
1939 Label* index_out_of_range_label = &index_out_of_range;
1940
danno@chromium.org40cb8782011-05-25 07:58:50 +00001941 if (kind_ == Code::CALL_IC &&
1942 (CallICBase::StringStubState::decode(extra_ic_state_) ==
1943 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001944 index_out_of_range_label = &miss;
1945 }
1946
1947 GenerateNameCheck(name, &name_miss);
1948
1949 // Check that the maps starting from the prototype haven't changed.
1950 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1951 Context::STRING_FUNCTION_INDEX,
1952 v0,
1953 &miss);
1954 ASSERT(object != holder);
1955 CheckPrototypes(JSObject::cast(object->GetPrototype()), v0, holder,
1956 a1, a3, t0, name, &miss);
1957
1958 Register receiver = v0;
1959 Register index = t1;
1960 Register scratch1 = a1;
1961 Register scratch2 = a3;
1962 Register result = v0;
1963 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1964 if (argc > 0) {
1965 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1966 } else {
1967 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1968 }
1969
1970 StringCharAtGenerator char_at_generator(receiver,
1971 index,
1972 scratch1,
1973 scratch2,
1974 result,
1975 &miss, // When not a string.
1976 &miss, // When not a number.
1977 index_out_of_range_label,
1978 STRING_INDEX_IS_NUMBER);
1979 char_at_generator.GenerateFast(masm());
1980 __ Drop(argc + 1);
1981 __ Ret();
1982
1983 StubRuntimeCallHelper call_helper;
1984 char_at_generator.GenerateSlow(masm(), call_helper);
1985
1986 if (index_out_of_range.is_linked()) {
1987 __ bind(&index_out_of_range);
1988 __ LoadRoot(v0, Heap::kEmptyStringRootIndex);
1989 __ Drop(argc + 1);
1990 __ Ret();
1991 }
1992
1993 __ bind(&miss);
1994 // Restore function name in a2.
1995 __ li(a2, Handle<String>(name));
1996 __ bind(&name_miss);
1997 MaybeObject* maybe_result = GenerateMissBranch();
1998 if (maybe_result->IsFailure()) return maybe_result;
1999
2000 // Return the generated code.
2001 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002002}
2003
2004
lrn@chromium.org7516f052011-03-30 08:52:27 +00002005MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall(
2006 Object* object,
2007 JSObject* holder,
2008 JSGlobalPropertyCell* cell,
2009 JSFunction* function,
2010 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002011 // ----------- S t a t e -------------
2012 // -- a2 : function name
2013 // -- ra : return address
2014 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2015 // -- ...
2016 // -- sp[argc * 4] : receiver
2017 // -----------------------------------
2018
2019 const int argc = arguments().immediate();
2020
2021 // If the object is not a JSObject or we got an unexpected number of
2022 // arguments, bail out to the regular call.
2023 if (!object->IsJSObject() || argc != 1) return heap()->undefined_value();
2024
2025 Label miss;
2026 GenerateNameCheck(name, &miss);
2027
2028 if (cell == NULL) {
2029 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
2030
2031 STATIC_ASSERT(kSmiTag == 0);
2032 __ JumpIfSmi(a1, &miss);
2033
2034 CheckPrototypes(JSObject::cast(object), a1, holder, v0, a3, t0, name,
2035 &miss);
2036 } else {
2037 ASSERT(cell->value() == function);
2038 GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
2039 GenerateLoadFunctionFromCell(cell, function, &miss);
2040 }
2041
2042 // Load the char code argument.
2043 Register code = a1;
2044 __ lw(code, MemOperand(sp, 0 * kPointerSize));
2045
2046 // Check the code is a smi.
2047 Label slow;
2048 STATIC_ASSERT(kSmiTag == 0);
2049 __ JumpIfNotSmi(code, &slow);
2050
2051 // Convert the smi code to uint16.
2052 __ And(code, code, Operand(Smi::FromInt(0xffff)));
2053
2054 StringCharFromCodeGenerator char_from_code_generator(code, v0);
2055 char_from_code_generator.GenerateFast(masm());
2056 __ Drop(argc + 1);
2057 __ Ret();
2058
2059 StubRuntimeCallHelper call_helper;
2060 char_from_code_generator.GenerateSlow(masm(), call_helper);
2061
2062 // Tail call the full function. We do not have to patch the receiver
2063 // because the function makes no use of it.
2064 __ bind(&slow);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002065 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002066
2067 __ bind(&miss);
2068 // a2: function name.
2069 MaybeObject* maybe_result = GenerateMissBranch();
2070 if (maybe_result->IsFailure()) return maybe_result;
2071
2072 // Return the generated code.
2073 return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002074}
2075
2076
lrn@chromium.org7516f052011-03-30 08:52:27 +00002077MaybeObject* CallStubCompiler::CompileMathFloorCall(Object* object,
2078 JSObject* holder,
2079 JSGlobalPropertyCell* cell,
2080 JSFunction* function,
2081 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002082 // ----------- S t a t e -------------
2083 // -- a2 : function name
2084 // -- ra : return address
2085 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2086 // -- ...
2087 // -- sp[argc * 4] : receiver
2088 // -----------------------------------
2089
2090 if (!CpuFeatures::IsSupported(FPU))
2091 return heap()->undefined_value();
2092 CpuFeatures::Scope scope_fpu(FPU);
2093
2094 const int argc = arguments().immediate();
2095
2096 // If the object is not a JSObject or we got an unexpected number of
2097 // arguments, bail out to the regular call.
2098 if (!object->IsJSObject() || argc != 1) return heap()->undefined_value();
2099
2100 Label miss, slow;
2101 GenerateNameCheck(name, &miss);
2102
2103 if (cell == NULL) {
2104 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
2105
2106 STATIC_ASSERT(kSmiTag == 0);
2107 __ JumpIfSmi(a1, &miss);
2108
2109 CheckPrototypes(JSObject::cast(object), a1, holder, a0, a3, t0, name,
2110 &miss);
2111 } else {
2112 ASSERT(cell->value() == function);
2113 GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
2114 GenerateLoadFunctionFromCell(cell, function, &miss);
2115 }
2116
2117 // Load the (only) argument into v0.
2118 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2119
2120 // If the argument is a smi, just return.
2121 STATIC_ASSERT(kSmiTag == 0);
2122 __ And(t0, v0, Operand(kSmiTagMask));
2123 __ Drop(argc + 1, eq, t0, Operand(zero_reg));
2124 __ Ret(eq, t0, Operand(zero_reg));
2125
danno@chromium.org40cb8782011-05-25 07:58:50 +00002126 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002127
2128 Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return;
2129
2130 // If fpu is enabled, we use the floor instruction.
2131
2132 // Load the HeapNumber value.
2133 __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2134
2135 // Backup FCSR.
2136 __ cfc1(a3, FCSR);
2137 // Clearing FCSR clears the exception mask with no side-effects.
2138 __ ctc1(zero_reg, FCSR);
2139 // Convert the argument to an integer.
2140 __ floor_w_d(f0, f0);
2141
2142 // Start checking for special cases.
2143 // Get the argument exponent and clear the sign bit.
2144 __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize));
2145 __ And(t2, t1, Operand(~HeapNumber::kSignMask));
2146 __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord);
2147
2148 // Retrieve FCSR and check for fpu errors.
2149 __ cfc1(t5, FCSR);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002150 __ And(t5, t5, Operand(kFCSRExceptionFlagMask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002151 __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));
2152
2153 // Check for NaN, Infinity, and -Infinity.
2154 // They are invariant through a Math.Floor call, so just
2155 // return the original argument.
2156 __ Subu(t3, t2, Operand(HeapNumber::kExponentMask
2157 >> HeapNumber::kMantissaBitsInTopWord));
2158 __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg));
2159 // We had an overflow or underflow in the conversion. Check if we
2160 // have a big exponent.
2161 // If greater or equal, the argument is already round and in v0.
2162 __ Branch(&restore_fcsr_and_return, ge, t3,
2163 Operand(HeapNumber::kMantissaBits));
2164 __ Branch(&wont_fit_smi);
2165
2166 __ bind(&no_fpu_error);
2167 // Move the result back to v0.
2168 __ mfc1(v0, f0);
2169 // Check if the result fits into a smi.
2170 __ Addu(a1, v0, Operand(0x40000000));
2171 __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg));
2172 // Tag the result.
2173 STATIC_ASSERT(kSmiTag == 0);
2174 __ sll(v0, v0, kSmiTagSize);
2175
2176 // Check for -0.
2177 __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg));
2178 // t1 already holds the HeapNumber exponent.
2179 __ And(t0, t1, Operand(HeapNumber::kSignMask));
2180 // If our HeapNumber is negative it was -0, so load its address and return.
2181 // Else v0 is loaded with 0, so we can also just return.
2182 __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg));
2183 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2184
2185 __ bind(&restore_fcsr_and_return);
2186 // Restore FCSR and return.
2187 __ ctc1(a3, FCSR);
2188
2189 __ Drop(argc + 1);
2190 __ Ret();
2191
2192 __ bind(&wont_fit_smi);
2193 // Restore FCSR and fall to slow case.
2194 __ ctc1(a3, FCSR);
2195
2196 __ bind(&slow);
2197 // Tail call the full function. We do not have to patch the receiver
2198 // because the function makes no use of it.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002199 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002200
2201 __ bind(&miss);
2202 // a2: function name.
2203 MaybeObject* obj = GenerateMissBranch();
2204 if (obj->IsFailure()) return obj;
2205
2206 // Return the generated code.
2207 return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002208}
2209
2210
lrn@chromium.org7516f052011-03-30 08:52:27 +00002211MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object,
2212 JSObject* holder,
2213 JSGlobalPropertyCell* cell,
2214 JSFunction* function,
2215 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002216 // ----------- S t a t e -------------
2217 // -- a2 : function name
2218 // -- ra : return address
2219 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2220 // -- ...
2221 // -- sp[argc * 4] : receiver
2222 // -----------------------------------
2223
2224 const int argc = arguments().immediate();
2225
2226 // If the object is not a JSObject or we got an unexpected number of
2227 // arguments, bail out to the regular call.
2228 if (!object->IsJSObject() || argc != 1) return heap()->undefined_value();
2229
2230 Label miss;
2231 GenerateNameCheck(name, &miss);
2232
2233 if (cell == NULL) {
2234 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
2235
2236 STATIC_ASSERT(kSmiTag == 0);
2237 __ JumpIfSmi(a1, &miss);
2238
2239 CheckPrototypes(JSObject::cast(object), a1, holder, v0, a3, t0, name,
2240 &miss);
2241 } else {
2242 ASSERT(cell->value() == function);
2243 GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
2244 GenerateLoadFunctionFromCell(cell, function, &miss);
2245 }
2246
2247 // Load the (only) argument into v0.
2248 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2249
2250 // Check if the argument is a smi.
2251 Label not_smi;
2252 STATIC_ASSERT(kSmiTag == 0);
2253 __ JumpIfNotSmi(v0, &not_smi);
2254
2255 // Do bitwise not or do nothing depending on the sign of the
2256 // argument.
2257 __ sra(t0, v0, kBitsPerInt - 1);
2258 __ Xor(a1, v0, t0);
2259
2260 // Add 1 or do nothing depending on the sign of the argument.
2261 __ Subu(v0, a1, t0);
2262
2263 // If the result is still negative, go to the slow case.
2264 // This only happens for the most negative smi.
2265 Label slow;
2266 __ Branch(&slow, lt, v0, Operand(zero_reg));
2267
2268 // Smi case done.
2269 __ Drop(argc + 1);
2270 __ Ret();
2271
2272 // Check if the argument is a heap number and load its exponent and
2273 // sign.
2274 __ bind(&not_smi);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002275 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002276 __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2277
2278 // Check the sign of the argument. If the argument is positive,
2279 // just return it.
2280 Label negative_sign;
2281 __ And(t0, a1, Operand(HeapNumber::kSignMask));
2282 __ Branch(&negative_sign, ne, t0, Operand(zero_reg));
2283 __ Drop(argc + 1);
2284 __ Ret();
2285
2286 // If the argument is negative, clear the sign, and return a new
2287 // number.
2288 __ bind(&negative_sign);
2289 __ Xor(a1, a1, Operand(HeapNumber::kSignMask));
2290 __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2291 __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
2292 __ AllocateHeapNumber(v0, t0, t1, t2, &slow);
2293 __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2294 __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2295 __ Drop(argc + 1);
2296 __ Ret();
2297
2298 // Tail call the full function. We do not have to patch the receiver
2299 // because the function makes no use of it.
2300 __ bind(&slow);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002301 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002302
2303 __ bind(&miss);
2304 // a2: function name.
2305 MaybeObject* maybe_result = GenerateMissBranch();
2306 if (maybe_result->IsFailure()) return maybe_result;
2307
2308 // Return the generated code.
2309 return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002310}
2311
2312
lrn@chromium.org7516f052011-03-30 08:52:27 +00002313MaybeObject* CallStubCompiler::CompileFastApiCall(
2314 const CallOptimization& optimization,
2315 Object* object,
2316 JSObject* holder,
2317 JSGlobalPropertyCell* cell,
2318 JSFunction* function,
2319 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002320
danno@chromium.org40cb8782011-05-25 07:58:50 +00002321 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002322
2323 ASSERT(optimization.is_simple_api_call());
2324 // Bail out if object is a global object as we don't want to
2325 // repatch it to global receiver.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002326 if (object->IsGlobalObject()) return heap()->undefined_value();
2327 if (cell != NULL) return heap()->undefined_value();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002328 if (!object->IsJSObject()) return heap()->undefined_value();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002329 int depth = optimization.GetPrototypeDepthOfExpectedType(
2330 JSObject::cast(object), holder);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002331 if (depth == kInvalidProtoDepth) return heap()->undefined_value();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002332
2333 Label miss, miss_before_stack_reserved;
2334
2335 GenerateNameCheck(name, &miss_before_stack_reserved);
2336
2337 // Get the receiver from the stack.
2338 const int argc = arguments().immediate();
2339 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2340
2341 // Check that the receiver isn't a smi.
2342 __ JumpIfSmi(a1, &miss_before_stack_reserved);
2343
2344 __ IncrementCounter(counters->call_const(), 1, a0, a3);
2345 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2346
2347 ReserveSpaceForFastApiCall(masm(), a0);
2348
2349 // Check that the maps haven't changed and find a Holder as a side effect.
2350 CheckPrototypes(JSObject::cast(object), a1, holder, a0, a3, t0, name,
2351 depth, &miss);
2352
2353 MaybeObject* result = GenerateFastApiDirectCall(masm(), optimization, argc);
2354 if (result->IsFailure()) return result;
2355
2356 __ bind(&miss);
2357 FreeSpaceForFastApiCall(masm());
2358
2359 __ bind(&miss_before_stack_reserved);
2360 MaybeObject* maybe_result = GenerateMissBranch();
2361 if (maybe_result->IsFailure()) return maybe_result;
2362
2363 // Return the generated code.
2364 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002365}
2366
2367
lrn@chromium.org7516f052011-03-30 08:52:27 +00002368MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
ager@chromium.org5c838252010-02-19 08:53:10 +00002369 JSObject* holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002370 JSFunction* function,
2371 String* name,
2372 CheckType check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002373 // ----------- S t a t e -------------
2374 // -- a2 : name
2375 // -- ra : return address
2376 // -----------------------------------
2377 if (HasCustomCallGenerator(function)) {
2378 MaybeObject* maybe_result = CompileCustomCall(
2379 object, holder, NULL, function, name);
2380 Object* result;
2381 if (!maybe_result->ToObject(&result)) return maybe_result;
2382 // Undefined means bail out to regular compiler.
2383 if (!result->IsUndefined()) return result;
2384 }
2385
2386 Label miss;
2387
2388 GenerateNameCheck(name, &miss);
2389
2390 // Get the receiver from the stack.
2391 const int argc = arguments().immediate();
2392 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2393
2394 // Check that the receiver isn't a smi.
2395 if (check != NUMBER_CHECK) {
2396 __ And(t1, a1, Operand(kSmiTagMask));
2397 __ Branch(&miss, eq, t1, Operand(zero_reg));
2398 }
2399
2400 // Make sure that it's okay not to patch the on stack receiver
2401 // unless we're doing a receiver map check.
2402 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
2403
2404 SharedFunctionInfo* function_info = function->shared();
2405 switch (check) {
2406 case RECEIVER_MAP_CHECK:
2407 __ IncrementCounter(masm()->isolate()->counters()->call_const(),
2408 1, a0, a3);
2409
2410 // Check that the maps haven't changed.
2411 CheckPrototypes(JSObject::cast(object), a1, holder, a0, a3, t0, name,
2412 &miss);
2413
2414 // Patch the receiver on the stack with the global proxy if
2415 // necessary.
2416 if (object->IsGlobalObject()) {
2417 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2418 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2419 }
2420 break;
2421
2422 case STRING_CHECK:
2423 if (!function->IsBuiltin() && !function_info->strict_mode()) {
2424 // Calling non-strict non-builtins with a value as the receiver
2425 // requires boxing.
2426 __ jmp(&miss);
2427 } else {
2428 // Check that the object is a two-byte string or a symbol.
2429 __ GetObjectType(a1, a3, a3);
2430 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2431 // Check that the maps starting from the prototype haven't changed.
2432 GenerateDirectLoadGlobalFunctionPrototype(
2433 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
2434 CheckPrototypes(JSObject::cast(object->GetPrototype()), a0, holder, a3,
2435 a1, t0, name, &miss);
2436 }
2437 break;
2438
2439 case NUMBER_CHECK: {
2440 if (!function->IsBuiltin() && !function_info->strict_mode()) {
2441 // Calling non-strict non-builtins with a value as the receiver
2442 // requires boxing.
2443 __ jmp(&miss);
2444 } else {
2445 Label fast;
2446 // Check that the object is a smi or a heap number.
2447 __ And(t1, a1, Operand(kSmiTagMask));
2448 __ Branch(&fast, eq, t1, Operand(zero_reg));
2449 __ GetObjectType(a1, a0, a0);
2450 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
2451 __ bind(&fast);
2452 // Check that the maps starting from the prototype haven't changed.
2453 GenerateDirectLoadGlobalFunctionPrototype(
2454 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
2455 CheckPrototypes(JSObject::cast(object->GetPrototype()), a0, holder, a3,
2456 a1, t0, name, &miss);
2457 }
2458 break;
2459 }
2460
2461 case BOOLEAN_CHECK: {
2462 if (!function->IsBuiltin() && !function_info->strict_mode()) {
2463 // Calling non-strict non-builtins with a value as the receiver
2464 // requires boxing.
2465 __ jmp(&miss);
2466 } else {
2467 Label fast;
2468 // Check that the object is a boolean.
2469 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
2470 __ Branch(&fast, eq, a1, Operand(t0));
2471 __ LoadRoot(t0, Heap::kFalseValueRootIndex);
2472 __ Branch(&miss, ne, a1, Operand(t0));
2473 __ bind(&fast);
2474 // Check that the maps starting from the prototype haven't changed.
2475 GenerateDirectLoadGlobalFunctionPrototype(
2476 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
2477 CheckPrototypes(JSObject::cast(object->GetPrototype()), a0, holder, a3,
2478 a1, t0, name, &miss);
2479 }
2480 break;
2481 }
2482
2483 default:
2484 UNREACHABLE();
2485 }
2486
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002487 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
2488 ? CALL_AS_FUNCTION
2489 : CALL_AS_METHOD;
2490 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002491
2492 // Handle call cache miss.
2493 __ bind(&miss);
2494
2495 MaybeObject* maybe_result = GenerateMissBranch();
2496 if (maybe_result->IsFailure()) return maybe_result;
2497
2498 // Return the generated code.
2499 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002500}
2501
2502
lrn@chromium.org7516f052011-03-30 08:52:27 +00002503MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
ager@chromium.org5c838252010-02-19 08:53:10 +00002504 JSObject* holder,
2505 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002506 // ----------- S t a t e -------------
2507 // -- a2 : name
2508 // -- ra : return address
2509 // -----------------------------------
2510
2511 Label miss;
2512
2513 GenerateNameCheck(name, &miss);
2514
2515 // Get the number of arguments.
2516 const int argc = arguments().immediate();
2517
2518 LookupResult lookup;
2519 LookupPostInterceptor(holder, name, &lookup);
2520
2521 // Get the receiver from the stack.
2522 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2523
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002524 CallInterceptorCompiler compiler(this, arguments(), a2, extra_ic_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002525 MaybeObject* result = compiler.Compile(masm(),
2526 object,
2527 holder,
2528 name,
2529 &lookup,
2530 a1,
2531 a3,
2532 t0,
2533 a0,
2534 &miss);
2535 if (result->IsFailure()) {
2536 return result;
2537 }
2538
2539 // Move returned value, the function to call, to a1.
2540 __ mov(a1, v0);
2541 // Restore receiver.
2542 __ lw(a0, MemOperand(sp, argc * kPointerSize));
2543
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002544 GenerateCallFunction(masm(), object, arguments(), &miss, extra_ic_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002545
2546 // Handle call cache miss.
2547 __ bind(&miss);
2548 MaybeObject* maybe_result = GenerateMissBranch();
2549 if (maybe_result->IsFailure()) return maybe_result;
2550
2551 // Return the generated code.
2552 return GetCode(INTERCEPTOR, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002553}
2554
2555
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002556MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
2557 GlobalObject* holder,
2558 JSGlobalPropertyCell* cell,
2559 JSFunction* function,
2560 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002561 // ----------- S t a t e -------------
2562 // -- a2 : name
2563 // -- ra : return address
2564 // -----------------------------------
2565
2566 if (HasCustomCallGenerator(function)) {
2567 MaybeObject* maybe_result = CompileCustomCall(
2568 object, holder, cell, function, name);
2569 Object* result;
2570 if (!maybe_result->ToObject(&result)) return maybe_result;
2571 // Undefined means bail out to regular compiler.
2572 if (!result->IsUndefined()) return result;
2573 }
2574
2575 Label miss;
2576
2577 GenerateNameCheck(name, &miss);
2578
2579 // Get the number of arguments.
2580 const int argc = arguments().immediate();
2581
2582 GenerateGlobalReceiverCheck(object, holder, name, &miss);
2583 GenerateLoadFunctionFromCell(cell, function, &miss);
2584
2585 // Patch the receiver on the stack with the global proxy if
2586 // necessary.
2587 if (object->IsGlobalObject()) {
2588 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
2589 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2590 }
2591
2592 // Setup the context (function already in r1).
2593 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
2594
2595 // Jump to the cached code (tail call).
2596 Counters* counters = masm()->isolate()->counters();
2597 __ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
2598 ASSERT(function->is_compiled());
2599 Handle<Code> code(function->code());
2600 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002601 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002602 ? CALL_AS_FUNCTION
2603 : CALL_AS_METHOD;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002604 if (V8::UseCrankshaft()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002605 // TODO(kasperl): For now, we always call indirectly through the
2606 // code field in the function to allow recompilation to take effect
2607 // without changing any of the call sites.
2608 __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
2609 __ InvokeCode(a3, expected, arguments(), JUMP_FUNCTION,
2610 NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002611 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00002612 __ InvokeCode(code, expected, arguments(), RelocInfo::CODE_TARGET,
2613 JUMP_FUNCTION, call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002614 }
2615
2616 // Handle call cache miss.
2617 __ bind(&miss);
2618 __ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
2619 MaybeObject* maybe_result = GenerateMissBranch();
2620 if (maybe_result->IsFailure()) return maybe_result;
2621
2622 // Return the generated code.
2623 return GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002624}
2625
2626
lrn@chromium.org7516f052011-03-30 08:52:27 +00002627MaybeObject* StoreStubCompiler::CompileStoreField(JSObject* object,
ager@chromium.org5c838252010-02-19 08:53:10 +00002628 int index,
2629 Map* transition,
2630 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002631 // ----------- S t a t e -------------
2632 // -- a0 : value
2633 // -- a1 : receiver
2634 // -- a2 : name
2635 // -- ra : return address
2636 // -----------------------------------
2637 Label miss;
2638
2639 // Name register might be clobbered.
2640 GenerateStoreField(masm(),
2641 object,
2642 index,
2643 transition,
2644 a1, a2, a3,
2645 &miss);
2646 __ bind(&miss);
2647 __ li(a2, Operand(Handle<String>(name))); // Restore name.
2648 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2649 __ Jump(ic, RelocInfo::CODE_TARGET);
2650
2651 // Return the generated code.
2652 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002653}
2654
2655
lrn@chromium.org7516f052011-03-30 08:52:27 +00002656MaybeObject* StoreStubCompiler::CompileStoreCallback(JSObject* object,
2657 AccessorInfo* callback,
2658 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002659 // ----------- S t a t e -------------
2660 // -- a0 : value
2661 // -- a1 : receiver
2662 // -- a2 : name
2663 // -- ra : return address
2664 // -----------------------------------
2665 Label miss;
2666
2667 // Check that the object isn't a smi.
2668 __ JumpIfSmi(a1, &miss);
2669
2670 // Check that the map of the object hasn't changed.
2671 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2672 __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map())));
2673
2674 // Perform global security token check if needed.
2675 if (object->IsJSGlobalProxy()) {
2676 __ CheckAccessGlobalProxy(a1, a3, &miss);
2677 }
2678
2679 // Stub never generated for non-global objects that require access
2680 // checks.
2681 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
2682
2683 __ push(a1); // Receiver.
2684 __ li(a3, Operand(Handle<AccessorInfo>(callback))); // Callback info.
2685 __ Push(a3, a2, a0);
2686
2687 // Do tail-call to the runtime system.
2688 ExternalReference store_callback_property =
2689 ExternalReference(IC_Utility(IC::kStoreCallbackProperty),
2690 masm()->isolate());
2691 __ TailCallExternalReference(store_callback_property, 4, 1);
2692
2693 // Handle store cache miss.
2694 __ bind(&miss);
2695 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2696 __ Jump(ic, RelocInfo::CODE_TARGET);
2697
2698 // Return the generated code.
2699 return GetCode(CALLBACKS, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002700}
2701
2702
lrn@chromium.org7516f052011-03-30 08:52:27 +00002703MaybeObject* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
2704 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002705 // ----------- S t a t e -------------
2706 // -- a0 : value
2707 // -- a1 : receiver
2708 // -- a2 : name
2709 // -- ra : return address
2710 // -----------------------------------
2711 Label miss;
2712
2713 // Check that the object isn't a smi.
2714 __ JumpIfSmi(a1, &miss);
2715
2716 // Check that the map of the object hasn't changed.
2717 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2718 __ Branch(&miss, ne, a3, Operand(Handle<Map>(receiver->map())));
2719
2720 // Perform global security token check if needed.
2721 if (receiver->IsJSGlobalProxy()) {
2722 __ CheckAccessGlobalProxy(a1, a3, &miss);
2723 }
2724
2725 // Stub is never generated for non-global objects that require access
2726 // checks.
2727 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2728
2729 __ Push(a1, a2, a0); // Receiver, name, value.
2730
2731 __ li(a0, Operand(Smi::FromInt(strict_mode_)));
2732 __ push(a0); // Strict mode.
2733
2734 // Do tail-call to the runtime system.
2735 ExternalReference store_ic_property =
2736 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty),
2737 masm()->isolate());
2738 __ TailCallExternalReference(store_ic_property, 4, 1);
2739
2740 // Handle store cache miss.
2741 __ bind(&miss);
2742 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2743 __ Jump(ic, RelocInfo::CODE_TARGET);
2744
2745 // Return the generated code.
2746 return GetCode(INTERCEPTOR, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002747}
2748
2749
lrn@chromium.org7516f052011-03-30 08:52:27 +00002750MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
2751 JSGlobalPropertyCell* cell,
2752 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002753 // ----------- S t a t e -------------
2754 // -- a0 : value
2755 // -- a1 : receiver
2756 // -- a2 : name
2757 // -- ra : return address
2758 // -----------------------------------
2759 Label miss;
2760
2761 // Check that the map of the global has not changed.
2762 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2763 __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map())));
2764
2765 // Check that the value in the cell is not the hole. If it is, this
2766 // cell could have been deleted and reintroducing the global needs
2767 // to update the property details in the property dictionary of the
2768 // global object. We bail out to the runtime system to do that.
2769 __ li(t0, Operand(Handle<JSGlobalPropertyCell>(cell)));
2770 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
2771 __ lw(t2, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2772 __ Branch(&miss, eq, t1, Operand(t2));
2773
2774 // Store the value in the cell.
2775 __ sw(a0, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2776 __ mov(v0, a0); // Stored value must be returned in v0.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002777
2778 // This trashes a0 but the value is returned in v0 anyway.
2779 __ RecordWriteField(t0,
2780 JSGlobalPropertyCell::kValueOffset,
2781 a0,
2782 a2,
2783 kRAHasNotBeenSaved,
2784 kDontSaveFPRegs,
2785 OMIT_REMEMBERED_SET);
2786
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002787 Counters* counters = masm()->isolate()->counters();
2788 __ IncrementCounter(counters->named_store_global_inline(), 1, a1, a3);
2789 __ Ret();
2790
2791 // Handle store cache miss.
2792 __ bind(&miss);
2793 __ IncrementCounter(counters->named_store_global_inline_miss(), 1, a1, a3);
2794 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2795 __ Jump(ic, RelocInfo::CODE_TARGET);
2796
2797 // Return the generated code.
2798 return GetCode(NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002799}
2800
2801
2802MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name,
2803 JSObject* object,
2804 JSObject* last) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002805 // ----------- S t a t e -------------
2806 // -- a0 : receiver
2807 // -- ra : return address
2808 // -----------------------------------
2809 Label miss;
2810
2811 // Check that the receiver is not a smi.
2812 __ JumpIfSmi(a0, &miss);
2813
2814 // Check the maps of the full prototype chain.
2815 CheckPrototypes(object, a0, last, a3, a1, t0, name, &miss);
2816
2817 // If the last object in the prototype chain is a global object,
2818 // check that the global property cell is empty.
2819 if (last->IsGlobalObject()) {
2820 MaybeObject* cell = GenerateCheckPropertyCell(masm(),
2821 GlobalObject::cast(last),
2822 name,
2823 a1,
2824 &miss);
2825 if (cell->IsFailure()) {
2826 miss.Unuse();
2827 return cell;
2828 }
2829 }
2830
2831 // Return undefined if maps of the full prototype chain is still the same.
2832 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2833 __ Ret();
2834
2835 __ bind(&miss);
2836 GenerateLoadMiss(masm(), Code::LOAD_IC);
2837
2838 // Return the generated code.
2839 return GetCode(NONEXISTENT, heap()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00002840}
2841
2842
2843MaybeObject* LoadStubCompiler::CompileLoadField(JSObject* object,
2844 JSObject* holder,
2845 int index,
2846 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002847 // ----------- S t a t e -------------
2848 // -- a0 : receiver
2849 // -- a2 : name
2850 // -- ra : return address
2851 // -----------------------------------
2852 Label miss;
2853
2854 __ mov(v0, a0);
2855
2856 GenerateLoadField(object, holder, v0, a3, a1, t0, index, name, &miss);
2857 __ bind(&miss);
2858 GenerateLoadMiss(masm(), Code::LOAD_IC);
2859
2860 // Return the generated code.
2861 return GetCode(FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002862}
2863
2864
2865MaybeObject* LoadStubCompiler::CompileLoadCallback(String* name,
2866 JSObject* object,
2867 JSObject* holder,
2868 AccessorInfo* callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002869 // ----------- S t a t e -------------
2870 // -- a0 : receiver
2871 // -- a2 : name
2872 // -- ra : return address
2873 // -----------------------------------
2874 Label miss;
2875
2876 MaybeObject* result = GenerateLoadCallback(object, holder, a0, a2, a3, a1, t0,
2877 callback, name, &miss);
2878 if (result->IsFailure()) {
2879 miss.Unuse();
2880 return result;
2881 }
2882
2883 __ bind(&miss);
2884 GenerateLoadMiss(masm(), Code::LOAD_IC);
2885
2886 // Return the generated code.
2887 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002888}
2889
2890
2891MaybeObject* LoadStubCompiler::CompileLoadConstant(JSObject* object,
2892 JSObject* holder,
2893 Object* value,
2894 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002895 // ----------- S t a t e -------------
2896 // -- a0 : receiver
2897 // -- a2 : name
2898 // -- ra : return address
2899 // -----------------------------------
2900 Label miss;
2901
2902 GenerateLoadConstant(object, holder, a0, a3, a1, t0, value, name, &miss);
2903 __ bind(&miss);
2904 GenerateLoadMiss(masm(), Code::LOAD_IC);
2905
2906 // Return the generated code.
2907 return GetCode(CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002908}
2909
2910
2911MaybeObject* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
2912 JSObject* holder,
2913 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002914 // ----------- S t a t e -------------
2915 // -- a0 : receiver
2916 // -- a2 : name
2917 // -- ra : return address
2918 // -- [sp] : receiver
2919 // -----------------------------------
2920 Label miss;
2921
2922 LookupResult lookup;
2923 LookupPostInterceptor(holder, name, &lookup);
2924 GenerateLoadInterceptor(object,
2925 holder,
2926 &lookup,
2927 a0,
2928 a2,
2929 a3,
2930 a1,
2931 t0,
2932 name,
2933 &miss);
2934 __ bind(&miss);
2935 GenerateLoadMiss(masm(), Code::LOAD_IC);
2936
2937 // Return the generated code.
2938 return GetCode(INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002939}
2940
2941
2942MaybeObject* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
2943 GlobalObject* holder,
2944 JSGlobalPropertyCell* cell,
2945 String* name,
2946 bool is_dont_delete) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002947 // ----------- S t a t e -------------
2948 // -- a0 : receiver
2949 // -- a2 : name
2950 // -- ra : return address
2951 // -----------------------------------
2952 Label miss;
2953
2954 // If the object is the holder then we know that it's a global
2955 // object which can only happen for contextual calls. In this case,
2956 // the receiver cannot be a smi.
2957 if (object != holder) {
2958 __ And(t0, a0, Operand(kSmiTagMask));
2959 __ Branch(&miss, eq, t0, Operand(zero_reg));
2960 }
2961
2962 // Check that the map of the global has not changed.
2963 CheckPrototypes(object, a0, holder, a3, t0, a1, name, &miss);
2964
2965 // Get the value from the cell.
2966 __ li(a3, Operand(Handle<JSGlobalPropertyCell>(cell)));
2967 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
2968
2969 // Check for deleted property if property can actually be deleted.
2970 if (!is_dont_delete) {
2971 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
2972 __ Branch(&miss, eq, t0, Operand(at));
2973 }
2974
2975 __ mov(v0, t0);
2976 Counters* counters = masm()->isolate()->counters();
2977 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
2978 __ Ret();
2979
2980 __ bind(&miss);
2981 __ IncrementCounter(counters->named_load_global_stub_miss(), 1, a1, a3);
2982 GenerateLoadMiss(masm(), Code::LOAD_IC);
2983
2984 // Return the generated code.
2985 return GetCode(NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002986}
2987
2988
2989MaybeObject* KeyedLoadStubCompiler::CompileLoadField(String* name,
2990 JSObject* receiver,
2991 JSObject* holder,
2992 int index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002993 // ----------- S t a t e -------------
2994 // -- ra : return address
2995 // -- a0 : key
2996 // -- a1 : receiver
2997 // -----------------------------------
2998 Label miss;
2999
3000 // Check the key is the cached one.
3001 __ Branch(&miss, ne, a0, Operand(Handle<String>(name)));
3002
3003 GenerateLoadField(receiver, holder, a1, a2, a3, t0, index, name, &miss);
3004 __ bind(&miss);
3005 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3006
3007 return GetCode(FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003008}
3009
3010
3011MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback(
3012 String* name,
3013 JSObject* receiver,
3014 JSObject* holder,
3015 AccessorInfo* callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003016 // ----------- S t a t e -------------
3017 // -- ra : return address
3018 // -- a0 : key
3019 // -- a1 : receiver
3020 // -----------------------------------
3021 Label miss;
3022
3023 // Check the key is the cached one.
3024 __ Branch(&miss, ne, a0, Operand(Handle<String>(name)));
3025
3026 MaybeObject* result = GenerateLoadCallback(receiver, holder, a1, a0, a2, a3,
3027 t0, callback, name, &miss);
3028 if (result->IsFailure()) {
3029 miss.Unuse();
3030 return result;
3031 }
3032
3033 __ bind(&miss);
3034 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3035
3036 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003037}
3038
3039
3040MaybeObject* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
3041 JSObject* receiver,
3042 JSObject* holder,
3043 Object* value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003044 // ----------- S t a t e -------------
3045 // -- ra : return address
3046 // -- a0 : key
3047 // -- a1 : receiver
3048 // -----------------------------------
3049 Label miss;
3050
3051 // Check the key is the cached one.
3052 __ Branch(&miss, ne, a0, Operand(Handle<String>(name)));
3053
3054 GenerateLoadConstant(receiver, holder, a1, a2, a3, t0, value, name, &miss);
3055 __ bind(&miss);
3056 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3057
3058 // Return the generated code.
3059 return GetCode(CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003060}
3061
3062
3063MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
3064 JSObject* holder,
3065 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003066 // ----------- S t a t e -------------
3067 // -- ra : return address
3068 // -- a0 : key
3069 // -- a1 : receiver
3070 // -----------------------------------
3071 Label miss;
3072
3073 // Check the key is the cached one.
3074 __ Branch(&miss, ne, a0, Operand(Handle<String>(name)));
3075
3076 LookupResult lookup;
3077 LookupPostInterceptor(holder, name, &lookup);
3078 GenerateLoadInterceptor(receiver,
3079 holder,
3080 &lookup,
3081 a1,
3082 a0,
3083 a2,
3084 a3,
3085 t0,
3086 name,
3087 &miss);
3088 __ bind(&miss);
3089 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3090
3091 return GetCode(INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003092}
3093
3094
3095MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003096 // ----------- S t a t e -------------
3097 // -- ra : return address
3098 // -- a0 : key
3099 // -- a1 : receiver
3100 // -----------------------------------
3101 Label miss;
3102
3103 // Check the key is the cached one.
3104 __ Branch(&miss, ne, a0, Operand(Handle<String>(name)));
3105
3106 GenerateLoadArrayLength(masm(), a1, a2, &miss);
3107 __ bind(&miss);
3108 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3109
3110 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003111}
3112
3113
3114MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003115 // ----------- S t a t e -------------
3116 // -- ra : return address
3117 // -- a0 : key
3118 // -- a1 : receiver
3119 // -----------------------------------
3120 Label miss;
3121
3122 Counters* counters = masm()->isolate()->counters();
3123 __ IncrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
3124
3125 // Check the key is the cached one.
3126 __ Branch(&miss, ne, a0, Operand(Handle<String>(name)));
3127
3128 GenerateLoadStringLength(masm(), a1, a2, a3, &miss, true);
3129 __ bind(&miss);
3130 __ DecrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
3131
3132 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3133
3134 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003135}
3136
3137
3138MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003139 // ----------- S t a t e -------------
3140 // -- ra : return address
3141 // -- a0 : key
3142 // -- a1 : receiver
3143 // -----------------------------------
3144 Label miss;
3145
3146 Counters* counters = masm()->isolate()->counters();
3147 __ IncrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
3148
3149 // Check the name hasn't changed.
3150 __ Branch(&miss, ne, a0, Operand(Handle<String>(name)));
3151
3152 GenerateLoadFunctionPrototype(masm(), a1, a2, a3, &miss);
3153 __ bind(&miss);
3154 __ DecrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
3155 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3156
3157 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003158}
3159
3160
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003161MaybeObject* KeyedLoadStubCompiler::CompileLoadElement(Map* receiver_map) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003162 // ----------- S t a t e -------------
3163 // -- ra : return address
3164 // -- a0 : key
3165 // -- a1 : receiver
3166 // -----------------------------------
danno@chromium.org40cb8782011-05-25 07:58:50 +00003167 Code* stub;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003168 ElementsKind elements_kind = receiver_map->elements_kind();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003169 MaybeObject* maybe_stub = KeyedLoadElementStub(elements_kind).TryGetCode();
danno@chromium.org40cb8782011-05-25 07:58:50 +00003170 if (!maybe_stub->To(&stub)) return maybe_stub;
3171 __ DispatchMap(a1,
3172 a2,
3173 Handle<Map>(receiver_map),
3174 Handle<Code>(stub),
3175 DO_SMI_CHECK);
3176
3177 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
3178 __ Jump(ic, RelocInfo::CODE_TARGET);
3179
3180 // Return the generated code.
3181 return GetCode(NORMAL, NULL);
3182}
3183
3184
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003185MaybeObject* KeyedLoadStubCompiler::CompileLoadPolymorphic(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003186 MapList* receiver_maps,
3187 CodeList* handler_ics) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003188 // ----------- S t a t e -------------
3189 // -- ra : return address
3190 // -- a0 : key
3191 // -- a1 : receiver
3192 // -----------------------------------
3193 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003194 __ JumpIfSmi(a1, &miss);
3195
danno@chromium.org40cb8782011-05-25 07:58:50 +00003196 int receiver_count = receiver_maps->length();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003197 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003198 for (int current = 0; current < receiver_count; ++current) {
3199 Handle<Map> map(receiver_maps->at(current));
3200 Handle<Code> code(handler_ics->at(current));
3201 __ Jump(code, RelocInfo::CODE_TARGET, eq, a2, Operand(map));
3202 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003203
3204 __ bind(&miss);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003205 Handle<Code> miss_ic = isolate()->builtins()->KeyedLoadIC_Miss();
3206 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003207
3208 // Return the generated code.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003209 return GetCode(NORMAL, NULL, MEGAMORPHIC);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003210}
3211
3212
3213MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
3214 int index,
3215 Map* transition,
3216 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003217 // ----------- S t a t e -------------
3218 // -- a0 : value
3219 // -- a1 : key
3220 // -- a2 : receiver
3221 // -- ra : return address
3222 // -----------------------------------
3223
3224 Label miss;
3225
3226 Counters* counters = masm()->isolate()->counters();
3227 __ IncrementCounter(counters->keyed_store_field(), 1, a3, t0);
3228
3229 // Check that the name has not changed.
3230 __ Branch(&miss, ne, a1, Operand(Handle<String>(name)));
3231
3232 // a3 is used as scratch register. a1 and a2 keep their values if a jump to
3233 // the miss label is generated.
3234 GenerateStoreField(masm(),
3235 object,
3236 index,
3237 transition,
3238 a2, a1, a3,
3239 &miss);
3240 __ bind(&miss);
3241
3242 __ DecrementCounter(counters->keyed_store_field(), 1, a3, t0);
3243 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss();
3244 __ Jump(ic, RelocInfo::CODE_TARGET);
3245
3246 // Return the generated code.
3247 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003248}
3249
3250
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003251MaybeObject* KeyedStoreStubCompiler::CompileStoreElement(Map* receiver_map) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003252 // ----------- S t a t e -------------
3253 // -- a0 : value
3254 // -- a1 : key
3255 // -- a2 : receiver
3256 // -- ra : return address
3257 // -- a3 : scratch
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003258 // -----------------------------------
danno@chromium.org40cb8782011-05-25 07:58:50 +00003259 Code* stub;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003260 ElementsKind elements_kind = receiver_map->elements_kind();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003261 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
3262 MaybeObject* maybe_stub =
3263 KeyedStoreElementStub(is_js_array, elements_kind).TryGetCode();
danno@chromium.org40cb8782011-05-25 07:58:50 +00003264 if (!maybe_stub->To(&stub)) return maybe_stub;
3265 __ DispatchMap(a2,
3266 a3,
3267 Handle<Map>(receiver_map),
3268 Handle<Code>(stub),
3269 DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003270
danno@chromium.org40cb8782011-05-25 07:58:50 +00003271 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003272 __ Jump(ic, RelocInfo::CODE_TARGET);
3273
3274 // Return the generated code.
3275 return GetCode(NORMAL, NULL);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003276}
3277
3278
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003279MaybeObject* KeyedStoreStubCompiler::CompileStorePolymorphic(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003280 MapList* receiver_maps,
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003281 CodeList* handler_stubs,
3282 MapList* transitioned_maps) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003283 // ----------- S t a t e -------------
3284 // -- a0 : value
3285 // -- a1 : key
3286 // -- a2 : receiver
3287 // -- ra : return address
3288 // -- a3 : scratch
3289 // -----------------------------------
3290 Label miss;
3291 __ JumpIfSmi(a2, &miss);
3292
3293 int receiver_count = receiver_maps->length();
3294 __ lw(a3, FieldMemOperand(a2, HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003295 for (int i = 0; i < receiver_count; ++i) {
3296 Handle<Map> map(receiver_maps->at(i));
3297 Handle<Code> code(handler_stubs->at(i));
3298 if (transitioned_maps->at(i) == NULL) {
3299 __ Jump(code, RelocInfo::CODE_TARGET, eq, a3, Operand(map));
3300 } else {
3301 Label next_map;
3302 __ Branch(&next_map, eq, a3, Operand(map));
3303 __ li(t0, Operand(Handle<Map>(transitioned_maps->at(i))));
3304 __ Jump(code, RelocInfo::CODE_TARGET);
3305 __ bind(&next_map);
3306 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003307 }
3308
3309 __ bind(&miss);
3310 Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
3311 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3312
3313 // Return the generated code.
3314 return GetCode(NORMAL, NULL, MEGAMORPHIC);
3315}
3316
3317
lrn@chromium.org7516f052011-03-30 08:52:27 +00003318MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003319 // a0 : argc
3320 // a1 : constructor
3321 // ra : return address
3322 // [sp] : last argument
3323 Label generic_stub_call;
3324
3325 // Use t7 for holding undefined which is used in several places below.
3326 __ LoadRoot(t7, Heap::kUndefinedValueRootIndex);
3327
3328#ifdef ENABLE_DEBUGGER_SUPPORT
3329 // Check to see whether there are any break points in the function code. If
3330 // there are jump to the generic constructor stub which calls the actual
3331 // code for the function thereby hitting the break points.
3332 __ lw(t5, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3333 __ lw(a2, FieldMemOperand(t5, SharedFunctionInfo::kDebugInfoOffset));
3334 __ Branch(&generic_stub_call, ne, a2, Operand(t7));
3335#endif
3336
3337 // Load the initial map and verify that it is in fact a map.
3338 // a1: constructor function
3339 // t7: undefined
3340 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
3341 __ And(t0, a2, Operand(kSmiTagMask));
3342 __ Branch(&generic_stub_call, eq, t0, Operand(zero_reg));
3343 __ GetObjectType(a2, a3, t0);
3344 __ Branch(&generic_stub_call, ne, t0, Operand(MAP_TYPE));
3345
3346#ifdef DEBUG
3347 // Cannot construct functions this way.
3348 // a0: argc
3349 // a1: constructor function
3350 // a2: initial map
3351 // t7: undefined
3352 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
3353 __ Check(ne, "Function constructed by construct stub.",
3354 a3, Operand(JS_FUNCTION_TYPE));
3355#endif
3356
3357 // Now allocate the JSObject in new space.
3358 // a0: argc
3359 // a1: constructor function
3360 // a2: initial map
3361 // t7: undefined
3362 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
3363 __ AllocateInNewSpace(a3,
3364 t4,
3365 t5,
3366 t6,
3367 &generic_stub_call,
3368 SIZE_IN_WORDS);
3369
3370 // Allocated the JSObject, now initialize the fields. Map is set to initial
3371 // map and properties and elements are set to empty fixed array.
3372 // a0: argc
3373 // a1: constructor function
3374 // a2: initial map
3375 // a3: object size (in words)
3376 // t4: JSObject (not tagged)
3377 // t7: undefined
3378 __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex);
3379 __ mov(t5, t4);
3380 __ sw(a2, MemOperand(t5, JSObject::kMapOffset));
3381 __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset));
3382 __ sw(t6, MemOperand(t5, JSObject::kElementsOffset));
3383 __ Addu(t5, t5, Operand(3 * kPointerSize));
3384 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
3385 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
3386 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
3387
3388
3389 // Calculate the location of the first argument. The stack contains only the
3390 // argc arguments.
3391 __ sll(a1, a0, kPointerSizeLog2);
3392 __ Addu(a1, a1, sp);
3393
3394 // Fill all the in-object properties with undefined.
3395 // a0: argc
3396 // a1: first argument
3397 // a3: object size (in words)
3398 // t4: JSObject (not tagged)
3399 // t5: First in-object property of JSObject (not tagged)
3400 // t7: undefined
3401 // Fill the initialized properties with a constant value or a passed argument
3402 // depending on the this.x = ...; assignment in the function.
3403 SharedFunctionInfo* shared = function->shared();
3404 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3405 if (shared->IsThisPropertyAssignmentArgument(i)) {
3406 Label not_passed, next;
3407 // Check if the argument assigned to the property is actually passed.
3408 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3409 __ Branch(&not_passed, less_equal, a0, Operand(arg_number));
3410 // Argument passed - find it on the stack.
3411 __ lw(a2, MemOperand(a1, (arg_number + 1) * -kPointerSize));
3412 __ sw(a2, MemOperand(t5));
3413 __ Addu(t5, t5, kPointerSize);
3414 __ jmp(&next);
3415 __ bind(&not_passed);
3416 // Set the property to undefined.
3417 __ sw(t7, MemOperand(t5));
3418 __ Addu(t5, t5, Operand(kPointerSize));
3419 __ bind(&next);
3420 } else {
3421 // Set the property to the constant value.
3422 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
3423 __ li(a2, Operand(constant));
3424 __ sw(a2, MemOperand(t5));
3425 __ Addu(t5, t5, kPointerSize);
3426 }
3427 }
3428
3429 // Fill the unused in-object property fields with undefined.
3430 ASSERT(function->has_initial_map());
3431 for (int i = shared->this_property_assignments_count();
3432 i < function->initial_map()->inobject_properties();
3433 i++) {
3434 __ sw(t7, MemOperand(t5));
3435 __ Addu(t5, t5, kPointerSize);
3436 }
3437
3438 // a0: argc
3439 // t4: JSObject (not tagged)
3440 // Move argc to a1 and the JSObject to return to v0 and tag it.
3441 __ mov(a1, a0);
3442 __ mov(v0, t4);
3443 __ Or(v0, v0, Operand(kHeapObjectTag));
3444
3445 // v0: JSObject
3446 // a1: argc
3447 // Remove caller arguments and receiver from the stack and return.
3448 __ sll(t0, a1, kPointerSizeLog2);
3449 __ Addu(sp, sp, t0);
3450 __ Addu(sp, sp, Operand(kPointerSize));
3451 Counters* counters = masm()->isolate()->counters();
3452 __ IncrementCounter(counters->constructed_objects(), 1, a1, a2);
3453 __ IncrementCounter(counters->constructed_objects_stub(), 1, a1, a2);
3454 __ Ret();
3455
3456 // Jump to the generic stub in case the specialized code cannot handle the
3457 // construction.
3458 __ bind(&generic_stub_call);
3459 Handle<Code> generic_construct_stub =
3460 masm()->isolate()->builtins()->JSConstructStubGeneric();
3461 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
3462
3463 // Return the generated code.
3464 return GetCode();
3465}
3466
3467
danno@chromium.org40cb8782011-05-25 07:58:50 +00003468#undef __
3469#define __ ACCESS_MASM(masm)
3470
3471
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003472void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3473 MacroAssembler* masm) {
3474 // ---------- S t a t e --------------
3475 // -- ra : return address
3476 // -- a0 : key
3477 // -- a1 : receiver
3478 // -----------------------------------
3479 Label slow, miss_force_generic;
3480
3481 Register key = a0;
3482 Register receiver = a1;
3483
3484 __ JumpIfNotSmi(key, &miss_force_generic);
3485 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
3486 __ sra(a2, a0, kSmiTagSize);
3487 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
3488 __ Ret();
3489
3490 // Slow case, key and receiver still in a0 and a1.
3491 __ bind(&slow);
3492 __ IncrementCounter(
3493 masm->isolate()->counters()->keyed_load_external_array_slow(),
3494 1, a2, a3);
3495 // Entry registers are intact.
3496 // ---------- S t a t e --------------
3497 // -- ra : return address
3498 // -- a0 : key
3499 // -- a1 : receiver
3500 // -----------------------------------
3501 Handle<Code> slow_ic =
3502 masm->isolate()->builtins()->KeyedLoadIC_Slow();
3503 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
3504
3505 // Miss case, call the runtime.
3506 __ bind(&miss_force_generic);
3507
3508 // ---------- S t a t e --------------
3509 // -- ra : return address
3510 // -- a0 : key
3511 // -- a1 : receiver
3512 // -----------------------------------
3513
3514 Handle<Code> miss_ic =
3515 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3516 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3517}
3518
3519
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003520static bool IsElementTypeSigned(ElementsKind elements_kind) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003521 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003522 case EXTERNAL_BYTE_ELEMENTS:
3523 case EXTERNAL_SHORT_ELEMENTS:
3524 case EXTERNAL_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003525 return true;
3526
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003527 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3528 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3529 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3530 case EXTERNAL_PIXEL_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003531 return false;
3532
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003533 case EXTERNAL_FLOAT_ELEMENTS:
3534 case EXTERNAL_DOUBLE_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003535 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003536 case FAST_ELEMENTS:
3537 case FAST_DOUBLE_ELEMENTS:
3538 case DICTIONARY_ELEMENTS:
3539 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003540 UNREACHABLE();
3541 return false;
3542 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003543 return false;
lrn@chromium.org7516f052011-03-30 08:52:27 +00003544}
3545
3546
danno@chromium.org40cb8782011-05-25 07:58:50 +00003547void KeyedLoadStubCompiler::GenerateLoadExternalArray(
3548 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003549 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003550 // ---------- S t a t e --------------
3551 // -- ra : return address
3552 // -- a0 : key
3553 // -- a1 : receiver
3554 // -----------------------------------
danno@chromium.org40cb8782011-05-25 07:58:50 +00003555 Label miss_force_generic, slow, failed_allocation;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003556
3557 Register key = a0;
3558 Register receiver = a1;
3559
danno@chromium.org40cb8782011-05-25 07:58:50 +00003560 // This stub is meant to be tail-jumped to, the receiver must already
3561 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003562
3563 // Check that the key is a smi.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003564 __ JumpIfNotSmi(key, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003565
3566 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3567 // a3: elements array
3568
3569 // Check that the index is in range.
3570 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3571 __ sra(t2, key, kSmiTagSize);
3572 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003573 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003574
3575 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3576 // a3: base pointer of external storage
3577
3578 // We are not untagging smi key and instead work with it
3579 // as if it was premultiplied by 2.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003580 STATIC_ASSERT((kSmiTag == 0) && (kSmiTagSize == 1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003581
3582 Register value = a2;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003583 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003584 case EXTERNAL_BYTE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003585 __ srl(t2, key, 1);
3586 __ addu(t3, a3, t2);
3587 __ lb(value, MemOperand(t3, 0));
3588 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003589 case EXTERNAL_PIXEL_ELEMENTS:
3590 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003591 __ srl(t2, key, 1);
3592 __ addu(t3, a3, t2);
3593 __ lbu(value, MemOperand(t3, 0));
3594 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003595 case EXTERNAL_SHORT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003596 __ addu(t3, a3, key);
3597 __ lh(value, MemOperand(t3, 0));
3598 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003599 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003600 __ addu(t3, a3, key);
3601 __ lhu(value, MemOperand(t3, 0));
3602 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003603 case EXTERNAL_INT_ELEMENTS:
3604 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003605 __ sll(t2, key, 1);
3606 __ addu(t3, a3, t2);
3607 __ lw(value, MemOperand(t3, 0));
3608 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003609 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003610 __ sll(t3, t2, 2);
3611 __ addu(t3, a3, t3);
3612 if (CpuFeatures::IsSupported(FPU)) {
3613 CpuFeatures::Scope scope(FPU);
3614 __ lwc1(f0, MemOperand(t3, 0));
3615 } else {
3616 __ lw(value, MemOperand(t3, 0));
3617 }
3618 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003619 case EXTERNAL_DOUBLE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003620 __ sll(t2, key, 2);
3621 __ addu(t3, a3, t2);
3622 if (CpuFeatures::IsSupported(FPU)) {
3623 CpuFeatures::Scope scope(FPU);
3624 __ ldc1(f0, MemOperand(t3, 0));
3625 } else {
3626 // t3: pointer to the beginning of the double we want to load.
3627 __ lw(a2, MemOperand(t3, 0));
3628 __ lw(a3, MemOperand(t3, Register::kSizeInBytes));
3629 }
3630 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003631 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003632 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003633 case FAST_DOUBLE_ELEMENTS:
3634 case DICTIONARY_ELEMENTS:
3635 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003636 UNREACHABLE();
3637 break;
3638 }
3639
3640 // For integer array types:
3641 // a2: value
3642 // For float array type:
3643 // f0: value (if FPU is supported)
3644 // a2: value (if FPU is not supported)
3645 // For double array type:
3646 // f0: value (if FPU is supported)
3647 // a2/a3: value (if FPU is not supported)
3648
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003649 if (elements_kind == EXTERNAL_INT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003650 // For the Int and UnsignedInt array types, we need to see whether
3651 // the value can be represented in a Smi. If not, we need to convert
3652 // it to a HeapNumber.
3653 Label box_int;
3654 __ Subu(t3, value, Operand(0xC0000000)); // Non-smi value gives neg result.
3655 __ Branch(&box_int, lt, t3, Operand(zero_reg));
3656 // Tag integer as smi and return it.
3657 __ sll(v0, value, kSmiTagSize);
3658 __ Ret();
3659
3660 __ bind(&box_int);
3661 // Allocate a HeapNumber for the result and perform int-to-double
3662 // conversion.
3663 // The arm version uses a temporary here to save r0, but we don't need to
3664 // (a0 is not modified).
3665 __ LoadRoot(t1, Heap::kHeapNumberMapRootIndex);
3666 __ AllocateHeapNumber(v0, a3, t0, t1, &slow);
3667
3668 if (CpuFeatures::IsSupported(FPU)) {
3669 CpuFeatures::Scope scope(FPU);
3670 __ mtc1(value, f0);
3671 __ cvt_d_w(f0, f0);
3672 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag));
3673 __ Ret();
3674 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003675 Register dst1 = t2;
3676 Register dst2 = t3;
3677 FloatingPointHelper::Destination dest =
3678 FloatingPointHelper::kCoreRegisters;
3679 FloatingPointHelper::ConvertIntToDouble(masm,
3680 value,
3681 dest,
3682 f0,
3683 dst1,
3684 dst2,
3685 t1,
3686 f2);
3687 __ sw(dst1, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3688 __ sw(dst2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3689 __ Ret();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003690 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003691 } else if (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003692 // The test is different for unsigned int values. Since we need
3693 // the value to be in the range of a positive smi, we can't
3694 // handle either of the top two bits being set in the value.
3695 if (CpuFeatures::IsSupported(FPU)) {
3696 CpuFeatures::Scope scope(FPU);
3697 Label pl_box_int;
3698 __ And(t2, value, Operand(0xC0000000));
3699 __ Branch(&pl_box_int, ne, t2, Operand(zero_reg));
3700
3701 // It can fit in an Smi.
3702 // Tag integer as smi and return it.
3703 __ sll(v0, value, kSmiTagSize);
3704 __ Ret();
3705
3706 __ bind(&pl_box_int);
3707 // Allocate a HeapNumber for the result and perform int-to-double
3708 // conversion. Don't use a0 and a1 as AllocateHeapNumber clobbers all
3709 // registers - also when jumping due to exhausted young space.
3710 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3711 __ AllocateHeapNumber(v0, t2, t3, t6, &slow);
3712
3713 // This is replaced by a macro:
3714 // __ mtc1(value, f0); // LS 32-bits.
3715 // __ mtc1(zero_reg, f1); // MS 32-bits are all zero.
3716 // __ cvt_d_l(f0, f0); // Use 64 bit conv to get correct unsigned 32-bit.
3717
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003718 __ Cvt_d_uw(f0, value, f22);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003719
3720 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag));
3721
3722 __ Ret();
3723 } else {
3724 // Check whether unsigned integer fits into smi.
3725 Label box_int_0, box_int_1, done;
3726 __ And(t2, value, Operand(0x80000000));
3727 __ Branch(&box_int_0, ne, t2, Operand(zero_reg));
3728 __ And(t2, value, Operand(0x40000000));
3729 __ Branch(&box_int_1, ne, t2, Operand(zero_reg));
3730
3731 // Tag integer as smi and return it.
3732 __ sll(v0, value, kSmiTagSize);
3733 __ Ret();
3734
3735 Register hiword = value; // a2.
3736 Register loword = a3;
3737
3738 __ bind(&box_int_0);
3739 // Integer does not have leading zeros.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003740 GenerateUInt2Double(masm, hiword, loword, t0, 0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003741 __ Branch(&done);
3742
3743 __ bind(&box_int_1);
3744 // Integer has one leading zero.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003745 GenerateUInt2Double(masm, hiword, loword, t0, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003746
3747
3748 __ bind(&done);
3749 // Integer was converted to double in registers hiword:loword.
3750 // Wrap it into a HeapNumber. Don't use a0 and a1 as AllocateHeapNumber
3751 // clobbers all registers - also when jumping due to exhausted young
3752 // space.
3753 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3754 __ AllocateHeapNumber(t2, t3, t5, t6, &slow);
3755
3756 __ sw(hiword, FieldMemOperand(t2, HeapNumber::kExponentOffset));
3757 __ sw(loword, FieldMemOperand(t2, HeapNumber::kMantissaOffset));
3758
3759 __ mov(v0, t2);
3760 __ Ret();
3761 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003762 } else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003763 // For the floating-point array type, we need to always allocate a
3764 // HeapNumber.
3765 if (CpuFeatures::IsSupported(FPU)) {
3766 CpuFeatures::Scope scope(FPU);
3767 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3768 // AllocateHeapNumber clobbers all registers - also when jumping due to
3769 // exhausted young space.
3770 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3771 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3772 // The float (single) value is already in fpu reg f0 (if we use float).
3773 __ cvt_d_s(f0, f0);
3774 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag));
3775 __ Ret();
3776 } else {
3777 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3778 // AllocateHeapNumber clobbers all registers - also when jumping due to
3779 // exhausted young space.
3780 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3781 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3782 // FPU is not available, do manual single to double conversion.
3783
3784 // a2: floating point value (binary32).
3785 // v0: heap number for result
3786
3787 // Extract mantissa to t4.
3788 __ And(t4, value, Operand(kBinary32MantissaMask));
3789
3790 // Extract exponent to t5.
3791 __ srl(t5, value, kBinary32MantissaBits);
3792 __ And(t5, t5, Operand(kBinary32ExponentMask >> kBinary32MantissaBits));
3793
3794 Label exponent_rebiased;
3795 __ Branch(&exponent_rebiased, eq, t5, Operand(zero_reg));
3796
3797 __ li(t0, 0x7ff);
3798 __ Xor(t1, t5, Operand(0xFF));
3799 __ movz(t5, t0, t1); // Set t5 to 0x7ff only if t5 is equal to 0xff.
3800 __ Branch(&exponent_rebiased, eq, t0, Operand(0xff));
3801
3802 // Rebias exponent.
3803 __ Addu(t5,
3804 t5,
3805 Operand(-kBinary32ExponentBias + HeapNumber::kExponentBias));
3806
3807 __ bind(&exponent_rebiased);
3808 __ And(a2, value, Operand(kBinary32SignMask));
3809 value = no_reg;
3810 __ sll(t0, t5, HeapNumber::kMantissaBitsInTopWord);
3811 __ or_(a2, a2, t0);
3812
3813 // Shift mantissa.
3814 static const int kMantissaShiftForHiWord =
3815 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3816
3817 static const int kMantissaShiftForLoWord =
3818 kBitsPerInt - kMantissaShiftForHiWord;
3819
3820 __ srl(t0, t4, kMantissaShiftForHiWord);
3821 __ or_(a2, a2, t0);
3822 __ sll(a0, t4, kMantissaShiftForLoWord);
3823
3824 __ sw(a2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3825 __ sw(a0, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3826 __ Ret();
3827 }
3828
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003829 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003830 if (CpuFeatures::IsSupported(FPU)) {
3831 CpuFeatures::Scope scope(FPU);
3832 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3833 // AllocateHeapNumber clobbers all registers - also when jumping due to
3834 // exhausted young space.
3835 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3836 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3837 // The double value is already in f0
3838 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
3839 __ Ret();
3840 } else {
3841 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3842 // AllocateHeapNumber clobbers all registers - also when jumping due to
3843 // exhausted young space.
3844 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3845 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3846
3847 __ sw(a2, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3848 __ sw(a3, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3849 __ Ret();
3850 }
3851
3852 } else {
3853 // Tag integer as smi and return it.
3854 __ sll(v0, value, kSmiTagSize);
3855 __ Ret();
3856 }
3857
3858 // Slow case, key and receiver still in a0 and a1.
3859 __ bind(&slow);
3860 __ IncrementCounter(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003861 masm->isolate()->counters()->keyed_load_external_array_slow(),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003862 1, a2, a3);
3863
3864 // ---------- S t a t e --------------
3865 // -- ra : return address
3866 // -- a0 : key
3867 // -- a1 : receiver
3868 // -----------------------------------
3869
3870 __ Push(a1, a0);
3871
3872 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
3873
danno@chromium.org40cb8782011-05-25 07:58:50 +00003874 __ bind(&miss_force_generic);
3875 Code* stub = masm->isolate()->builtins()->builtin(
3876 Builtins::kKeyedLoadIC_MissForceGeneric);
3877 __ Jump(Handle<Code>(stub), RelocInfo::CODE_TARGET);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003878}
3879
3880
danno@chromium.org40cb8782011-05-25 07:58:50 +00003881void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3882 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003883 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003884 // ---------- S t a t e --------------
3885 // -- a0 : value
3886 // -- a1 : key
3887 // -- a2 : receiver
3888 // -- ra : return address
3889 // -----------------------------------
3890
danno@chromium.org40cb8782011-05-25 07:58:50 +00003891 Label slow, check_heap_number, miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003892
3893 // Register usage.
3894 Register value = a0;
3895 Register key = a1;
3896 Register receiver = a2;
3897 // a3 mostly holds the elements array or the destination external array.
3898
danno@chromium.org40cb8782011-05-25 07:58:50 +00003899 // This stub is meant to be tail-jumped to, the receiver must already
3900 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003901
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003902 // Check that the key is a smi.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003903 __ JumpIfNotSmi(key, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003904
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003905 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3906
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003907 // Check that the index is in range.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003908 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3909 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003910 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003911
3912 // Handle both smis and HeapNumbers in the fast path. Go to the
3913 // runtime for all other kinds of values.
3914 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003915
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003916 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003917 // Double to pixel conversion is only implemented in the runtime for now.
3918 __ JumpIfNotSmi(value, &slow);
3919 } else {
3920 __ JumpIfNotSmi(value, &check_heap_number);
3921 }
3922 __ SmiUntag(t1, value);
3923 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3924
3925 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003926 // t1: value (integer).
3927
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003928 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003929 case EXTERNAL_PIXEL_ELEMENTS: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003930 // Clamp the value to [0..255].
3931 // v0 is used as a scratch register here.
3932 Label done;
3933 __ li(v0, Operand(255));
3934 // Normal branch: nop in delay slot.
3935 __ Branch(&done, gt, t1, Operand(v0));
3936 // Use delay slot in this branch.
3937 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg));
3938 __ mov(v0, zero_reg); // In delay slot.
3939 __ mov(v0, t1); // Value is in range 0..255.
3940 __ bind(&done);
3941 __ mov(t1, v0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003942
3943 __ srl(t8, key, 1);
3944 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003945 __ sb(t1, MemOperand(t8, 0));
3946 }
3947 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003948 case EXTERNAL_BYTE_ELEMENTS:
3949 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003950 __ srl(t8, key, 1);
3951 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003952 __ sb(t1, MemOperand(t8, 0));
3953 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003954 case EXTERNAL_SHORT_ELEMENTS:
3955 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003956 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003957 __ sh(t1, MemOperand(t8, 0));
3958 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003959 case EXTERNAL_INT_ELEMENTS:
3960 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003961 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003962 __ addu(t8, a3, t8);
3963 __ sw(t1, MemOperand(t8, 0));
3964 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003965 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003966 // Perform int-to-float conversion and store to memory.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003967 __ SmiUntag(t0, key);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003968 StoreIntAsFloat(masm, a3, t0, t1, t2, t3, t4);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003969 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003970 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003971 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003972 __ addu(a3, a3, t8);
3973 // a3: effective address of the double element
3974 FloatingPointHelper::Destination destination;
3975 if (CpuFeatures::IsSupported(FPU)) {
3976 destination = FloatingPointHelper::kFPURegisters;
3977 } else {
3978 destination = FloatingPointHelper::kCoreRegisters;
3979 }
3980 FloatingPointHelper::ConvertIntToDouble(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003981 masm, t1, destination,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003982 f0, t2, t3, // These are: double_dst, dst1, dst2.
3983 t0, f2); // These are: scratch2, single_scratch.
3984 if (destination == FloatingPointHelper::kFPURegisters) {
3985 CpuFeatures::Scope scope(FPU);
3986 __ sdc1(f0, MemOperand(a3, 0));
3987 } else {
3988 __ sw(t2, MemOperand(a3, 0));
3989 __ sw(t3, MemOperand(a3, Register::kSizeInBytes));
3990 }
3991 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003992 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003993 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003994 case FAST_DOUBLE_ELEMENTS:
3995 case DICTIONARY_ELEMENTS:
3996 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003997 UNREACHABLE();
3998 break;
3999 }
4000
4001 // Entry registers are intact, a0 holds the value which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004002 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004003 __ Ret();
4004
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004005 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004006 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004007 __ bind(&check_heap_number);
4008 __ GetObjectType(value, t1, t2);
4009 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE));
4010
4011 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
4012
4013 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004014
4015 // The WebGL specification leaves the behavior of storing NaN and
4016 // +/-Infinity into integer arrays basically undefined. For more
4017 // reproducible behavior, convert these to zero.
4018
4019 if (CpuFeatures::IsSupported(FPU)) {
4020 CpuFeatures::Scope scope(FPU);
4021
4022 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
4023
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004024 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004025 __ cvt_s_d(f0, f0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004026 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004027 __ addu(t8, a3, t8);
4028 __ swc1(f0, MemOperand(t8, 0));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004029 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004030 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004031 __ addu(t8, a3, t8);
4032 __ sdc1(f0, MemOperand(t8, 0));
4033 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00004034 __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004035
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004036 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004037 case EXTERNAL_BYTE_ELEMENTS:
4038 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004039 __ srl(t8, key, 1);
4040 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004041 __ sb(t3, MemOperand(t8, 0));
4042 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004043 case EXTERNAL_SHORT_ELEMENTS:
4044 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004045 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004046 __ sh(t3, MemOperand(t8, 0));
4047 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004048 case EXTERNAL_INT_ELEMENTS:
4049 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004050 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004051 __ addu(t8, a3, t8);
4052 __ sw(t3, MemOperand(t8, 0));
4053 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004054 case EXTERNAL_PIXEL_ELEMENTS:
4055 case EXTERNAL_FLOAT_ELEMENTS:
4056 case EXTERNAL_DOUBLE_ELEMENTS:
4057 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004058 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004059 case FAST_DOUBLE_ELEMENTS:
4060 case DICTIONARY_ELEMENTS:
4061 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004062 UNREACHABLE();
4063 break;
4064 }
4065 }
4066
4067 // Entry registers are intact, a0 holds the value
4068 // which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004069 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004070 __ Ret();
4071 } else {
4072 // FPU is not available, do manual conversions.
4073
4074 __ lw(t3, FieldMemOperand(value, HeapNumber::kExponentOffset));
4075 __ lw(t4, FieldMemOperand(value, HeapNumber::kMantissaOffset));
4076
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004077 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004078 Label done, nan_or_infinity_or_zero;
4079 static const int kMantissaInHiWordShift =
4080 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
4081
4082 static const int kMantissaInLoWordShift =
4083 kBitsPerInt - kMantissaInHiWordShift;
4084
4085 // Test for all special exponent values: zeros, subnormal numbers, NaNs
4086 // and infinities. All these should be converted to 0.
4087 __ li(t5, HeapNumber::kExponentMask);
4088 __ and_(t6, t3, t5);
4089 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(zero_reg));
4090
4091 __ xor_(t1, t6, t5);
4092 __ li(t2, kBinary32ExponentMask);
4093 __ movz(t6, t2, t1); // Only if t6 is equal to t5.
4094 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(t5));
4095
4096 // Rebias exponent.
4097 __ srl(t6, t6, HeapNumber::kExponentShift);
4098 __ Addu(t6,
4099 t6,
4100 Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
4101
4102 __ li(t1, Operand(kBinary32MaxExponent));
4103 __ Slt(t1, t1, t6);
4104 __ And(t2, t3, Operand(HeapNumber::kSignMask));
4105 __ Or(t2, t2, Operand(kBinary32ExponentMask));
4106 __ movn(t3, t2, t1); // Only if t6 is gt kBinary32MaxExponent.
4107 __ Branch(&done, gt, t6, Operand(kBinary32MaxExponent));
4108
4109 __ Slt(t1, t6, Operand(kBinary32MinExponent));
4110 __ And(t2, t3, Operand(HeapNumber::kSignMask));
4111 __ movn(t3, t2, t1); // Only if t6 is lt kBinary32MinExponent.
4112 __ Branch(&done, lt, t6, Operand(kBinary32MinExponent));
4113
4114 __ And(t7, t3, Operand(HeapNumber::kSignMask));
4115 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4116 __ sll(t3, t3, kMantissaInHiWordShift);
4117 __ or_(t7, t7, t3);
4118 __ srl(t4, t4, kMantissaInLoWordShift);
4119 __ or_(t7, t7, t4);
4120 __ sll(t6, t6, kBinary32ExponentShift);
4121 __ or_(t3, t7, t6);
4122
4123 __ bind(&done);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004124 __ sll(t9, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004125 __ addu(t9, a2, t9);
4126 __ sw(t3, MemOperand(t9, 0));
4127
4128 // Entry registers are intact, a0 holds the value which is the return
4129 // value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004130 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004131 __ Ret();
4132
4133 __ bind(&nan_or_infinity_or_zero);
4134 __ And(t7, t3, Operand(HeapNumber::kSignMask));
4135 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4136 __ or_(t6, t6, t7);
4137 __ sll(t3, t3, kMantissaInHiWordShift);
4138 __ or_(t6, t6, t3);
4139 __ srl(t4, t4, kMantissaInLoWordShift);
4140 __ or_(t3, t6, t4);
4141 __ Branch(&done);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004142 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004143 __ sll(t8, t0, 3);
4144 __ addu(t8, a3, t8);
4145 // t8: effective address of destination element.
4146 __ sw(t4, MemOperand(t8, 0));
4147 __ sw(t3, MemOperand(t8, Register::kSizeInBytes));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004148 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004149 __ Ret();
4150 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004151 bool is_signed_type = IsElementTypeSigned(elements_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004152 int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
4153 int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
4154
4155 Label done, sign;
4156
4157 // Test for all special exponent values: zeros, subnormal numbers, NaNs
4158 // and infinities. All these should be converted to 0.
4159 __ li(t5, HeapNumber::kExponentMask);
4160 __ and_(t6, t3, t5);
4161 __ movz(t3, zero_reg, t6); // Only if t6 is equal to zero.
4162 __ Branch(&done, eq, t6, Operand(zero_reg));
4163
4164 __ xor_(t2, t6, t5);
4165 __ movz(t3, zero_reg, t2); // Only if t6 is equal to t5.
4166 __ Branch(&done, eq, t6, Operand(t5));
4167
4168 // Unbias exponent.
4169 __ srl(t6, t6, HeapNumber::kExponentShift);
4170 __ Subu(t6, t6, Operand(HeapNumber::kExponentBias));
4171 // If exponent is negative then result is 0.
4172 __ slt(t2, t6, zero_reg);
4173 __ movn(t3, zero_reg, t2); // Only if exponent is negative.
4174 __ Branch(&done, lt, t6, Operand(zero_reg));
4175
4176 // If exponent is too big then result is minimal value.
4177 __ slti(t1, t6, meaningfull_bits - 1);
4178 __ li(t2, min_value);
4179 __ movz(t3, t2, t1); // Only if t6 is ge meaningfull_bits - 1.
4180 __ Branch(&done, ge, t6, Operand(meaningfull_bits - 1));
4181
4182 __ And(t5, t3, Operand(HeapNumber::kSignMask));
4183 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4184 __ Or(t3, t3, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
4185
4186 __ li(t9, HeapNumber::kMantissaBitsInTopWord);
4187 __ subu(t6, t9, t6);
4188 __ slt(t1, t6, zero_reg);
4189 __ srlv(t2, t3, t6);
4190 __ movz(t3, t2, t1); // Only if t6 is positive.
4191 __ Branch(&sign, ge, t6, Operand(zero_reg));
4192
4193 __ subu(t6, zero_reg, t6);
4194 __ sllv(t3, t3, t6);
4195 __ li(t9, meaningfull_bits);
4196 __ subu(t6, t9, t6);
4197 __ srlv(t4, t4, t6);
4198 __ or_(t3, t3, t4);
4199
4200 __ bind(&sign);
4201 __ subu(t2, t3, zero_reg);
4202 __ movz(t3, t2, t5); // Only if t5 is zero.
4203
4204 __ bind(&done);
4205
4206 // Result is in t3.
4207 // This switch block should be exactly the same as above (FPU mode).
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004208 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004209 case EXTERNAL_BYTE_ELEMENTS:
4210 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004211 __ srl(t8, key, 1);
4212 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004213 __ sb(t3, MemOperand(t8, 0));
4214 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004215 case EXTERNAL_SHORT_ELEMENTS:
4216 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004217 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004218 __ sh(t3, MemOperand(t8, 0));
4219 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004220 case EXTERNAL_INT_ELEMENTS:
4221 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004222 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004223 __ addu(t8, a3, t8);
4224 __ sw(t3, MemOperand(t8, 0));
4225 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004226 case EXTERNAL_PIXEL_ELEMENTS:
4227 case EXTERNAL_FLOAT_ELEMENTS:
4228 case EXTERNAL_DOUBLE_ELEMENTS:
4229 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004230 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004231 case FAST_DOUBLE_ELEMENTS:
4232 case DICTIONARY_ELEMENTS:
4233 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004234 UNREACHABLE();
4235 break;
4236 }
4237 }
4238 }
4239 }
4240
danno@chromium.org40cb8782011-05-25 07:58:50 +00004241 // Slow case, key and receiver still in a0 and a1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004242 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004243 __ IncrementCounter(
4244 masm->isolate()->counters()->keyed_load_external_array_slow(),
4245 1, a2, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004246 // Entry registers are intact.
4247 // ---------- S t a t e --------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004248 // -- ra : return address
danno@chromium.org40cb8782011-05-25 07:58:50 +00004249 // -- a0 : key
4250 // -- a1 : receiver
4251 // -----------------------------------
4252 Handle<Code> slow_ic =
4253 masm->isolate()->builtins()->KeyedStoreIC_Slow();
4254 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4255
4256 // Miss case, call the runtime.
4257 __ bind(&miss_force_generic);
4258
4259 // ---------- S t a t e --------------
4260 // -- ra : return address
4261 // -- a0 : key
4262 // -- a1 : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004263 // -----------------------------------
4264
danno@chromium.org40cb8782011-05-25 07:58:50 +00004265 Handle<Code> miss_ic =
4266 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4267 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
4268}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004269
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004270
danno@chromium.org40cb8782011-05-25 07:58:50 +00004271void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
4272 // ----------- S t a t e -------------
4273 // -- ra : return address
4274 // -- a0 : key
4275 // -- a1 : receiver
4276 // -----------------------------------
4277 Label miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004278
danno@chromium.org40cb8782011-05-25 07:58:50 +00004279 // This stub is meant to be tail-jumped to, the receiver must already
4280 // have been verified by the caller to not be a smi.
4281
4282 // Check that the key is a smi.
4283 __ JumpIfNotSmi(a0, &miss_force_generic);
4284
4285 // Get the elements array.
4286 __ lw(a2, FieldMemOperand(a1, JSObject::kElementsOffset));
4287 __ AssertFastElements(a2);
4288
4289 // Check that the key is within bounds.
4290 __ lw(a3, FieldMemOperand(a2, FixedArray::kLengthOffset));
4291 __ Branch(&miss_force_generic, hs, a0, Operand(a3));
4292
4293 // Load the result and make sure it's not the hole.
4294 __ Addu(a3, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004295 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004296 __ sll(t0, a0, kPointerSizeLog2 - kSmiTagSize);
4297 __ Addu(t0, t0, a3);
4298 __ lw(t0, MemOperand(t0));
4299 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
4300 __ Branch(&miss_force_generic, eq, t0, Operand(t1));
4301 __ mov(v0, t0);
4302 __ Ret();
4303
4304 __ bind(&miss_force_generic);
4305 Code* stub = masm->isolate()->builtins()->builtin(
4306 Builtins::kKeyedLoadIC_MissForceGeneric);
4307 __ Jump(Handle<Code>(stub), RelocInfo::CODE_TARGET);
4308}
4309
4310
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004311void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
4312 MacroAssembler* masm) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004313 // ----------- S t a t e -------------
4314 // -- ra : return address
4315 // -- a0 : key
4316 // -- a1 : receiver
4317 // -----------------------------------
4318 Label miss_force_generic, slow_allocate_heapnumber;
4319
4320 Register key_reg = a0;
4321 Register receiver_reg = a1;
4322 Register elements_reg = a2;
4323 Register heap_number_reg = a2;
4324 Register indexed_double_offset = a3;
4325 Register scratch = t0;
4326 Register scratch2 = t1;
4327 Register scratch3 = t2;
4328 Register heap_number_map = t3;
4329
4330 // This stub is meant to be tail-jumped to, the receiver must already
4331 // have been verified by the caller to not be a smi.
4332
4333 // Check that the key is a smi.
4334 __ JumpIfNotSmi(key_reg, &miss_force_generic);
4335
4336 // Get the elements array.
4337 __ lw(elements_reg,
4338 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4339
4340 // Check that the key is within bounds.
4341 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4342 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4343
4344 // Load the upper word of the double in the fixed array and test for NaN.
4345 __ sll(scratch2, key_reg, kDoubleSizeLog2 - kSmiTagSize);
4346 __ Addu(indexed_double_offset, elements_reg, Operand(scratch2));
4347 uint32_t upper_32_offset = FixedArray::kHeaderSize + sizeof(kHoleNanLower32);
4348 __ lw(scratch, FieldMemOperand(indexed_double_offset, upper_32_offset));
4349 __ Branch(&miss_force_generic, eq, scratch, Operand(kHoleNanUpper32));
4350
4351 // Non-NaN. Allocate a new heap number and copy the double value into it.
4352 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
4353 __ AllocateHeapNumber(heap_number_reg, scratch2, scratch3,
4354 heap_number_map, &slow_allocate_heapnumber);
4355
4356 // Don't need to reload the upper 32 bits of the double, it's already in
4357 // scratch.
4358 __ sw(scratch, FieldMemOperand(heap_number_reg,
4359 HeapNumber::kExponentOffset));
4360 __ lw(scratch, FieldMemOperand(indexed_double_offset,
4361 FixedArray::kHeaderSize));
4362 __ sw(scratch, FieldMemOperand(heap_number_reg,
4363 HeapNumber::kMantissaOffset));
4364
4365 __ mov(v0, heap_number_reg);
4366 __ Ret();
4367
4368 __ bind(&slow_allocate_heapnumber);
4369 Handle<Code> slow_ic =
4370 masm->isolate()->builtins()->KeyedLoadIC_Slow();
4371 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4372
4373 __ bind(&miss_force_generic);
4374 Handle<Code> miss_ic =
4375 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4376 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004377}
4378
4379
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004380void KeyedStoreStubCompiler::GenerateStoreFastElement(
4381 MacroAssembler* masm,
4382 bool is_js_array,
4383 ElementsKind elements_kind) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00004384 // ----------- S t a t e -------------
4385 // -- a0 : value
4386 // -- a1 : key
4387 // -- a2 : receiver
4388 // -- ra : return address
4389 // -- a3 : scratch
4390 // -- a4 : scratch (elements)
4391 // -----------------------------------
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004392 Label miss_force_generic, transition_elements_kind;
danno@chromium.org40cb8782011-05-25 07:58:50 +00004393
4394 Register value_reg = a0;
4395 Register key_reg = a1;
4396 Register receiver_reg = a2;
4397 Register scratch = a3;
4398 Register elements_reg = t0;
4399 Register scratch2 = t1;
4400 Register scratch3 = t2;
4401
4402 // This stub is meant to be tail-jumped to, the receiver must already
4403 // have been verified by the caller to not be a smi.
4404
4405 // Check that the key is a smi.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00004406 __ JumpIfNotSmi(key_reg, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004407
4408 // Get the elements array and make sure it is a fast element array, not 'cow'.
4409 __ lw(elements_reg,
4410 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4411 __ CheckMap(elements_reg,
4412 scratch,
4413 Heap::kFixedArrayMapRootIndex,
4414 &miss_force_generic,
4415 DONT_DO_SMI_CHECK);
4416
4417 // Check that the key is within bounds.
4418 if (is_js_array) {
4419 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4420 } else {
4421 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4422 }
4423 // Compare smis.
4424 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4425
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004426 if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
4427 __ JumpIfNotSmi(value_reg, &transition_elements_kind);
4428 __ Addu(scratch,
4429 elements_reg,
4430 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4431 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4432 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4433 __ Addu(scratch, scratch, scratch2);
4434 __ sw(value_reg, MemOperand(scratch));
4435 } else {
4436 ASSERT(elements_kind == FAST_ELEMENTS);
4437 __ Addu(scratch,
4438 elements_reg,
4439 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4440 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4441 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4442 __ Addu(scratch, scratch, scratch2);
4443 __ sw(value_reg, MemOperand(scratch));
4444 __ mov(receiver_reg, value_reg);
4445 ASSERT(elements_kind == FAST_ELEMENTS);
4446 __ RecordWrite(elements_reg, // Object.
4447 scratch, // Address.
4448 receiver_reg, // Value.
4449 kRAHasNotBeenSaved,
4450 kDontSaveFPRegs);
4451 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004452 // value_reg (a0) is preserved.
4453 // Done.
4454 __ Ret();
4455
4456 __ bind(&miss_force_generic);
4457 Handle<Code> ic =
4458 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4459 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004460
4461 __ bind(&transition_elements_kind);
4462 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4463 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004464}
4465
4466
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004467void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
4468 MacroAssembler* masm,
4469 bool is_js_array) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004470 // ----------- S t a t e -------------
4471 // -- a0 : value
4472 // -- a1 : key
4473 // -- a2 : receiver
4474 // -- ra : return address
4475 // -- a3 : scratch
4476 // -- t0 : scratch (elements_reg)
4477 // -- t1 : scratch (mantissa_reg)
4478 // -- t2 : scratch (exponent_reg)
4479 // -- t3 : scratch4
4480 // -----------------------------------
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004481 Label miss_force_generic, transition_elements_kind;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004482
4483 Register value_reg = a0;
4484 Register key_reg = a1;
4485 Register receiver_reg = a2;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004486 Register elements_reg = a3;
4487 Register scratch1 = t0;
4488 Register scratch2 = t1;
4489 Register scratch3 = t2;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004490 Register scratch4 = t3;
4491
4492 // This stub is meant to be tail-jumped to, the receiver must already
4493 // have been verified by the caller to not be a smi.
4494 __ JumpIfNotSmi(key_reg, &miss_force_generic);
4495
4496 __ lw(elements_reg,
4497 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4498
4499 // Check that the key is within bounds.
4500 if (is_js_array) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004501 __ lw(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004502 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004503 __ lw(scratch1,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004504 FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4505 }
4506 // Compare smis, unsigned compare catches both negative and out-of-bound
4507 // indexes.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004508 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch1));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004509
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004510 __ StoreNumberToDoubleElements(value_reg,
4511 key_reg,
4512 receiver_reg,
4513 elements_reg,
4514 scratch1,
4515 scratch2,
4516 scratch3,
4517 scratch4,
4518 &transition_elements_kind);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004519
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004520 __ Ret(USE_DELAY_SLOT);
4521 __ mov(v0, value_reg); // In delay slot.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004522
4523 // Handle store cache miss, replacing the ic with the generic stub.
4524 __ bind(&miss_force_generic);
4525 Handle<Code> ic =
4526 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4527 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004528
4529 __ bind(&transition_elements_kind);
4530 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4531 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004532}
4533
4534
ager@chromium.org5c838252010-02-19 08:53:10 +00004535#undef __
4536
4537} } // namespace v8::internal
4538
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004539#endif // V8_TARGET_ARCH_MIPS