blob: 296f186e940c69c4ee5bd33649c29c71fa2ea3ba [file] [log] [blame]
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001// Copyright 2011 the V8 project authors. All rights reserved.
ager@chromium.org5c838252010-02-19 08:53:10 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000030#if defined(V8_TARGET_ARCH_MIPS)
31
ager@chromium.org5c838252010-02-19 08:53:10 +000032#include "ic-inl.h"
karlklose@chromium.org83a47282011-05-11 11:54:09 +000033#include "codegen.h"
ager@chromium.org5c838252010-02-19 08:53:10 +000034#include "stub-cache.h"
35
36namespace v8 {
37namespace internal {
38
39#define __ ACCESS_MASM(masm)
40
41
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000042static void ProbeTable(Isolate* isolate,
43 MacroAssembler* masm,
44 Code::Flags flags,
45 StubCache::Table table,
46 Register name,
47 Register offset,
48 Register scratch,
49 Register scratch2) {
50 ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
51 ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
52
53 uint32_t key_off_addr = reinterpret_cast<uint32_t>(key_offset.address());
54 uint32_t value_off_addr = reinterpret_cast<uint32_t>(value_offset.address());
55
56 // Check the relative positions of the address fields.
57 ASSERT(value_off_addr > key_off_addr);
58 ASSERT((value_off_addr - key_off_addr) % 4 == 0);
59 ASSERT((value_off_addr - key_off_addr) < (256 * 4));
60
61 Label miss;
62 Register offsets_base_addr = scratch;
63
64 // Check that the key in the entry matches the name.
65 __ li(offsets_base_addr, Operand(key_offset));
66 __ sll(scratch2, offset, 1);
67 __ addu(scratch2, offsets_base_addr, scratch2);
68 __ lw(scratch2, MemOperand(scratch2));
69 __ Branch(&miss, ne, name, Operand(scratch2));
70
71 // Get the code entry from the cache.
72 __ Addu(offsets_base_addr, offsets_base_addr,
73 Operand(value_off_addr - key_off_addr));
74 __ sll(scratch2, offset, 1);
75 __ addu(scratch2, offsets_base_addr, scratch2);
76 __ lw(scratch2, MemOperand(scratch2));
77
78 // Check that the flags match what we're looking for.
79 __ lw(scratch2, FieldMemOperand(scratch2, Code::kFlagsOffset));
80 __ And(scratch2, scratch2, Operand(~Code::kFlagsNotUsedInLookup));
81 __ Branch(&miss, ne, scratch2, Operand(flags));
82
83 // Re-load code entry from cache.
84 __ sll(offset, offset, 1);
85 __ addu(offset, offset, offsets_base_addr);
86 __ lw(offset, MemOperand(offset));
87
88 // Jump to the first instruction in the code stub.
89 __ Addu(offset, offset, Operand(Code::kHeaderSize - kHeapObjectTag));
90 __ Jump(offset);
91
92 // Miss: fall through.
93 __ bind(&miss);
94}
95
96
97// Helper function used to check that the dictionary doesn't contain
98// the property. This function may return false negatives, so miss_label
99// must always call a backup property check that is complete.
100// This function is safe to call if the receiver has fast properties.
101// Name must be a symbol and receiver must be a heap object.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000102static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
103 Label* miss_label,
104 Register receiver,
105 Handle<String> name,
106 Register scratch0,
107 Register scratch1) {
108 ASSERT(name->IsSymbol());
109 Counters* counters = masm->isolate()->counters();
110 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
111 __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
112
113 Label done;
114
115 const int kInterceptorOrAccessCheckNeededMask =
116 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
117
118 // Bail out if the receiver has a named interceptor or requires access checks.
119 Register map = scratch1;
120 __ lw(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
121 __ lbu(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
122 __ And(scratch0, scratch0, Operand(kInterceptorOrAccessCheckNeededMask));
123 __ Branch(miss_label, ne, scratch0, Operand(zero_reg));
124
125 // Check that receiver is a JSObject.
126 __ lbu(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
127 __ Branch(miss_label, lt, scratch0, Operand(FIRST_SPEC_OBJECT_TYPE));
128
129 // Load properties array.
130 Register properties = scratch0;
131 __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
132 // Check that the properties array is a dictionary.
133 __ lw(map, FieldMemOperand(properties, HeapObject::kMapOffset));
134 Register tmp = properties;
135 __ LoadRoot(tmp, Heap::kHashTableMapRootIndex);
136 __ Branch(miss_label, ne, map, Operand(tmp));
137
138 // Restore the temporarily used register.
139 __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
140
141
142 StringDictionaryLookupStub::GenerateNegativeLookup(masm,
143 miss_label,
144 &done,
145 receiver,
146 properties,
147 name,
148 scratch1);
149 __ bind(&done);
150 __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
151}
152
153
154// TODO(kmillikin): Eliminate this function when the stub cache is fully
155// handlified.
156MUST_USE_RESULT static MaybeObject* TryGenerateDictionaryNegativeLookup(
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000157 MacroAssembler* masm,
158 Label* miss_label,
159 Register receiver,
160 String* name,
161 Register scratch0,
162 Register scratch1) {
163 ASSERT(name->IsSymbol());
164 Counters* counters = masm->isolate()->counters();
165 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
166 __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
167
168 Label done;
169
170 const int kInterceptorOrAccessCheckNeededMask =
171 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
172
173 // Bail out if the receiver has a named interceptor or requires access checks.
174 Register map = scratch1;
175 __ lw(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
176 __ lbu(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
177 __ And(at, scratch0, Operand(kInterceptorOrAccessCheckNeededMask));
178 __ Branch(miss_label, ne, at, Operand(zero_reg));
179
180
181 // Check that receiver is a JSObject.
182 __ lbu(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000183 __ Branch(miss_label, lt, scratch0, Operand(FIRST_SPEC_OBJECT_TYPE));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000184
185 // Load properties array.
186 Register properties = scratch0;
187 __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
188 // Check that the properties array is a dictionary.
189 __ lw(map, FieldMemOperand(properties, HeapObject::kMapOffset));
190 Register tmp = properties;
191 __ LoadRoot(tmp, Heap::kHashTableMapRootIndex);
192 __ Branch(miss_label, ne, map, Operand(tmp));
193
194 // Restore the temporarily used register.
195 __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
196
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000197 MaybeObject* result = StringDictionaryLookupStub::TryGenerateNegativeLookup(
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000198 masm,
199 miss_label,
200 &done,
201 receiver,
202 properties,
203 name,
204 scratch1);
205 if (result->IsFailure()) return result;
206
207 __ bind(&done);
208 __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
209
210 return result;
211}
212
213
ager@chromium.org5c838252010-02-19 08:53:10 +0000214void StubCache::GenerateProbe(MacroAssembler* masm,
215 Code::Flags flags,
216 Register receiver,
217 Register name,
218 Register scratch,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000219 Register extra,
220 Register extra2) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000221 Isolate* isolate = masm->isolate();
222 Label miss;
223
224 // Make sure that code is valid. The shifting code relies on the
225 // entry size being 8.
226 ASSERT(sizeof(Entry) == 8);
227
228 // Make sure the flags does not name a specific type.
229 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
230
231 // Make sure that there are no register conflicts.
232 ASSERT(!scratch.is(receiver));
233 ASSERT(!scratch.is(name));
234 ASSERT(!extra.is(receiver));
235 ASSERT(!extra.is(name));
236 ASSERT(!extra.is(scratch));
237 ASSERT(!extra2.is(receiver));
238 ASSERT(!extra2.is(name));
239 ASSERT(!extra2.is(scratch));
240 ASSERT(!extra2.is(extra));
241
242 // Check scratch, extra and extra2 registers are valid.
243 ASSERT(!scratch.is(no_reg));
244 ASSERT(!extra.is(no_reg));
245 ASSERT(!extra2.is(no_reg));
246
247 // Check that the receiver isn't a smi.
248 __ JumpIfSmi(receiver, &miss, t0);
249
250 // Get the map of the receiver and compute the hash.
251 __ lw(scratch, FieldMemOperand(name, String::kHashFieldOffset));
252 __ lw(t8, FieldMemOperand(receiver, HeapObject::kMapOffset));
253 __ Addu(scratch, scratch, Operand(t8));
254 __ Xor(scratch, scratch, Operand(flags));
255 __ And(scratch,
256 scratch,
257 Operand((kPrimaryTableSize - 1) << kHeapObjectTagSize));
258
259 // Probe the primary table.
260 ProbeTable(isolate, masm, flags, kPrimary, name, scratch, extra, extra2);
261
262 // Primary miss: Compute hash for secondary probe.
263 __ Subu(scratch, scratch, Operand(name));
264 __ Addu(scratch, scratch, Operand(flags));
265 __ And(scratch,
266 scratch,
267 Operand((kSecondaryTableSize - 1) << kHeapObjectTagSize));
268
269 // Probe the secondary table.
270 ProbeTable(isolate, masm, flags, kSecondary, name, scratch, extra, extra2);
271
272 // Cache miss: Fall-through and let caller handle the miss by
273 // entering the runtime system.
274 __ bind(&miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000275}
276
277
278void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
279 int index,
280 Register prototype) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000281 // Load the global or builtins object from the current context.
282 __ lw(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
283 // Load the global context from the global or builtins object.
284 __ lw(prototype,
285 FieldMemOperand(prototype, GlobalObject::kGlobalContextOffset));
286 // Load the function from the global context.
287 __ lw(prototype, MemOperand(prototype, Context::SlotOffset(index)));
288 // Load the initial map. The global functions all have initial maps.
289 __ lw(prototype,
290 FieldMemOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
291 // Load the prototype from the initial map.
292 __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000293}
294
295
lrn@chromium.org7516f052011-03-30 08:52:27 +0000296void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
297 MacroAssembler* masm, int index, Register prototype, Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000298 Isolate* isolate = masm->isolate();
299 // Check we're still in the same context.
300 __ lw(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
301 ASSERT(!prototype.is(at));
302 __ li(at, isolate->global());
303 __ Branch(miss, ne, prototype, Operand(at));
304 // Get the global function with the given index.
305 JSFunction* function =
306 JSFunction::cast(isolate->global_context()->get(index));
307 // Load its initial map. The global functions all have initial maps.
308 __ li(prototype, Handle<Map>(function->initial_map()));
309 // Load the prototype from the initial map.
310 __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000311}
312
313
ager@chromium.org5c838252010-02-19 08:53:10 +0000314// Load a fast property out of a holder object (src). In-object properties
315// are loaded directly otherwise the property is loaded from the properties
316// fixed array.
317void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000318 Register dst,
319 Register src,
320 Handle<JSObject> holder,
321 int index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000322 // Adjust for the number of properties stored in the holder.
323 index -= holder->map()->inobject_properties();
324 if (index < 0) {
325 // Get the property straight out of the holder.
326 int offset = holder->map()->instance_size() + (index * kPointerSize);
327 __ lw(dst, FieldMemOperand(src, offset));
328 } else {
329 // Calculate the offset into the properties array.
330 int offset = index * kPointerSize + FixedArray::kHeaderSize;
331 __ lw(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
332 __ lw(dst, FieldMemOperand(dst, offset));
333 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000334}
335
336
337void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
338 Register receiver,
339 Register scratch,
340 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000341 // Check that the receiver isn't a smi.
342 __ And(scratch, receiver, Operand(kSmiTagMask));
343 __ Branch(miss_label, eq, scratch, Operand(zero_reg));
344
345 // Check that the object is a JS array.
346 __ GetObjectType(receiver, scratch, scratch);
347 __ Branch(miss_label, ne, scratch, Operand(JS_ARRAY_TYPE));
348
349 // Load length directly from the JS array.
350 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
351 __ Ret();
352}
353
354
355// Generate code to check if an object is a string. If the object is a
356// heap object, its map's instance type is left in the scratch1 register.
357// If this is not needed, scratch1 and scratch2 may be the same register.
358static void GenerateStringCheck(MacroAssembler* masm,
359 Register receiver,
360 Register scratch1,
361 Register scratch2,
362 Label* smi,
363 Label* non_string_object) {
364 // Check that the receiver isn't a smi.
365 __ JumpIfSmi(receiver, smi, t0);
366
367 // Check that the object is a string.
368 __ lw(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
369 __ lbu(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
370 __ And(scratch2, scratch1, Operand(kIsNotStringMask));
371 // The cast is to resolve the overload for the argument of 0x0.
372 __ Branch(non_string_object,
373 ne,
374 scratch2,
375 Operand(static_cast<int32_t>(kStringTag)));
ager@chromium.org5c838252010-02-19 08:53:10 +0000376}
377
378
lrn@chromium.org7516f052011-03-30 08:52:27 +0000379// Generate code to load the length from a string object and return the length.
380// If the receiver object is not a string or a wrapped string object the
381// execution continues at the miss label. The register containing the
382// receiver is potentially clobbered.
383void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
384 Register receiver,
385 Register scratch1,
386 Register scratch2,
387 Label* miss,
388 bool support_wrappers) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000389 Label check_wrapper;
390
391 // Check if the object is a string leaving the instance type in the
392 // scratch1 register.
393 GenerateStringCheck(masm, receiver, scratch1, scratch2, miss,
394 support_wrappers ? &check_wrapper : miss);
395
396 // Load length directly from the string.
397 __ lw(v0, FieldMemOperand(receiver, String::kLengthOffset));
398 __ Ret();
399
400 if (support_wrappers) {
401 // Check if the object is a JSValue wrapper.
402 __ bind(&check_wrapper);
403 __ Branch(miss, ne, scratch1, Operand(JS_VALUE_TYPE));
404
405 // Unwrap the value and check if the wrapped value is a string.
406 __ lw(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
407 GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
408 __ lw(v0, FieldMemOperand(scratch1, String::kLengthOffset));
409 __ Ret();
410 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000411}
412
413
ager@chromium.org5c838252010-02-19 08:53:10 +0000414void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
415 Register receiver,
416 Register scratch1,
417 Register scratch2,
418 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000419 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
420 __ mov(v0, scratch1);
421 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000422}
423
424
lrn@chromium.org7516f052011-03-30 08:52:27 +0000425// Generate StoreField code, value is passed in a0 register.
ager@chromium.org5c838252010-02-19 08:53:10 +0000426// After executing generated code, the receiver_reg and name_reg
427// may be clobbered.
428void StubCompiler::GenerateStoreField(MacroAssembler* masm,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000429 Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +0000430 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000431 Handle<Map> transition,
ager@chromium.org5c838252010-02-19 08:53:10 +0000432 Register receiver_reg,
433 Register name_reg,
434 Register scratch,
435 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000436 // a0 : value.
437 Label exit;
438
439 // Check that the receiver isn't a smi.
440 __ JumpIfSmi(receiver_reg, miss_label, scratch);
441
442 // Check that the map of the receiver hasn't changed.
443 __ lw(scratch, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
444 __ Branch(miss_label, ne, scratch, Operand(Handle<Map>(object->map())));
445
446 // Perform global security token check if needed.
447 if (object->IsJSGlobalProxy()) {
448 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
449 }
450
451 // Stub never generated for non-global objects that require access
452 // checks.
453 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
454
455 // Perform map transition for the receiver if necessary.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000456 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000457 // The properties must be extended before we can store the value.
458 // We jump to a runtime call that extends the properties array.
459 __ push(receiver_reg);
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000460 __ li(a2, Operand(transition));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000461 __ Push(a2, a0);
462 __ TailCallExternalReference(
463 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
464 masm->isolate()),
465 3, 1);
466 return;
467 }
468
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000469 if (!transition.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000470 // Update the map of the object; no write barrier updating is
471 // needed because the map is never in new space.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000472 __ li(t0, Operand(transition));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000473 __ sw(t0, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
474 }
475
476 // Adjust for the number of properties stored in the object. Even in the
477 // face of a transition we can use the old map here because the size of the
478 // object and the number of in-object properties is not going to change.
479 index -= object->map()->inobject_properties();
480
481 if (index < 0) {
482 // Set the property straight into the object.
483 int offset = object->map()->instance_size() + (index * kPointerSize);
484 __ sw(a0, FieldMemOperand(receiver_reg, offset));
485
486 // Skip updating write barrier if storing a smi.
487 __ JumpIfSmi(a0, &exit, scratch);
488
489 // Update the write barrier for the array address.
490 // Pass the now unused name_reg as a scratch register.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000491 __ mov(name_reg, a0);
492 __ RecordWriteField(receiver_reg,
493 offset,
494 name_reg,
495 scratch,
496 kRAHasNotBeenSaved,
497 kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000498 } else {
499 // Write to the properties array.
500 int offset = index * kPointerSize + FixedArray::kHeaderSize;
501 // Get the properties array.
502 __ lw(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
503 __ sw(a0, FieldMemOperand(scratch, offset));
504
505 // Skip updating write barrier if storing a smi.
506 __ JumpIfSmi(a0, &exit);
507
508 // Update the write barrier for the array address.
509 // Ok to clobber receiver_reg and name_reg, since we return.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000510 __ mov(name_reg, a0);
511 __ RecordWriteField(scratch,
512 offset,
513 name_reg,
514 receiver_reg,
515 kRAHasNotBeenSaved,
516 kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000517 }
518
519 // Return the value (register v0).
520 __ bind(&exit);
521 __ mov(v0, a0);
522 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000523}
524
525
526void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000527 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000528 Handle<Code> code = (kind == Code::LOAD_IC)
529 ? masm->isolate()->builtins()->LoadIC_Miss()
530 : masm->isolate()->builtins()->KeyedLoadIC_Miss();
531 __ Jump(code, RelocInfo::CODE_TARGET);
ager@chromium.org5c838252010-02-19 08:53:10 +0000532}
533
534
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000535static void GenerateCallFunction(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000536 Handle<Object> object,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000537 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000538 Label* miss,
539 Code::ExtraICState extra_ic_state) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000540 // ----------- S t a t e -------------
541 // -- a0: receiver
542 // -- a1: function to call
543 // -----------------------------------
544 // Check that the function really is a function.
545 __ JumpIfSmi(a1, miss);
546 __ GetObjectType(a1, a3, a3);
547 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
548
549 // Patch the receiver on the stack with the global proxy if
550 // necessary.
551 if (object->IsGlobalObject()) {
552 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
553 __ sw(a3, MemOperand(sp, arguments.immediate() * kPointerSize));
554 }
555
556 // Invoke the function.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000557 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
558 ? CALL_AS_FUNCTION
559 : CALL_AS_METHOD;
560 __ InvokeFunction(a1, arguments, JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000561}
562
563
564static void PushInterceptorArguments(MacroAssembler* masm,
565 Register receiver,
566 Register holder,
567 Register name,
568 JSObject* holder_obj) {
569 __ push(name);
570 InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
571 ASSERT(!masm->isolate()->heap()->InNewSpace(interceptor));
572 Register scratch = name;
573 __ li(scratch, Operand(Handle<Object>(interceptor)));
574 __ Push(scratch, receiver, holder);
575 __ lw(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
576 __ push(scratch);
577}
578
579
580static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
581 Register receiver,
582 Register holder,
583 Register name,
584 JSObject* holder_obj) {
585 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
586
587 ExternalReference ref =
588 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
589 masm->isolate());
590 __ li(a0, Operand(5));
591 __ li(a1, Operand(ref));
592
593 CEntryStub stub(1);
594 __ CallStub(&stub);
595}
596
597
598static const int kFastApiCallArguments = 3;
599
600
601// Reserves space for the extra arguments to FastHandleApiCall in the
602// caller's frame.
603//
604// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
605static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
606 Register scratch) {
607 ASSERT(Smi::FromInt(0) == 0);
608 for (int i = 0; i < kFastApiCallArguments; i++) {
609 __ push(zero_reg);
610 }
611}
612
613
614// Undoes the effects of ReserveSpaceForFastApiCall.
615static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
616 __ Drop(kFastApiCallArguments);
617}
618
619
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000620static MaybeObject* GenerateFastApiDirectCall(
621 MacroAssembler* masm,
622 const CallOptimization& optimization,
623 int argc) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000624 // ----------- S t a t e -------------
625 // -- sp[0] : holder (set by CheckPrototypes)
626 // -- sp[4] : callee js function
627 // -- sp[8] : call data
628 // -- sp[12] : last js argument
629 // -- ...
630 // -- sp[(argc + 3) * 4] : first js argument
631 // -- sp[(argc + 4) * 4] : receiver
632 // -----------------------------------
633 // Get the function and setup the context.
634 JSFunction* function = optimization.constant_function();
635 __ li(t1, Operand(Handle<JSFunction>(function)));
636 __ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset));
637
638 // Pass the additional arguments FastHandleApiCall expects.
639 Object* call_data = optimization.api_call_info()->data();
640 Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info());
641 if (masm->isolate()->heap()->InNewSpace(call_data)) {
642 __ li(a0, api_call_info_handle);
643 __ lw(t2, FieldMemOperand(a0, CallHandlerInfo::kDataOffset));
644 } else {
645 __ li(t2, Operand(Handle<Object>(call_data)));
646 }
647
648 // Store js function and call data.
649 __ sw(t1, MemOperand(sp, 1 * kPointerSize));
650 __ sw(t2, MemOperand(sp, 2 * kPointerSize));
651
652 // a2 points to call data as expected by Arguments
653 // (refer to layout above).
654 __ Addu(a2, sp, Operand(2 * kPointerSize));
655
656 Object* callback = optimization.api_call_info()->callback();
657 Address api_function_address = v8::ToCData<Address>(callback);
658 ApiFunction fun(api_function_address);
659
660 const int kApiStackSpace = 4;
661
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000662 FrameScope frame_scope(masm, StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000663 __ EnterExitFrame(false, kApiStackSpace);
664
665 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
666 // struct from the function (which is currently the case). This means we pass
667 // the first argument in a1 instead of a0. TryCallApiFunctionAndReturn
668 // will handle setting up a0.
669
670 // a1 = v8::Arguments&
671 // Arguments is built at sp + 1 (sp is a reserved spot for ra).
672 __ Addu(a1, sp, kPointerSize);
673
674 // v8::Arguments::implicit_args = data
675 __ sw(a2, MemOperand(a1, 0 * kPointerSize));
676 // v8::Arguments::values = last argument
677 __ Addu(t0, a2, Operand(argc * kPointerSize));
678 __ sw(t0, MemOperand(a1, 1 * kPointerSize));
679 // v8::Arguments::length_ = argc
680 __ li(t0, Operand(argc));
681 __ sw(t0, MemOperand(a1, 2 * kPointerSize));
682 // v8::Arguments::is_construct_call = 0
683 __ sw(zero_reg, MemOperand(a1, 3 * kPointerSize));
684
685 // Emitting a stub call may try to allocate (if the code is not
686 // already generated). Do not allow the assembler to perform a
687 // garbage collection but instead return the allocation failure
688 // object.
689 const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
690 ExternalReference ref =
691 ExternalReference(&fun,
692 ExternalReference::DIRECT_API_CALL,
693 masm->isolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000694 AllowExternalCallThatCantCauseGC scope(masm);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000695 return masm->TryCallApiFunctionAndReturn(ref, kStackUnwindSpace);
696}
697
lrn@chromium.org7516f052011-03-30 08:52:27 +0000698class CallInterceptorCompiler BASE_EMBEDDED {
699 public:
700 CallInterceptorCompiler(StubCompiler* stub_compiler,
701 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000702 Register name,
703 Code::ExtraICState extra_ic_state)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000704 : stub_compiler_(stub_compiler),
705 arguments_(arguments),
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000706 name_(name),
707 extra_ic_state_(extra_ic_state) {}
lrn@chromium.org7516f052011-03-30 08:52:27 +0000708
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000709 MaybeObject* Compile(MacroAssembler* masm,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000710 JSObject* object,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000711 JSObject* holder,
712 String* name,
713 LookupResult* lookup,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000714 Register receiver,
715 Register scratch1,
716 Register scratch2,
717 Register scratch3,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000718 Label* miss) {
719 ASSERT(holder->HasNamedInterceptor());
720 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
721
722 // Check that the receiver isn't a smi.
723 __ JumpIfSmi(receiver, miss);
724
725 CallOptimization optimization(lookup);
726
727 if (optimization.is_constant_call()) {
728 return CompileCacheable(masm,
729 object,
730 receiver,
731 scratch1,
732 scratch2,
733 scratch3,
734 holder,
735 lookup,
736 name,
737 optimization,
738 miss);
739 } else {
740 CompileRegular(masm,
741 object,
742 receiver,
743 scratch1,
744 scratch2,
745 scratch3,
746 name,
747 holder,
748 miss);
749 return masm->isolate()->heap()->undefined_value();
750 }
751 }
752
753 private:
754 MaybeObject* CompileCacheable(MacroAssembler* masm,
755 JSObject* object,
756 Register receiver,
757 Register scratch1,
758 Register scratch2,
759 Register scratch3,
760 JSObject* interceptor_holder,
761 LookupResult* lookup,
762 String* name,
763 const CallOptimization& optimization,
764 Label* miss_label) {
765 ASSERT(optimization.is_constant_call());
766 ASSERT(!lookup->holder()->IsGlobalObject());
767
768 Counters* counters = masm->isolate()->counters();
769
770 int depth1 = kInvalidProtoDepth;
771 int depth2 = kInvalidProtoDepth;
772 bool can_do_fast_api_call = false;
773 if (optimization.is_simple_api_call() &&
774 !lookup->holder()->IsGlobalObject()) {
775 depth1 =
776 optimization.GetPrototypeDepthOfExpectedType(object,
777 interceptor_holder);
778 if (depth1 == kInvalidProtoDepth) {
779 depth2 =
780 optimization.GetPrototypeDepthOfExpectedType(interceptor_holder,
781 lookup->holder());
782 }
783 can_do_fast_api_call = (depth1 != kInvalidProtoDepth) ||
784 (depth2 != kInvalidProtoDepth);
785 }
786
787 __ IncrementCounter(counters->call_const_interceptor(), 1,
788 scratch1, scratch2);
789
790 if (can_do_fast_api_call) {
791 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
792 scratch1, scratch2);
793 ReserveSpaceForFastApiCall(masm, scratch1);
794 }
795
796 // Check that the maps from receiver to interceptor's holder
797 // haven't changed and thus we can invoke interceptor.
798 Label miss_cleanup;
799 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
800 Register holder =
801 stub_compiler_->CheckPrototypes(object, receiver,
802 interceptor_holder, scratch1,
803 scratch2, scratch3, name, depth1, miss);
804
805 // Invoke an interceptor and if it provides a value,
806 // branch to |regular_invoke|.
807 Label regular_invoke;
808 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
809 &regular_invoke);
810
811 // Interceptor returned nothing for this property. Try to use cached
812 // constant function.
813
814 // Check that the maps from interceptor's holder to constant function's
815 // holder haven't changed and thus we can use cached constant function.
816 if (interceptor_holder != lookup->holder()) {
817 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
818 lookup->holder(), scratch1,
819 scratch2, scratch3, name, depth2, miss);
820 } else {
821 // CheckPrototypes has a side effect of fetching a 'holder'
822 // for API (object which is instanceof for the signature). It's
823 // safe to omit it here, as if present, it should be fetched
824 // by the previous CheckPrototypes.
825 ASSERT(depth2 == kInvalidProtoDepth);
826 }
827
828 // Invoke function.
829 if (can_do_fast_api_call) {
830 MaybeObject* result = GenerateFastApiDirectCall(masm,
831 optimization,
832 arguments_.immediate());
833 if (result->IsFailure()) return result;
834 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000835 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
836 ? CALL_AS_FUNCTION
837 : CALL_AS_METHOD;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000838 __ InvokeFunction(optimization.constant_function(), arguments_,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000839 JUMP_FUNCTION, call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000840 }
841
842 // Deferred code for fast API call case---clean preallocated space.
843 if (can_do_fast_api_call) {
844 __ bind(&miss_cleanup);
845 FreeSpaceForFastApiCall(masm);
846 __ Branch(miss_label);
847 }
848
849 // Invoke a regular function.
850 __ bind(&regular_invoke);
851 if (can_do_fast_api_call) {
852 FreeSpaceForFastApiCall(masm);
853 }
854
855 return masm->isolate()->heap()->undefined_value();
lrn@chromium.org7516f052011-03-30 08:52:27 +0000856 }
857
858 void CompileRegular(MacroAssembler* masm,
859 JSObject* object,
860 Register receiver,
861 Register scratch1,
862 Register scratch2,
863 Register scratch3,
864 String* name,
865 JSObject* interceptor_holder,
866 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000867 Register holder =
868 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
869 scratch1, scratch2, scratch3, name,
870 miss_label);
871
872 // Call a runtime function to load the interceptor property.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000873 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000874 // Save the name_ register across the call.
875 __ push(name_);
876
877 PushInterceptorArguments(masm,
878 receiver,
879 holder,
880 name_,
881 interceptor_holder);
882
883 __ CallExternalReference(
884 ExternalReference(
885 IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
886 masm->isolate()),
887 5);
888
889 // Restore the name_ register.
890 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000891
892 // Leave the internal frame.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000893 }
894
895 void LoadWithInterceptor(MacroAssembler* masm,
896 Register receiver,
897 Register holder,
898 JSObject* holder_obj,
899 Register scratch,
900 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000901 {
902 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000903
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000904 __ Push(holder, name_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000905
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000906 CompileCallLoadPropertyWithInterceptor(masm,
907 receiver,
908 holder,
909 name_,
910 holder_obj);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000911
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000912 __ pop(name_); // Restore the name.
913 __ pop(receiver); // Restore the holder.
914 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000915
916 // If interceptor returns no-result sentinel, call the constant function.
917 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
918 __ Branch(interceptor_succeeded, ne, v0, Operand(scratch));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000919 }
920
921 StubCompiler* stub_compiler_;
922 const ParameterCount& arguments_;
923 Register name_;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000924 Code::ExtraICState extra_ic_state_;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000925};
926
927
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000928
929// Generate code to check that a global property cell is empty. Create
930// the property cell at compilation time if no cell exists for the
931// property.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000932static void GenerateCheckPropertyCell(MacroAssembler* masm,
933 Handle<GlobalObject> global,
934 Handle<String> name,
935 Register scratch,
936 Label* miss) {
937 Handle<JSGlobalPropertyCell> cell =
938 GlobalObject::EnsurePropertyCell(global, name);
939 ASSERT(cell->value()->IsTheHole());
940 __ li(scratch, Operand(cell));
941 __ lw(scratch,
942 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
943 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
944 __ Branch(miss, ne, scratch, Operand(at));
945}
946
947
948// TODO(kmillikin): Eliminate this function when the stub cache is fully
949// handlified.
950MUST_USE_RESULT static MaybeObject* TryGenerateCheckPropertyCell(
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000951 MacroAssembler* masm,
952 GlobalObject* global,
953 String* name,
954 Register scratch,
955 Label* miss) {
956 Object* probe;
957 { MaybeObject* maybe_probe = global->EnsurePropertyCell(name);
958 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
959 }
960 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
961 ASSERT(cell->value()->IsTheHole());
962 __ li(scratch, Operand(Handle<Object>(cell)));
963 __ lw(scratch,
964 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
965 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
966 __ Branch(miss, ne, scratch, Operand(at));
967 return cell;
968}
969
970
971// Calls GenerateCheckPropertyCell for each global object in the prototype chain
972// from object to (but not including) holder.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000973static void GenerateCheckPropertyCells(MacroAssembler* masm,
974 Handle<JSObject> object,
975 Handle<JSObject> holder,
976 Handle<String> name,
977 Register scratch,
978 Label* miss) {
979 Handle<JSObject> current = object;
980 while (!current.is_identical_to(holder)) {
981 if (current->IsGlobalObject()) {
982 GenerateCheckPropertyCell(masm,
983 Handle<GlobalObject>::cast(current),
984 name,
985 scratch,
986 miss);
987 }
988 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
989 }
990}
991
992
993// TODO(kmillikin): Eliminate this function when the stub cache is fully
994// handlified.
995MUST_USE_RESULT static MaybeObject* TryGenerateCheckPropertyCells(
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000996 MacroAssembler* masm,
997 JSObject* object,
998 JSObject* holder,
999 String* name,
1000 Register scratch,
1001 Label* miss) {
1002 JSObject* current = object;
1003 while (current != holder) {
1004 if (current->IsGlobalObject()) {
1005 // Returns a cell or a failure.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001006 MaybeObject* result = TryGenerateCheckPropertyCell(
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001007 masm,
1008 GlobalObject::cast(current),
1009 name,
1010 scratch,
1011 miss);
1012 if (result->IsFailure()) return result;
1013 }
1014 ASSERT(current->IsJSObject());
1015 current = JSObject::cast(current->GetPrototype());
1016 }
1017 return NULL;
1018}
1019
1020
1021// Convert and store int passed in register ival to IEEE 754 single precision
1022// floating point value at memory location (dst + 4 * wordoffset)
1023// If FPU is available use it for conversion.
1024static void StoreIntAsFloat(MacroAssembler* masm,
1025 Register dst,
1026 Register wordoffset,
1027 Register ival,
1028 Register fval,
1029 Register scratch1,
1030 Register scratch2) {
1031 if (CpuFeatures::IsSupported(FPU)) {
1032 CpuFeatures::Scope scope(FPU);
1033 __ mtc1(ival, f0);
1034 __ cvt_s_w(f0, f0);
1035 __ sll(scratch1, wordoffset, 2);
1036 __ addu(scratch1, dst, scratch1);
1037 __ swc1(f0, MemOperand(scratch1, 0));
1038 } else {
1039 // FPU is not available, do manual conversions.
1040
1041 Label not_special, done;
1042 // Move sign bit from source to destination. This works because the sign
1043 // bit in the exponent word of the double has the same position and polarity
1044 // as the 2's complement sign bit in a Smi.
1045 ASSERT(kBinary32SignMask == 0x80000000u);
1046
1047 __ And(fval, ival, Operand(kBinary32SignMask));
1048 // Negate value if it is negative.
1049 __ subu(scratch1, zero_reg, ival);
1050 __ movn(ival, scratch1, fval);
1051
1052 // We have -1, 0 or 1, which we treat specially. Register ival contains
1053 // absolute value: it is either equal to 1 (special case of -1 and 1),
1054 // greater than 1 (not a special case) or less than 1 (special case of 0).
1055 __ Branch(&not_special, gt, ival, Operand(1));
1056
1057 // For 1 or -1 we need to or in the 0 exponent (biased).
1058 static const uint32_t exponent_word_for_1 =
1059 kBinary32ExponentBias << kBinary32ExponentShift;
1060
1061 __ Xor(scratch1, ival, Operand(1));
1062 __ li(scratch2, exponent_word_for_1);
1063 __ or_(scratch2, fval, scratch2);
1064 __ movz(fval, scratch2, scratch1); // Only if ival is equal to 1.
1065 __ Branch(&done);
1066
1067 __ bind(&not_special);
1068 // Count leading zeros.
1069 // Gets the wrong answer for 0, but we already checked for that case above.
1070 Register zeros = scratch2;
1071 __ clz(zeros, ival);
1072
1073 // Compute exponent and or it into the exponent register.
1074 __ li(scratch1, (kBitsPerInt - 1) + kBinary32ExponentBias);
1075 __ subu(scratch1, scratch1, zeros);
1076
1077 __ sll(scratch1, scratch1, kBinary32ExponentShift);
1078 __ or_(fval, fval, scratch1);
1079
1080 // Shift up the source chopping the top bit off.
1081 __ Addu(zeros, zeros, Operand(1));
1082 // This wouldn't work for 1 and -1 as the shift would be 32 which means 0.
1083 __ sllv(ival, ival, zeros);
1084 // And the top (top 20 bits).
1085 __ srl(scratch1, ival, kBitsPerInt - kBinary32MantissaBits);
1086 __ or_(fval, fval, scratch1);
1087
1088 __ bind(&done);
1089
1090 __ sll(scratch1, wordoffset, 2);
1091 __ addu(scratch1, dst, scratch1);
1092 __ sw(fval, MemOperand(scratch1, 0));
1093 }
1094}
1095
1096
1097// Convert unsigned integer with specified number of leading zeroes in binary
1098// representation to IEEE 754 double.
1099// Integer to convert is passed in register hiword.
1100// Resulting double is returned in registers hiword:loword.
1101// This functions does not work correctly for 0.
1102static void GenerateUInt2Double(MacroAssembler* masm,
1103 Register hiword,
1104 Register loword,
1105 Register scratch,
1106 int leading_zeroes) {
1107 const int meaningful_bits = kBitsPerInt - leading_zeroes - 1;
1108 const int biased_exponent = HeapNumber::kExponentBias + meaningful_bits;
1109
1110 const int mantissa_shift_for_hi_word =
1111 meaningful_bits - HeapNumber::kMantissaBitsInTopWord;
1112
1113 const int mantissa_shift_for_lo_word =
1114 kBitsPerInt - mantissa_shift_for_hi_word;
1115
1116 __ li(scratch, biased_exponent << HeapNumber::kExponentShift);
1117 if (mantissa_shift_for_hi_word > 0) {
1118 __ sll(loword, hiword, mantissa_shift_for_lo_word);
1119 __ srl(hiword, hiword, mantissa_shift_for_hi_word);
1120 __ or_(hiword, scratch, hiword);
1121 } else {
1122 __ mov(loword, zero_reg);
1123 __ sll(hiword, hiword, mantissa_shift_for_hi_word);
1124 __ or_(hiword, scratch, hiword);
1125 }
1126
1127 // If least significant bit of biased exponent was not 1 it was corrupted
1128 // by most significant bit of mantissa so we should fix that.
1129 if (!(biased_exponent & 1)) {
1130 __ li(scratch, 1 << HeapNumber::kExponentShift);
1131 __ nor(scratch, scratch, scratch);
1132 __ and_(hiword, hiword, scratch);
1133 }
1134}
1135
1136
ager@chromium.org5c838252010-02-19 08:53:10 +00001137#undef __
1138#define __ ACCESS_MASM(masm())
1139
1140
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001141Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
1142 Register object_reg,
1143 Handle<JSObject> holder,
1144 Register holder_reg,
1145 Register scratch1,
1146 Register scratch2,
1147 Handle<String> name,
1148 int save_at_depth,
1149 Label* miss) {
1150 // Make sure there's no overlap between holder and object registers.
1151 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1152 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1153 && !scratch2.is(scratch1));
1154
1155 // Keep track of the current object in register reg.
1156 Register reg = object_reg;
1157 int depth = 0;
1158
1159 if (save_at_depth == depth) {
1160 __ sw(reg, MemOperand(sp));
1161 }
1162
1163 // Check the maps in the prototype chain.
1164 // Traverse the prototype chain from the object and do map checks.
1165 Handle<JSObject> current = object;
1166 while (!current.is_identical_to(holder)) {
1167 ++depth;
1168
1169 // Only global objects and objects that do not require access
1170 // checks are allowed in stubs.
1171 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1172
1173 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
1174 if (!current->HasFastProperties() &&
1175 !current->IsJSGlobalObject() &&
1176 !current->IsJSGlobalProxy()) {
1177 if (!name->IsSymbol()) {
1178 name = factory()->LookupSymbol(name);
1179 }
1180 ASSERT(current->property_dictionary()->FindEntry(*name) ==
1181 StringDictionary::kNotFound);
1182
1183 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1184 scratch1, scratch2);
1185
1186 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1187 reg = holder_reg; // From now on the object will be in holder_reg.
1188 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1189 } else {
1190 Handle<Map> current_map(current->map());
1191 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1192 // Branch on the result of the map check.
1193 __ Branch(miss, ne, scratch1, Operand(current_map));
1194 // Check access rights to the global object. This has to happen after
1195 // the map check so that we know that the object is actually a global
1196 // object.
1197 if (current->IsJSGlobalProxy()) {
1198 __ CheckAccessGlobalProxy(reg, scratch2, miss);
1199 }
1200 reg = holder_reg; // From now on the object will be in holder_reg.
1201
1202 if (heap()->InNewSpace(*prototype)) {
1203 // The prototype is in new space; we cannot store a reference to it
1204 // in the code. Load it from the map.
1205 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1206 } else {
1207 // The prototype is in old space; load it directly.
1208 __ li(reg, Operand(prototype));
1209 }
1210 }
1211
1212 if (save_at_depth == depth) {
1213 __ sw(reg, MemOperand(sp));
1214 }
1215
1216 // Go to the next object in the prototype chain.
1217 current = prototype;
1218 }
1219
1220 // Log the check depth.
1221 LOG(masm()->isolate(), IntEvent("check-maps-depth", depth + 1));
1222
1223 // Check the holder map.
1224 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1225 __ Branch(miss, ne, scratch1, Operand(Handle<Map>(current->map())));
1226
1227 // Perform security check for access to the global object.
1228 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1229 if (holder->IsJSGlobalProxy()) {
1230 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1231 }
1232
1233 // If we've skipped any global objects, it's not enough to verify that
1234 // their maps haven't changed. We also need to check that the property
1235 // cell for the property is still empty.
1236 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1237
1238 // Return the register containing the holder.
1239 return reg;
1240}
1241
1242
lrn@chromium.org7516f052011-03-30 08:52:27 +00001243Register StubCompiler::CheckPrototypes(JSObject* object,
1244 Register object_reg,
1245 JSObject* holder,
1246 Register holder_reg,
1247 Register scratch1,
1248 Register scratch2,
1249 String* name,
1250 int save_at_depth,
1251 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001252 // Make sure there's no overlap between holder and object registers.
1253 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1254 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1255 && !scratch2.is(scratch1));
1256
1257 // Keep track of the current object in register reg.
1258 Register reg = object_reg;
1259 int depth = 0;
1260
1261 if (save_at_depth == depth) {
1262 __ sw(reg, MemOperand(sp));
1263 }
1264
1265 // Check the maps in the prototype chain.
1266 // Traverse the prototype chain from the object and do map checks.
1267 JSObject* current = object;
1268 while (current != holder) {
1269 depth++;
1270
1271 // Only global objects and objects that do not require access
1272 // checks are allowed in stubs.
1273 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1274
1275 ASSERT(current->GetPrototype()->IsJSObject());
1276 JSObject* prototype = JSObject::cast(current->GetPrototype());
1277 if (!current->HasFastProperties() &&
1278 !current->IsJSGlobalObject() &&
1279 !current->IsJSGlobalProxy()) {
1280 if (!name->IsSymbol()) {
1281 MaybeObject* maybe_lookup_result = heap()->LookupSymbol(name);
1282 Object* lookup_result = NULL; // Initialization to please compiler.
1283 if (!maybe_lookup_result->ToObject(&lookup_result)) {
1284 set_failure(Failure::cast(maybe_lookup_result));
1285 return reg;
1286 }
1287 name = String::cast(lookup_result);
1288 }
1289 ASSERT(current->property_dictionary()->FindEntry(name) ==
1290 StringDictionary::kNotFound);
1291
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001292 MaybeObject* negative_lookup =
1293 TryGenerateDictionaryNegativeLookup(masm(),
1294 miss,
1295 reg,
1296 name,
1297 scratch1,
1298 scratch2);
1299
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001300 if (negative_lookup->IsFailure()) {
1301 set_failure(Failure::cast(negative_lookup));
1302 return reg;
1303 }
1304
1305 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1306 reg = holder_reg; // From now the object is in holder_reg.
1307 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1308 } else if (heap()->InNewSpace(prototype)) {
1309 // Get the map of the current object.
1310 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1311
1312 // Branch on the result of the map check.
1313 __ Branch(miss, ne, scratch1, Operand(Handle<Map>(current->map())));
1314
1315 // Check access rights to the global object. This has to happen
1316 // after the map check so that we know that the object is
1317 // actually a global object.
1318 if (current->IsJSGlobalProxy()) {
1319 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1320 // Restore scratch register to be the map of the object. In the
1321 // new space case below, we load the prototype from the map in
1322 // the scratch register.
1323 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1324 }
1325
1326 reg = holder_reg; // From now the object is in holder_reg.
1327 // The prototype is in new space; we cannot store a reference
1328 // to it in the code. Load it from the map.
1329 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1330 } else {
1331 // Check the map of the current object.
1332 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1333 // Branch on the result of the map check.
1334 __ Branch(miss, ne, scratch1, Operand(Handle<Map>(current->map())));
1335 // Check access rights to the global object. This has to happen
1336 // after the map check so that we know that the object is
1337 // actually a global object.
1338 if (current->IsJSGlobalProxy()) {
1339 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1340 }
1341 // The prototype is in old space; load it directly.
1342 reg = holder_reg; // From now the object is in holder_reg.
1343 __ li(reg, Operand(Handle<JSObject>(prototype)));
1344 }
1345
1346 if (save_at_depth == depth) {
1347 __ sw(reg, MemOperand(sp));
1348 }
1349
1350 // Go to the next object in the prototype chain.
1351 current = prototype;
1352 }
1353
1354 // Check the holder map.
1355 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1356 __ Branch(miss, ne, scratch1, Operand(Handle<Map>(current->map())));
1357
1358 // Log the check depth.
1359 LOG(masm()->isolate(), IntEvent("check-maps-depth", depth + 1));
1360 // Perform security check for access to the global object.
1361 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1362 if (holder->IsJSGlobalProxy()) {
1363 __ CheckAccessGlobalProxy(reg, scratch1, miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001364 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001365
1366 // If we've skipped any global objects, it's not enough to verify
1367 // that their maps haven't changed. We also need to check that the
1368 // property cell for the property is still empty.
1369
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001370 MaybeObject* result = TryGenerateCheckPropertyCells(masm(),
1371 object,
1372 holder,
1373 name,
1374 scratch1,
1375 miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001376 if (result->IsFailure()) set_failure(Failure::cast(result));
1377
1378 // Return the register containing the holder.
1379 return reg;
lrn@chromium.org7516f052011-03-30 08:52:27 +00001380}
1381
1382
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001383void StubCompiler::GenerateLoadField(Handle<JSObject> object,
1384 Handle<JSObject> holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001385 Register receiver,
1386 Register scratch1,
1387 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001388 Register scratch3,
ager@chromium.org5c838252010-02-19 08:53:10 +00001389 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001390 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001391 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001392 // Check that the receiver isn't a smi.
1393 __ And(scratch1, receiver, Operand(kSmiTagMask));
1394 __ Branch(miss, eq, scratch1, Operand(zero_reg));
1395
1396 // Check that the maps haven't changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001397 Register reg = CheckPrototypes(
1398 object, receiver, holder, scratch1, scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001399 GenerateFastPropertyLoad(masm(), v0, reg, holder, index);
1400 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001401}
1402
1403
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001404void StubCompiler::GenerateLoadConstant(Handle<JSObject> object,
1405 Handle<JSObject> holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001406 Register receiver,
1407 Register scratch1,
1408 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001409 Register scratch3,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001410 Handle<Object> value,
1411 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001412 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001413 // Check that the receiver isn't a smi.
1414 __ JumpIfSmi(receiver, miss, scratch1);
1415
1416 // Check that the maps haven't changed.
1417 Register reg =
1418 CheckPrototypes(object, receiver, holder,
1419 scratch1, scratch2, scratch3, name, miss);
1420
1421 // Return the constant value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001422 __ li(v0, Operand(value));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001423 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001424}
1425
1426
lrn@chromium.org7516f052011-03-30 08:52:27 +00001427MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object,
1428 JSObject* holder,
1429 Register receiver,
1430 Register name_reg,
1431 Register scratch1,
1432 Register scratch2,
1433 Register scratch3,
1434 AccessorInfo* callback,
1435 String* name,
1436 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001437 // Check that the receiver isn't a smi.
1438 __ JumpIfSmi(receiver, miss, scratch1);
1439
1440 // Check that the maps haven't changed.
1441 Register reg =
1442 CheckPrototypes(object, receiver, holder, scratch1, scratch2, scratch3,
1443 name, miss);
1444
1445 // Build AccessorInfo::args_ list on the stack and push property name below
1446 // the exit frame to make GC aware of them and store pointers to them.
1447 __ push(receiver);
1448 __ mov(scratch2, sp); // scratch2 = AccessorInfo::args_
1449 Handle<AccessorInfo> callback_handle(callback);
1450 if (heap()->InNewSpace(callback_handle->data())) {
1451 __ li(scratch3, callback_handle);
1452 __ lw(scratch3, FieldMemOperand(scratch3, AccessorInfo::kDataOffset));
1453 } else {
1454 __ li(scratch3, Handle<Object>(callback_handle->data()));
1455 }
1456 __ Push(reg, scratch3, name_reg);
1457 __ mov(a2, scratch2); // Saved in case scratch2 == a1.
1458 __ mov(a1, sp); // a1 (first argument - see note below) = Handle<String>
1459
1460 Address getter_address = v8::ToCData<Address>(callback->getter());
1461 ApiFunction fun(getter_address);
1462
1463 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
1464 // struct from the function (which is currently the case). This means we pass
1465 // the arguments in a1-a2 instead of a0-a1. TryCallApiFunctionAndReturn
1466 // will handle setting up a0.
1467
1468 const int kApiStackSpace = 1;
1469
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001470 FrameScope frame_scope(masm(), StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001471 __ EnterExitFrame(false, kApiStackSpace);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001472
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001473 // Create AccessorInfo instance on the stack above the exit frame with
1474 // scratch2 (internal::Object **args_) as the data.
1475 __ sw(a2, MemOperand(sp, kPointerSize));
1476 // a2 (second argument - see note above) = AccessorInfo&
1477 __ Addu(a2, sp, kPointerSize);
1478
1479 // Emitting a stub call may try to allocate (if the code is not
1480 // already generated). Do not allow the assembler to perform a
1481 // garbage collection but instead return the allocation failure
1482 // object.
1483 ExternalReference ref =
1484 ExternalReference(&fun,
1485 ExternalReference::DIRECT_GETTER_CALL,
1486 masm()->isolate());
1487 // 4 args - will be freed later by LeaveExitFrame.
1488 return masm()->TryCallApiFunctionAndReturn(ref, 4);
ager@chromium.org5c838252010-02-19 08:53:10 +00001489}
1490
1491
1492void StubCompiler::GenerateLoadInterceptor(JSObject* object,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001493 JSObject* interceptor_holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001494 LookupResult* lookup,
1495 Register receiver,
1496 Register name_reg,
1497 Register scratch1,
1498 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001499 Register scratch3,
ager@chromium.org5c838252010-02-19 08:53:10 +00001500 String* name,
1501 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001502 ASSERT(interceptor_holder->HasNamedInterceptor());
1503 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1504
1505 // Check that the receiver isn't a smi.
1506 __ JumpIfSmi(receiver, miss);
1507
1508 // So far the most popular follow ups for interceptor loads are FIELD
1509 // and CALLBACKS, so inline only them, other cases may be added
1510 // later.
1511 bool compile_followup_inline = false;
1512 if (lookup->IsProperty() && lookup->IsCacheable()) {
1513 if (lookup->type() == FIELD) {
1514 compile_followup_inline = true;
1515 } else if (lookup->type() == CALLBACKS &&
1516 lookup->GetCallbackObject()->IsAccessorInfo() &&
1517 AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) {
1518 compile_followup_inline = true;
1519 }
1520 }
1521
1522 if (compile_followup_inline) {
1523 // Compile the interceptor call, followed by inline code to load the
1524 // property from further up the prototype chain if the call fails.
1525 // Check that the maps haven't changed.
1526 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1527 scratch1, scratch2, scratch3,
1528 name, miss);
1529 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
1530
1531 // Save necessary data before invoking an interceptor.
1532 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001533 {
1534 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001535
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001536 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
1537 // CALLBACKS case needs a receiver to be passed into C++ callback.
1538 __ Push(receiver, holder_reg, name_reg);
1539 } else {
1540 __ Push(holder_reg, name_reg);
1541 }
1542
1543 // Invoke an interceptor. Note: map checks from receiver to
1544 // interceptor's holder has been compiled before (see a caller
1545 // of this method).
1546 CompileCallLoadPropertyWithInterceptor(masm(),
1547 receiver,
1548 holder_reg,
1549 name_reg,
1550 interceptor_holder);
1551
1552 // Check if interceptor provided a value for property. If it's
1553 // the case, return immediately.
1554 Label interceptor_failed;
1555 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
1556 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1));
1557 frame_scope.GenerateLeaveFrame();
1558 __ Ret();
1559
1560 __ bind(&interceptor_failed);
1561 __ pop(name_reg);
1562 __ pop(holder_reg);
1563 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
1564 __ pop(receiver);
1565 }
1566
1567 // Leave the internal frame.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001568 }
1569
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001570 // Check that the maps from interceptor's holder to lookup's holder
1571 // haven't changed. And load lookup's holder into |holder| register.
1572 if (interceptor_holder != lookup->holder()) {
1573 holder_reg = CheckPrototypes(interceptor_holder,
1574 holder_reg,
1575 lookup->holder(),
1576 scratch1,
1577 scratch2,
1578 scratch3,
1579 name,
1580 miss);
1581 }
1582
1583 if (lookup->type() == FIELD) {
1584 // We found FIELD property in prototype chain of interceptor's holder.
1585 // Retrieve a field from field's holder.
1586 GenerateFastPropertyLoad(masm(), v0, holder_reg,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001587 Handle<JSObject>(lookup->holder()),
1588 lookup->GetFieldIndex());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001589 __ Ret();
1590 } else {
1591 // We found CALLBACKS property in prototype chain of interceptor's
1592 // holder.
1593 ASSERT(lookup->type() == CALLBACKS);
1594 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
1595 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
1596 ASSERT(callback != NULL);
1597 ASSERT(callback->getter() != NULL);
1598
1599 // Tail call to runtime.
1600 // Important invariant in CALLBACKS case: the code above must be
1601 // structured to never clobber |receiver| register.
1602 __ li(scratch2, Handle<AccessorInfo>(callback));
1603 // holder_reg is either receiver or scratch1.
1604 if (!receiver.is(holder_reg)) {
1605 ASSERT(scratch1.is(holder_reg));
1606 __ Push(receiver, holder_reg);
1607 __ lw(scratch3,
1608 FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
1609 __ Push(scratch3, scratch2, name_reg);
1610 } else {
1611 __ push(receiver);
1612 __ lw(scratch3,
1613 FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
1614 __ Push(holder_reg, scratch3, scratch2, name_reg);
1615 }
1616
1617 ExternalReference ref =
1618 ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
1619 masm()->isolate());
1620 __ TailCallExternalReference(ref, 5, 1);
1621 }
1622 } else { // !compile_followup_inline
1623 // Call the runtime system to load the interceptor.
1624 // Check that the maps haven't changed.
1625 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1626 scratch1, scratch2, scratch3,
1627 name, miss);
1628 PushInterceptorArguments(masm(), receiver, holder_reg,
1629 name_reg, interceptor_holder);
1630
1631 ExternalReference ref = ExternalReference(
1632 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), masm()->isolate());
1633 __ TailCallExternalReference(ref, 5, 1);
1634 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001635}
1636
1637
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001638void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001639 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001640 __ Branch(miss, ne, a2, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001641 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001642}
1643
1644
lrn@chromium.org7516f052011-03-30 08:52:27 +00001645void CallStubCompiler::GenerateGlobalReceiverCheck(JSObject* object,
1646 JSObject* holder,
1647 String* name,
1648 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001649 ASSERT(holder->IsGlobalObject());
1650
1651 // Get the number of arguments.
1652 const int argc = arguments().immediate();
1653
1654 // Get the receiver from the stack.
1655 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1656
1657 // If the object is the holder then we know that it's a global
1658 // object which can only happen for contextual calls. In this case,
1659 // the receiver cannot be a smi.
1660 if (object != holder) {
1661 __ JumpIfSmi(a0, miss);
1662 }
1663
1664 // Check that the maps haven't changed.
1665 CheckPrototypes(object, a0, holder, a3, a1, t0, name, miss);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001666}
1667
1668
lrn@chromium.org7516f052011-03-30 08:52:27 +00001669void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell,
1670 JSFunction* function,
1671 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001672 // Get the value from the cell.
1673 __ li(a3, Operand(Handle<JSGlobalPropertyCell>(cell)));
1674 __ lw(a1, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
1675
1676 // Check that the cell contains the same function.
1677 if (heap()->InNewSpace(function)) {
1678 // We can't embed a pointer to a function in new space so we have
1679 // to verify that the shared function info is unchanged. This has
1680 // the nice side effect that multiple closures based on the same
1681 // function can all use this call IC. Before we load through the
1682 // function, we have to verify that it still is a function.
1683 __ JumpIfSmi(a1, miss);
1684 __ GetObjectType(a1, a3, a3);
1685 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
1686
1687 // Check the shared function info. Make sure it hasn't changed.
1688 __ li(a3, Handle<SharedFunctionInfo>(function->shared()));
1689 __ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
1690 __ Branch(miss, ne, t0, Operand(a3));
1691 } else {
1692 __ Branch(miss, ne, a1, Operand(Handle<JSFunction>(function)));
1693 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001694}
1695
1696
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001697void CallStubCompiler::GenerateMissBranch() {
1698 Handle<Code> code =
danno@chromium.org40cb8782011-05-25 07:58:50 +00001699 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1700 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001701 extra_state_);
1702 __ Jump(code, RelocInfo::CODE_TARGET);
1703}
1704
1705
1706// TODO(kmillikin): Eliminate this function when the stub cache is fully
1707// handlified.
1708MaybeObject* CallStubCompiler::TryGenerateMissBranch() {
1709 MaybeObject* maybe_obj =
1710 isolate()->stub_cache()->TryComputeCallMiss(arguments().immediate(),
1711 kind_,
1712 extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001713 Object* obj;
1714 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1715 __ Jump(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET);
1716 return obj;
ager@chromium.org5c838252010-02-19 08:53:10 +00001717}
1718
1719
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001720Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1721 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001722 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001723 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001724 // ----------- S t a t e -------------
1725 // -- a2 : name
1726 // -- ra : return address
1727 // -----------------------------------
1728 Label miss;
1729
1730 GenerateNameCheck(name, &miss);
1731
1732 const int argc = arguments().immediate();
1733
1734 // Get the receiver of the function from the stack into a0.
1735 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1736 // Check that the receiver isn't a smi.
1737 __ JumpIfSmi(a0, &miss, t0);
1738
1739 // Do the right check and compute the holder register.
1740 Register reg = CheckPrototypes(object, a0, holder, a1, a3, t0, name, &miss);
1741 GenerateFastPropertyLoad(masm(), a1, reg, holder, index);
1742
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001743 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001744
1745 // Handle call cache miss.
1746 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001747 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001748
1749 // Return the generated code.
1750 return GetCode(FIELD, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001751}
1752
1753
lrn@chromium.org7516f052011-03-30 08:52:27 +00001754MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
1755 JSObject* holder,
1756 JSGlobalPropertyCell* cell,
1757 JSFunction* function,
1758 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001759 // ----------- S t a t e -------------
1760 // -- a2 : name
1761 // -- ra : return address
1762 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1763 // -- ...
1764 // -- sp[argc * 4] : receiver
1765 // -----------------------------------
1766
1767 // If object is not an array, bail out to regular call.
1768 if (!object->IsJSArray() || cell != NULL) return heap()->undefined_value();
1769
1770 Label miss;
1771
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001772 GenerateNameCheck(Handle<String>(name), &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001773
1774 Register receiver = a1;
1775
1776 // Get the receiver from the stack.
1777 const int argc = arguments().immediate();
1778 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1779
1780 // Check that the receiver isn't a smi.
1781 __ JumpIfSmi(receiver, &miss);
1782
1783 // Check that the maps haven't changed.
1784 CheckPrototypes(JSObject::cast(object), receiver,
1785 holder, a3, v0, t0, name, &miss);
1786
1787 if (argc == 0) {
1788 // Nothing to do, just return the length.
1789 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1790 __ Drop(argc + 1);
1791 __ Ret();
1792 } else {
1793 Label call_builtin;
1794
1795 Register elements = a3;
1796 Register end_elements = t1;
1797
1798 // Get the elements array of the object.
1799 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1800
1801 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001802 __ CheckMap(elements,
1803 v0,
1804 Heap::kFixedArrayMapRootIndex,
1805 &call_builtin,
1806 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001807
1808 if (argc == 1) { // Otherwise fall through to call the builtin.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001809 Label attempt_to_grow_elements;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001810
1811 // Get the array's length into v0 and calculate new length.
1812 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1813 STATIC_ASSERT(kSmiTagSize == 1);
1814 STATIC_ASSERT(kSmiTag == 0);
1815 __ Addu(v0, v0, Operand(Smi::FromInt(argc)));
1816
1817 // Get the element's length.
1818 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1819
1820 // Check if we could survive without allocation.
1821 __ Branch(&attempt_to_grow_elements, gt, v0, Operand(t0));
1822
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001823 // Check if value is a smi.
1824 Label with_write_barrier;
1825 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1826 __ JumpIfNotSmi(t0, &with_write_barrier);
1827
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001828 // Save new length.
1829 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1830
1831 // Push the element.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001832 // We may need a register containing the address end_elements below,
1833 // so write back the value in end_elements.
1834 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1835 __ Addu(end_elements, elements, end_elements);
1836 const int kEndElementsOffset =
1837 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001838 __ Addu(end_elements, end_elements, kEndElementsOffset);
1839 __ sw(t0, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001840
1841 // Check for a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001842 __ Drop(argc + 1);
1843 __ Ret();
1844
1845 __ bind(&with_write_barrier);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001846
1847 __ lw(t2, FieldMemOperand(receiver, HeapObject::kMapOffset));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001848 __ CheckFastObjectElements(t2, t2, &call_builtin);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001849
1850 // Save new length.
1851 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1852
1853 // Push the element.
1854 // We may need a register containing the address end_elements below,
1855 // so write back the value in end_elements.
1856 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1857 __ Addu(end_elements, elements, end_elements);
1858 __ Addu(end_elements, end_elements, kEndElementsOffset);
1859 __ sw(t0, MemOperand(end_elements));
1860
1861 __ RecordWrite(elements,
1862 end_elements,
1863 t0,
1864 kRAHasNotBeenSaved,
1865 kDontSaveFPRegs,
1866 EMIT_REMEMBERED_SET,
1867 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001868 __ Drop(argc + 1);
1869 __ Ret();
1870
1871 __ bind(&attempt_to_grow_elements);
1872 // v0: array's length + 1.
1873 // t0: elements' length.
1874
1875 if (!FLAG_inline_new) {
1876 __ Branch(&call_builtin);
1877 }
1878
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001879 __ lw(a2, MemOperand(sp, (argc - 1) * kPointerSize));
1880 // Growing elements that are SMI-only requires special handling in case
1881 // the new element is non-Smi. For now, delegate to the builtin.
1882 Label no_fast_elements_check;
1883 __ JumpIfSmi(a2, &no_fast_elements_check);
1884 __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1885 __ CheckFastObjectElements(t3, t3, &call_builtin);
1886 __ bind(&no_fast_elements_check);
1887
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001888 ExternalReference new_space_allocation_top =
1889 ExternalReference::new_space_allocation_top_address(
1890 masm()->isolate());
1891 ExternalReference new_space_allocation_limit =
1892 ExternalReference::new_space_allocation_limit_address(
1893 masm()->isolate());
1894
1895 const int kAllocationDelta = 4;
1896 // Load top and check if it is the end of elements.
1897 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1898 __ Addu(end_elements, elements, end_elements);
1899 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset));
1900 __ li(t3, Operand(new_space_allocation_top));
1901 __ lw(t2, MemOperand(t3));
1902 __ Branch(&call_builtin, ne, end_elements, Operand(t2));
1903
1904 __ li(t5, Operand(new_space_allocation_limit));
1905 __ lw(t5, MemOperand(t5));
1906 __ Addu(t2, t2, Operand(kAllocationDelta * kPointerSize));
1907 __ Branch(&call_builtin, hi, t2, Operand(t5));
1908
1909 // We fit and could grow elements.
1910 // Update new_space_allocation_top.
1911 __ sw(t2, MemOperand(t3));
1912 // Push the argument.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001913 __ sw(a2, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001914 // Fill the rest with holes.
1915 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1916 for (int i = 1; i < kAllocationDelta; i++) {
1917 __ sw(t2, MemOperand(end_elements, i * kPointerSize));
1918 }
1919
1920 // Update elements' and array's sizes.
1921 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1922 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta)));
1923 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1924
1925 // Elements are in new space, so write barrier is not required.
1926 __ Drop(argc + 1);
1927 __ Ret();
1928 }
1929 __ bind(&call_builtin);
1930 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
1931 masm()->isolate()),
1932 argc + 1,
1933 1);
1934 }
1935
1936 // Handle call cache miss.
1937 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001938 MaybeObject* maybe_result = TryGenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001939 if (maybe_result->IsFailure()) return maybe_result;
1940
1941 // Return the generated code.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001942 return TryGetCode(function);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001943}
1944
1945
1946MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object,
1947 JSObject* holder,
1948 JSGlobalPropertyCell* cell,
1949 JSFunction* function,
ager@chromium.org5c838252010-02-19 08:53:10 +00001950 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001951 // ----------- S t a t e -------------
1952 // -- a2 : name
1953 // -- ra : return address
1954 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1955 // -- ...
1956 // -- sp[argc * 4] : receiver
1957 // -----------------------------------
1958
1959 // If object is not an array, bail out to regular call.
1960 if (!object->IsJSArray() || cell != NULL) return heap()->undefined_value();
1961
1962 Label miss, return_undefined, call_builtin;
1963
1964 Register receiver = a1;
1965 Register elements = a3;
1966
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001967 GenerateNameCheck(Handle<String>(name), &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001968
1969 // Get the receiver from the stack.
1970 const int argc = arguments().immediate();
1971 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1972
1973 // Check that the receiver isn't a smi.
1974 __ JumpIfSmi(receiver, &miss);
1975
1976 // Check that the maps haven't changed.
1977 CheckPrototypes(JSObject::cast(object),
1978 receiver, holder, elements, t0, v0, name, &miss);
1979
1980 // Get the elements array of the object.
1981 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1982
1983 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001984 __ CheckMap(elements,
1985 v0,
1986 Heap::kFixedArrayMapRootIndex,
1987 &call_builtin,
1988 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001989
1990 // Get the array's length into t0 and calculate new length.
1991 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1992 __ Subu(t0, t0, Operand(Smi::FromInt(1)));
1993 __ Branch(&return_undefined, lt, t0, Operand(zero_reg));
1994
1995 // Get the last element.
1996 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1997 STATIC_ASSERT(kSmiTagSize == 1);
1998 STATIC_ASSERT(kSmiTag == 0);
1999 // We can't address the last element in one operation. Compute the more
2000 // expensive shift first, and use an offset later on.
2001 __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize);
2002 __ Addu(elements, elements, t1);
2003 __ lw(v0, MemOperand(elements, FixedArray::kHeaderSize - kHeapObjectTag));
2004 __ Branch(&call_builtin, eq, v0, Operand(t2));
2005
2006 // Set the array's length.
2007 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
2008
2009 // Fill with the hole.
2010 __ sw(t2, MemOperand(elements, FixedArray::kHeaderSize - kHeapObjectTag));
2011 __ Drop(argc + 1);
2012 __ Ret();
2013
2014 __ bind(&return_undefined);
2015 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2016 __ Drop(argc + 1);
2017 __ Ret();
2018
2019 __ bind(&call_builtin);
2020 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop,
2021 masm()->isolate()),
2022 argc + 1,
2023 1);
2024
2025 // Handle call cache miss.
2026 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002027 MaybeObject* maybe_result = TryGenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002028 if (maybe_result->IsFailure()) return maybe_result;
2029
2030 // Return the generated code.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002031 return TryGetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002032}
2033
2034
lrn@chromium.org7516f052011-03-30 08:52:27 +00002035MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
2036 Object* object,
2037 JSObject* holder,
2038 JSGlobalPropertyCell* cell,
2039 JSFunction* function,
2040 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002041 // ----------- S t a t e -------------
2042 // -- a2 : function name
2043 // -- ra : return address
2044 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2045 // -- ...
2046 // -- sp[argc * 4] : receiver
2047 // -----------------------------------
2048
2049 // If object is not a string, bail out to regular call.
2050 if (!object->IsString() || cell != NULL) return heap()->undefined_value();
2051
2052 const int argc = arguments().immediate();
2053
2054 Label miss;
2055 Label name_miss;
2056 Label index_out_of_range;
2057
2058 Label* index_out_of_range_label = &index_out_of_range;
2059
danno@chromium.org40cb8782011-05-25 07:58:50 +00002060 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002061 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002062 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002063 index_out_of_range_label = &miss;
2064 }
2065
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002066 GenerateNameCheck(Handle<String>(name), &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002067
2068 // Check that the maps starting from the prototype haven't changed.
2069 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2070 Context::STRING_FUNCTION_INDEX,
2071 v0,
2072 &miss);
2073 ASSERT(object != holder);
2074 CheckPrototypes(JSObject::cast(object->GetPrototype()), v0, holder,
2075 a1, a3, t0, name, &miss);
2076
2077 Register receiver = a1;
2078 Register index = t1;
2079 Register scratch = a3;
2080 Register result = v0;
2081 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
2082 if (argc > 0) {
2083 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
2084 } else {
2085 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
2086 }
2087
2088 StringCharCodeAtGenerator char_code_at_generator(receiver,
2089 index,
2090 scratch,
2091 result,
2092 &miss, // When not a string.
2093 &miss, // When not a number.
2094 index_out_of_range_label,
2095 STRING_INDEX_IS_NUMBER);
2096 char_code_at_generator.GenerateFast(masm());
2097 __ Drop(argc + 1);
2098 __ Ret();
2099
2100 StubRuntimeCallHelper call_helper;
2101 char_code_at_generator.GenerateSlow(masm(), call_helper);
2102
2103 if (index_out_of_range.is_linked()) {
2104 __ bind(&index_out_of_range);
2105 __ LoadRoot(v0, Heap::kNanValueRootIndex);
2106 __ Drop(argc + 1);
2107 __ Ret();
2108 }
2109
2110 __ bind(&miss);
2111 // Restore function name in a2.
2112 __ li(a2, Handle<String>(name));
2113 __ bind(&name_miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002114 MaybeObject* maybe_result = TryGenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002115 if (maybe_result->IsFailure()) return maybe_result;
2116
2117 // Return the generated code.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002118 return TryGetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002119}
2120
2121
lrn@chromium.org7516f052011-03-30 08:52:27 +00002122MaybeObject* CallStubCompiler::CompileStringCharAtCall(
2123 Object* object,
2124 JSObject* holder,
2125 JSGlobalPropertyCell* cell,
2126 JSFunction* function,
2127 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002128 // ----------- S t a t e -------------
2129 // -- a2 : function name
2130 // -- ra : return address
2131 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2132 // -- ...
2133 // -- sp[argc * 4] : receiver
2134 // -----------------------------------
2135
2136 // If object is not a string, bail out to regular call.
2137 if (!object->IsString() || cell != NULL) return heap()->undefined_value();
2138
2139 const int argc = arguments().immediate();
2140
2141 Label miss;
2142 Label name_miss;
2143 Label index_out_of_range;
2144 Label* index_out_of_range_label = &index_out_of_range;
2145
danno@chromium.org40cb8782011-05-25 07:58:50 +00002146 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002147 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002148 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002149 index_out_of_range_label = &miss;
2150 }
2151
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002152 GenerateNameCheck(Handle<String>(name), &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002153
2154 // Check that the maps starting from the prototype haven't changed.
2155 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2156 Context::STRING_FUNCTION_INDEX,
2157 v0,
2158 &miss);
2159 ASSERT(object != holder);
2160 CheckPrototypes(JSObject::cast(object->GetPrototype()), v0, holder,
2161 a1, a3, t0, name, &miss);
2162
2163 Register receiver = v0;
2164 Register index = t1;
2165 Register scratch1 = a1;
2166 Register scratch2 = a3;
2167 Register result = v0;
2168 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
2169 if (argc > 0) {
2170 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
2171 } else {
2172 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
2173 }
2174
2175 StringCharAtGenerator char_at_generator(receiver,
2176 index,
2177 scratch1,
2178 scratch2,
2179 result,
2180 &miss, // When not a string.
2181 &miss, // When not a number.
2182 index_out_of_range_label,
2183 STRING_INDEX_IS_NUMBER);
2184 char_at_generator.GenerateFast(masm());
2185 __ Drop(argc + 1);
2186 __ Ret();
2187
2188 StubRuntimeCallHelper call_helper;
2189 char_at_generator.GenerateSlow(masm(), call_helper);
2190
2191 if (index_out_of_range.is_linked()) {
2192 __ bind(&index_out_of_range);
2193 __ LoadRoot(v0, Heap::kEmptyStringRootIndex);
2194 __ Drop(argc + 1);
2195 __ Ret();
2196 }
2197
2198 __ bind(&miss);
2199 // Restore function name in a2.
2200 __ li(a2, Handle<String>(name));
2201 __ bind(&name_miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002202 MaybeObject* maybe_result = TryGenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002203 if (maybe_result->IsFailure()) return maybe_result;
2204
2205 // Return the generated code.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002206 return TryGetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002207}
2208
2209
lrn@chromium.org7516f052011-03-30 08:52:27 +00002210MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall(
2211 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;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002231 GenerateNameCheck(Handle<String>(name), &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002232
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 char code argument.
2248 Register code = a1;
2249 __ lw(code, MemOperand(sp, 0 * kPointerSize));
2250
2251 // Check the code is a smi.
2252 Label slow;
2253 STATIC_ASSERT(kSmiTag == 0);
2254 __ JumpIfNotSmi(code, &slow);
2255
2256 // Convert the smi code to uint16.
2257 __ And(code, code, Operand(Smi::FromInt(0xffff)));
2258
2259 StringCharFromCodeGenerator char_from_code_generator(code, v0);
2260 char_from_code_generator.GenerateFast(masm());
2261 __ Drop(argc + 1);
2262 __ Ret();
2263
2264 StubRuntimeCallHelper call_helper;
2265 char_from_code_generator.GenerateSlow(masm(), call_helper);
2266
2267 // Tail call the full function. We do not have to patch the receiver
2268 // because the function makes no use of it.
2269 __ bind(&slow);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002270 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002271
2272 __ bind(&miss);
2273 // a2: function name.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002274 MaybeObject* maybe_result = TryGenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002275 if (maybe_result->IsFailure()) return maybe_result;
2276
2277 // Return the generated code.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002278 return (cell == NULL) ? TryGetCode(function) : TryGetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002279}
2280
2281
lrn@chromium.org7516f052011-03-30 08:52:27 +00002282MaybeObject* CallStubCompiler::CompileMathFloorCall(Object* object,
2283 JSObject* holder,
2284 JSGlobalPropertyCell* cell,
2285 JSFunction* function,
2286 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002287 // ----------- S t a t e -------------
2288 // -- a2 : function name
2289 // -- ra : return address
2290 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2291 // -- ...
2292 // -- sp[argc * 4] : receiver
2293 // -----------------------------------
2294
2295 if (!CpuFeatures::IsSupported(FPU))
2296 return heap()->undefined_value();
2297 CpuFeatures::Scope scope_fpu(FPU);
2298
2299 const int argc = arguments().immediate();
2300
2301 // If the object is not a JSObject or we got an unexpected number of
2302 // arguments, bail out to the regular call.
2303 if (!object->IsJSObject() || argc != 1) return heap()->undefined_value();
2304
2305 Label miss, slow;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002306 GenerateNameCheck(Handle<String>(name), &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002307
2308 if (cell == NULL) {
2309 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
2310
2311 STATIC_ASSERT(kSmiTag == 0);
2312 __ JumpIfSmi(a1, &miss);
2313
2314 CheckPrototypes(JSObject::cast(object), a1, holder, a0, a3, t0, name,
2315 &miss);
2316 } else {
2317 ASSERT(cell->value() == function);
2318 GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
2319 GenerateLoadFunctionFromCell(cell, function, &miss);
2320 }
2321
2322 // Load the (only) argument into v0.
2323 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2324
2325 // If the argument is a smi, just return.
2326 STATIC_ASSERT(kSmiTag == 0);
2327 __ And(t0, v0, Operand(kSmiTagMask));
2328 __ Drop(argc + 1, eq, t0, Operand(zero_reg));
2329 __ Ret(eq, t0, Operand(zero_reg));
2330
danno@chromium.org40cb8782011-05-25 07:58:50 +00002331 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002332
2333 Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return;
2334
2335 // If fpu is enabled, we use the floor instruction.
2336
2337 // Load the HeapNumber value.
2338 __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2339
2340 // Backup FCSR.
2341 __ cfc1(a3, FCSR);
2342 // Clearing FCSR clears the exception mask with no side-effects.
2343 __ ctc1(zero_reg, FCSR);
2344 // Convert the argument to an integer.
2345 __ floor_w_d(f0, f0);
2346
2347 // Start checking for special cases.
2348 // Get the argument exponent and clear the sign bit.
2349 __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize));
2350 __ And(t2, t1, Operand(~HeapNumber::kSignMask));
2351 __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord);
2352
2353 // Retrieve FCSR and check for fpu errors.
2354 __ cfc1(t5, FCSR);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002355 __ And(t5, t5, Operand(kFCSRExceptionFlagMask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002356 __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));
2357
2358 // Check for NaN, Infinity, and -Infinity.
2359 // They are invariant through a Math.Floor call, so just
2360 // return the original argument.
2361 __ Subu(t3, t2, Operand(HeapNumber::kExponentMask
2362 >> HeapNumber::kMantissaBitsInTopWord));
2363 __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg));
2364 // We had an overflow or underflow in the conversion. Check if we
2365 // have a big exponent.
2366 // If greater or equal, the argument is already round and in v0.
2367 __ Branch(&restore_fcsr_and_return, ge, t3,
2368 Operand(HeapNumber::kMantissaBits));
2369 __ Branch(&wont_fit_smi);
2370
2371 __ bind(&no_fpu_error);
2372 // Move the result back to v0.
2373 __ mfc1(v0, f0);
2374 // Check if the result fits into a smi.
2375 __ Addu(a1, v0, Operand(0x40000000));
2376 __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg));
2377 // Tag the result.
2378 STATIC_ASSERT(kSmiTag == 0);
2379 __ sll(v0, v0, kSmiTagSize);
2380
2381 // Check for -0.
2382 __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg));
2383 // t1 already holds the HeapNumber exponent.
2384 __ And(t0, t1, Operand(HeapNumber::kSignMask));
2385 // If our HeapNumber is negative it was -0, so load its address and return.
2386 // Else v0 is loaded with 0, so we can also just return.
2387 __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg));
2388 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2389
2390 __ bind(&restore_fcsr_and_return);
2391 // Restore FCSR and return.
2392 __ ctc1(a3, FCSR);
2393
2394 __ Drop(argc + 1);
2395 __ Ret();
2396
2397 __ bind(&wont_fit_smi);
2398 // Restore FCSR and fall to slow case.
2399 __ ctc1(a3, FCSR);
2400
2401 __ bind(&slow);
2402 // Tail call the full function. We do not have to patch the receiver
2403 // because the function makes no use of it.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002404 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002405
2406 __ bind(&miss);
2407 // a2: function name.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002408 MaybeObject* obj = TryGenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002409 if (obj->IsFailure()) return obj;
2410
2411 // Return the generated code.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002412 return (cell == NULL) ? TryGetCode(function) : TryGetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002413}
2414
2415
lrn@chromium.org7516f052011-03-30 08:52:27 +00002416MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object,
2417 JSObject* holder,
2418 JSGlobalPropertyCell* cell,
2419 JSFunction* function,
2420 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002421 // ----------- S t a t e -------------
2422 // -- a2 : function name
2423 // -- ra : return address
2424 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2425 // -- ...
2426 // -- sp[argc * 4] : receiver
2427 // -----------------------------------
2428
2429 const int argc = arguments().immediate();
2430
2431 // If the object is not a JSObject or we got an unexpected number of
2432 // arguments, bail out to the regular call.
2433 if (!object->IsJSObject() || argc != 1) return heap()->undefined_value();
2434
2435 Label miss;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002436 GenerateNameCheck(Handle<String>(name), &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002437
2438 if (cell == NULL) {
2439 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
2440
2441 STATIC_ASSERT(kSmiTag == 0);
2442 __ JumpIfSmi(a1, &miss);
2443
2444 CheckPrototypes(JSObject::cast(object), a1, holder, v0, a3, t0, name,
2445 &miss);
2446 } else {
2447 ASSERT(cell->value() == function);
2448 GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
2449 GenerateLoadFunctionFromCell(cell, function, &miss);
2450 }
2451
2452 // Load the (only) argument into v0.
2453 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2454
2455 // Check if the argument is a smi.
2456 Label not_smi;
2457 STATIC_ASSERT(kSmiTag == 0);
2458 __ JumpIfNotSmi(v0, &not_smi);
2459
2460 // Do bitwise not or do nothing depending on the sign of the
2461 // argument.
2462 __ sra(t0, v0, kBitsPerInt - 1);
2463 __ Xor(a1, v0, t0);
2464
2465 // Add 1 or do nothing depending on the sign of the argument.
2466 __ Subu(v0, a1, t0);
2467
2468 // If the result is still negative, go to the slow case.
2469 // This only happens for the most negative smi.
2470 Label slow;
2471 __ Branch(&slow, lt, v0, Operand(zero_reg));
2472
2473 // Smi case done.
2474 __ Drop(argc + 1);
2475 __ Ret();
2476
2477 // Check if the argument is a heap number and load its exponent and
2478 // sign.
2479 __ bind(&not_smi);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002480 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002481 __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2482
2483 // Check the sign of the argument. If the argument is positive,
2484 // just return it.
2485 Label negative_sign;
2486 __ And(t0, a1, Operand(HeapNumber::kSignMask));
2487 __ Branch(&negative_sign, ne, t0, Operand(zero_reg));
2488 __ Drop(argc + 1);
2489 __ Ret();
2490
2491 // If the argument is negative, clear the sign, and return a new
2492 // number.
2493 __ bind(&negative_sign);
2494 __ Xor(a1, a1, Operand(HeapNumber::kSignMask));
2495 __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2496 __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
2497 __ AllocateHeapNumber(v0, t0, t1, t2, &slow);
2498 __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2499 __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2500 __ Drop(argc + 1);
2501 __ Ret();
2502
2503 // Tail call the full function. We do not have to patch the receiver
2504 // because the function makes no use of it.
2505 __ bind(&slow);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002506 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002507
2508 __ bind(&miss);
2509 // a2: function name.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002510 MaybeObject* maybe_result = TryGenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002511 if (maybe_result->IsFailure()) return maybe_result;
2512
2513 // Return the generated code.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002514 return (cell == NULL) ? TryGetCode(function) : TryGetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002515}
2516
2517
lrn@chromium.org7516f052011-03-30 08:52:27 +00002518MaybeObject* CallStubCompiler::CompileFastApiCall(
2519 const CallOptimization& optimization,
2520 Object* object,
2521 JSObject* holder,
2522 JSGlobalPropertyCell* cell,
2523 JSFunction* function,
2524 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002525
danno@chromium.org40cb8782011-05-25 07:58:50 +00002526 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002527
2528 ASSERT(optimization.is_simple_api_call());
2529 // Bail out if object is a global object as we don't want to
2530 // repatch it to global receiver.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002531 if (object->IsGlobalObject()) return heap()->undefined_value();
2532 if (cell != NULL) return heap()->undefined_value();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002533 if (!object->IsJSObject()) return heap()->undefined_value();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002534 int depth = optimization.GetPrototypeDepthOfExpectedType(
2535 JSObject::cast(object), holder);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002536 if (depth == kInvalidProtoDepth) return heap()->undefined_value();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002537
2538 Label miss, miss_before_stack_reserved;
2539
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002540 GenerateNameCheck(Handle<String>(name), &miss_before_stack_reserved);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002541
2542 // Get the receiver from the stack.
2543 const int argc = arguments().immediate();
2544 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2545
2546 // Check that the receiver isn't a smi.
2547 __ JumpIfSmi(a1, &miss_before_stack_reserved);
2548
2549 __ IncrementCounter(counters->call_const(), 1, a0, a3);
2550 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2551
2552 ReserveSpaceForFastApiCall(masm(), a0);
2553
2554 // Check that the maps haven't changed and find a Holder as a side effect.
2555 CheckPrototypes(JSObject::cast(object), a1, holder, a0, a3, t0, name,
2556 depth, &miss);
2557
2558 MaybeObject* result = GenerateFastApiDirectCall(masm(), optimization, argc);
2559 if (result->IsFailure()) return result;
2560
2561 __ bind(&miss);
2562 FreeSpaceForFastApiCall(masm());
2563
2564 __ bind(&miss_before_stack_reserved);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002565 MaybeObject* maybe_result = TryGenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002566 if (maybe_result->IsFailure()) return maybe_result;
2567
2568 // Return the generated code.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002569 return TryGetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002570}
2571
2572
lrn@chromium.org7516f052011-03-30 08:52:27 +00002573MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
ager@chromium.org5c838252010-02-19 08:53:10 +00002574 JSObject* holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002575 JSFunction* function,
2576 String* name,
2577 CheckType check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002578 // ----------- S t a t e -------------
2579 // -- a2 : name
2580 // -- ra : return address
2581 // -----------------------------------
2582 if (HasCustomCallGenerator(function)) {
2583 MaybeObject* maybe_result = CompileCustomCall(
2584 object, holder, NULL, function, name);
2585 Object* result;
2586 if (!maybe_result->ToObject(&result)) return maybe_result;
2587 // Undefined means bail out to regular compiler.
2588 if (!result->IsUndefined()) return result;
2589 }
2590
2591 Label miss;
2592
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002593 GenerateNameCheck(Handle<String>(name), &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002594
2595 // Get the receiver from the stack.
2596 const int argc = arguments().immediate();
2597 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2598
2599 // Check that the receiver isn't a smi.
2600 if (check != NUMBER_CHECK) {
2601 __ And(t1, a1, Operand(kSmiTagMask));
2602 __ Branch(&miss, eq, t1, Operand(zero_reg));
2603 }
2604
2605 // Make sure that it's okay not to patch the on stack receiver
2606 // unless we're doing a receiver map check.
2607 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
2608
2609 SharedFunctionInfo* function_info = function->shared();
2610 switch (check) {
2611 case RECEIVER_MAP_CHECK:
2612 __ IncrementCounter(masm()->isolate()->counters()->call_const(),
2613 1, a0, a3);
2614
2615 // Check that the maps haven't changed.
2616 CheckPrototypes(JSObject::cast(object), a1, holder, a0, a3, t0, name,
2617 &miss);
2618
2619 // Patch the receiver on the stack with the global proxy if
2620 // necessary.
2621 if (object->IsGlobalObject()) {
2622 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2623 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2624 }
2625 break;
2626
2627 case STRING_CHECK:
2628 if (!function->IsBuiltin() && !function_info->strict_mode()) {
2629 // Calling non-strict non-builtins with a value as the receiver
2630 // requires boxing.
2631 __ jmp(&miss);
2632 } else {
2633 // Check that the object is a two-byte string or a symbol.
2634 __ GetObjectType(a1, a3, a3);
2635 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2636 // Check that the maps starting from the prototype haven't changed.
2637 GenerateDirectLoadGlobalFunctionPrototype(
2638 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
2639 CheckPrototypes(JSObject::cast(object->GetPrototype()), a0, holder, a3,
2640 a1, t0, name, &miss);
2641 }
2642 break;
2643
2644 case NUMBER_CHECK: {
2645 if (!function->IsBuiltin() && !function_info->strict_mode()) {
2646 // Calling non-strict non-builtins with a value as the receiver
2647 // requires boxing.
2648 __ jmp(&miss);
2649 } else {
2650 Label fast;
2651 // Check that the object is a smi or a heap number.
2652 __ And(t1, a1, Operand(kSmiTagMask));
2653 __ Branch(&fast, eq, t1, Operand(zero_reg));
2654 __ GetObjectType(a1, a0, a0);
2655 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
2656 __ bind(&fast);
2657 // Check that the maps starting from the prototype haven't changed.
2658 GenerateDirectLoadGlobalFunctionPrototype(
2659 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
2660 CheckPrototypes(JSObject::cast(object->GetPrototype()), a0, holder, a3,
2661 a1, t0, name, &miss);
2662 }
2663 break;
2664 }
2665
2666 case BOOLEAN_CHECK: {
2667 if (!function->IsBuiltin() && !function_info->strict_mode()) {
2668 // Calling non-strict non-builtins with a value as the receiver
2669 // requires boxing.
2670 __ jmp(&miss);
2671 } else {
2672 Label fast;
2673 // Check that the object is a boolean.
2674 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
2675 __ Branch(&fast, eq, a1, Operand(t0));
2676 __ LoadRoot(t0, Heap::kFalseValueRootIndex);
2677 __ Branch(&miss, ne, a1, Operand(t0));
2678 __ bind(&fast);
2679 // Check that the maps starting from the prototype haven't changed.
2680 GenerateDirectLoadGlobalFunctionPrototype(
2681 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
2682 CheckPrototypes(JSObject::cast(object->GetPrototype()), a0, holder, a3,
2683 a1, t0, name, &miss);
2684 }
2685 break;
2686 }
2687
2688 default:
2689 UNREACHABLE();
2690 }
2691
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002692 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002693 ? CALL_AS_FUNCTION
2694 : CALL_AS_METHOD;
2695 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002696
2697 // Handle call cache miss.
2698 __ bind(&miss);
2699
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002700 MaybeObject* maybe_result = TryGenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002701 if (maybe_result->IsFailure()) return maybe_result;
2702
2703 // Return the generated code.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002704 return TryGetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002705}
2706
2707
lrn@chromium.org7516f052011-03-30 08:52:27 +00002708MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
ager@chromium.org5c838252010-02-19 08:53:10 +00002709 JSObject* holder,
2710 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002711 // ----------- S t a t e -------------
2712 // -- a2 : name
2713 // -- ra : return address
2714 // -----------------------------------
2715
2716 Label miss;
2717
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002718 GenerateNameCheck(Handle<String>(name), &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002719
2720 // Get the number of arguments.
2721 const int argc = arguments().immediate();
2722
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002723 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002724 LookupPostInterceptor(holder, name, &lookup);
2725
2726 // Get the receiver from the stack.
2727 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2728
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002729 CallInterceptorCompiler compiler(this, arguments(), a2, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002730 MaybeObject* result = compiler.Compile(masm(),
2731 object,
2732 holder,
2733 name,
2734 &lookup,
2735 a1,
2736 a3,
2737 t0,
2738 a0,
2739 &miss);
2740 if (result->IsFailure()) {
2741 return result;
2742 }
2743
2744 // Move returned value, the function to call, to a1.
2745 __ mov(a1, v0);
2746 // Restore receiver.
2747 __ lw(a0, MemOperand(sp, argc * kPointerSize));
2748
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002749 GenerateCallFunction(masm(), Handle<Object>(object), arguments(), &miss,
2750 extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002751
2752 // Handle call cache miss.
2753 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002754 MaybeObject* maybe_result = TryGenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002755 if (maybe_result->IsFailure()) return maybe_result;
2756
2757 // Return the generated code.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002758 return TryGetCode(INTERCEPTOR, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002759}
2760
2761
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002762MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
2763 GlobalObject* holder,
2764 JSGlobalPropertyCell* cell,
2765 JSFunction* function,
2766 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002767 // ----------- S t a t e -------------
2768 // -- a2 : name
2769 // -- ra : return address
2770 // -----------------------------------
2771
2772 if (HasCustomCallGenerator(function)) {
2773 MaybeObject* maybe_result = CompileCustomCall(
2774 object, holder, cell, function, name);
2775 Object* result;
2776 if (!maybe_result->ToObject(&result)) return maybe_result;
2777 // Undefined means bail out to regular compiler.
2778 if (!result->IsUndefined()) return result;
2779 }
2780
2781 Label miss;
2782
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002783 GenerateNameCheck(Handle<String>(name), &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002784
2785 // Get the number of arguments.
2786 const int argc = arguments().immediate();
2787
2788 GenerateGlobalReceiverCheck(object, holder, name, &miss);
2789 GenerateLoadFunctionFromCell(cell, function, &miss);
2790
2791 // Patch the receiver on the stack with the global proxy if
2792 // necessary.
2793 if (object->IsGlobalObject()) {
2794 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
2795 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2796 }
2797
2798 // Setup the context (function already in r1).
2799 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
2800
2801 // Jump to the cached code (tail call).
2802 Counters* counters = masm()->isolate()->counters();
2803 __ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002804 Handle<Code> code(function->code());
2805 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002806 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002807 ? CALL_AS_FUNCTION
2808 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002809 // We call indirectly through the code field in the function to
2810 // allow recompilation to take effect without changing any of the
2811 // call sites.
2812 __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
2813 __ InvokeCode(a3, expected, arguments(), JUMP_FUNCTION,
2814 NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002815
2816 // Handle call cache miss.
2817 __ bind(&miss);
2818 __ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002819 MaybeObject* maybe_result = TryGenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002820 if (maybe_result->IsFailure()) return maybe_result;
2821
2822 // Return the generated code.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002823 return TryGetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002824}
2825
2826
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002827Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +00002828 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002829 Handle<Map> transition,
2830 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002831 // ----------- S t a t e -------------
2832 // -- a0 : value
2833 // -- a1 : receiver
2834 // -- a2 : name
2835 // -- ra : return address
2836 // -----------------------------------
2837 Label miss;
2838
2839 // Name register might be clobbered.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002840 GenerateStoreField(masm(), object, index, transition, a1, a2, a3, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002841 __ bind(&miss);
2842 __ li(a2, Operand(Handle<String>(name))); // Restore name.
2843 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2844 __ Jump(ic, RelocInfo::CODE_TARGET);
2845
2846 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002847 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002848}
2849
2850
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002851Handle<Code> StoreStubCompiler::CompileStoreCallback(
2852 Handle<JSObject> object,
2853 Handle<AccessorInfo> callback,
2854 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002855 // ----------- S t a t e -------------
2856 // -- a0 : value
2857 // -- a1 : receiver
2858 // -- a2 : name
2859 // -- ra : return address
2860 // -----------------------------------
2861 Label miss;
2862
2863 // Check that the object isn't a smi.
2864 __ JumpIfSmi(a1, &miss);
2865
2866 // Check that the map of the object hasn't changed.
2867 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2868 __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map())));
2869
2870 // Perform global security token check if needed.
2871 if (object->IsJSGlobalProxy()) {
2872 __ CheckAccessGlobalProxy(a1, a3, &miss);
2873 }
2874
2875 // Stub never generated for non-global objects that require access
2876 // checks.
2877 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
2878
2879 __ push(a1); // Receiver.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002880 __ li(a3, Operand(callback)); // Callback info.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002881 __ Push(a3, a2, a0);
2882
2883 // Do tail-call to the runtime system.
2884 ExternalReference store_callback_property =
2885 ExternalReference(IC_Utility(IC::kStoreCallbackProperty),
2886 masm()->isolate());
2887 __ TailCallExternalReference(store_callback_property, 4, 1);
2888
2889 // Handle store cache miss.
2890 __ bind(&miss);
2891 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2892 __ Jump(ic, RelocInfo::CODE_TARGET);
2893
2894 // Return the generated code.
2895 return GetCode(CALLBACKS, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002896}
2897
2898
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002899Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
2900 Handle<JSObject> receiver,
2901 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002902 // ----------- S t a t e -------------
2903 // -- a0 : value
2904 // -- a1 : receiver
2905 // -- a2 : name
2906 // -- ra : return address
2907 // -----------------------------------
2908 Label miss;
2909
2910 // Check that the object isn't a smi.
2911 __ JumpIfSmi(a1, &miss);
2912
2913 // Check that the map of the object hasn't changed.
2914 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2915 __ Branch(&miss, ne, a3, Operand(Handle<Map>(receiver->map())));
2916
2917 // Perform global security token check if needed.
2918 if (receiver->IsJSGlobalProxy()) {
2919 __ CheckAccessGlobalProxy(a1, a3, &miss);
2920 }
2921
2922 // Stub is never generated for non-global objects that require access
2923 // checks.
2924 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2925
2926 __ Push(a1, a2, a0); // Receiver, name, value.
2927
2928 __ li(a0, Operand(Smi::FromInt(strict_mode_)));
2929 __ push(a0); // Strict mode.
2930
2931 // Do tail-call to the runtime system.
2932 ExternalReference store_ic_property =
2933 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty),
2934 masm()->isolate());
2935 __ TailCallExternalReference(store_ic_property, 4, 1);
2936
2937 // Handle store cache miss.
2938 __ bind(&miss);
2939 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2940 __ Jump(ic, RelocInfo::CODE_TARGET);
2941
2942 // Return the generated code.
2943 return GetCode(INTERCEPTOR, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002944}
2945
2946
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002947Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2948 Handle<GlobalObject> object,
2949 Handle<JSGlobalPropertyCell> cell,
2950 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002951 // ----------- S t a t e -------------
2952 // -- a0 : value
2953 // -- a1 : receiver
2954 // -- a2 : name
2955 // -- ra : return address
2956 // -----------------------------------
2957 Label miss;
2958
2959 // Check that the map of the global has not changed.
2960 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2961 __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map())));
2962
2963 // Check that the value in the cell is not the hole. If it is, this
2964 // cell could have been deleted and reintroducing the global needs
2965 // to update the property details in the property dictionary of the
2966 // global object. We bail out to the runtime system to do that.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002967 __ li(t0, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002968 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
2969 __ lw(t2, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2970 __ Branch(&miss, eq, t1, Operand(t2));
2971
2972 // Store the value in the cell.
2973 __ sw(a0, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2974 __ mov(v0, a0); // Stored value must be returned in v0.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002975
2976 // This trashes a0 but the value is returned in v0 anyway.
2977 __ RecordWriteField(t0,
2978 JSGlobalPropertyCell::kValueOffset,
2979 a0,
2980 a2,
2981 kRAHasNotBeenSaved,
2982 kDontSaveFPRegs,
2983 OMIT_REMEMBERED_SET);
2984
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002985 Counters* counters = masm()->isolate()->counters();
2986 __ IncrementCounter(counters->named_store_global_inline(), 1, a1, a3);
2987 __ Ret();
2988
2989 // Handle store cache miss.
2990 __ bind(&miss);
2991 __ IncrementCounter(counters->named_store_global_inline_miss(), 1, a1, a3);
2992 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2993 __ Jump(ic, RelocInfo::CODE_TARGET);
2994
2995 // Return the generated code.
2996 return GetCode(NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002997}
2998
2999
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003000Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
3001 Handle<JSObject> object,
3002 Handle<JSObject> last) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003003 // ----------- S t a t e -------------
3004 // -- a0 : receiver
3005 // -- ra : return address
3006 // -----------------------------------
3007 Label miss;
3008
3009 // Check that the receiver is not a smi.
3010 __ JumpIfSmi(a0, &miss);
3011
3012 // Check the maps of the full prototype chain.
3013 CheckPrototypes(object, a0, last, a3, a1, t0, name, &miss);
3014
3015 // If the last object in the prototype chain is a global object,
3016 // check that the global property cell is empty.
3017 if (last->IsGlobalObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003018 GenerateCheckPropertyCell(
3019 masm(), Handle<GlobalObject>::cast(last), name, a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003020 }
3021
3022 // Return undefined if maps of the full prototype chain is still the same.
3023 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
3024 __ Ret();
3025
3026 __ bind(&miss);
3027 GenerateLoadMiss(masm(), Code::LOAD_IC);
3028
3029 // Return the generated code.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003030 return GetCode(NONEXISTENT, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00003031}
3032
3033
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003034Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object,
3035 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00003036 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003037 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003038 // ----------- S t a t e -------------
3039 // -- a0 : receiver
3040 // -- a2 : name
3041 // -- ra : return address
3042 // -----------------------------------
3043 Label miss;
3044
3045 __ mov(v0, a0);
3046
3047 GenerateLoadField(object, holder, v0, a3, a1, t0, index, name, &miss);
3048 __ bind(&miss);
3049 GenerateLoadMiss(masm(), Code::LOAD_IC);
3050
3051 // Return the generated code.
3052 return GetCode(FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003053}
3054
3055
3056MaybeObject* LoadStubCompiler::CompileLoadCallback(String* name,
3057 JSObject* object,
3058 JSObject* holder,
3059 AccessorInfo* callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003060 // ----------- S t a t e -------------
3061 // -- a0 : receiver
3062 // -- a2 : name
3063 // -- ra : return address
3064 // -----------------------------------
3065 Label miss;
3066
3067 MaybeObject* result = GenerateLoadCallback(object, holder, a0, a2, a3, a1, t0,
3068 callback, name, &miss);
3069 if (result->IsFailure()) {
3070 miss.Unuse();
3071 return result;
3072 }
3073
3074 __ bind(&miss);
3075 GenerateLoadMiss(masm(), Code::LOAD_IC);
3076
3077 // Return the generated code.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003078 return TryGetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003079}
3080
3081
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003082Handle<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object,
3083 Handle<JSObject> holder,
3084 Handle<Object> value,
3085 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003086 // ----------- S t a t e -------------
3087 // -- a0 : receiver
3088 // -- a2 : name
3089 // -- ra : return address
3090 // -----------------------------------
3091 Label miss;
3092
3093 GenerateLoadConstant(object, holder, a0, a3, a1, t0, value, name, &miss);
3094 __ bind(&miss);
3095 GenerateLoadMiss(masm(), Code::LOAD_IC);
3096
3097 // Return the generated code.
3098 return GetCode(CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003099}
3100
3101
3102MaybeObject* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
3103 JSObject* holder,
3104 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003105 // ----------- S t a t e -------------
3106 // -- a0 : receiver
3107 // -- a2 : name
3108 // -- ra : return address
3109 // -- [sp] : receiver
3110 // -----------------------------------
3111 Label miss;
3112
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003113 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003114 LookupPostInterceptor(holder, name, &lookup);
3115 GenerateLoadInterceptor(object,
3116 holder,
3117 &lookup,
3118 a0,
3119 a2,
3120 a3,
3121 a1,
3122 t0,
3123 name,
3124 &miss);
3125 __ bind(&miss);
3126 GenerateLoadMiss(masm(), Code::LOAD_IC);
3127
3128 // Return the generated code.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003129 return TryGetCode(INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003130}
3131
3132
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003133Handle<Code> LoadStubCompiler::CompileLoadGlobal(
3134 Handle<JSObject> object,
3135 Handle<GlobalObject> holder,
3136 Handle<JSGlobalPropertyCell> cell,
3137 Handle<String> name,
3138 bool is_dont_delete) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003139 // ----------- S t a t e -------------
3140 // -- a0 : receiver
3141 // -- a2 : name
3142 // -- ra : return address
3143 // -----------------------------------
3144 Label miss;
3145
3146 // If the object is the holder then we know that it's a global
3147 // object which can only happen for contextual calls. In this case,
3148 // the receiver cannot be a smi.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003149 if (!object.is_identical_to(holder)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003150 __ And(t0, a0, Operand(kSmiTagMask));
3151 __ Branch(&miss, eq, t0, Operand(zero_reg));
3152 }
3153
3154 // Check that the map of the global has not changed.
3155 CheckPrototypes(object, a0, holder, a3, t0, a1, name, &miss);
3156
3157 // Get the value from the cell.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003158 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003159 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
3160
3161 // Check for deleted property if property can actually be deleted.
3162 if (!is_dont_delete) {
3163 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
3164 __ Branch(&miss, eq, t0, Operand(at));
3165 }
3166
3167 __ mov(v0, t0);
3168 Counters* counters = masm()->isolate()->counters();
3169 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
3170 __ Ret();
3171
3172 __ bind(&miss);
3173 __ IncrementCounter(counters->named_load_global_stub_miss(), 1, a1, a3);
3174 GenerateLoadMiss(masm(), Code::LOAD_IC);
3175
3176 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003177 return GetCode(NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003178}
3179
3180
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003181Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
3182 Handle<JSObject> receiver,
3183 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00003184 int index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003185 // ----------- S t a t e -------------
3186 // -- ra : return address
3187 // -- a0 : key
3188 // -- a1 : receiver
3189 // -----------------------------------
3190 Label miss;
3191
3192 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003193 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003194
3195 GenerateLoadField(receiver, holder, a1, a2, a3, t0, index, name, &miss);
3196 __ bind(&miss);
3197 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3198
3199 return GetCode(FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003200}
3201
3202
3203MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback(
3204 String* name,
3205 JSObject* receiver,
3206 JSObject* holder,
3207 AccessorInfo* callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003208 // ----------- S t a t e -------------
3209 // -- ra : return address
3210 // -- a0 : key
3211 // -- a1 : receiver
3212 // -----------------------------------
3213 Label miss;
3214
3215 // Check the key is the cached one.
3216 __ Branch(&miss, ne, a0, Operand(Handle<String>(name)));
3217
3218 MaybeObject* result = GenerateLoadCallback(receiver, holder, a1, a0, a2, a3,
3219 t0, callback, name, &miss);
3220 if (result->IsFailure()) {
3221 miss.Unuse();
3222 return result;
3223 }
3224
3225 __ bind(&miss);
3226 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3227
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003228 return TryGetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003229}
3230
3231
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003232Handle<Code> KeyedLoadStubCompiler::CompileLoadConstant(
3233 Handle<String> name,
3234 Handle<JSObject> receiver,
3235 Handle<JSObject> holder,
3236 Handle<Object> value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003237 // ----------- S t a t e -------------
3238 // -- ra : return address
3239 // -- a0 : key
3240 // -- a1 : receiver
3241 // -----------------------------------
3242 Label miss;
3243
3244 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003245 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003246
3247 GenerateLoadConstant(receiver, holder, a1, a2, a3, t0, value, name, &miss);
3248 __ bind(&miss);
3249 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3250
3251 // Return the generated code.
3252 return GetCode(CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003253}
3254
3255
3256MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
3257 JSObject* holder,
3258 String* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003259 // ----------- S t a t e -------------
3260 // -- ra : return address
3261 // -- a0 : key
3262 // -- a1 : receiver
3263 // -----------------------------------
3264 Label miss;
3265
3266 // Check the key is the cached one.
3267 __ Branch(&miss, ne, a0, Operand(Handle<String>(name)));
3268
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003269 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003270 LookupPostInterceptor(holder, name, &lookup);
3271 GenerateLoadInterceptor(receiver,
3272 holder,
3273 &lookup,
3274 a1,
3275 a0,
3276 a2,
3277 a3,
3278 t0,
3279 name,
3280 &miss);
3281 __ bind(&miss);
3282 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3283
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003284 return TryGetCode(INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003285}
3286
3287
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003288Handle<Code> KeyedLoadStubCompiler::CompileLoadArrayLength(
3289 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003290 // ----------- S t a t e -------------
3291 // -- ra : return address
3292 // -- a0 : key
3293 // -- a1 : receiver
3294 // -----------------------------------
3295 Label miss;
3296
3297 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003298 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003299
3300 GenerateLoadArrayLength(masm(), a1, a2, &miss);
3301 __ bind(&miss);
3302 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3303
3304 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003305}
3306
3307
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003308Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength(
3309 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003310 // ----------- S t a t e -------------
3311 // -- ra : return address
3312 // -- a0 : key
3313 // -- a1 : receiver
3314 // -----------------------------------
3315 Label miss;
3316
3317 Counters* counters = masm()->isolate()->counters();
3318 __ IncrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
3319
3320 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003321 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003322
3323 GenerateLoadStringLength(masm(), a1, a2, a3, &miss, true);
3324 __ bind(&miss);
3325 __ DecrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
3326
3327 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3328
3329 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003330}
3331
3332
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003333Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype(
3334 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003335 // ----------- S t a t e -------------
3336 // -- ra : return address
3337 // -- a0 : key
3338 // -- a1 : receiver
3339 // -----------------------------------
3340 Label miss;
3341
3342 Counters* counters = masm()->isolate()->counters();
3343 __ IncrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
3344
3345 // Check the name hasn't changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003346 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003347
3348 GenerateLoadFunctionPrototype(masm(), a1, a2, a3, &miss);
3349 __ bind(&miss);
3350 __ DecrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
3351 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3352
3353 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003354}
3355
3356
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003357Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
3358 Handle<Map> receiver_map) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003359 // ----------- S t a t e -------------
3360 // -- ra : return address
3361 // -- a0 : key
3362 // -- a1 : receiver
3363 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003364 ElementsKind elements_kind = receiver_map->elements_kind();
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003365 Handle<Code> stub = KeyedLoadElementStub(elements_kind).GetCode();
3366
3367 __ DispatchMap(a1, a2, receiver_map, stub, DO_SMI_CHECK);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003368
3369 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
3370 __ Jump(ic, RelocInfo::CODE_TARGET);
3371
3372 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003373 return GetCode(NORMAL, factory()->empty_string());
danno@chromium.org40cb8782011-05-25 07:58:50 +00003374}
3375
3376
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003377Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
3378 MapHandleList* receiver_maps,
3379 CodeHandleList* handler_ics) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003380 // ----------- S t a t e -------------
3381 // -- ra : return address
3382 // -- a0 : key
3383 // -- a1 : receiver
3384 // -----------------------------------
3385 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003386 __ JumpIfSmi(a1, &miss);
3387
danno@chromium.org40cb8782011-05-25 07:58:50 +00003388 int receiver_count = receiver_maps->length();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003389 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003390 for (int current = 0; current < receiver_count; ++current) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003391 __ Jump(handler_ics->at(current), RelocInfo::CODE_TARGET,
3392 eq, a2, Operand(receiver_maps->at(current)));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003393 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003394
3395 __ bind(&miss);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003396 Handle<Code> miss_ic = isolate()->builtins()->KeyedLoadIC_Miss();
3397 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003398
3399 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003400 return GetCode(NORMAL, factory()->empty_string(), MEGAMORPHIC);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003401}
3402
3403
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003404Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +00003405 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003406 Handle<Map> transition,
3407 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003408 // ----------- S t a t e -------------
3409 // -- a0 : value
3410 // -- a1 : key
3411 // -- a2 : receiver
3412 // -- ra : return address
3413 // -----------------------------------
3414
3415 Label miss;
3416
3417 Counters* counters = masm()->isolate()->counters();
3418 __ IncrementCounter(counters->keyed_store_field(), 1, a3, t0);
3419
3420 // Check that the name has not changed.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003421 __ Branch(&miss, ne, a1, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003422
3423 // a3 is used as scratch register. a1 and a2 keep their values if a jump to
3424 // the miss label is generated.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003425 GenerateStoreField(masm(), object, index, transition, a2, a1, a3, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003426 __ bind(&miss);
3427
3428 __ DecrementCounter(counters->keyed_store_field(), 1, a3, t0);
3429 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss();
3430 __ Jump(ic, RelocInfo::CODE_TARGET);
3431
3432 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003433 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003434}
3435
3436
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003437Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
3438 Handle<Map> receiver_map) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003439 // ----------- S t a t e -------------
3440 // -- a0 : value
3441 // -- a1 : key
3442 // -- a2 : receiver
3443 // -- ra : return address
3444 // -- a3 : scratch
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003445 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003446 ElementsKind elements_kind = receiver_map->elements_kind();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003447 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003448 Handle<Code> stub =
3449 KeyedStoreElementStub(is_js_array, elements_kind).GetCode();
3450
3451 __ DispatchMap(a2, a3, receiver_map, stub, DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003452
danno@chromium.org40cb8782011-05-25 07:58:50 +00003453 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003454 __ Jump(ic, RelocInfo::CODE_TARGET);
3455
3456 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003457 return GetCode(NORMAL, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00003458}
3459
3460
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003461Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
3462 MapHandleList* receiver_maps,
3463 CodeHandleList* handler_stubs,
3464 MapHandleList* transitioned_maps) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003465 // ----------- S t a t e -------------
3466 // -- a0 : value
3467 // -- a1 : key
3468 // -- a2 : receiver
3469 // -- ra : return address
3470 // -- a3 : scratch
3471 // -----------------------------------
3472 Label miss;
3473 __ JumpIfSmi(a2, &miss);
3474
3475 int receiver_count = receiver_maps->length();
3476 __ lw(a3, FieldMemOperand(a2, HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003477 for (int i = 0; i < receiver_count; ++i) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003478 if (transitioned_maps->at(i).is_null()) {
3479 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq,
3480 a3, Operand(receiver_maps->at(i)));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003481 } else {
3482 Label next_map;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003483 __ Branch(&next_map, ne, a3, Operand(receiver_maps->at(i)));
3484 __ li(a3, Operand(transitioned_maps->at(i)));
3485 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003486 __ bind(&next_map);
3487 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003488 }
3489
3490 __ bind(&miss);
3491 Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
3492 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3493
3494 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003495 return GetCode(NORMAL, factory()->empty_string(), MEGAMORPHIC);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003496}
3497
3498
lrn@chromium.org7516f052011-03-30 08:52:27 +00003499MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003500 // a0 : argc
3501 // a1 : constructor
3502 // ra : return address
3503 // [sp] : last argument
3504 Label generic_stub_call;
3505
3506 // Use t7 for holding undefined which is used in several places below.
3507 __ LoadRoot(t7, Heap::kUndefinedValueRootIndex);
3508
3509#ifdef ENABLE_DEBUGGER_SUPPORT
3510 // Check to see whether there are any break points in the function code. If
3511 // there are jump to the generic constructor stub which calls the actual
3512 // code for the function thereby hitting the break points.
3513 __ lw(t5, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3514 __ lw(a2, FieldMemOperand(t5, SharedFunctionInfo::kDebugInfoOffset));
3515 __ Branch(&generic_stub_call, ne, a2, Operand(t7));
3516#endif
3517
3518 // Load the initial map and verify that it is in fact a map.
3519 // a1: constructor function
3520 // t7: undefined
3521 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
3522 __ And(t0, a2, Operand(kSmiTagMask));
3523 __ Branch(&generic_stub_call, eq, t0, Operand(zero_reg));
3524 __ GetObjectType(a2, a3, t0);
3525 __ Branch(&generic_stub_call, ne, t0, Operand(MAP_TYPE));
3526
3527#ifdef DEBUG
3528 // Cannot construct functions this way.
3529 // a0: argc
3530 // a1: constructor function
3531 // a2: initial map
3532 // t7: undefined
3533 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
3534 __ Check(ne, "Function constructed by construct stub.",
3535 a3, Operand(JS_FUNCTION_TYPE));
3536#endif
3537
3538 // Now allocate the JSObject in new space.
3539 // a0: argc
3540 // a1: constructor function
3541 // a2: initial map
3542 // t7: undefined
3543 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
3544 __ AllocateInNewSpace(a3,
3545 t4,
3546 t5,
3547 t6,
3548 &generic_stub_call,
3549 SIZE_IN_WORDS);
3550
3551 // Allocated the JSObject, now initialize the fields. Map is set to initial
3552 // map and properties and elements are set to empty fixed array.
3553 // a0: argc
3554 // a1: constructor function
3555 // a2: initial map
3556 // a3: object size (in words)
3557 // t4: JSObject (not tagged)
3558 // t7: undefined
3559 __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex);
3560 __ mov(t5, t4);
3561 __ sw(a2, MemOperand(t5, JSObject::kMapOffset));
3562 __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset));
3563 __ sw(t6, MemOperand(t5, JSObject::kElementsOffset));
3564 __ Addu(t5, t5, Operand(3 * kPointerSize));
3565 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
3566 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
3567 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
3568
3569
3570 // Calculate the location of the first argument. The stack contains only the
3571 // argc arguments.
3572 __ sll(a1, a0, kPointerSizeLog2);
3573 __ Addu(a1, a1, sp);
3574
3575 // Fill all the in-object properties with undefined.
3576 // a0: argc
3577 // a1: first argument
3578 // a3: object size (in words)
3579 // t4: JSObject (not tagged)
3580 // t5: First in-object property of JSObject (not tagged)
3581 // t7: undefined
3582 // Fill the initialized properties with a constant value or a passed argument
3583 // depending on the this.x = ...; assignment in the function.
3584 SharedFunctionInfo* shared = function->shared();
3585 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3586 if (shared->IsThisPropertyAssignmentArgument(i)) {
3587 Label not_passed, next;
3588 // Check if the argument assigned to the property is actually passed.
3589 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3590 __ Branch(&not_passed, less_equal, a0, Operand(arg_number));
3591 // Argument passed - find it on the stack.
3592 __ lw(a2, MemOperand(a1, (arg_number + 1) * -kPointerSize));
3593 __ sw(a2, MemOperand(t5));
3594 __ Addu(t5, t5, kPointerSize);
3595 __ jmp(&next);
3596 __ bind(&not_passed);
3597 // Set the property to undefined.
3598 __ sw(t7, MemOperand(t5));
3599 __ Addu(t5, t5, Operand(kPointerSize));
3600 __ bind(&next);
3601 } else {
3602 // Set the property to the constant value.
3603 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
3604 __ li(a2, Operand(constant));
3605 __ sw(a2, MemOperand(t5));
3606 __ Addu(t5, t5, kPointerSize);
3607 }
3608 }
3609
3610 // Fill the unused in-object property fields with undefined.
3611 ASSERT(function->has_initial_map());
3612 for (int i = shared->this_property_assignments_count();
3613 i < function->initial_map()->inobject_properties();
3614 i++) {
3615 __ sw(t7, MemOperand(t5));
3616 __ Addu(t5, t5, kPointerSize);
3617 }
3618
3619 // a0: argc
3620 // t4: JSObject (not tagged)
3621 // Move argc to a1 and the JSObject to return to v0 and tag it.
3622 __ mov(a1, a0);
3623 __ mov(v0, t4);
3624 __ Or(v0, v0, Operand(kHeapObjectTag));
3625
3626 // v0: JSObject
3627 // a1: argc
3628 // Remove caller arguments and receiver from the stack and return.
3629 __ sll(t0, a1, kPointerSizeLog2);
3630 __ Addu(sp, sp, t0);
3631 __ Addu(sp, sp, Operand(kPointerSize));
3632 Counters* counters = masm()->isolate()->counters();
3633 __ IncrementCounter(counters->constructed_objects(), 1, a1, a2);
3634 __ IncrementCounter(counters->constructed_objects_stub(), 1, a1, a2);
3635 __ Ret();
3636
3637 // Jump to the generic stub in case the specialized code cannot handle the
3638 // construction.
3639 __ bind(&generic_stub_call);
3640 Handle<Code> generic_construct_stub =
3641 masm()->isolate()->builtins()->JSConstructStubGeneric();
3642 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
3643
3644 // Return the generated code.
3645 return GetCode();
3646}
3647
3648
danno@chromium.org40cb8782011-05-25 07:58:50 +00003649#undef __
3650#define __ ACCESS_MASM(masm)
3651
3652
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003653void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3654 MacroAssembler* masm) {
3655 // ---------- S t a t e --------------
3656 // -- ra : return address
3657 // -- a0 : key
3658 // -- a1 : receiver
3659 // -----------------------------------
3660 Label slow, miss_force_generic;
3661
3662 Register key = a0;
3663 Register receiver = a1;
3664
3665 __ JumpIfNotSmi(key, &miss_force_generic);
3666 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
3667 __ sra(a2, a0, kSmiTagSize);
3668 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
3669 __ Ret();
3670
3671 // Slow case, key and receiver still in a0 and a1.
3672 __ bind(&slow);
3673 __ IncrementCounter(
3674 masm->isolate()->counters()->keyed_load_external_array_slow(),
3675 1, a2, a3);
3676 // Entry registers are intact.
3677 // ---------- S t a t e --------------
3678 // -- ra : return address
3679 // -- a0 : key
3680 // -- a1 : receiver
3681 // -----------------------------------
3682 Handle<Code> slow_ic =
3683 masm->isolate()->builtins()->KeyedLoadIC_Slow();
3684 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
3685
3686 // Miss case, call the runtime.
3687 __ bind(&miss_force_generic);
3688
3689 // ---------- S t a t e --------------
3690 // -- ra : return address
3691 // -- a0 : key
3692 // -- a1 : receiver
3693 // -----------------------------------
3694
3695 Handle<Code> miss_ic =
3696 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3697 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3698}
3699
3700
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003701static bool IsElementTypeSigned(ElementsKind elements_kind) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003702 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003703 case EXTERNAL_BYTE_ELEMENTS:
3704 case EXTERNAL_SHORT_ELEMENTS:
3705 case EXTERNAL_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003706 return true;
3707
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003708 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3709 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3710 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3711 case EXTERNAL_PIXEL_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003712 return false;
3713
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003714 case EXTERNAL_FLOAT_ELEMENTS:
3715 case EXTERNAL_DOUBLE_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003716 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003717 case FAST_ELEMENTS:
3718 case FAST_DOUBLE_ELEMENTS:
3719 case DICTIONARY_ELEMENTS:
3720 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003721 UNREACHABLE();
3722 return false;
3723 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003724 return false;
lrn@chromium.org7516f052011-03-30 08:52:27 +00003725}
3726
3727
danno@chromium.org40cb8782011-05-25 07:58:50 +00003728void KeyedLoadStubCompiler::GenerateLoadExternalArray(
3729 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003730 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003731 // ---------- S t a t e --------------
3732 // -- ra : return address
3733 // -- a0 : key
3734 // -- a1 : receiver
3735 // -----------------------------------
danno@chromium.org40cb8782011-05-25 07:58:50 +00003736 Label miss_force_generic, slow, failed_allocation;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003737
3738 Register key = a0;
3739 Register receiver = a1;
3740
danno@chromium.org40cb8782011-05-25 07:58:50 +00003741 // This stub is meant to be tail-jumped to, the receiver must already
3742 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003743
3744 // Check that the key is a smi.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003745 __ JumpIfNotSmi(key, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003746
3747 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3748 // a3: elements array
3749
3750 // Check that the index is in range.
3751 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3752 __ sra(t2, key, kSmiTagSize);
3753 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003754 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003755
3756 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3757 // a3: base pointer of external storage
3758
3759 // We are not untagging smi key and instead work with it
3760 // as if it was premultiplied by 2.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003761 STATIC_ASSERT((kSmiTag == 0) && (kSmiTagSize == 1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003762
3763 Register value = a2;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003764 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003765 case EXTERNAL_BYTE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003766 __ srl(t2, key, 1);
3767 __ addu(t3, a3, t2);
3768 __ lb(value, MemOperand(t3, 0));
3769 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003770 case EXTERNAL_PIXEL_ELEMENTS:
3771 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003772 __ srl(t2, key, 1);
3773 __ addu(t3, a3, t2);
3774 __ lbu(value, MemOperand(t3, 0));
3775 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003776 case EXTERNAL_SHORT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003777 __ addu(t3, a3, key);
3778 __ lh(value, MemOperand(t3, 0));
3779 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003780 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003781 __ addu(t3, a3, key);
3782 __ lhu(value, MemOperand(t3, 0));
3783 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003784 case EXTERNAL_INT_ELEMENTS:
3785 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003786 __ sll(t2, key, 1);
3787 __ addu(t3, a3, t2);
3788 __ lw(value, MemOperand(t3, 0));
3789 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003790 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003791 __ sll(t3, t2, 2);
3792 __ addu(t3, a3, t3);
3793 if (CpuFeatures::IsSupported(FPU)) {
3794 CpuFeatures::Scope scope(FPU);
3795 __ lwc1(f0, MemOperand(t3, 0));
3796 } else {
3797 __ lw(value, MemOperand(t3, 0));
3798 }
3799 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003800 case EXTERNAL_DOUBLE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003801 __ sll(t2, key, 2);
3802 __ addu(t3, a3, t2);
3803 if (CpuFeatures::IsSupported(FPU)) {
3804 CpuFeatures::Scope scope(FPU);
3805 __ ldc1(f0, MemOperand(t3, 0));
3806 } else {
3807 // t3: pointer to the beginning of the double we want to load.
3808 __ lw(a2, MemOperand(t3, 0));
3809 __ lw(a3, MemOperand(t3, Register::kSizeInBytes));
3810 }
3811 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003812 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003813 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003814 case FAST_DOUBLE_ELEMENTS:
3815 case DICTIONARY_ELEMENTS:
3816 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003817 UNREACHABLE();
3818 break;
3819 }
3820
3821 // For integer array types:
3822 // a2: value
3823 // For float array type:
3824 // f0: value (if FPU is supported)
3825 // a2: value (if FPU is not supported)
3826 // For double array type:
3827 // f0: value (if FPU is supported)
3828 // a2/a3: value (if FPU is not supported)
3829
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003830 if (elements_kind == EXTERNAL_INT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003831 // For the Int and UnsignedInt array types, we need to see whether
3832 // the value can be represented in a Smi. If not, we need to convert
3833 // it to a HeapNumber.
3834 Label box_int;
3835 __ Subu(t3, value, Operand(0xC0000000)); // Non-smi value gives neg result.
3836 __ Branch(&box_int, lt, t3, Operand(zero_reg));
3837 // Tag integer as smi and return it.
3838 __ sll(v0, value, kSmiTagSize);
3839 __ Ret();
3840
3841 __ bind(&box_int);
3842 // Allocate a HeapNumber for the result and perform int-to-double
3843 // conversion.
3844 // The arm version uses a temporary here to save r0, but we don't need to
3845 // (a0 is not modified).
3846 __ LoadRoot(t1, Heap::kHeapNumberMapRootIndex);
3847 __ AllocateHeapNumber(v0, a3, t0, t1, &slow);
3848
3849 if (CpuFeatures::IsSupported(FPU)) {
3850 CpuFeatures::Scope scope(FPU);
3851 __ mtc1(value, f0);
3852 __ cvt_d_w(f0, f0);
3853 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag));
3854 __ Ret();
3855 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003856 Register dst1 = t2;
3857 Register dst2 = t3;
3858 FloatingPointHelper::Destination dest =
3859 FloatingPointHelper::kCoreRegisters;
3860 FloatingPointHelper::ConvertIntToDouble(masm,
3861 value,
3862 dest,
3863 f0,
3864 dst1,
3865 dst2,
3866 t1,
3867 f2);
3868 __ sw(dst1, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3869 __ sw(dst2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3870 __ Ret();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003871 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003872 } else if (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003873 // The test is different for unsigned int values. Since we need
3874 // the value to be in the range of a positive smi, we can't
3875 // handle either of the top two bits being set in the value.
3876 if (CpuFeatures::IsSupported(FPU)) {
3877 CpuFeatures::Scope scope(FPU);
3878 Label pl_box_int;
3879 __ And(t2, value, Operand(0xC0000000));
3880 __ Branch(&pl_box_int, ne, t2, Operand(zero_reg));
3881
3882 // It can fit in an Smi.
3883 // Tag integer as smi and return it.
3884 __ sll(v0, value, kSmiTagSize);
3885 __ Ret();
3886
3887 __ bind(&pl_box_int);
3888 // Allocate a HeapNumber for the result and perform int-to-double
3889 // conversion. Don't use a0 and a1 as AllocateHeapNumber clobbers all
3890 // registers - also when jumping due to exhausted young space.
3891 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3892 __ AllocateHeapNumber(v0, t2, t3, t6, &slow);
3893
3894 // This is replaced by a macro:
3895 // __ mtc1(value, f0); // LS 32-bits.
3896 // __ mtc1(zero_reg, f1); // MS 32-bits are all zero.
3897 // __ cvt_d_l(f0, f0); // Use 64 bit conv to get correct unsigned 32-bit.
3898
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003899 __ Cvt_d_uw(f0, value, f22);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003900
3901 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag));
3902
3903 __ Ret();
3904 } else {
3905 // Check whether unsigned integer fits into smi.
3906 Label box_int_0, box_int_1, done;
3907 __ And(t2, value, Operand(0x80000000));
3908 __ Branch(&box_int_0, ne, t2, Operand(zero_reg));
3909 __ And(t2, value, Operand(0x40000000));
3910 __ Branch(&box_int_1, ne, t2, Operand(zero_reg));
3911
3912 // Tag integer as smi and return it.
3913 __ sll(v0, value, kSmiTagSize);
3914 __ Ret();
3915
3916 Register hiword = value; // a2.
3917 Register loword = a3;
3918
3919 __ bind(&box_int_0);
3920 // Integer does not have leading zeros.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003921 GenerateUInt2Double(masm, hiword, loword, t0, 0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003922 __ Branch(&done);
3923
3924 __ bind(&box_int_1);
3925 // Integer has one leading zero.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003926 GenerateUInt2Double(masm, hiword, loword, t0, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003927
3928
3929 __ bind(&done);
3930 // Integer was converted to double in registers hiword:loword.
3931 // Wrap it into a HeapNumber. Don't use a0 and a1 as AllocateHeapNumber
3932 // clobbers all registers - also when jumping due to exhausted young
3933 // space.
3934 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3935 __ AllocateHeapNumber(t2, t3, t5, t6, &slow);
3936
3937 __ sw(hiword, FieldMemOperand(t2, HeapNumber::kExponentOffset));
3938 __ sw(loword, FieldMemOperand(t2, HeapNumber::kMantissaOffset));
3939
3940 __ mov(v0, t2);
3941 __ Ret();
3942 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003943 } else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003944 // For the floating-point array type, we need to always allocate a
3945 // HeapNumber.
3946 if (CpuFeatures::IsSupported(FPU)) {
3947 CpuFeatures::Scope scope(FPU);
3948 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3949 // AllocateHeapNumber clobbers all registers - also when jumping due to
3950 // exhausted young space.
3951 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3952 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3953 // The float (single) value is already in fpu reg f0 (if we use float).
3954 __ cvt_d_s(f0, f0);
3955 __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag));
3956 __ Ret();
3957 } else {
3958 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3959 // AllocateHeapNumber clobbers all registers - also when jumping due to
3960 // exhausted young space.
3961 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3962 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3963 // FPU is not available, do manual single to double conversion.
3964
3965 // a2: floating point value (binary32).
3966 // v0: heap number for result
3967
3968 // Extract mantissa to t4.
3969 __ And(t4, value, Operand(kBinary32MantissaMask));
3970
3971 // Extract exponent to t5.
3972 __ srl(t5, value, kBinary32MantissaBits);
3973 __ And(t5, t5, Operand(kBinary32ExponentMask >> kBinary32MantissaBits));
3974
3975 Label exponent_rebiased;
3976 __ Branch(&exponent_rebiased, eq, t5, Operand(zero_reg));
3977
3978 __ li(t0, 0x7ff);
3979 __ Xor(t1, t5, Operand(0xFF));
3980 __ movz(t5, t0, t1); // Set t5 to 0x7ff only if t5 is equal to 0xff.
3981 __ Branch(&exponent_rebiased, eq, t0, Operand(0xff));
3982
3983 // Rebias exponent.
3984 __ Addu(t5,
3985 t5,
3986 Operand(-kBinary32ExponentBias + HeapNumber::kExponentBias));
3987
3988 __ bind(&exponent_rebiased);
3989 __ And(a2, value, Operand(kBinary32SignMask));
3990 value = no_reg;
3991 __ sll(t0, t5, HeapNumber::kMantissaBitsInTopWord);
3992 __ or_(a2, a2, t0);
3993
3994 // Shift mantissa.
3995 static const int kMantissaShiftForHiWord =
3996 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3997
3998 static const int kMantissaShiftForLoWord =
3999 kBitsPerInt - kMantissaShiftForHiWord;
4000
4001 __ srl(t0, t4, kMantissaShiftForHiWord);
4002 __ or_(a2, a2, t0);
4003 __ sll(a0, t4, kMantissaShiftForLoWord);
4004
4005 __ sw(a2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
4006 __ sw(a0, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
4007 __ Ret();
4008 }
4009
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004010 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004011 if (CpuFeatures::IsSupported(FPU)) {
4012 CpuFeatures::Scope scope(FPU);
4013 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
4014 // AllocateHeapNumber clobbers all registers - also when jumping due to
4015 // exhausted young space.
4016 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
4017 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
4018 // The double value is already in f0
4019 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
4020 __ Ret();
4021 } else {
4022 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
4023 // AllocateHeapNumber clobbers all registers - also when jumping due to
4024 // exhausted young space.
4025 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
4026 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
4027
4028 __ sw(a2, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
4029 __ sw(a3, FieldMemOperand(v0, HeapNumber::kExponentOffset));
4030 __ Ret();
4031 }
4032
4033 } else {
4034 // Tag integer as smi and return it.
4035 __ sll(v0, value, kSmiTagSize);
4036 __ Ret();
4037 }
4038
4039 // Slow case, key and receiver still in a0 and a1.
4040 __ bind(&slow);
4041 __ IncrementCounter(
danno@chromium.org40cb8782011-05-25 07:58:50 +00004042 masm->isolate()->counters()->keyed_load_external_array_slow(),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004043 1, a2, a3);
4044
4045 // ---------- S t a t e --------------
4046 // -- ra : return address
4047 // -- a0 : key
4048 // -- a1 : receiver
4049 // -----------------------------------
4050
4051 __ Push(a1, a0);
4052
4053 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
4054
danno@chromium.org40cb8782011-05-25 07:58:50 +00004055 __ bind(&miss_force_generic);
4056 Code* stub = masm->isolate()->builtins()->builtin(
4057 Builtins::kKeyedLoadIC_MissForceGeneric);
4058 __ Jump(Handle<Code>(stub), RelocInfo::CODE_TARGET);
lrn@chromium.org7516f052011-03-30 08:52:27 +00004059}
4060
4061
danno@chromium.org40cb8782011-05-25 07:58:50 +00004062void KeyedStoreStubCompiler::GenerateStoreExternalArray(
4063 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004064 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004065 // ---------- S t a t e --------------
4066 // -- a0 : value
4067 // -- a1 : key
4068 // -- a2 : receiver
4069 // -- ra : return address
4070 // -----------------------------------
4071
danno@chromium.org40cb8782011-05-25 07:58:50 +00004072 Label slow, check_heap_number, miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004073
4074 // Register usage.
4075 Register value = a0;
4076 Register key = a1;
4077 Register receiver = a2;
4078 // a3 mostly holds the elements array or the destination external array.
4079
danno@chromium.org40cb8782011-05-25 07:58:50 +00004080 // This stub is meant to be tail-jumped to, the receiver must already
4081 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004082
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004083 // Check that the key is a smi.
danno@chromium.org40cb8782011-05-25 07:58:50 +00004084 __ JumpIfNotSmi(key, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004085
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004086 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
4087
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004088 // Check that the index is in range.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004089 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
4090 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004091 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004092
4093 // Handle both smis and HeapNumbers in the fast path. Go to the
4094 // runtime for all other kinds of values.
4095 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004096
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004097 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004098 // Double to pixel conversion is only implemented in the runtime for now.
4099 __ JumpIfNotSmi(value, &slow);
4100 } else {
4101 __ JumpIfNotSmi(value, &check_heap_number);
4102 }
4103 __ SmiUntag(t1, value);
4104 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
4105
4106 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004107 // t1: value (integer).
4108
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004109 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004110 case EXTERNAL_PIXEL_ELEMENTS: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004111 // Clamp the value to [0..255].
4112 // v0 is used as a scratch register here.
4113 Label done;
4114 __ li(v0, Operand(255));
4115 // Normal branch: nop in delay slot.
4116 __ Branch(&done, gt, t1, Operand(v0));
4117 // Use delay slot in this branch.
4118 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg));
4119 __ mov(v0, zero_reg); // In delay slot.
4120 __ mov(v0, t1); // Value is in range 0..255.
4121 __ bind(&done);
4122 __ mov(t1, v0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004123
4124 __ srl(t8, key, 1);
4125 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004126 __ sb(t1, MemOperand(t8, 0));
4127 }
4128 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004129 case EXTERNAL_BYTE_ELEMENTS:
4130 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004131 __ srl(t8, key, 1);
4132 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004133 __ sb(t1, MemOperand(t8, 0));
4134 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004135 case EXTERNAL_SHORT_ELEMENTS:
4136 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004137 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004138 __ sh(t1, MemOperand(t8, 0));
4139 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004140 case EXTERNAL_INT_ELEMENTS:
4141 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004142 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004143 __ addu(t8, a3, t8);
4144 __ sw(t1, MemOperand(t8, 0));
4145 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004146 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004147 // Perform int-to-float conversion and store to memory.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004148 __ SmiUntag(t0, key);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004149 StoreIntAsFloat(masm, a3, t0, t1, t2, t3, t4);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004150 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004151 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004152 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004153 __ addu(a3, a3, t8);
4154 // a3: effective address of the double element
4155 FloatingPointHelper::Destination destination;
4156 if (CpuFeatures::IsSupported(FPU)) {
4157 destination = FloatingPointHelper::kFPURegisters;
4158 } else {
4159 destination = FloatingPointHelper::kCoreRegisters;
4160 }
4161 FloatingPointHelper::ConvertIntToDouble(
danno@chromium.org40cb8782011-05-25 07:58:50 +00004162 masm, t1, destination,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004163 f0, t2, t3, // These are: double_dst, dst1, dst2.
4164 t0, f2); // These are: scratch2, single_scratch.
4165 if (destination == FloatingPointHelper::kFPURegisters) {
4166 CpuFeatures::Scope scope(FPU);
4167 __ sdc1(f0, MemOperand(a3, 0));
4168 } else {
4169 __ sw(t2, MemOperand(a3, 0));
4170 __ sw(t3, MemOperand(a3, Register::kSizeInBytes));
4171 }
4172 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004173 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004174 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004175 case FAST_DOUBLE_ELEMENTS:
4176 case DICTIONARY_ELEMENTS:
4177 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004178 UNREACHABLE();
4179 break;
4180 }
4181
4182 // Entry registers are intact, a0 holds the value which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004183 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004184 __ Ret();
4185
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004186 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004187 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004188 __ bind(&check_heap_number);
4189 __ GetObjectType(value, t1, t2);
4190 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE));
4191
4192 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
4193
4194 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004195
4196 // The WebGL specification leaves the behavior of storing NaN and
4197 // +/-Infinity into integer arrays basically undefined. For more
4198 // reproducible behavior, convert these to zero.
4199
4200 if (CpuFeatures::IsSupported(FPU)) {
4201 CpuFeatures::Scope scope(FPU);
4202
4203 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
4204
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004205 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004206 __ cvt_s_d(f0, f0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004207 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004208 __ addu(t8, a3, t8);
4209 __ swc1(f0, MemOperand(t8, 0));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004210 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004211 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004212 __ addu(t8, a3, t8);
4213 __ sdc1(f0, MemOperand(t8, 0));
4214 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00004215 __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004216
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004217 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004218 case EXTERNAL_BYTE_ELEMENTS:
4219 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004220 __ srl(t8, key, 1);
4221 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004222 __ sb(t3, MemOperand(t8, 0));
4223 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004224 case EXTERNAL_SHORT_ELEMENTS:
4225 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004226 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004227 __ sh(t3, MemOperand(t8, 0));
4228 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004229 case EXTERNAL_INT_ELEMENTS:
4230 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004231 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004232 __ addu(t8, a3, t8);
4233 __ sw(t3, MemOperand(t8, 0));
4234 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004235 case EXTERNAL_PIXEL_ELEMENTS:
4236 case EXTERNAL_FLOAT_ELEMENTS:
4237 case EXTERNAL_DOUBLE_ELEMENTS:
4238 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004239 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004240 case FAST_DOUBLE_ELEMENTS:
4241 case DICTIONARY_ELEMENTS:
4242 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004243 UNREACHABLE();
4244 break;
4245 }
4246 }
4247
4248 // Entry registers are intact, a0 holds the value
4249 // which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004250 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004251 __ Ret();
4252 } else {
4253 // FPU is not available, do manual conversions.
4254
4255 __ lw(t3, FieldMemOperand(value, HeapNumber::kExponentOffset));
4256 __ lw(t4, FieldMemOperand(value, HeapNumber::kMantissaOffset));
4257
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004258 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004259 Label done, nan_or_infinity_or_zero;
4260 static const int kMantissaInHiWordShift =
4261 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
4262
4263 static const int kMantissaInLoWordShift =
4264 kBitsPerInt - kMantissaInHiWordShift;
4265
4266 // Test for all special exponent values: zeros, subnormal numbers, NaNs
4267 // and infinities. All these should be converted to 0.
4268 __ li(t5, HeapNumber::kExponentMask);
4269 __ and_(t6, t3, t5);
4270 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(zero_reg));
4271
4272 __ xor_(t1, t6, t5);
4273 __ li(t2, kBinary32ExponentMask);
4274 __ movz(t6, t2, t1); // Only if t6 is equal to t5.
4275 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(t5));
4276
4277 // Rebias exponent.
4278 __ srl(t6, t6, HeapNumber::kExponentShift);
4279 __ Addu(t6,
4280 t6,
4281 Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
4282
4283 __ li(t1, Operand(kBinary32MaxExponent));
4284 __ Slt(t1, t1, t6);
4285 __ And(t2, t3, Operand(HeapNumber::kSignMask));
4286 __ Or(t2, t2, Operand(kBinary32ExponentMask));
4287 __ movn(t3, t2, t1); // Only if t6 is gt kBinary32MaxExponent.
4288 __ Branch(&done, gt, t6, Operand(kBinary32MaxExponent));
4289
4290 __ Slt(t1, t6, Operand(kBinary32MinExponent));
4291 __ And(t2, t3, Operand(HeapNumber::kSignMask));
4292 __ movn(t3, t2, t1); // Only if t6 is lt kBinary32MinExponent.
4293 __ Branch(&done, lt, t6, Operand(kBinary32MinExponent));
4294
4295 __ And(t7, t3, Operand(HeapNumber::kSignMask));
4296 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4297 __ sll(t3, t3, kMantissaInHiWordShift);
4298 __ or_(t7, t7, t3);
4299 __ srl(t4, t4, kMantissaInLoWordShift);
4300 __ or_(t7, t7, t4);
4301 __ sll(t6, t6, kBinary32ExponentShift);
4302 __ or_(t3, t7, t6);
4303
4304 __ bind(&done);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004305 __ sll(t9, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004306 __ addu(t9, a2, t9);
4307 __ sw(t3, MemOperand(t9, 0));
4308
4309 // Entry registers are intact, a0 holds the value which is the return
4310 // value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004311 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004312 __ Ret();
4313
4314 __ bind(&nan_or_infinity_or_zero);
4315 __ And(t7, t3, Operand(HeapNumber::kSignMask));
4316 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4317 __ or_(t6, t6, t7);
4318 __ sll(t3, t3, kMantissaInHiWordShift);
4319 __ or_(t6, t6, t3);
4320 __ srl(t4, t4, kMantissaInLoWordShift);
4321 __ or_(t3, t6, t4);
4322 __ Branch(&done);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004323 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004324 __ sll(t8, t0, 3);
4325 __ addu(t8, a3, t8);
4326 // t8: effective address of destination element.
4327 __ sw(t4, MemOperand(t8, 0));
4328 __ sw(t3, MemOperand(t8, Register::kSizeInBytes));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004329 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004330 __ Ret();
4331 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004332 bool is_signed_type = IsElementTypeSigned(elements_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004333 int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
4334 int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
4335
4336 Label done, sign;
4337
4338 // Test for all special exponent values: zeros, subnormal numbers, NaNs
4339 // and infinities. All these should be converted to 0.
4340 __ li(t5, HeapNumber::kExponentMask);
4341 __ and_(t6, t3, t5);
4342 __ movz(t3, zero_reg, t6); // Only if t6 is equal to zero.
4343 __ Branch(&done, eq, t6, Operand(zero_reg));
4344
4345 __ xor_(t2, t6, t5);
4346 __ movz(t3, zero_reg, t2); // Only if t6 is equal to t5.
4347 __ Branch(&done, eq, t6, Operand(t5));
4348
4349 // Unbias exponent.
4350 __ srl(t6, t6, HeapNumber::kExponentShift);
4351 __ Subu(t6, t6, Operand(HeapNumber::kExponentBias));
4352 // If exponent is negative then result is 0.
4353 __ slt(t2, t6, zero_reg);
4354 __ movn(t3, zero_reg, t2); // Only if exponent is negative.
4355 __ Branch(&done, lt, t6, Operand(zero_reg));
4356
4357 // If exponent is too big then result is minimal value.
4358 __ slti(t1, t6, meaningfull_bits - 1);
4359 __ li(t2, min_value);
4360 __ movz(t3, t2, t1); // Only if t6 is ge meaningfull_bits - 1.
4361 __ Branch(&done, ge, t6, Operand(meaningfull_bits - 1));
4362
4363 __ And(t5, t3, Operand(HeapNumber::kSignMask));
4364 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4365 __ Or(t3, t3, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
4366
4367 __ li(t9, HeapNumber::kMantissaBitsInTopWord);
4368 __ subu(t6, t9, t6);
4369 __ slt(t1, t6, zero_reg);
4370 __ srlv(t2, t3, t6);
4371 __ movz(t3, t2, t1); // Only if t6 is positive.
4372 __ Branch(&sign, ge, t6, Operand(zero_reg));
4373
4374 __ subu(t6, zero_reg, t6);
4375 __ sllv(t3, t3, t6);
4376 __ li(t9, meaningfull_bits);
4377 __ subu(t6, t9, t6);
4378 __ srlv(t4, t4, t6);
4379 __ or_(t3, t3, t4);
4380
4381 __ bind(&sign);
4382 __ subu(t2, t3, zero_reg);
4383 __ movz(t3, t2, t5); // Only if t5 is zero.
4384
4385 __ bind(&done);
4386
4387 // Result is in t3.
4388 // This switch block should be exactly the same as above (FPU mode).
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004389 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004390 case EXTERNAL_BYTE_ELEMENTS:
4391 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004392 __ srl(t8, key, 1);
4393 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004394 __ sb(t3, MemOperand(t8, 0));
4395 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004396 case EXTERNAL_SHORT_ELEMENTS:
4397 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004398 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004399 __ sh(t3, MemOperand(t8, 0));
4400 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004401 case EXTERNAL_INT_ELEMENTS:
4402 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004403 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004404 __ addu(t8, a3, t8);
4405 __ sw(t3, MemOperand(t8, 0));
4406 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004407 case EXTERNAL_PIXEL_ELEMENTS:
4408 case EXTERNAL_FLOAT_ELEMENTS:
4409 case EXTERNAL_DOUBLE_ELEMENTS:
4410 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004411 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004412 case FAST_DOUBLE_ELEMENTS:
4413 case DICTIONARY_ELEMENTS:
4414 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004415 UNREACHABLE();
4416 break;
4417 }
4418 }
4419 }
4420 }
4421
danno@chromium.org40cb8782011-05-25 07:58:50 +00004422 // Slow case, key and receiver still in a0 and a1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004423 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004424 __ IncrementCounter(
4425 masm->isolate()->counters()->keyed_load_external_array_slow(),
4426 1, a2, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004427 // Entry registers are intact.
4428 // ---------- S t a t e --------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004429 // -- ra : return address
danno@chromium.org40cb8782011-05-25 07:58:50 +00004430 // -- a0 : key
4431 // -- a1 : receiver
4432 // -----------------------------------
4433 Handle<Code> slow_ic =
4434 masm->isolate()->builtins()->KeyedStoreIC_Slow();
4435 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4436
4437 // Miss case, call the runtime.
4438 __ bind(&miss_force_generic);
4439
4440 // ---------- S t a t e --------------
4441 // -- ra : return address
4442 // -- a0 : key
4443 // -- a1 : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004444 // -----------------------------------
4445
danno@chromium.org40cb8782011-05-25 07:58:50 +00004446 Handle<Code> miss_ic =
4447 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4448 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
4449}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004450
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004451
danno@chromium.org40cb8782011-05-25 07:58:50 +00004452void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
4453 // ----------- S t a t e -------------
4454 // -- ra : return address
4455 // -- a0 : key
4456 // -- a1 : receiver
4457 // -----------------------------------
4458 Label miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004459
danno@chromium.org40cb8782011-05-25 07:58:50 +00004460 // This stub is meant to be tail-jumped to, the receiver must already
4461 // have been verified by the caller to not be a smi.
4462
4463 // Check that the key is a smi.
4464 __ JumpIfNotSmi(a0, &miss_force_generic);
4465
4466 // Get the elements array.
4467 __ lw(a2, FieldMemOperand(a1, JSObject::kElementsOffset));
4468 __ AssertFastElements(a2);
4469
4470 // Check that the key is within bounds.
4471 __ lw(a3, FieldMemOperand(a2, FixedArray::kLengthOffset));
4472 __ Branch(&miss_force_generic, hs, a0, Operand(a3));
4473
4474 // Load the result and make sure it's not the hole.
4475 __ Addu(a3, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004476 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004477 __ sll(t0, a0, kPointerSizeLog2 - kSmiTagSize);
4478 __ Addu(t0, t0, a3);
4479 __ lw(t0, MemOperand(t0));
4480 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
4481 __ Branch(&miss_force_generic, eq, t0, Operand(t1));
4482 __ mov(v0, t0);
4483 __ Ret();
4484
4485 __ bind(&miss_force_generic);
4486 Code* stub = masm->isolate()->builtins()->builtin(
4487 Builtins::kKeyedLoadIC_MissForceGeneric);
4488 __ Jump(Handle<Code>(stub), RelocInfo::CODE_TARGET);
4489}
4490
4491
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004492void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
4493 MacroAssembler* masm) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004494 // ----------- S t a t e -------------
4495 // -- ra : return address
4496 // -- a0 : key
4497 // -- a1 : receiver
4498 // -----------------------------------
4499 Label miss_force_generic, slow_allocate_heapnumber;
4500
4501 Register key_reg = a0;
4502 Register receiver_reg = a1;
4503 Register elements_reg = a2;
4504 Register heap_number_reg = a2;
4505 Register indexed_double_offset = a3;
4506 Register scratch = t0;
4507 Register scratch2 = t1;
4508 Register scratch3 = t2;
4509 Register heap_number_map = t3;
4510
4511 // This stub is meant to be tail-jumped to, the receiver must already
4512 // have been verified by the caller to not be a smi.
4513
4514 // Check that the key is a smi.
4515 __ JumpIfNotSmi(key_reg, &miss_force_generic);
4516
4517 // Get the elements array.
4518 __ lw(elements_reg,
4519 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4520
4521 // Check that the key is within bounds.
4522 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4523 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4524
4525 // Load the upper word of the double in the fixed array and test for NaN.
4526 __ sll(scratch2, key_reg, kDoubleSizeLog2 - kSmiTagSize);
4527 __ Addu(indexed_double_offset, elements_reg, Operand(scratch2));
4528 uint32_t upper_32_offset = FixedArray::kHeaderSize + sizeof(kHoleNanLower32);
4529 __ lw(scratch, FieldMemOperand(indexed_double_offset, upper_32_offset));
4530 __ Branch(&miss_force_generic, eq, scratch, Operand(kHoleNanUpper32));
4531
4532 // Non-NaN. Allocate a new heap number and copy the double value into it.
4533 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
4534 __ AllocateHeapNumber(heap_number_reg, scratch2, scratch3,
4535 heap_number_map, &slow_allocate_heapnumber);
4536
4537 // Don't need to reload the upper 32 bits of the double, it's already in
4538 // scratch.
4539 __ sw(scratch, FieldMemOperand(heap_number_reg,
4540 HeapNumber::kExponentOffset));
4541 __ lw(scratch, FieldMemOperand(indexed_double_offset,
4542 FixedArray::kHeaderSize));
4543 __ sw(scratch, FieldMemOperand(heap_number_reg,
4544 HeapNumber::kMantissaOffset));
4545
4546 __ mov(v0, heap_number_reg);
4547 __ Ret();
4548
4549 __ bind(&slow_allocate_heapnumber);
4550 Handle<Code> slow_ic =
4551 masm->isolate()->builtins()->KeyedLoadIC_Slow();
4552 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4553
4554 __ bind(&miss_force_generic);
4555 Handle<Code> miss_ic =
4556 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4557 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004558}
4559
4560
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004561void KeyedStoreStubCompiler::GenerateStoreFastElement(
4562 MacroAssembler* masm,
4563 bool is_js_array,
4564 ElementsKind elements_kind) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00004565 // ----------- S t a t e -------------
4566 // -- a0 : value
4567 // -- a1 : key
4568 // -- a2 : receiver
4569 // -- ra : return address
4570 // -- a3 : scratch
4571 // -- a4 : scratch (elements)
4572 // -----------------------------------
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004573 Label miss_force_generic, transition_elements_kind;
danno@chromium.org40cb8782011-05-25 07:58:50 +00004574
4575 Register value_reg = a0;
4576 Register key_reg = a1;
4577 Register receiver_reg = a2;
4578 Register scratch = a3;
4579 Register elements_reg = t0;
4580 Register scratch2 = t1;
4581 Register scratch3 = t2;
4582
4583 // This stub is meant to be tail-jumped to, the receiver must already
4584 // have been verified by the caller to not be a smi.
4585
4586 // Check that the key is a smi.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00004587 __ JumpIfNotSmi(key_reg, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004588
4589 // Get the elements array and make sure it is a fast element array, not 'cow'.
4590 __ lw(elements_reg,
4591 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4592 __ CheckMap(elements_reg,
4593 scratch,
4594 Heap::kFixedArrayMapRootIndex,
4595 &miss_force_generic,
4596 DONT_DO_SMI_CHECK);
4597
4598 // Check that the key is within bounds.
4599 if (is_js_array) {
4600 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4601 } else {
4602 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4603 }
4604 // Compare smis.
4605 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4606
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004607 if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
4608 __ JumpIfNotSmi(value_reg, &transition_elements_kind);
4609 __ Addu(scratch,
4610 elements_reg,
4611 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4612 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4613 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4614 __ Addu(scratch, scratch, scratch2);
4615 __ sw(value_reg, MemOperand(scratch));
4616 } else {
4617 ASSERT(elements_kind == FAST_ELEMENTS);
4618 __ Addu(scratch,
4619 elements_reg,
4620 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4621 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4622 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4623 __ Addu(scratch, scratch, scratch2);
4624 __ sw(value_reg, MemOperand(scratch));
4625 __ mov(receiver_reg, value_reg);
4626 ASSERT(elements_kind == FAST_ELEMENTS);
4627 __ RecordWrite(elements_reg, // Object.
4628 scratch, // Address.
4629 receiver_reg, // Value.
4630 kRAHasNotBeenSaved,
4631 kDontSaveFPRegs);
4632 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004633 // value_reg (a0) is preserved.
4634 // Done.
4635 __ Ret();
4636
4637 __ bind(&miss_force_generic);
4638 Handle<Code> ic =
4639 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4640 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004641
4642 __ bind(&transition_elements_kind);
4643 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4644 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004645}
4646
4647
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004648void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
4649 MacroAssembler* masm,
4650 bool is_js_array) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004651 // ----------- S t a t e -------------
4652 // -- a0 : value
4653 // -- a1 : key
4654 // -- a2 : receiver
4655 // -- ra : return address
4656 // -- a3 : scratch
4657 // -- t0 : scratch (elements_reg)
4658 // -- t1 : scratch (mantissa_reg)
4659 // -- t2 : scratch (exponent_reg)
4660 // -- t3 : scratch4
4661 // -----------------------------------
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004662 Label miss_force_generic, transition_elements_kind;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004663
4664 Register value_reg = a0;
4665 Register key_reg = a1;
4666 Register receiver_reg = a2;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004667 Register elements_reg = a3;
4668 Register scratch1 = t0;
4669 Register scratch2 = t1;
4670 Register scratch3 = t2;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004671 Register scratch4 = t3;
4672
4673 // This stub is meant to be tail-jumped to, the receiver must already
4674 // have been verified by the caller to not be a smi.
4675 __ JumpIfNotSmi(key_reg, &miss_force_generic);
4676
4677 __ lw(elements_reg,
4678 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4679
4680 // Check that the key is within bounds.
4681 if (is_js_array) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004682 __ lw(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004683 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004684 __ lw(scratch1,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004685 FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4686 }
4687 // Compare smis, unsigned compare catches both negative and out-of-bound
4688 // indexes.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004689 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch1));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004690
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004691 __ StoreNumberToDoubleElements(value_reg,
4692 key_reg,
4693 receiver_reg,
4694 elements_reg,
4695 scratch1,
4696 scratch2,
4697 scratch3,
4698 scratch4,
4699 &transition_elements_kind);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004700
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004701 __ Ret(USE_DELAY_SLOT);
4702 __ mov(v0, value_reg); // In delay slot.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004703
4704 // Handle store cache miss, replacing the ic with the generic stub.
4705 __ bind(&miss_force_generic);
4706 Handle<Code> ic =
4707 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4708 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004709
4710 __ bind(&transition_elements_kind);
4711 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4712 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004713}
4714
4715
ager@chromium.org5c838252010-02-19 08:53:10 +00004716#undef __
4717
4718} } // namespace v8::internal
4719
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004720#endif // V8_TARGET_ARCH_MIPS