blob: 676b523e23275e83d942159f5efcb7343f3adb9c [file] [log] [blame]
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001// Copyright 2012 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,
fschneider@chromium.org35814e52012-03-01 15:43:35 +000046 Register receiver,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000047 Register name,
fschneider@chromium.org35814e52012-03-01 15:43:35 +000048 // Number of the cache entry, not scaled.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000049 Register offset,
50 Register scratch,
fschneider@chromium.org35814e52012-03-01 15:43:35 +000051 Register scratch2,
52 Register offset_scratch) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000053 ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
54 ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
fschneider@chromium.org35814e52012-03-01 15:43:35 +000055 ExternalReference map_offset(isolate->stub_cache()->map_reference(table));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000056
57 uint32_t key_off_addr = reinterpret_cast<uint32_t>(key_offset.address());
58 uint32_t value_off_addr = reinterpret_cast<uint32_t>(value_offset.address());
fschneider@chromium.org35814e52012-03-01 15:43:35 +000059 uint32_t map_off_addr = reinterpret_cast<uint32_t>(map_offset.address());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000060
61 // Check the relative positions of the address fields.
62 ASSERT(value_off_addr > key_off_addr);
63 ASSERT((value_off_addr - key_off_addr) % 4 == 0);
64 ASSERT((value_off_addr - key_off_addr) < (256 * 4));
fschneider@chromium.org35814e52012-03-01 15:43:35 +000065 ASSERT(map_off_addr > key_off_addr);
66 ASSERT((map_off_addr - key_off_addr) % 4 == 0);
67 ASSERT((map_off_addr - key_off_addr) < (256 * 4));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000068
69 Label miss;
fschneider@chromium.org35814e52012-03-01 15:43:35 +000070 Register base_addr = scratch;
71 scratch = no_reg;
72
73 // Multiply by 3 because there are 3 fields per entry (name, code, map).
74 __ sll(offset_scratch, offset, 1);
75 __ Addu(offset_scratch, offset_scratch, offset);
76
77 // Calculate the base address of the entry.
78 __ li(base_addr, Operand(key_offset));
79 __ sll(at, offset_scratch, kPointerSizeLog2);
80 __ Addu(base_addr, base_addr, at);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000081
82 // Check that the key in the entry matches the name.
fschneider@chromium.org35814e52012-03-01 15:43:35 +000083 __ lw(at, MemOperand(base_addr, 0));
84 __ Branch(&miss, ne, name, Operand(at));
85
86 // Check the map matches.
87 __ lw(at, MemOperand(base_addr, map_off_addr - key_off_addr));
88 __ lw(scratch2, FieldMemOperand(receiver, HeapObject::kMapOffset));
89 __ Branch(&miss, ne, at, Operand(scratch2));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000090
91 // Get the code entry from the cache.
fschneider@chromium.org35814e52012-03-01 15:43:35 +000092 Register code = scratch2;
93 scratch2 = no_reg;
94 __ lw(code, MemOperand(base_addr, value_off_addr - key_off_addr));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000095
96 // Check that the flags match what we're looking for.
fschneider@chromium.org35814e52012-03-01 15:43:35 +000097 Register flags_reg = base_addr;
98 base_addr = no_reg;
99 __ lw(flags_reg, FieldMemOperand(code, Code::kFlagsOffset));
100 __ And(flags_reg, flags_reg, Operand(~Code::kFlagsNotUsedInLookup));
101 __ Branch(&miss, ne, flags_reg, Operand(flags));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000102
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000103#ifdef DEBUG
104 if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
105 __ jmp(&miss);
106 } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
107 __ jmp(&miss);
108 }
109#endif
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000110
111 // Jump to the first instruction in the code stub.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000112 __ Addu(at, code, Operand(Code::kHeaderSize - kHeapObjectTag));
113 __ Jump(at);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000114
115 // Miss: fall through.
116 __ bind(&miss);
117}
118
119
120// Helper function used to check that the dictionary doesn't contain
121// the property. This function may return false negatives, so miss_label
122// must always call a backup property check that is complete.
123// This function is safe to call if the receiver has fast properties.
124// Name must be a symbol and receiver must be a heap object.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000125static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
126 Label* miss_label,
127 Register receiver,
128 Handle<String> name,
129 Register scratch0,
130 Register scratch1) {
131 ASSERT(name->IsSymbol());
132 Counters* counters = masm->isolate()->counters();
133 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
134 __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
135
136 Label done;
137
138 const int kInterceptorOrAccessCheckNeededMask =
139 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
140
141 // Bail out if the receiver has a named interceptor or requires access checks.
142 Register map = scratch1;
143 __ lw(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
144 __ lbu(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
145 __ And(scratch0, scratch0, Operand(kInterceptorOrAccessCheckNeededMask));
146 __ Branch(miss_label, ne, scratch0, Operand(zero_reg));
147
148 // Check that receiver is a JSObject.
149 __ lbu(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
150 __ Branch(miss_label, lt, scratch0, Operand(FIRST_SPEC_OBJECT_TYPE));
151
152 // Load properties array.
153 Register properties = scratch0;
154 __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
155 // Check that the properties array is a dictionary.
156 __ lw(map, FieldMemOperand(properties, HeapObject::kMapOffset));
157 Register tmp = properties;
158 __ LoadRoot(tmp, Heap::kHashTableMapRootIndex);
159 __ Branch(miss_label, ne, map, Operand(tmp));
160
161 // Restore the temporarily used register.
162 __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
163
164
165 StringDictionaryLookupStub::GenerateNegativeLookup(masm,
166 miss_label,
167 &done,
168 receiver,
169 properties,
170 name,
171 scratch1);
172 __ bind(&done);
173 __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
174}
175
176
ager@chromium.org5c838252010-02-19 08:53:10 +0000177void StubCache::GenerateProbe(MacroAssembler* masm,
178 Code::Flags flags,
179 Register receiver,
180 Register name,
181 Register scratch,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000182 Register extra,
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000183 Register extra2,
184 Register extra3) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000185 Isolate* isolate = masm->isolate();
186 Label miss;
187
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000188 // Make sure that code is valid. The multiplying code relies on the
189 // entry size being 12.
190 ASSERT(sizeof(Entry) == 12);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000191
192 // Make sure the flags does not name a specific type.
193 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
194
195 // Make sure that there are no register conflicts.
196 ASSERT(!scratch.is(receiver));
197 ASSERT(!scratch.is(name));
198 ASSERT(!extra.is(receiver));
199 ASSERT(!extra.is(name));
200 ASSERT(!extra.is(scratch));
201 ASSERT(!extra2.is(receiver));
202 ASSERT(!extra2.is(name));
203 ASSERT(!extra2.is(scratch));
204 ASSERT(!extra2.is(extra));
205
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000206 // Check register validity.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000207 ASSERT(!scratch.is(no_reg));
208 ASSERT(!extra.is(no_reg));
209 ASSERT(!extra2.is(no_reg));
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000210 ASSERT(!extra3.is(no_reg));
211
212 Counters* counters = masm->isolate()->counters();
213 __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1,
214 extra2, extra3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000215
216 // Check that the receiver isn't a smi.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000217 __ JumpIfSmi(receiver, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000218
219 // Get the map of the receiver and compute the hash.
220 __ lw(scratch, FieldMemOperand(name, String::kHashFieldOffset));
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000221 __ lw(at, FieldMemOperand(receiver, HeapObject::kMapOffset));
222 __ Addu(scratch, scratch, at);
223 uint32_t mask = kPrimaryTableSize - 1;
224 // We shift out the last two bits because they are not part of the hash and
225 // they are always 01 for maps.
226 __ srl(scratch, scratch, kHeapObjectTagSize);
227 __ Xor(scratch, scratch, Operand((flags >> kHeapObjectTagSize) & mask));
228 __ And(scratch, scratch, Operand(mask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000229
230 // Probe the primary table.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000231 ProbeTable(isolate,
232 masm,
233 flags,
234 kPrimary,
235 receiver,
236 name,
237 scratch,
238 extra,
239 extra2,
240 extra3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000241
242 // Primary miss: Compute hash for secondary probe.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000243 __ srl(at, name, kHeapObjectTagSize);
244 __ Subu(scratch, scratch, at);
245 uint32_t mask2 = kSecondaryTableSize - 1;
246 __ Addu(scratch, scratch, Operand((flags >> kHeapObjectTagSize) & mask2));
247 __ And(scratch, scratch, Operand(mask2));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000248
249 // Probe the secondary table.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000250 ProbeTable(isolate,
251 masm,
252 flags,
253 kSecondary,
254 receiver,
255 name,
256 scratch,
257 extra,
258 extra2,
259 extra3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000260
261 // Cache miss: Fall-through and let caller handle the miss by
262 // entering the runtime system.
263 __ bind(&miss);
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000264 __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1,
265 extra2, extra3);
ager@chromium.org5c838252010-02-19 08:53:10 +0000266}
267
268
269void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
270 int index,
271 Register prototype) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000272 // Load the global or builtins object from the current context.
273 __ lw(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
274 // Load the global context from the global or builtins object.
275 __ lw(prototype,
276 FieldMemOperand(prototype, GlobalObject::kGlobalContextOffset));
277 // Load the function from the global context.
278 __ lw(prototype, MemOperand(prototype, Context::SlotOffset(index)));
279 // Load the initial map. The global functions all have initial maps.
280 __ lw(prototype,
281 FieldMemOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
282 // Load the prototype from the initial map.
283 __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000284}
285
286
lrn@chromium.org7516f052011-03-30 08:52:27 +0000287void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000288 MacroAssembler* masm,
289 int index,
290 Register prototype,
291 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000292 Isolate* isolate = masm->isolate();
293 // Check we're still in the same context.
294 __ lw(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
295 ASSERT(!prototype.is(at));
296 __ li(at, isolate->global());
297 __ Branch(miss, ne, prototype, Operand(at));
298 // Get the global function with the given index.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000299 Handle<JSFunction> function(
300 JSFunction::cast(isolate->global_context()->get(index)));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000301 // Load its initial map. The global functions all have initial maps.
302 __ li(prototype, Handle<Map>(function->initial_map()));
303 // Load the prototype from the initial map.
304 __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000305}
306
307
ager@chromium.org5c838252010-02-19 08:53:10 +0000308// Load a fast property out of a holder object (src). In-object properties
309// are loaded directly otherwise the property is loaded from the properties
310// fixed array.
311void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000312 Register dst,
313 Register src,
314 Handle<JSObject> holder,
315 int index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000316 // Adjust for the number of properties stored in the holder.
317 index -= holder->map()->inobject_properties();
318 if (index < 0) {
319 // Get the property straight out of the holder.
320 int offset = holder->map()->instance_size() + (index * kPointerSize);
321 __ lw(dst, FieldMemOperand(src, offset));
322 } else {
323 // Calculate the offset into the properties array.
324 int offset = index * kPointerSize + FixedArray::kHeaderSize;
325 __ lw(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
326 __ lw(dst, FieldMemOperand(dst, offset));
327 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000328}
329
330
331void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
332 Register receiver,
333 Register scratch,
334 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000335 // Check that the receiver isn't a smi.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000336 __ JumpIfSmi(receiver, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000337
338 // Check that the object is a JS array.
339 __ GetObjectType(receiver, scratch, scratch);
340 __ Branch(miss_label, ne, scratch, Operand(JS_ARRAY_TYPE));
341
342 // Load length directly from the JS array.
343 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
344 __ Ret();
345}
346
347
348// Generate code to check if an object is a string. If the object is a
349// heap object, its map's instance type is left in the scratch1 register.
350// If this is not needed, scratch1 and scratch2 may be the same register.
351static void GenerateStringCheck(MacroAssembler* masm,
352 Register receiver,
353 Register scratch1,
354 Register scratch2,
355 Label* smi,
356 Label* non_string_object) {
357 // Check that the receiver isn't a smi.
358 __ JumpIfSmi(receiver, smi, t0);
359
360 // Check that the object is a string.
361 __ lw(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
362 __ lbu(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
363 __ And(scratch2, scratch1, Operand(kIsNotStringMask));
364 // The cast is to resolve the overload for the argument of 0x0.
365 __ Branch(non_string_object,
366 ne,
367 scratch2,
368 Operand(static_cast<int32_t>(kStringTag)));
ager@chromium.org5c838252010-02-19 08:53:10 +0000369}
370
371
lrn@chromium.org7516f052011-03-30 08:52:27 +0000372// Generate code to load the length from a string object and return the length.
373// If the receiver object is not a string or a wrapped string object the
374// execution continues at the miss label. The register containing the
375// receiver is potentially clobbered.
376void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
377 Register receiver,
378 Register scratch1,
379 Register scratch2,
380 Label* miss,
381 bool support_wrappers) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000382 Label check_wrapper;
383
384 // Check if the object is a string leaving the instance type in the
385 // scratch1 register.
386 GenerateStringCheck(masm, receiver, scratch1, scratch2, miss,
387 support_wrappers ? &check_wrapper : miss);
388
389 // Load length directly from the string.
390 __ lw(v0, FieldMemOperand(receiver, String::kLengthOffset));
391 __ Ret();
392
393 if (support_wrappers) {
394 // Check if the object is a JSValue wrapper.
395 __ bind(&check_wrapper);
396 __ Branch(miss, ne, scratch1, Operand(JS_VALUE_TYPE));
397
398 // Unwrap the value and check if the wrapped value is a string.
399 __ lw(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
400 GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
401 __ lw(v0, FieldMemOperand(scratch1, String::kLengthOffset));
402 __ Ret();
403 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000404}
405
406
ager@chromium.org5c838252010-02-19 08:53:10 +0000407void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
408 Register receiver,
409 Register scratch1,
410 Register scratch2,
411 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000412 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
413 __ mov(v0, scratch1);
414 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000415}
416
417
lrn@chromium.org7516f052011-03-30 08:52:27 +0000418// Generate StoreField code, value is passed in a0 register.
ager@chromium.org5c838252010-02-19 08:53:10 +0000419// After executing generated code, the receiver_reg and name_reg
420// may be clobbered.
421void StubCompiler::GenerateStoreField(MacroAssembler* masm,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000422 Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +0000423 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000424 Handle<Map> transition,
ager@chromium.org5c838252010-02-19 08:53:10 +0000425 Register receiver_reg,
426 Register name_reg,
427 Register scratch,
428 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000429 // a0 : value.
430 Label exit;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000431 // Check that the map of the object hasn't changed.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000432 CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
433 : REQUIRE_EXACT_MAP;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000434 __ CheckMap(receiver_reg, scratch, Handle<Map>(object->map()), miss_label,
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000435 DO_SMI_CHECK, mode);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000436
437 // Perform global security token check if needed.
438 if (object->IsJSGlobalProxy()) {
439 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
440 }
441
442 // Stub never generated for non-global objects that require access
443 // checks.
444 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
445
446 // Perform map transition for the receiver if necessary.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000447 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000448 // The properties must be extended before we can store the value.
449 // We jump to a runtime call that extends the properties array.
450 __ push(receiver_reg);
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000451 __ li(a2, Operand(transition));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000452 __ Push(a2, a0);
453 __ TailCallExternalReference(
454 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
455 masm->isolate()),
456 3, 1);
457 return;
458 }
459
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000460 if (!transition.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000461 // Update the map of the object; no write barrier updating is
462 // needed because the map is never in new space.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000463 __ li(t0, Operand(transition));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000464 __ sw(t0, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
465 }
466
467 // Adjust for the number of properties stored in the object. Even in the
468 // face of a transition we can use the old map here because the size of the
469 // object and the number of in-object properties is not going to change.
470 index -= object->map()->inobject_properties();
471
472 if (index < 0) {
473 // Set the property straight into the object.
474 int offset = object->map()->instance_size() + (index * kPointerSize);
475 __ sw(a0, FieldMemOperand(receiver_reg, offset));
476
477 // Skip updating write barrier if storing a smi.
478 __ JumpIfSmi(a0, &exit, scratch);
479
480 // Update the write barrier for the array address.
481 // Pass the now unused name_reg as a scratch register.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000482 __ mov(name_reg, a0);
483 __ RecordWriteField(receiver_reg,
484 offset,
485 name_reg,
486 scratch,
487 kRAHasNotBeenSaved,
488 kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000489 } else {
490 // Write to the properties array.
491 int offset = index * kPointerSize + FixedArray::kHeaderSize;
492 // Get the properties array.
493 __ lw(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
494 __ sw(a0, FieldMemOperand(scratch, offset));
495
496 // Skip updating write barrier if storing a smi.
497 __ JumpIfSmi(a0, &exit);
498
499 // Update the write barrier for the array address.
500 // Ok to clobber receiver_reg and name_reg, since we return.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000501 __ mov(name_reg, a0);
502 __ RecordWriteField(scratch,
503 offset,
504 name_reg,
505 receiver_reg,
506 kRAHasNotBeenSaved,
507 kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000508 }
509
510 // Return the value (register v0).
511 __ bind(&exit);
512 __ mov(v0, a0);
513 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000514}
515
516
517void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000518 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000519 Handle<Code> code = (kind == Code::LOAD_IC)
520 ? masm->isolate()->builtins()->LoadIC_Miss()
521 : masm->isolate()->builtins()->KeyedLoadIC_Miss();
522 __ Jump(code, RelocInfo::CODE_TARGET);
ager@chromium.org5c838252010-02-19 08:53:10 +0000523}
524
525
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000526static void GenerateCallFunction(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000527 Handle<Object> object,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000528 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000529 Label* miss,
530 Code::ExtraICState extra_ic_state) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000531 // ----------- S t a t e -------------
532 // -- a0: receiver
533 // -- a1: function to call
534 // -----------------------------------
535 // Check that the function really is a function.
536 __ JumpIfSmi(a1, miss);
537 __ GetObjectType(a1, a3, a3);
538 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
539
540 // Patch the receiver on the stack with the global proxy if
541 // necessary.
542 if (object->IsGlobalObject()) {
543 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
544 __ sw(a3, MemOperand(sp, arguments.immediate() * kPointerSize));
545 }
546
547 // Invoke the function.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000548 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
549 ? CALL_AS_FUNCTION
550 : CALL_AS_METHOD;
551 __ InvokeFunction(a1, arguments, JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000552}
553
554
555static void PushInterceptorArguments(MacroAssembler* masm,
556 Register receiver,
557 Register holder,
558 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000559 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000560 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000561 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
562 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000563 Register scratch = name;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000564 __ li(scratch, Operand(interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000565 __ Push(scratch, receiver, holder);
566 __ lw(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
567 __ push(scratch);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000568 __ li(scratch, Operand(ExternalReference::isolate_address()));
569 __ push(scratch);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000570}
571
572
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000573static void CompileCallLoadPropertyWithInterceptor(
574 MacroAssembler* masm,
575 Register receiver,
576 Register holder,
577 Register name,
578 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000579 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
580
581 ExternalReference ref =
582 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
583 masm->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000584 __ PrepareCEntryArgs(6);
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000585 __ PrepareCEntryFunction(ref);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000586
587 CEntryStub stub(1);
588 __ CallStub(&stub);
589}
590
591
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000592static const int kFastApiCallArguments = 4;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000593
594
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000595// Reserves space for the extra arguments to API function in the
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000596// caller's frame.
597//
598// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
599static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
600 Register scratch) {
601 ASSERT(Smi::FromInt(0) == 0);
602 for (int i = 0; i < kFastApiCallArguments; i++) {
603 __ push(zero_reg);
604 }
605}
606
607
608// Undoes the effects of ReserveSpaceForFastApiCall.
609static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
610 __ Drop(kFastApiCallArguments);
611}
612
613
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000614static void GenerateFastApiDirectCall(MacroAssembler* masm,
615 const CallOptimization& optimization,
616 int argc) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000617 // ----------- S t a t e -------------
618 // -- sp[0] : holder (set by CheckPrototypes)
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000619 // -- sp[4] : callee JS function
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000620 // -- sp[8] : call data
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000621 // -- sp[12] : isolate
622 // -- sp[16] : last JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000623 // -- ...
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000624 // -- sp[(argc + 3) * 4] : first JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000625 // -- sp[(argc + 4) * 4] : receiver
626 // -----------------------------------
627 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000628 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000629 __ LoadHeapObject(t1, function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000630 __ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset));
631
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000632 // Pass the additional arguments.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000633 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
634 Handle<Object> call_data(api_call_info->data());
635 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
636 __ li(a0, api_call_info);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000637 __ lw(t2, FieldMemOperand(a0, CallHandlerInfo::kDataOffset));
638 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000639 __ li(t2, call_data);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000640 }
641
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000642 __ li(t3, Operand(ExternalReference::isolate_address()));
643 // Store JS function, call data and isolate.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000644 __ sw(t1, MemOperand(sp, 1 * kPointerSize));
645 __ sw(t2, MemOperand(sp, 2 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000646 __ sw(t3, MemOperand(sp, 3 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000647
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000648 // Prepare arguments.
649 __ Addu(a2, sp, Operand(3 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000650
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000651 // Allocate the v8::Arguments structure in the arguments' space since
652 // it's not controlled by GC.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000653 const int kApiStackSpace = 4;
654
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000655 FrameScope frame_scope(masm, StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000656 __ EnterExitFrame(false, kApiStackSpace);
657
658 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
659 // struct from the function (which is currently the case). This means we pass
660 // the first argument in a1 instead of a0. TryCallApiFunctionAndReturn
661 // will handle setting up a0.
662
663 // a1 = v8::Arguments&
664 // Arguments is built at sp + 1 (sp is a reserved spot for ra).
665 __ Addu(a1, sp, kPointerSize);
666
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000667 // v8::Arguments::implicit_args_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000668 __ sw(a2, MemOperand(a1, 0 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000669 // v8::Arguments::values_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000670 __ Addu(t0, a2, Operand(argc * kPointerSize));
671 __ sw(t0, MemOperand(a1, 1 * kPointerSize));
672 // v8::Arguments::length_ = argc
673 __ li(t0, Operand(argc));
674 __ sw(t0, MemOperand(a1, 2 * kPointerSize));
675 // v8::Arguments::is_construct_call = 0
676 __ sw(zero_reg, MemOperand(a1, 3 * kPointerSize));
677
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000678 const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000679 Address function_address = v8::ToCData<Address>(api_call_info->callback());
680 ApiFunction fun(function_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000681 ExternalReference ref =
682 ExternalReference(&fun,
683 ExternalReference::DIRECT_API_CALL,
684 masm->isolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000685 AllowExternalCallThatCantCauseGC scope(masm);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000686 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000687}
688
lrn@chromium.org7516f052011-03-30 08:52:27 +0000689class CallInterceptorCompiler BASE_EMBEDDED {
690 public:
691 CallInterceptorCompiler(StubCompiler* stub_compiler,
692 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000693 Register name,
694 Code::ExtraICState extra_ic_state)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000695 : stub_compiler_(stub_compiler),
696 arguments_(arguments),
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000697 name_(name),
698 extra_ic_state_(extra_ic_state) {}
lrn@chromium.org7516f052011-03-30 08:52:27 +0000699
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000700 void Compile(MacroAssembler* masm,
701 Handle<JSObject> object,
702 Handle<JSObject> holder,
703 Handle<String> name,
704 LookupResult* lookup,
705 Register receiver,
706 Register scratch1,
707 Register scratch2,
708 Register scratch3,
709 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000710 ASSERT(holder->HasNamedInterceptor());
711 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
712
713 // Check that the receiver isn't a smi.
714 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000715 CallOptimization optimization(lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000716 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000717 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
718 holder, lookup, name, optimization, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000719 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000720 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
721 name, holder, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000722 }
723 }
724
725 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000726 void CompileCacheable(MacroAssembler* masm,
727 Handle<JSObject> object,
728 Register receiver,
729 Register scratch1,
730 Register scratch2,
731 Register scratch3,
732 Handle<JSObject> interceptor_holder,
733 LookupResult* lookup,
734 Handle<String> name,
735 const CallOptimization& optimization,
736 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000737 ASSERT(optimization.is_constant_call());
738 ASSERT(!lookup->holder()->IsGlobalObject());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000739 Counters* counters = masm->isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000740 int depth1 = kInvalidProtoDepth;
741 int depth2 = kInvalidProtoDepth;
742 bool can_do_fast_api_call = false;
743 if (optimization.is_simple_api_call() &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000744 !lookup->holder()->IsGlobalObject()) {
745 depth1 = optimization.GetPrototypeDepthOfExpectedType(
746 object, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000747 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000748 depth2 = optimization.GetPrototypeDepthOfExpectedType(
749 interceptor_holder, Handle<JSObject>(lookup->holder()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000750 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000751 can_do_fast_api_call =
752 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000753 }
754
755 __ IncrementCounter(counters->call_const_interceptor(), 1,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000756 scratch1, scratch2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000757
758 if (can_do_fast_api_call) {
759 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
760 scratch1, scratch2);
761 ReserveSpaceForFastApiCall(masm, scratch1);
762 }
763
764 // Check that the maps from receiver to interceptor's holder
765 // haven't changed and thus we can invoke interceptor.
766 Label miss_cleanup;
767 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
768 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000769 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
770 scratch1, scratch2, scratch3,
771 name, depth1, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000772
773 // Invoke an interceptor and if it provides a value,
774 // branch to |regular_invoke|.
775 Label regular_invoke;
776 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
777 &regular_invoke);
778
779 // Interceptor returned nothing for this property. Try to use cached
780 // constant function.
781
782 // Check that the maps from interceptor's holder to constant function's
783 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000784 if (*interceptor_holder != lookup->holder()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000785 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000786 Handle<JSObject>(lookup->holder()),
787 scratch1, scratch2, scratch3,
788 name, depth2, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000789 } else {
790 // CheckPrototypes has a side effect of fetching a 'holder'
791 // for API (object which is instanceof for the signature). It's
792 // safe to omit it here, as if present, it should be fetched
793 // by the previous CheckPrototypes.
794 ASSERT(depth2 == kInvalidProtoDepth);
795 }
796
797 // Invoke function.
798 if (can_do_fast_api_call) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000799 GenerateFastApiDirectCall(masm, optimization, arguments_.immediate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000800 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000801 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
802 ? CALL_AS_FUNCTION
803 : CALL_AS_METHOD;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000804 __ InvokeFunction(optimization.constant_function(), arguments_,
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000805 JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000806 }
807
808 // Deferred code for fast API call case---clean preallocated space.
809 if (can_do_fast_api_call) {
810 __ bind(&miss_cleanup);
811 FreeSpaceForFastApiCall(masm);
812 __ Branch(miss_label);
813 }
814
815 // Invoke a regular function.
816 __ bind(&regular_invoke);
817 if (can_do_fast_api_call) {
818 FreeSpaceForFastApiCall(masm);
819 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000820 }
821
822 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000823 Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000824 Register receiver,
825 Register scratch1,
826 Register scratch2,
827 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000828 Handle<String> name,
829 Handle<JSObject> interceptor_holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000830 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000831 Register holder =
832 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000833 scratch1, scratch2, scratch3,
834 name, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000835
836 // Call a runtime function to load the interceptor property.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000837 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000838 // Save the name_ register across the call.
839 __ push(name_);
840
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000841 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000842
843 __ CallExternalReference(
844 ExternalReference(
845 IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
846 masm->isolate()),
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000847 6);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000848 // Restore the name_ register.
849 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000850 // Leave the internal frame.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000851 }
852
853 void LoadWithInterceptor(MacroAssembler* masm,
854 Register receiver,
855 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000856 Handle<JSObject> holder_obj,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000857 Register scratch,
858 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000859 {
860 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000861
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000862 __ Push(holder, name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000863 CompileCallLoadPropertyWithInterceptor(masm,
864 receiver,
865 holder,
866 name_,
867 holder_obj);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000868 __ pop(name_); // Restore the name.
869 __ pop(receiver); // Restore the holder.
870 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000871 // If interceptor returns no-result sentinel, call the constant function.
872 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
873 __ Branch(interceptor_succeeded, ne, v0, Operand(scratch));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000874 }
875
876 StubCompiler* stub_compiler_;
877 const ParameterCount& arguments_;
878 Register name_;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000879 Code::ExtraICState extra_ic_state_;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000880};
881
882
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000883
884// Generate code to check that a global property cell is empty. Create
885// the property cell at compilation time if no cell exists for the
886// property.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000887static void GenerateCheckPropertyCell(MacroAssembler* masm,
888 Handle<GlobalObject> global,
889 Handle<String> name,
890 Register scratch,
891 Label* miss) {
892 Handle<JSGlobalPropertyCell> cell =
893 GlobalObject::EnsurePropertyCell(global, name);
894 ASSERT(cell->value()->IsTheHole());
895 __ li(scratch, Operand(cell));
896 __ lw(scratch,
897 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
898 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
899 __ Branch(miss, ne, scratch, Operand(at));
900}
901
902
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000903// Calls GenerateCheckPropertyCell for each global object in the prototype chain
904// from object to (but not including) holder.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000905static void GenerateCheckPropertyCells(MacroAssembler* masm,
906 Handle<JSObject> object,
907 Handle<JSObject> holder,
908 Handle<String> name,
909 Register scratch,
910 Label* miss) {
911 Handle<JSObject> current = object;
912 while (!current.is_identical_to(holder)) {
913 if (current->IsGlobalObject()) {
914 GenerateCheckPropertyCell(masm,
915 Handle<GlobalObject>::cast(current),
916 name,
917 scratch,
918 miss);
919 }
920 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
921 }
922}
923
924
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000925// Convert and store int passed in register ival to IEEE 754 single precision
926// floating point value at memory location (dst + 4 * wordoffset)
927// If FPU is available use it for conversion.
928static void StoreIntAsFloat(MacroAssembler* masm,
929 Register dst,
930 Register wordoffset,
931 Register ival,
932 Register fval,
933 Register scratch1,
934 Register scratch2) {
935 if (CpuFeatures::IsSupported(FPU)) {
936 CpuFeatures::Scope scope(FPU);
937 __ mtc1(ival, f0);
938 __ cvt_s_w(f0, f0);
939 __ sll(scratch1, wordoffset, 2);
940 __ addu(scratch1, dst, scratch1);
941 __ swc1(f0, MemOperand(scratch1, 0));
942 } else {
943 // FPU is not available, do manual conversions.
944
945 Label not_special, done;
946 // Move sign bit from source to destination. This works because the sign
947 // bit in the exponent word of the double has the same position and polarity
948 // as the 2's complement sign bit in a Smi.
949 ASSERT(kBinary32SignMask == 0x80000000u);
950
951 __ And(fval, ival, Operand(kBinary32SignMask));
952 // Negate value if it is negative.
953 __ subu(scratch1, zero_reg, ival);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +0000954 __ Movn(ival, scratch1, fval);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000955
956 // We have -1, 0 or 1, which we treat specially. Register ival contains
957 // absolute value: it is either equal to 1 (special case of -1 and 1),
958 // greater than 1 (not a special case) or less than 1 (special case of 0).
959 __ Branch(&not_special, gt, ival, Operand(1));
960
961 // For 1 or -1 we need to or in the 0 exponent (biased).
962 static const uint32_t exponent_word_for_1 =
963 kBinary32ExponentBias << kBinary32ExponentShift;
964
965 __ Xor(scratch1, ival, Operand(1));
966 __ li(scratch2, exponent_word_for_1);
967 __ or_(scratch2, fval, scratch2);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +0000968 __ Movz(fval, scratch2, scratch1); // Only if ival is equal to 1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000969 __ Branch(&done);
970
971 __ bind(&not_special);
972 // Count leading zeros.
973 // Gets the wrong answer for 0, but we already checked for that case above.
974 Register zeros = scratch2;
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +0000975 __ Clz(zeros, ival);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000976
977 // Compute exponent and or it into the exponent register.
978 __ li(scratch1, (kBitsPerInt - 1) + kBinary32ExponentBias);
979 __ subu(scratch1, scratch1, zeros);
980
981 __ sll(scratch1, scratch1, kBinary32ExponentShift);
982 __ or_(fval, fval, scratch1);
983
984 // Shift up the source chopping the top bit off.
985 __ Addu(zeros, zeros, Operand(1));
986 // This wouldn't work for 1 and -1 as the shift would be 32 which means 0.
987 __ sllv(ival, ival, zeros);
988 // And the top (top 20 bits).
989 __ srl(scratch1, ival, kBitsPerInt - kBinary32MantissaBits);
990 __ or_(fval, fval, scratch1);
991
992 __ bind(&done);
993
994 __ sll(scratch1, wordoffset, 2);
995 __ addu(scratch1, dst, scratch1);
996 __ sw(fval, MemOperand(scratch1, 0));
997 }
998}
999
1000
1001// Convert unsigned integer with specified number of leading zeroes in binary
1002// representation to IEEE 754 double.
1003// Integer to convert is passed in register hiword.
1004// Resulting double is returned in registers hiword:loword.
1005// This functions does not work correctly for 0.
1006static void GenerateUInt2Double(MacroAssembler* masm,
1007 Register hiword,
1008 Register loword,
1009 Register scratch,
1010 int leading_zeroes) {
1011 const int meaningful_bits = kBitsPerInt - leading_zeroes - 1;
1012 const int biased_exponent = HeapNumber::kExponentBias + meaningful_bits;
1013
1014 const int mantissa_shift_for_hi_word =
1015 meaningful_bits - HeapNumber::kMantissaBitsInTopWord;
1016
1017 const int mantissa_shift_for_lo_word =
1018 kBitsPerInt - mantissa_shift_for_hi_word;
1019
1020 __ li(scratch, biased_exponent << HeapNumber::kExponentShift);
1021 if (mantissa_shift_for_hi_word > 0) {
1022 __ sll(loword, hiword, mantissa_shift_for_lo_word);
1023 __ srl(hiword, hiword, mantissa_shift_for_hi_word);
1024 __ or_(hiword, scratch, hiword);
1025 } else {
1026 __ mov(loword, zero_reg);
1027 __ sll(hiword, hiword, mantissa_shift_for_hi_word);
1028 __ or_(hiword, scratch, hiword);
1029 }
1030
1031 // If least significant bit of biased exponent was not 1 it was corrupted
1032 // by most significant bit of mantissa so we should fix that.
1033 if (!(biased_exponent & 1)) {
1034 __ li(scratch, 1 << HeapNumber::kExponentShift);
1035 __ nor(scratch, scratch, scratch);
1036 __ and_(hiword, hiword, scratch);
1037 }
1038}
1039
1040
ager@chromium.org5c838252010-02-19 08:53:10 +00001041#undef __
1042#define __ ACCESS_MASM(masm())
1043
1044
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001045Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
1046 Register object_reg,
1047 Handle<JSObject> holder,
1048 Register holder_reg,
1049 Register scratch1,
1050 Register scratch2,
1051 Handle<String> name,
1052 int save_at_depth,
1053 Label* miss) {
1054 // Make sure there's no overlap between holder and object registers.
1055 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1056 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1057 && !scratch2.is(scratch1));
1058
1059 // Keep track of the current object in register reg.
1060 Register reg = object_reg;
1061 int depth = 0;
1062
1063 if (save_at_depth == depth) {
1064 __ sw(reg, MemOperand(sp));
1065 }
1066
1067 // Check the maps in the prototype chain.
1068 // Traverse the prototype chain from the object and do map checks.
1069 Handle<JSObject> current = object;
1070 while (!current.is_identical_to(holder)) {
1071 ++depth;
1072
1073 // Only global objects and objects that do not require access
1074 // checks are allowed in stubs.
1075 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1076
1077 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
1078 if (!current->HasFastProperties() &&
1079 !current->IsJSGlobalObject() &&
1080 !current->IsJSGlobalProxy()) {
1081 if (!name->IsSymbol()) {
1082 name = factory()->LookupSymbol(name);
1083 }
1084 ASSERT(current->property_dictionary()->FindEntry(*name) ==
1085 StringDictionary::kNotFound);
1086
1087 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1088 scratch1, scratch2);
1089
1090 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1091 reg = holder_reg; // From now on the object will be in holder_reg.
1092 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1093 } else {
1094 Handle<Map> current_map(current->map());
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001095 __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK,
1096 ALLOW_ELEMENT_TRANSITION_MAPS);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001097 // Check access rights to the global object. This has to happen after
1098 // the map check so that we know that the object is actually a global
1099 // object.
1100 if (current->IsJSGlobalProxy()) {
1101 __ CheckAccessGlobalProxy(reg, scratch2, miss);
1102 }
1103 reg = holder_reg; // From now on the object will be in holder_reg.
1104
1105 if (heap()->InNewSpace(*prototype)) {
1106 // The prototype is in new space; we cannot store a reference to it
1107 // in the code. Load it from the map.
1108 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1109 } else {
1110 // The prototype is in old space; load it directly.
1111 __ li(reg, Operand(prototype));
1112 }
1113 }
1114
1115 if (save_at_depth == depth) {
1116 __ sw(reg, MemOperand(sp));
1117 }
1118
1119 // Go to the next object in the prototype chain.
1120 current = prototype;
1121 }
1122
1123 // Log the check depth.
1124 LOG(masm()->isolate(), IntEvent("check-maps-depth", depth + 1));
1125
1126 // Check the holder map.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001127 __ CheckMap(reg, scratch1, Handle<Map>(current->map()), miss,
1128 DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001129
1130 // Perform security check for access to the global object.
1131 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1132 if (holder->IsJSGlobalProxy()) {
1133 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1134 }
1135
1136 // If we've skipped any global objects, it's not enough to verify that
1137 // their maps haven't changed. We also need to check that the property
1138 // cell for the property is still empty.
1139 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1140
1141 // Return the register containing the holder.
1142 return reg;
1143}
1144
1145
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001146void StubCompiler::GenerateLoadField(Handle<JSObject> object,
1147 Handle<JSObject> holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001148 Register receiver,
1149 Register scratch1,
1150 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001151 Register scratch3,
ager@chromium.org5c838252010-02-19 08:53:10 +00001152 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001153 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001154 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001155 // Check that the receiver isn't a smi.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001156 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001157
1158 // Check that the maps haven't changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001159 Register reg = CheckPrototypes(
1160 object, receiver, holder, scratch1, scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001161 GenerateFastPropertyLoad(masm(), v0, reg, holder, index);
1162 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001163}
1164
1165
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001166void StubCompiler::GenerateLoadConstant(Handle<JSObject> object,
1167 Handle<JSObject> holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001168 Register receiver,
1169 Register scratch1,
1170 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001171 Register scratch3,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001172 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001173 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001174 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001175 // Check that the receiver isn't a smi.
1176 __ JumpIfSmi(receiver, miss, scratch1);
1177
1178 // Check that the maps haven't changed.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001179 CheckPrototypes(object, receiver, holder,
1180 scratch1, scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001181
1182 // Return the constant value.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001183 __ LoadHeapObject(v0, value);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001184 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001185}
1186
1187
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001188void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
1189 Handle<JSObject> holder,
1190 Register receiver,
1191 Register name_reg,
1192 Register scratch1,
1193 Register scratch2,
1194 Register scratch3,
1195 Handle<AccessorInfo> callback,
1196 Handle<String> name,
1197 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001198 // Check that the receiver isn't a smi.
1199 __ JumpIfSmi(receiver, miss, scratch1);
1200
1201 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001202 Register reg = CheckPrototypes(object, receiver, holder, scratch1,
1203 scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001204
1205 // Build AccessorInfo::args_ list on the stack and push property name below
1206 // the exit frame to make GC aware of them and store pointers to them.
1207 __ push(receiver);
1208 __ mov(scratch2, sp); // scratch2 = AccessorInfo::args_
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001209 if (heap()->InNewSpace(callback->data())) {
1210 __ li(scratch3, callback);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001211 __ lw(scratch3, FieldMemOperand(scratch3, AccessorInfo::kDataOffset));
1212 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001213 __ li(scratch3, Handle<Object>(callback->data()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001214 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001215 __ Subu(sp, sp, 4 * kPointerSize);
1216 __ sw(reg, MemOperand(sp, 3 * kPointerSize));
1217 __ sw(scratch3, MemOperand(sp, 2 * kPointerSize));
1218 __ li(scratch3, Operand(ExternalReference::isolate_address()));
1219 __ sw(scratch3, MemOperand(sp, 1 * kPointerSize));
1220 __ sw(name_reg, MemOperand(sp, 0 * kPointerSize));
1221
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001222 __ mov(a2, scratch2); // Saved in case scratch2 == a1.
1223 __ mov(a1, sp); // a1 (first argument - see note below) = Handle<String>
1224
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001225 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
1226 // struct from the function (which is currently the case). This means we pass
1227 // the arguments in a1-a2 instead of a0-a1. TryCallApiFunctionAndReturn
1228 // will handle setting up a0.
1229
1230 const int kApiStackSpace = 1;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001231 FrameScope frame_scope(masm(), StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001232 __ EnterExitFrame(false, kApiStackSpace);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001233
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001234 // Create AccessorInfo instance on the stack above the exit frame with
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001235 // scratch2 (internal::Object** args_) as the data.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001236 __ sw(a2, MemOperand(sp, kPointerSize));
1237 // a2 (second argument - see note above) = AccessorInfo&
1238 __ Addu(a2, sp, kPointerSize);
1239
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001240 const int kStackUnwindSpace = 5;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001241 Address getter_address = v8::ToCData<Address>(callback->getter());
1242 ApiFunction fun(getter_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001243 ExternalReference ref =
1244 ExternalReference(&fun,
1245 ExternalReference::DIRECT_GETTER_CALL,
1246 masm()->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001247 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
ager@chromium.org5c838252010-02-19 08:53:10 +00001248}
1249
1250
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001251void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
1252 Handle<JSObject> interceptor_holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001253 LookupResult* lookup,
1254 Register receiver,
1255 Register name_reg,
1256 Register scratch1,
1257 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001258 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001259 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001260 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001261 ASSERT(interceptor_holder->HasNamedInterceptor());
1262 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1263
1264 // Check that the receiver isn't a smi.
1265 __ JumpIfSmi(receiver, miss);
1266
1267 // So far the most popular follow ups for interceptor loads are FIELD
1268 // and CALLBACKS, so inline only them, other cases may be added
1269 // later.
1270 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001271 if (lookup->IsFound() && lookup->IsCacheable()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001272 if (lookup->type() == FIELD) {
1273 compile_followup_inline = true;
1274 } else if (lookup->type() == CALLBACKS &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001275 lookup->GetCallbackObject()->IsAccessorInfo()) {
1276 compile_followup_inline =
1277 AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001278 }
1279 }
1280
1281 if (compile_followup_inline) {
1282 // Compile the interceptor call, followed by inline code to load the
1283 // property from further up the prototype chain if the call fails.
1284 // Check that the maps haven't changed.
1285 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1286 scratch1, scratch2, scratch3,
1287 name, miss);
1288 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
1289
1290 // Save necessary data before invoking an interceptor.
1291 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001292 {
1293 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001294 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
1295 // CALLBACKS case needs a receiver to be passed into C++ callback.
1296 __ Push(receiver, holder_reg, name_reg);
1297 } else {
1298 __ Push(holder_reg, name_reg);
1299 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001300 // Invoke an interceptor. Note: map checks from receiver to
1301 // interceptor's holder has been compiled before (see a caller
1302 // of this method).
1303 CompileCallLoadPropertyWithInterceptor(masm(),
1304 receiver,
1305 holder_reg,
1306 name_reg,
1307 interceptor_holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001308 // Check if interceptor provided a value for property. If it's
1309 // the case, return immediately.
1310 Label interceptor_failed;
1311 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
1312 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1));
1313 frame_scope.GenerateLeaveFrame();
1314 __ Ret();
1315
1316 __ bind(&interceptor_failed);
1317 __ pop(name_reg);
1318 __ pop(holder_reg);
1319 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
1320 __ pop(receiver);
1321 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001322 // Leave the internal frame.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001323 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001324 // Check that the maps from interceptor's holder to lookup's holder
1325 // haven't changed. And load lookup's holder into |holder| register.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001326 if (*interceptor_holder != lookup->holder()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001327 holder_reg = CheckPrototypes(interceptor_holder,
1328 holder_reg,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001329 Handle<JSObject>(lookup->holder()),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001330 scratch1,
1331 scratch2,
1332 scratch3,
1333 name,
1334 miss);
1335 }
1336
1337 if (lookup->type() == FIELD) {
1338 // We found FIELD property in prototype chain of interceptor's holder.
1339 // Retrieve a field from field's holder.
1340 GenerateFastPropertyLoad(masm(), v0, holder_reg,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001341 Handle<JSObject>(lookup->holder()),
1342 lookup->GetFieldIndex());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001343 __ Ret();
1344 } else {
1345 // We found CALLBACKS property in prototype chain of interceptor's
1346 // holder.
1347 ASSERT(lookup->type() == CALLBACKS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001348 Handle<AccessorInfo> callback(
1349 AccessorInfo::cast(lookup->GetCallbackObject()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001350 ASSERT(callback->getter() != NULL);
1351
1352 // Tail call to runtime.
1353 // Important invariant in CALLBACKS case: the code above must be
1354 // structured to never clobber |receiver| register.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001355 __ li(scratch2, callback);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001356
1357 __ Push(receiver, holder_reg);
1358 __ lw(scratch3,
1359 FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
1360 __ li(scratch1, Operand(ExternalReference::isolate_address()));
1361 __ Push(scratch3, scratch1, scratch2, name_reg);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001362
1363 ExternalReference ref =
1364 ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
1365 masm()->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001366 __ TailCallExternalReference(ref, 6, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001367 }
1368 } else { // !compile_followup_inline
1369 // Call the runtime system to load the interceptor.
1370 // Check that the maps haven't changed.
1371 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1372 scratch1, scratch2, scratch3,
1373 name, miss);
1374 PushInterceptorArguments(masm(), receiver, holder_reg,
1375 name_reg, interceptor_holder);
1376
1377 ExternalReference ref = ExternalReference(
1378 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), masm()->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001379 __ TailCallExternalReference(ref, 6, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001380 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001381}
1382
1383
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001384void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001385 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001386 __ Branch(miss, ne, a2, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001387 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001388}
1389
1390
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001391void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1392 Handle<JSObject> holder,
1393 Handle<String> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001394 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001395 ASSERT(holder->IsGlobalObject());
1396
1397 // Get the number of arguments.
1398 const int argc = arguments().immediate();
1399
1400 // Get the receiver from the stack.
1401 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1402
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001403 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001404 __ JumpIfSmi(a0, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001405 CheckPrototypes(object, a0, holder, a3, a1, t0, name, miss);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001406}
1407
1408
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001409void CallStubCompiler::GenerateLoadFunctionFromCell(
1410 Handle<JSGlobalPropertyCell> cell,
1411 Handle<JSFunction> function,
1412 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001413 // Get the value from the cell.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001414 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001415 __ lw(a1, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
1416
1417 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001418 if (heap()->InNewSpace(*function)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001419 // We can't embed a pointer to a function in new space so we have
1420 // to verify that the shared function info is unchanged. This has
1421 // the nice side effect that multiple closures based on the same
1422 // function can all use this call IC. Before we load through the
1423 // function, we have to verify that it still is a function.
1424 __ JumpIfSmi(a1, miss);
1425 __ GetObjectType(a1, a3, a3);
1426 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
1427
1428 // Check the shared function info. Make sure it hasn't changed.
1429 __ li(a3, Handle<SharedFunctionInfo>(function->shared()));
1430 __ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
1431 __ Branch(miss, ne, t0, Operand(a3));
1432 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001433 __ Branch(miss, ne, a1, Operand(function));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001434 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001435}
1436
1437
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001438void CallStubCompiler::GenerateMissBranch() {
1439 Handle<Code> code =
danno@chromium.org40cb8782011-05-25 07:58:50 +00001440 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1441 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001442 extra_state_);
1443 __ Jump(code, RelocInfo::CODE_TARGET);
1444}
1445
1446
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001447Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1448 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001449 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001450 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001451 // ----------- S t a t e -------------
1452 // -- a2 : name
1453 // -- ra : return address
1454 // -----------------------------------
1455 Label miss;
1456
1457 GenerateNameCheck(name, &miss);
1458
1459 const int argc = arguments().immediate();
1460
1461 // Get the receiver of the function from the stack into a0.
1462 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1463 // Check that the receiver isn't a smi.
1464 __ JumpIfSmi(a0, &miss, t0);
1465
1466 // Do the right check and compute the holder register.
1467 Register reg = CheckPrototypes(object, a0, holder, a1, a3, t0, name, &miss);
1468 GenerateFastPropertyLoad(masm(), a1, reg, holder, index);
1469
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001470 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001471
1472 // Handle call cache miss.
1473 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001474 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001475
1476 // Return the generated code.
1477 return GetCode(FIELD, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001478}
1479
1480
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001481Handle<Code> CallStubCompiler::CompileArrayPushCall(
1482 Handle<Object> object,
1483 Handle<JSObject> holder,
1484 Handle<JSGlobalPropertyCell> cell,
1485 Handle<JSFunction> function,
1486 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001487 // ----------- S t a t e -------------
1488 // -- a2 : name
1489 // -- ra : return address
1490 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1491 // -- ...
1492 // -- sp[argc * 4] : receiver
1493 // -----------------------------------
1494
1495 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001496 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001497
1498 Label miss;
1499
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001500 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001501
1502 Register receiver = a1;
1503
1504 // Get the receiver from the stack.
1505 const int argc = arguments().immediate();
1506 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1507
1508 // Check that the receiver isn't a smi.
1509 __ JumpIfSmi(receiver, &miss);
1510
1511 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001512 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, a3, v0, t0,
1513 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001514
1515 if (argc == 0) {
1516 // Nothing to do, just return the length.
1517 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1518 __ Drop(argc + 1);
1519 __ Ret();
1520 } else {
1521 Label call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001522 if (argc == 1) { // Otherwise fall through to call the builtin.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001523 Label attempt_to_grow_elements;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001524
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001525 Register elements = t2;
1526 Register end_elements = t1;
1527 // Get the elements array of the object.
1528 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1529
1530 // Check that the elements are in fast mode and writable.
1531 __ CheckMap(elements,
1532 v0,
1533 Heap::kFixedArrayMapRootIndex,
1534 &call_builtin,
1535 DONT_DO_SMI_CHECK);
1536
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001537 // Get the array's length into v0 and calculate new length.
1538 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1539 STATIC_ASSERT(kSmiTagSize == 1);
1540 STATIC_ASSERT(kSmiTag == 0);
1541 __ Addu(v0, v0, Operand(Smi::FromInt(argc)));
1542
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001543 // Get the elements' length.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001544 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1545
1546 // Check if we could survive without allocation.
1547 __ Branch(&attempt_to_grow_elements, gt, v0, Operand(t0));
1548
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001549 // Check if value is a smi.
1550 Label with_write_barrier;
1551 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1552 __ JumpIfNotSmi(t0, &with_write_barrier);
1553
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001554 // Save new length.
1555 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1556
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001557 // Store the value.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001558 // We may need a register containing the address end_elements below,
1559 // so write back the value in end_elements.
1560 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1561 __ Addu(end_elements, elements, end_elements);
1562 const int kEndElementsOffset =
1563 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001564 __ Addu(end_elements, end_elements, kEndElementsOffset);
1565 __ sw(t0, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001566
1567 // Check for a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001568 __ Drop(argc + 1);
1569 __ Ret();
1570
1571 __ bind(&with_write_barrier);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001572
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001573 __ lw(a3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1574
1575 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
1576 Label fast_object, not_fast_object;
1577 __ CheckFastObjectElements(a3, t3, &not_fast_object);
1578 __ jmp(&fast_object);
1579 // In case of fast smi-only, convert to fast object, otherwise bail out.
1580 __ bind(&not_fast_object);
1581 __ CheckFastSmiOnlyElements(a3, t3, &call_builtin);
1582 // edx: receiver
1583 // r3: map
1584 __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
1585 FAST_ELEMENTS,
1586 a3,
1587 t3,
1588 &call_builtin);
1589 __ mov(a2, receiver);
1590 ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm());
1591 __ bind(&fast_object);
1592 } else {
1593 __ CheckFastObjectElements(a3, a3, &call_builtin);
1594 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001595
1596 // Save new length.
1597 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1598
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001599 // Store the value.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001600 // We may need a register containing the address end_elements below,
1601 // so write back the value in end_elements.
1602 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1603 __ Addu(end_elements, elements, end_elements);
1604 __ Addu(end_elements, end_elements, kEndElementsOffset);
1605 __ sw(t0, MemOperand(end_elements));
1606
1607 __ RecordWrite(elements,
1608 end_elements,
1609 t0,
1610 kRAHasNotBeenSaved,
1611 kDontSaveFPRegs,
1612 EMIT_REMEMBERED_SET,
1613 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001614 __ Drop(argc + 1);
1615 __ Ret();
1616
1617 __ bind(&attempt_to_grow_elements);
1618 // v0: array's length + 1.
1619 // t0: elements' length.
1620
1621 if (!FLAG_inline_new) {
1622 __ Branch(&call_builtin);
1623 }
1624
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001625 __ lw(a2, MemOperand(sp, (argc - 1) * kPointerSize));
1626 // Growing elements that are SMI-only requires special handling in case
1627 // the new element is non-Smi. For now, delegate to the builtin.
1628 Label no_fast_elements_check;
1629 __ JumpIfSmi(a2, &no_fast_elements_check);
1630 __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1631 __ CheckFastObjectElements(t3, t3, &call_builtin);
1632 __ bind(&no_fast_elements_check);
1633
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001634 ExternalReference new_space_allocation_top =
1635 ExternalReference::new_space_allocation_top_address(
1636 masm()->isolate());
1637 ExternalReference new_space_allocation_limit =
1638 ExternalReference::new_space_allocation_limit_address(
1639 masm()->isolate());
1640
1641 const int kAllocationDelta = 4;
1642 // Load top and check if it is the end of elements.
1643 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1644 __ Addu(end_elements, elements, end_elements);
1645 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset));
1646 __ li(t3, Operand(new_space_allocation_top));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001647 __ lw(a3, MemOperand(t3));
1648 __ Branch(&call_builtin, ne, end_elements, Operand(a3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001649
1650 __ li(t5, Operand(new_space_allocation_limit));
1651 __ lw(t5, MemOperand(t5));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001652 __ Addu(a3, a3, Operand(kAllocationDelta * kPointerSize));
1653 __ Branch(&call_builtin, hi, a3, Operand(t5));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001654
1655 // We fit and could grow elements.
1656 // Update new_space_allocation_top.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001657 __ sw(a3, MemOperand(t3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001658 // Push the argument.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001659 __ sw(a2, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001660 // Fill the rest with holes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001661 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001662 for (int i = 1; i < kAllocationDelta; i++) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001663 __ sw(a3, MemOperand(end_elements, i * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001664 }
1665
1666 // Update elements' and array's sizes.
1667 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1668 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta)));
1669 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1670
1671 // Elements are in new space, so write barrier is not required.
1672 __ Drop(argc + 1);
1673 __ Ret();
1674 }
1675 __ bind(&call_builtin);
1676 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
1677 masm()->isolate()),
1678 argc + 1,
1679 1);
1680 }
1681
1682 // Handle call cache miss.
1683 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001684 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001685
1686 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001687 return GetCode(function);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001688}
1689
1690
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001691Handle<Code> CallStubCompiler::CompileArrayPopCall(
1692 Handle<Object> object,
1693 Handle<JSObject> holder,
1694 Handle<JSGlobalPropertyCell> cell,
1695 Handle<JSFunction> function,
1696 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001697 // ----------- S t a t e -------------
1698 // -- a2 : name
1699 // -- ra : return address
1700 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1701 // -- ...
1702 // -- sp[argc * 4] : receiver
1703 // -----------------------------------
1704
1705 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001706 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001707
1708 Label miss, return_undefined, call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001709 Register receiver = a1;
1710 Register elements = a3;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001711 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001712
1713 // Get the receiver from the stack.
1714 const int argc = arguments().immediate();
1715 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001716 // Check that the receiver isn't a smi.
1717 __ JumpIfSmi(receiver, &miss);
1718
1719 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001720 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, elements,
1721 t0, v0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001722
1723 // Get the elements array of the object.
1724 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1725
1726 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001727 __ CheckMap(elements,
1728 v0,
1729 Heap::kFixedArrayMapRootIndex,
1730 &call_builtin,
1731 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001732
1733 // Get the array's length into t0 and calculate new length.
1734 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1735 __ Subu(t0, t0, Operand(Smi::FromInt(1)));
1736 __ Branch(&return_undefined, lt, t0, Operand(zero_reg));
1737
1738 // Get the last element.
1739 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1740 STATIC_ASSERT(kSmiTagSize == 1);
1741 STATIC_ASSERT(kSmiTag == 0);
1742 // We can't address the last element in one operation. Compute the more
1743 // expensive shift first, and use an offset later on.
1744 __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize);
1745 __ Addu(elements, elements, t1);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001746 __ lw(v0, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001747 __ Branch(&call_builtin, eq, v0, Operand(t2));
1748
1749 // Set the array's length.
1750 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1751
1752 // Fill with the hole.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001753 __ sw(t2, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001754 __ Drop(argc + 1);
1755 __ Ret();
1756
1757 __ bind(&return_undefined);
1758 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
1759 __ Drop(argc + 1);
1760 __ Ret();
1761
1762 __ bind(&call_builtin);
1763 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop,
1764 masm()->isolate()),
1765 argc + 1,
1766 1);
1767
1768 // Handle call cache miss.
1769 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001770 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001771
1772 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001773 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001774}
1775
1776
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001777Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1778 Handle<Object> object,
1779 Handle<JSObject> holder,
1780 Handle<JSGlobalPropertyCell> cell,
1781 Handle<JSFunction> function,
1782 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001783 // ----------- S t a t e -------------
1784 // -- a2 : function name
1785 // -- ra : return address
1786 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1787 // -- ...
1788 // -- sp[argc * 4] : receiver
1789 // -----------------------------------
1790
1791 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001792 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001793
1794 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001795 Label miss;
1796 Label name_miss;
1797 Label index_out_of_range;
1798
1799 Label* index_out_of_range_label = &index_out_of_range;
1800
danno@chromium.org40cb8782011-05-25 07:58:50 +00001801 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001802 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001803 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001804 index_out_of_range_label = &miss;
1805 }
1806
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001807 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001808
1809 // Check that the maps starting from the prototype haven't changed.
1810 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1811 Context::STRING_FUNCTION_INDEX,
1812 v0,
1813 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001814 ASSERT(!object.is_identical_to(holder));
1815 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1816 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001817
1818 Register receiver = a1;
1819 Register index = t1;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001820 Register result = v0;
1821 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1822 if (argc > 0) {
1823 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1824 } else {
1825 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1826 }
1827
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001828 StringCharCodeAtGenerator generator(receiver,
1829 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001830 result,
1831 &miss, // When not a string.
1832 &miss, // When not a number.
1833 index_out_of_range_label,
1834 STRING_INDEX_IS_NUMBER);
1835 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001836 __ Drop(argc + 1);
1837 __ Ret();
1838
1839 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001840 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001841
1842 if (index_out_of_range.is_linked()) {
1843 __ bind(&index_out_of_range);
1844 __ LoadRoot(v0, Heap::kNanValueRootIndex);
1845 __ Drop(argc + 1);
1846 __ Ret();
1847 }
1848
1849 __ bind(&miss);
1850 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001851 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001852 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001853 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001854
1855 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001856 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001857}
1858
1859
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001860Handle<Code> CallStubCompiler::CompileStringCharAtCall(
1861 Handle<Object> object,
1862 Handle<JSObject> holder,
1863 Handle<JSGlobalPropertyCell> cell,
1864 Handle<JSFunction> function,
1865 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001866 // ----------- S t a t e -------------
1867 // -- a2 : function name
1868 // -- ra : return address
1869 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1870 // -- ...
1871 // -- sp[argc * 4] : receiver
1872 // -----------------------------------
1873
1874 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001875 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001876
1877 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001878 Label miss;
1879 Label name_miss;
1880 Label index_out_of_range;
1881 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00001882 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001883 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001884 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001885 index_out_of_range_label = &miss;
1886 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001887 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001888
1889 // Check that the maps starting from the prototype haven't changed.
1890 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1891 Context::STRING_FUNCTION_INDEX,
1892 v0,
1893 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001894 ASSERT(!object.is_identical_to(holder));
1895 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1896 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001897
1898 Register receiver = v0;
1899 Register index = t1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001900 Register scratch = a3;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001901 Register result = v0;
1902 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1903 if (argc > 0) {
1904 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1905 } else {
1906 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1907 }
1908
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001909 StringCharAtGenerator generator(receiver,
1910 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00001911 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001912 result,
1913 &miss, // When not a string.
1914 &miss, // When not a number.
1915 index_out_of_range_label,
1916 STRING_INDEX_IS_NUMBER);
1917 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001918 __ Drop(argc + 1);
1919 __ Ret();
1920
1921 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001922 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001923
1924 if (index_out_of_range.is_linked()) {
1925 __ bind(&index_out_of_range);
1926 __ LoadRoot(v0, Heap::kEmptyStringRootIndex);
1927 __ Drop(argc + 1);
1928 __ Ret();
1929 }
1930
1931 __ bind(&miss);
1932 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001933 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001934 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001935 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001936
1937 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001938 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001939}
1940
1941
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001942Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
1943 Handle<Object> object,
1944 Handle<JSObject> holder,
1945 Handle<JSGlobalPropertyCell> cell,
1946 Handle<JSFunction> function,
1947 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001948 // ----------- S t a t e -------------
1949 // -- a2 : function name
1950 // -- ra : return address
1951 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1952 // -- ...
1953 // -- sp[argc * 4] : receiver
1954 // -----------------------------------
1955
1956 const int argc = arguments().immediate();
1957
1958 // If the object is not a JSObject or we got an unexpected number of
1959 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001960 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001961
1962 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001963 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001964
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001965 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001966 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
1967
1968 STATIC_ASSERT(kSmiTag == 0);
1969 __ JumpIfSmi(a1, &miss);
1970
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001971 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
1972 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001973 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001974 ASSERT(cell->value() == *function);
1975 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
1976 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001977 GenerateLoadFunctionFromCell(cell, function, &miss);
1978 }
1979
1980 // Load the char code argument.
1981 Register code = a1;
1982 __ lw(code, MemOperand(sp, 0 * kPointerSize));
1983
1984 // Check the code is a smi.
1985 Label slow;
1986 STATIC_ASSERT(kSmiTag == 0);
1987 __ JumpIfNotSmi(code, &slow);
1988
1989 // Convert the smi code to uint16.
1990 __ And(code, code, Operand(Smi::FromInt(0xffff)));
1991
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001992 StringCharFromCodeGenerator generator(code, v0);
1993 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001994 __ Drop(argc + 1);
1995 __ Ret();
1996
1997 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001998 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001999
2000 // Tail call the full function. We do not have to patch the receiver
2001 // because the function makes no use of it.
2002 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002003 __ InvokeFunction(
2004 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002005
2006 __ bind(&miss);
2007 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002008 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002009
2010 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002011 return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002012}
2013
2014
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002015Handle<Code> CallStubCompiler::CompileMathFloorCall(
2016 Handle<Object> object,
2017 Handle<JSObject> holder,
2018 Handle<JSGlobalPropertyCell> cell,
2019 Handle<JSFunction> function,
2020 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002021 // ----------- S t a t e -------------
2022 // -- a2 : function name
2023 // -- ra : return address
2024 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2025 // -- ...
2026 // -- sp[argc * 4] : receiver
2027 // -----------------------------------
2028
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002029 if (!CpuFeatures::IsSupported(FPU)) {
2030 return Handle<Code>::null();
2031 }
2032
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002033 CpuFeatures::Scope scope_fpu(FPU);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002034 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002035 // If the object is not a JSObject or we got an unexpected number of
2036 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002037 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002038
2039 Label miss, slow;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002040 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002041
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002042 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002043 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002044 STATIC_ASSERT(kSmiTag == 0);
2045 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002046 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2047 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002048 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002049 ASSERT(cell->value() == *function);
2050 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2051 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002052 GenerateLoadFunctionFromCell(cell, function, &miss);
2053 }
2054
2055 // Load the (only) argument into v0.
2056 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2057
2058 // If the argument is a smi, just return.
2059 STATIC_ASSERT(kSmiTag == 0);
2060 __ And(t0, v0, Operand(kSmiTagMask));
2061 __ Drop(argc + 1, eq, t0, Operand(zero_reg));
2062 __ Ret(eq, t0, Operand(zero_reg));
2063
danno@chromium.org40cb8782011-05-25 07:58:50 +00002064 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002065
2066 Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return;
2067
2068 // If fpu is enabled, we use the floor instruction.
2069
2070 // Load the HeapNumber value.
2071 __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2072
2073 // Backup FCSR.
2074 __ cfc1(a3, FCSR);
2075 // Clearing FCSR clears the exception mask with no side-effects.
2076 __ ctc1(zero_reg, FCSR);
2077 // Convert the argument to an integer.
2078 __ floor_w_d(f0, f0);
2079
2080 // Start checking for special cases.
2081 // Get the argument exponent and clear the sign bit.
2082 __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize));
2083 __ And(t2, t1, Operand(~HeapNumber::kSignMask));
2084 __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord);
2085
2086 // Retrieve FCSR and check for fpu errors.
2087 __ cfc1(t5, FCSR);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002088 __ And(t5, t5, Operand(kFCSRExceptionFlagMask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002089 __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));
2090
2091 // Check for NaN, Infinity, and -Infinity.
2092 // They are invariant through a Math.Floor call, so just
2093 // return the original argument.
2094 __ Subu(t3, t2, Operand(HeapNumber::kExponentMask
2095 >> HeapNumber::kMantissaBitsInTopWord));
2096 __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg));
2097 // We had an overflow or underflow in the conversion. Check if we
2098 // have a big exponent.
2099 // If greater or equal, the argument is already round and in v0.
2100 __ Branch(&restore_fcsr_and_return, ge, t3,
2101 Operand(HeapNumber::kMantissaBits));
2102 __ Branch(&wont_fit_smi);
2103
2104 __ bind(&no_fpu_error);
2105 // Move the result back to v0.
2106 __ mfc1(v0, f0);
2107 // Check if the result fits into a smi.
2108 __ Addu(a1, v0, Operand(0x40000000));
2109 __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg));
2110 // Tag the result.
2111 STATIC_ASSERT(kSmiTag == 0);
2112 __ sll(v0, v0, kSmiTagSize);
2113
2114 // Check for -0.
2115 __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg));
2116 // t1 already holds the HeapNumber exponent.
2117 __ And(t0, t1, Operand(HeapNumber::kSignMask));
2118 // If our HeapNumber is negative it was -0, so load its address and return.
2119 // Else v0 is loaded with 0, so we can also just return.
2120 __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg));
2121 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2122
2123 __ bind(&restore_fcsr_and_return);
2124 // Restore FCSR and return.
2125 __ ctc1(a3, FCSR);
2126
2127 __ Drop(argc + 1);
2128 __ Ret();
2129
2130 __ bind(&wont_fit_smi);
2131 // Restore FCSR and fall to slow case.
2132 __ ctc1(a3, FCSR);
2133
2134 __ bind(&slow);
2135 // Tail call the full function. We do not have to patch the receiver
2136 // because the function makes no use of it.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002137 __ InvokeFunction(
2138 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002139
2140 __ bind(&miss);
2141 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002142 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002143
2144 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002145 return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002146}
2147
2148
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002149Handle<Code> CallStubCompiler::CompileMathAbsCall(
2150 Handle<Object> object,
2151 Handle<JSObject> holder,
2152 Handle<JSGlobalPropertyCell> cell,
2153 Handle<JSFunction> function,
2154 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002155 // ----------- S t a t e -------------
2156 // -- a2 : function name
2157 // -- ra : return address
2158 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2159 // -- ...
2160 // -- sp[argc * 4] : receiver
2161 // -----------------------------------
2162
2163 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002164 // If the object is not a JSObject or we got an unexpected number of
2165 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002166 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002167
2168 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002169
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002170 GenerateNameCheck(name, &miss);
2171 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002172 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002173 STATIC_ASSERT(kSmiTag == 0);
2174 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002175 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2176 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002177 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002178 ASSERT(cell->value() == *function);
2179 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2180 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002181 GenerateLoadFunctionFromCell(cell, function, &miss);
2182 }
2183
2184 // Load the (only) argument into v0.
2185 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2186
2187 // Check if the argument is a smi.
2188 Label not_smi;
2189 STATIC_ASSERT(kSmiTag == 0);
2190 __ JumpIfNotSmi(v0, &not_smi);
2191
2192 // Do bitwise not or do nothing depending on the sign of the
2193 // argument.
2194 __ sra(t0, v0, kBitsPerInt - 1);
2195 __ Xor(a1, v0, t0);
2196
2197 // Add 1 or do nothing depending on the sign of the argument.
2198 __ Subu(v0, a1, t0);
2199
2200 // If the result is still negative, go to the slow case.
2201 // This only happens for the most negative smi.
2202 Label slow;
2203 __ Branch(&slow, lt, v0, Operand(zero_reg));
2204
2205 // Smi case done.
2206 __ Drop(argc + 1);
2207 __ Ret();
2208
2209 // Check if the argument is a heap number and load its exponent and
2210 // sign.
2211 __ bind(&not_smi);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002212 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002213 __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2214
2215 // Check the sign of the argument. If the argument is positive,
2216 // just return it.
2217 Label negative_sign;
2218 __ And(t0, a1, Operand(HeapNumber::kSignMask));
2219 __ Branch(&negative_sign, ne, t0, Operand(zero_reg));
2220 __ Drop(argc + 1);
2221 __ Ret();
2222
2223 // If the argument is negative, clear the sign, and return a new
2224 // number.
2225 __ bind(&negative_sign);
2226 __ Xor(a1, a1, Operand(HeapNumber::kSignMask));
2227 __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2228 __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
2229 __ AllocateHeapNumber(v0, t0, t1, t2, &slow);
2230 __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2231 __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2232 __ Drop(argc + 1);
2233 __ Ret();
2234
2235 // Tail call the full function. We do not have to patch the receiver
2236 // because the function makes no use of it.
2237 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002238 __ InvokeFunction(
2239 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002240
2241 __ bind(&miss);
2242 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002243 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002244
2245 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002246 return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002247}
2248
2249
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002250Handle<Code> CallStubCompiler::CompileFastApiCall(
lrn@chromium.org7516f052011-03-30 08:52:27 +00002251 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002252 Handle<Object> object,
2253 Handle<JSObject> holder,
2254 Handle<JSGlobalPropertyCell> cell,
2255 Handle<JSFunction> function,
2256 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002257
danno@chromium.org40cb8782011-05-25 07:58:50 +00002258 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002259
2260 ASSERT(optimization.is_simple_api_call());
2261 // Bail out if object is a global object as we don't want to
2262 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002263 if (object->IsGlobalObject()) return Handle<Code>::null();
2264 if (!cell.is_null()) return Handle<Code>::null();
2265 if (!object->IsJSObject()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002266 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002267 Handle<JSObject>::cast(object), holder);
2268 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002269
2270 Label miss, miss_before_stack_reserved;
2271
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002272 GenerateNameCheck(name, &miss_before_stack_reserved);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002273
2274 // Get the receiver from the stack.
2275 const int argc = arguments().immediate();
2276 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2277
2278 // Check that the receiver isn't a smi.
2279 __ JumpIfSmi(a1, &miss_before_stack_reserved);
2280
2281 __ IncrementCounter(counters->call_const(), 1, a0, a3);
2282 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2283
2284 ReserveSpaceForFastApiCall(masm(), a0);
2285
2286 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002287 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002288 depth, &miss);
2289
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002290 GenerateFastApiDirectCall(masm(), optimization, argc);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002291
2292 __ bind(&miss);
2293 FreeSpaceForFastApiCall(masm());
2294
2295 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002296 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002297
2298 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002299 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002300}
2301
2302
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002303Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object,
2304 Handle<JSObject> holder,
2305 Handle<JSFunction> function,
2306 Handle<String> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002307 CheckType check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002308 // ----------- S t a t e -------------
2309 // -- a2 : name
2310 // -- ra : return address
2311 // -----------------------------------
2312 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002313 Handle<Code> code = CompileCustomCall(object, holder,
2314 Handle<JSGlobalPropertyCell>::null(),
2315 function, name);
2316 // A null handle means bail out to the regular compiler code below.
2317 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002318 }
2319
2320 Label miss;
2321
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002322 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002323
2324 // Get the receiver from the stack.
2325 const int argc = arguments().immediate();
2326 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2327
2328 // Check that the receiver isn't a smi.
2329 if (check != NUMBER_CHECK) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002330 __ JumpIfSmi(a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002331 }
2332
2333 // Make sure that it's okay not to patch the on stack receiver
2334 // unless we're doing a receiver map check.
2335 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002336 switch (check) {
2337 case RECEIVER_MAP_CHECK:
2338 __ IncrementCounter(masm()->isolate()->counters()->call_const(),
2339 1, a0, a3);
2340
2341 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002342 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2343 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002344
2345 // Patch the receiver on the stack with the global proxy if
2346 // necessary.
2347 if (object->IsGlobalObject()) {
2348 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2349 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2350 }
2351 break;
2352
2353 case STRING_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002354 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002355 // Check that the object is a two-byte string or a symbol.
2356 __ GetObjectType(a1, a3, a3);
2357 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2358 // Check that the maps starting from the prototype haven't changed.
2359 GenerateDirectLoadGlobalFunctionPrototype(
2360 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002361 CheckPrototypes(
2362 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2363 a0, holder, a3, a1, t0, name, &miss);
2364 } else {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002365 // Calling non-strict non-builtins with a value as the receiver
2366 // requires boxing.
2367 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002368 }
2369 break;
2370
2371 case NUMBER_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002372 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002373 Label fast;
2374 // Check that the object is a smi or a heap number.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002375 __ JumpIfSmi(a1, &fast);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002376 __ GetObjectType(a1, a0, a0);
2377 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
2378 __ bind(&fast);
2379 // Check that the maps starting from the prototype haven't changed.
2380 GenerateDirectLoadGlobalFunctionPrototype(
2381 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002382 CheckPrototypes(
2383 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2384 a0, holder, a3, a1, t0, name, &miss);
2385 } else {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002386 // Calling non-strict non-builtins with a value as the receiver
2387 // requires boxing.
2388 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002389 }
2390 break;
2391
2392 case BOOLEAN_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002393 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002394 Label fast;
2395 // Check that the object is a boolean.
2396 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
2397 __ Branch(&fast, eq, a1, Operand(t0));
2398 __ LoadRoot(t0, Heap::kFalseValueRootIndex);
2399 __ Branch(&miss, ne, a1, Operand(t0));
2400 __ bind(&fast);
2401 // Check that the maps starting from the prototype haven't changed.
2402 GenerateDirectLoadGlobalFunctionPrototype(
2403 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002404 CheckPrototypes(
2405 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2406 a0, holder, a3, a1, t0, name, &miss);
2407 } else {
2408 // Calling non-strict non-builtins with a value as the receiver
2409 // requires boxing.
2410 __ jmp(&miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002411 }
2412 break;
2413 }
2414
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002415 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002416 ? CALL_AS_FUNCTION
2417 : CALL_AS_METHOD;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002418 __ InvokeFunction(
2419 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002420
2421 // Handle call cache miss.
2422 __ bind(&miss);
2423
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002424 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002425
2426 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002427 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002428}
2429
2430
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002431Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2432 Handle<JSObject> holder,
2433 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002434 // ----------- S t a t e -------------
2435 // -- a2 : name
2436 // -- ra : return address
2437 // -----------------------------------
2438
2439 Label miss;
2440
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002441 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002442
2443 // Get the number of arguments.
2444 const int argc = arguments().immediate();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002445 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002446 LookupPostInterceptor(holder, name, &lookup);
2447
2448 // Get the receiver from the stack.
2449 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2450
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002451 CallInterceptorCompiler compiler(this, arguments(), a2, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002452 compiler.Compile(masm(), object, holder, name, &lookup, a1, a3, t0, a0,
2453 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002454
2455 // Move returned value, the function to call, to a1.
2456 __ mov(a1, v0);
2457 // Restore receiver.
2458 __ lw(a0, MemOperand(sp, argc * kPointerSize));
2459
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002460 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002461
2462 // Handle call cache miss.
2463 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002464 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002465
2466 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002467 return GetCode(INTERCEPTOR, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002468}
2469
2470
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002471Handle<Code> CallStubCompiler::CompileCallGlobal(
2472 Handle<JSObject> object,
2473 Handle<GlobalObject> holder,
2474 Handle<JSGlobalPropertyCell> cell,
2475 Handle<JSFunction> function,
2476 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002477 // ----------- S t a t e -------------
2478 // -- a2 : name
2479 // -- ra : return address
2480 // -----------------------------------
2481
2482 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002483 Handle<Code> code = CompileCustomCall(object, holder, cell, function, name);
2484 // A null handle means bail out to the regular compiler code below.
2485 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002486 }
2487
2488 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002489 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002490
2491 // Get the number of arguments.
2492 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002493 GenerateGlobalReceiverCheck(object, holder, name, &miss);
2494 GenerateLoadFunctionFromCell(cell, function, &miss);
2495
2496 // Patch the receiver on the stack with the global proxy if
2497 // necessary.
2498 if (object->IsGlobalObject()) {
2499 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
2500 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2501 }
2502
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002503 // Set up the context (function already in r1).
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002504 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
2505
2506 // Jump to the cached code (tail call).
2507 Counters* counters = masm()->isolate()->counters();
2508 __ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002509 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002510 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002511 ? CALL_AS_FUNCTION
2512 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002513 // We call indirectly through the code field in the function to
2514 // allow recompilation to take effect without changing any of the
2515 // call sites.
2516 __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
2517 __ InvokeCode(a3, expected, arguments(), JUMP_FUNCTION,
2518 NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002519
2520 // Handle call cache miss.
2521 __ bind(&miss);
2522 __ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002523 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002524
2525 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002526 return GetCode(NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002527}
2528
2529
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002530Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +00002531 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002532 Handle<Map> transition,
2533 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002534 // ----------- S t a t e -------------
2535 // -- a0 : value
2536 // -- a1 : receiver
2537 // -- a2 : name
2538 // -- ra : return address
2539 // -----------------------------------
2540 Label miss;
2541
2542 // Name register might be clobbered.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002543 GenerateStoreField(masm(), object, index, transition, a1, a2, a3, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002544 __ bind(&miss);
2545 __ li(a2, Operand(Handle<String>(name))); // Restore name.
2546 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2547 __ Jump(ic, RelocInfo::CODE_TARGET);
2548
2549 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002550 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002551}
2552
2553
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002554Handle<Code> StoreStubCompiler::CompileStoreCallback(
2555 Handle<JSObject> object,
2556 Handle<AccessorInfo> callback,
2557 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002558 // ----------- S t a t e -------------
2559 // -- a0 : value
2560 // -- a1 : receiver
2561 // -- a2 : name
2562 // -- ra : return address
2563 // -----------------------------------
2564 Label miss;
2565
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002566 // Check that the map of the object hasn't changed.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002567 __ CheckMap(a1, a3, Handle<Map>(object->map()), &miss,
2568 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002569
2570 // Perform global security token check if needed.
2571 if (object->IsJSGlobalProxy()) {
2572 __ CheckAccessGlobalProxy(a1, a3, &miss);
2573 }
2574
2575 // Stub never generated for non-global objects that require access
2576 // checks.
2577 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
2578
2579 __ push(a1); // Receiver.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002580 __ li(a3, Operand(callback)); // Callback info.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002581 __ Push(a3, a2, a0);
2582
2583 // Do tail-call to the runtime system.
2584 ExternalReference store_callback_property =
2585 ExternalReference(IC_Utility(IC::kStoreCallbackProperty),
2586 masm()->isolate());
2587 __ TailCallExternalReference(store_callback_property, 4, 1);
2588
2589 // Handle store cache miss.
2590 __ bind(&miss);
2591 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2592 __ Jump(ic, RelocInfo::CODE_TARGET);
2593
2594 // Return the generated code.
2595 return GetCode(CALLBACKS, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002596}
2597
2598
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002599Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
2600 Handle<JSObject> receiver,
2601 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002602 // ----------- S t a t e -------------
2603 // -- a0 : value
2604 // -- a1 : receiver
2605 // -- a2 : name
2606 // -- ra : return address
2607 // -----------------------------------
2608 Label miss;
2609
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002610 // Check that the map of the object hasn't changed.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002611 __ CheckMap(a1, a3, Handle<Map>(receiver->map()), &miss,
2612 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002613
2614 // Perform global security token check if needed.
2615 if (receiver->IsJSGlobalProxy()) {
2616 __ CheckAccessGlobalProxy(a1, a3, &miss);
2617 }
2618
2619 // Stub is never generated for non-global objects that require access
2620 // checks.
2621 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2622
2623 __ Push(a1, a2, a0); // Receiver, name, value.
2624
2625 __ li(a0, Operand(Smi::FromInt(strict_mode_)));
2626 __ push(a0); // Strict mode.
2627
2628 // Do tail-call to the runtime system.
2629 ExternalReference store_ic_property =
2630 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty),
2631 masm()->isolate());
2632 __ TailCallExternalReference(store_ic_property, 4, 1);
2633
2634 // Handle store cache miss.
2635 __ bind(&miss);
2636 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2637 __ Jump(ic, RelocInfo::CODE_TARGET);
2638
2639 // Return the generated code.
2640 return GetCode(INTERCEPTOR, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002641}
2642
2643
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002644Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2645 Handle<GlobalObject> object,
2646 Handle<JSGlobalPropertyCell> cell,
2647 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002648 // ----------- S t a t e -------------
2649 // -- a0 : value
2650 // -- a1 : receiver
2651 // -- a2 : name
2652 // -- ra : return address
2653 // -----------------------------------
2654 Label miss;
2655
2656 // Check that the map of the global has not changed.
2657 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2658 __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map())));
2659
2660 // Check that the value in the cell is not the hole. If it is, this
2661 // cell could have been deleted and reintroducing the global needs
2662 // to update the property details in the property dictionary of the
2663 // global object. We bail out to the runtime system to do that.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002664 __ li(t0, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002665 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
2666 __ lw(t2, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2667 __ Branch(&miss, eq, t1, Operand(t2));
2668
2669 // Store the value in the cell.
2670 __ sw(a0, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2671 __ mov(v0, a0); // Stored value must be returned in v0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002672 // Cells are always rescanned, so no write barrier here.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002673
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002674 Counters* counters = masm()->isolate()->counters();
2675 __ IncrementCounter(counters->named_store_global_inline(), 1, a1, a3);
2676 __ Ret();
2677
2678 // Handle store cache miss.
2679 __ bind(&miss);
2680 __ IncrementCounter(counters->named_store_global_inline_miss(), 1, a1, a3);
2681 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2682 __ Jump(ic, RelocInfo::CODE_TARGET);
2683
2684 // Return the generated code.
2685 return GetCode(NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002686}
2687
2688
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002689Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
2690 Handle<JSObject> object,
2691 Handle<JSObject> last) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002692 // ----------- S t a t e -------------
2693 // -- a0 : receiver
2694 // -- ra : return address
2695 // -----------------------------------
2696 Label miss;
2697
2698 // Check that the receiver is not a smi.
2699 __ JumpIfSmi(a0, &miss);
2700
2701 // Check the maps of the full prototype chain.
2702 CheckPrototypes(object, a0, last, a3, a1, t0, name, &miss);
2703
2704 // If the last object in the prototype chain is a global object,
2705 // check that the global property cell is empty.
2706 if (last->IsGlobalObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002707 GenerateCheckPropertyCell(
2708 masm(), Handle<GlobalObject>::cast(last), name, a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002709 }
2710
2711 // Return undefined if maps of the full prototype chain is still the same.
2712 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2713 __ Ret();
2714
2715 __ bind(&miss);
2716 GenerateLoadMiss(masm(), Code::LOAD_IC);
2717
2718 // Return the generated code.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002719 return GetCode(NONEXISTENT, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00002720}
2721
2722
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002723Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object,
2724 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002725 int index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002726 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002727 // ----------- S t a t e -------------
2728 // -- a0 : receiver
2729 // -- a2 : name
2730 // -- ra : return address
2731 // -----------------------------------
2732 Label miss;
2733
2734 __ mov(v0, a0);
2735
2736 GenerateLoadField(object, holder, v0, a3, a1, t0, index, name, &miss);
2737 __ bind(&miss);
2738 GenerateLoadMiss(masm(), Code::LOAD_IC);
2739
2740 // Return the generated code.
2741 return GetCode(FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002742}
2743
2744
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002745Handle<Code> LoadStubCompiler::CompileLoadCallback(
2746 Handle<String> name,
2747 Handle<JSObject> object,
2748 Handle<JSObject> holder,
2749 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002750 // ----------- S t a t e -------------
2751 // -- a0 : receiver
2752 // -- a2 : name
2753 // -- ra : return address
2754 // -----------------------------------
2755 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002756 GenerateLoadCallback(object, holder, a0, a2, a3, a1, t0, callback, name,
2757 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002758 __ bind(&miss);
2759 GenerateLoadMiss(masm(), Code::LOAD_IC);
2760
2761 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002762 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002763}
2764
2765
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002766Handle<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object,
2767 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002768 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002769 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002770 // ----------- S t a t e -------------
2771 // -- a0 : receiver
2772 // -- a2 : name
2773 // -- ra : return address
2774 // -----------------------------------
2775 Label miss;
2776
2777 GenerateLoadConstant(object, holder, a0, a3, a1, t0, value, name, &miss);
2778 __ bind(&miss);
2779 GenerateLoadMiss(masm(), Code::LOAD_IC);
2780
2781 // Return the generated code.
2782 return GetCode(CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002783}
2784
2785
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002786Handle<Code> LoadStubCompiler::CompileLoadInterceptor(Handle<JSObject> object,
2787 Handle<JSObject> holder,
2788 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002789 // ----------- S t a t e -------------
2790 // -- a0 : receiver
2791 // -- a2 : name
2792 // -- ra : return address
2793 // -- [sp] : receiver
2794 // -----------------------------------
2795 Label miss;
2796
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002797 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002798 LookupPostInterceptor(holder, name, &lookup);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002799 GenerateLoadInterceptor(object, holder, &lookup, a0, a2, a3, a1, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002800 &miss);
2801 __ bind(&miss);
2802 GenerateLoadMiss(masm(), Code::LOAD_IC);
2803
2804 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002805 return GetCode(INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002806}
2807
2808
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002809Handle<Code> LoadStubCompiler::CompileLoadGlobal(
2810 Handle<JSObject> object,
2811 Handle<GlobalObject> holder,
2812 Handle<JSGlobalPropertyCell> cell,
2813 Handle<String> name,
2814 bool is_dont_delete) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002815 // ----------- S t a t e -------------
2816 // -- a0 : receiver
2817 // -- a2 : name
2818 // -- ra : return address
2819 // -----------------------------------
2820 Label miss;
2821
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002822 // Check that the map of the global has not changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00002823 __ JumpIfSmi(a0, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002824 CheckPrototypes(object, a0, holder, a3, t0, a1, name, &miss);
2825
2826 // Get the value from the cell.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002827 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002828 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
2829
2830 // Check for deleted property if property can actually be deleted.
2831 if (!is_dont_delete) {
2832 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
2833 __ Branch(&miss, eq, t0, Operand(at));
2834 }
2835
2836 __ mov(v0, t0);
2837 Counters* counters = masm()->isolate()->counters();
2838 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
2839 __ Ret();
2840
2841 __ bind(&miss);
2842 __ IncrementCounter(counters->named_load_global_stub_miss(), 1, a1, a3);
2843 GenerateLoadMiss(masm(), Code::LOAD_IC);
2844
2845 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002846 return GetCode(NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002847}
2848
2849
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002850Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
2851 Handle<JSObject> receiver,
2852 Handle<JSObject> holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002853 int index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002854 // ----------- S t a t e -------------
2855 // -- ra : return address
2856 // -- a0 : key
2857 // -- a1 : receiver
2858 // -----------------------------------
2859 Label miss;
2860
2861 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002862 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002863
2864 GenerateLoadField(receiver, holder, a1, a2, a3, t0, index, name, &miss);
2865 __ bind(&miss);
2866 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2867
2868 return GetCode(FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002869}
2870
2871
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002872Handle<Code> KeyedLoadStubCompiler::CompileLoadCallback(
2873 Handle<String> name,
2874 Handle<JSObject> receiver,
2875 Handle<JSObject> holder,
2876 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002877 // ----------- S t a t e -------------
2878 // -- ra : return address
2879 // -- a0 : key
2880 // -- a1 : receiver
2881 // -----------------------------------
2882 Label miss;
2883
2884 // Check the key is the cached one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002885 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002886
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002887 GenerateLoadCallback(receiver, holder, a1, a0, a2, a3, t0, callback, name,
2888 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002889 __ bind(&miss);
2890 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2891
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002892 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002893}
2894
2895
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002896Handle<Code> KeyedLoadStubCompiler::CompileLoadConstant(
2897 Handle<String> name,
2898 Handle<JSObject> receiver,
2899 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002900 Handle<JSFunction> value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002901 // ----------- S t a t e -------------
2902 // -- ra : return address
2903 // -- a0 : key
2904 // -- a1 : receiver
2905 // -----------------------------------
2906 Label miss;
2907
2908 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002909 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002910
2911 GenerateLoadConstant(receiver, holder, a1, a2, a3, t0, value, name, &miss);
2912 __ bind(&miss);
2913 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2914
2915 // Return the generated code.
2916 return GetCode(CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002917}
2918
2919
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002920Handle<Code> KeyedLoadStubCompiler::CompileLoadInterceptor(
2921 Handle<JSObject> receiver,
2922 Handle<JSObject> holder,
2923 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002924 // ----------- S t a t e -------------
2925 // -- ra : return address
2926 // -- a0 : key
2927 // -- a1 : receiver
2928 // -----------------------------------
2929 Label miss;
2930
2931 // Check the key is the cached one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002932 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002933
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002934 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002935 LookupPostInterceptor(holder, name, &lookup);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002936 GenerateLoadInterceptor(receiver, holder, &lookup, a1, a0, a2, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002937 &miss);
2938 __ bind(&miss);
2939 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2940
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002941 return GetCode(INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002942}
2943
2944
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002945Handle<Code> KeyedLoadStubCompiler::CompileLoadArrayLength(
2946 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002947 // ----------- S t a t e -------------
2948 // -- ra : return address
2949 // -- a0 : key
2950 // -- a1 : receiver
2951 // -----------------------------------
2952 Label miss;
2953
2954 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002955 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002956
2957 GenerateLoadArrayLength(masm(), a1, a2, &miss);
2958 __ bind(&miss);
2959 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2960
2961 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002962}
2963
2964
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002965Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength(
2966 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002967 // ----------- S t a t e -------------
2968 // -- ra : return address
2969 // -- a0 : key
2970 // -- a1 : receiver
2971 // -----------------------------------
2972 Label miss;
2973
2974 Counters* counters = masm()->isolate()->counters();
2975 __ IncrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
2976
2977 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002978 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002979
2980 GenerateLoadStringLength(masm(), a1, a2, a3, &miss, true);
2981 __ bind(&miss);
2982 __ DecrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
2983
2984 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2985
2986 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002987}
2988
2989
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002990Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype(
2991 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002992 // ----------- S t a t e -------------
2993 // -- ra : return address
2994 // -- a0 : key
2995 // -- a1 : receiver
2996 // -----------------------------------
2997 Label miss;
2998
2999 Counters* counters = masm()->isolate()->counters();
3000 __ IncrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
3001
3002 // Check the name hasn't changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003003 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003004
3005 GenerateLoadFunctionPrototype(masm(), a1, a2, a3, &miss);
3006 __ bind(&miss);
3007 __ DecrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
3008 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3009
3010 return GetCode(CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003011}
3012
3013
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003014Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
3015 Handle<Map> receiver_map) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003016 // ----------- S t a t e -------------
3017 // -- ra : return address
3018 // -- a0 : key
3019 // -- a1 : receiver
3020 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003021 ElementsKind elements_kind = receiver_map->elements_kind();
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003022 Handle<Code> stub = KeyedLoadElementStub(elements_kind).GetCode();
3023
3024 __ DispatchMap(a1, a2, receiver_map, stub, DO_SMI_CHECK);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003025
3026 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
3027 __ Jump(ic, RelocInfo::CODE_TARGET);
3028
3029 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003030 return GetCode(NORMAL, factory()->empty_string());
danno@chromium.org40cb8782011-05-25 07:58:50 +00003031}
3032
3033
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003034Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
3035 MapHandleList* receiver_maps,
3036 CodeHandleList* handler_ics) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003037 // ----------- S t a t e -------------
3038 // -- ra : return address
3039 // -- a0 : key
3040 // -- a1 : receiver
3041 // -----------------------------------
3042 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003043 __ JumpIfSmi(a1, &miss);
3044
danno@chromium.org40cb8782011-05-25 07:58:50 +00003045 int receiver_count = receiver_maps->length();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003046 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003047 for (int current = 0; current < receiver_count; ++current) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003048 __ Jump(handler_ics->at(current), RelocInfo::CODE_TARGET,
3049 eq, a2, Operand(receiver_maps->at(current)));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003050 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003051
3052 __ bind(&miss);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003053 Handle<Code> miss_ic = isolate()->builtins()->KeyedLoadIC_Miss();
3054 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003055
3056 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003057 return GetCode(NORMAL, factory()->empty_string(), MEGAMORPHIC);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003058}
3059
3060
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003061Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +00003062 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003063 Handle<Map> transition,
3064 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003065 // ----------- S t a t e -------------
3066 // -- a0 : value
3067 // -- a1 : key
3068 // -- a2 : receiver
3069 // -- ra : return address
3070 // -----------------------------------
3071
3072 Label miss;
3073
3074 Counters* counters = masm()->isolate()->counters();
3075 __ IncrementCounter(counters->keyed_store_field(), 1, a3, t0);
3076
3077 // Check that the name has not changed.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003078 __ Branch(&miss, ne, a1, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003079
3080 // a3 is used as scratch register. a1 and a2 keep their values if a jump to
3081 // the miss label is generated.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003082 GenerateStoreField(masm(), object, index, transition, a2, a1, a3, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003083 __ bind(&miss);
3084
3085 __ DecrementCounter(counters->keyed_store_field(), 1, a3, t0);
3086 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss();
3087 __ Jump(ic, RelocInfo::CODE_TARGET);
3088
3089 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003090 return GetCode(transition.is_null() ? FIELD : MAP_TRANSITION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003091}
3092
3093
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003094Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
3095 Handle<Map> receiver_map) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003096 // ----------- S t a t e -------------
3097 // -- a0 : value
3098 // -- a1 : key
3099 // -- a2 : receiver
3100 // -- ra : return address
3101 // -- a3 : scratch
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003102 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003103 ElementsKind elements_kind = receiver_map->elements_kind();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003104 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003105 Handle<Code> stub =
yangguo@chromium.org56454712012-02-16 15:33:53 +00003106 KeyedStoreElementStub(is_js_array, elements_kind, grow_mode_).GetCode();
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003107
3108 __ DispatchMap(a2, a3, receiver_map, stub, DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003109
danno@chromium.org40cb8782011-05-25 07:58:50 +00003110 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003111 __ Jump(ic, RelocInfo::CODE_TARGET);
3112
3113 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003114 return GetCode(NORMAL, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00003115}
3116
3117
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003118Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
3119 MapHandleList* receiver_maps,
3120 CodeHandleList* handler_stubs,
3121 MapHandleList* transitioned_maps) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003122 // ----------- S t a t e -------------
3123 // -- a0 : value
3124 // -- a1 : key
3125 // -- a2 : receiver
3126 // -- ra : return address
3127 // -- a3 : scratch
3128 // -----------------------------------
3129 Label miss;
3130 __ JumpIfSmi(a2, &miss);
3131
3132 int receiver_count = receiver_maps->length();
3133 __ lw(a3, FieldMemOperand(a2, HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003134 for (int i = 0; i < receiver_count; ++i) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003135 if (transitioned_maps->at(i).is_null()) {
3136 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq,
3137 a3, Operand(receiver_maps->at(i)));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003138 } else {
3139 Label next_map;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003140 __ Branch(&next_map, ne, a3, Operand(receiver_maps->at(i)));
3141 __ li(a3, Operand(transitioned_maps->at(i)));
3142 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003143 __ bind(&next_map);
3144 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003145 }
3146
3147 __ bind(&miss);
3148 Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
3149 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3150
3151 // Return the generated code.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003152 return GetCode(NORMAL, factory()->empty_string(), MEGAMORPHIC);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003153}
3154
3155
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003156Handle<Code> ConstructStubCompiler::CompileConstructStub(
3157 Handle<JSFunction> function) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003158 // a0 : argc
3159 // a1 : constructor
3160 // ra : return address
3161 // [sp] : last argument
3162 Label generic_stub_call;
3163
3164 // Use t7 for holding undefined which is used in several places below.
3165 __ LoadRoot(t7, Heap::kUndefinedValueRootIndex);
3166
3167#ifdef ENABLE_DEBUGGER_SUPPORT
3168 // Check to see whether there are any break points in the function code. If
3169 // there are jump to the generic constructor stub which calls the actual
3170 // code for the function thereby hitting the break points.
3171 __ lw(t5, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3172 __ lw(a2, FieldMemOperand(t5, SharedFunctionInfo::kDebugInfoOffset));
3173 __ Branch(&generic_stub_call, ne, a2, Operand(t7));
3174#endif
3175
3176 // Load the initial map and verify that it is in fact a map.
3177 // a1: constructor function
3178 // t7: undefined
3179 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003180 __ JumpIfSmi(a2, &generic_stub_call);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003181 __ GetObjectType(a2, a3, t0);
3182 __ Branch(&generic_stub_call, ne, t0, Operand(MAP_TYPE));
3183
3184#ifdef DEBUG
3185 // Cannot construct functions this way.
3186 // a0: argc
3187 // a1: constructor function
3188 // a2: initial map
3189 // t7: undefined
3190 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
3191 __ Check(ne, "Function constructed by construct stub.",
3192 a3, Operand(JS_FUNCTION_TYPE));
3193#endif
3194
3195 // Now allocate the JSObject in new space.
3196 // a0: argc
3197 // a1: constructor function
3198 // a2: initial map
3199 // t7: undefined
3200 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003201 __ AllocateInNewSpace(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003202
3203 // Allocated the JSObject, now initialize the fields. Map is set to initial
3204 // map and properties and elements are set to empty fixed array.
3205 // a0: argc
3206 // a1: constructor function
3207 // a2: initial map
3208 // a3: object size (in words)
3209 // t4: JSObject (not tagged)
3210 // t7: undefined
3211 __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex);
3212 __ mov(t5, t4);
3213 __ sw(a2, MemOperand(t5, JSObject::kMapOffset));
3214 __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset));
3215 __ sw(t6, MemOperand(t5, JSObject::kElementsOffset));
3216 __ Addu(t5, t5, Operand(3 * kPointerSize));
3217 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
3218 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
3219 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
3220
3221
3222 // Calculate the location of the first argument. The stack contains only the
3223 // argc arguments.
3224 __ sll(a1, a0, kPointerSizeLog2);
3225 __ Addu(a1, a1, sp);
3226
3227 // Fill all the in-object properties with undefined.
3228 // a0: argc
3229 // a1: first argument
3230 // a3: object size (in words)
3231 // t4: JSObject (not tagged)
3232 // t5: First in-object property of JSObject (not tagged)
3233 // t7: undefined
3234 // Fill the initialized properties with a constant value or a passed argument
3235 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003236 Handle<SharedFunctionInfo> shared(function->shared());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003237 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3238 if (shared->IsThisPropertyAssignmentArgument(i)) {
3239 Label not_passed, next;
3240 // Check if the argument assigned to the property is actually passed.
3241 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3242 __ Branch(&not_passed, less_equal, a0, Operand(arg_number));
3243 // Argument passed - find it on the stack.
3244 __ lw(a2, MemOperand(a1, (arg_number + 1) * -kPointerSize));
3245 __ sw(a2, MemOperand(t5));
3246 __ Addu(t5, t5, kPointerSize);
3247 __ jmp(&next);
3248 __ bind(&not_passed);
3249 // Set the property to undefined.
3250 __ sw(t7, MemOperand(t5));
3251 __ Addu(t5, t5, Operand(kPointerSize));
3252 __ bind(&next);
3253 } else {
3254 // Set the property to the constant value.
3255 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
3256 __ li(a2, Operand(constant));
3257 __ sw(a2, MemOperand(t5));
3258 __ Addu(t5, t5, kPointerSize);
3259 }
3260 }
3261
3262 // Fill the unused in-object property fields with undefined.
3263 ASSERT(function->has_initial_map());
3264 for (int i = shared->this_property_assignments_count();
3265 i < function->initial_map()->inobject_properties();
3266 i++) {
3267 __ sw(t7, MemOperand(t5));
3268 __ Addu(t5, t5, kPointerSize);
3269 }
3270
3271 // a0: argc
3272 // t4: JSObject (not tagged)
3273 // Move argc to a1 and the JSObject to return to v0 and tag it.
3274 __ mov(a1, a0);
3275 __ mov(v0, t4);
3276 __ Or(v0, v0, Operand(kHeapObjectTag));
3277
3278 // v0: JSObject
3279 // a1: argc
3280 // Remove caller arguments and receiver from the stack and return.
3281 __ sll(t0, a1, kPointerSizeLog2);
3282 __ Addu(sp, sp, t0);
3283 __ Addu(sp, sp, Operand(kPointerSize));
3284 Counters* counters = masm()->isolate()->counters();
3285 __ IncrementCounter(counters->constructed_objects(), 1, a1, a2);
3286 __ IncrementCounter(counters->constructed_objects_stub(), 1, a1, a2);
3287 __ Ret();
3288
3289 // Jump to the generic stub in case the specialized code cannot handle the
3290 // construction.
3291 __ bind(&generic_stub_call);
3292 Handle<Code> generic_construct_stub =
3293 masm()->isolate()->builtins()->JSConstructStubGeneric();
3294 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
3295
3296 // Return the generated code.
3297 return GetCode();
3298}
3299
3300
danno@chromium.org40cb8782011-05-25 07:58:50 +00003301#undef __
3302#define __ ACCESS_MASM(masm)
3303
3304
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003305void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3306 MacroAssembler* masm) {
3307 // ---------- S t a t e --------------
3308 // -- ra : return address
3309 // -- a0 : key
3310 // -- a1 : receiver
3311 // -----------------------------------
3312 Label slow, miss_force_generic;
3313
3314 Register key = a0;
3315 Register receiver = a1;
3316
3317 __ JumpIfNotSmi(key, &miss_force_generic);
3318 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
3319 __ sra(a2, a0, kSmiTagSize);
3320 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
3321 __ Ret();
3322
3323 // Slow case, key and receiver still in a0 and a1.
3324 __ bind(&slow);
3325 __ IncrementCounter(
3326 masm->isolate()->counters()->keyed_load_external_array_slow(),
3327 1, a2, a3);
3328 // Entry registers are intact.
3329 // ---------- S t a t e --------------
3330 // -- ra : return address
3331 // -- a0 : key
3332 // -- a1 : receiver
3333 // -----------------------------------
3334 Handle<Code> slow_ic =
3335 masm->isolate()->builtins()->KeyedLoadIC_Slow();
3336 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
3337
3338 // Miss case, call the runtime.
3339 __ bind(&miss_force_generic);
3340
3341 // ---------- S t a t e --------------
3342 // -- ra : return address
3343 // -- a0 : key
3344 // -- a1 : receiver
3345 // -----------------------------------
3346
3347 Handle<Code> miss_ic =
3348 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3349 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3350}
3351
3352
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003353static bool IsElementTypeSigned(ElementsKind elements_kind) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003354 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003355 case EXTERNAL_BYTE_ELEMENTS:
3356 case EXTERNAL_SHORT_ELEMENTS:
3357 case EXTERNAL_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003358 return true;
3359
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003360 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3361 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3362 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3363 case EXTERNAL_PIXEL_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003364 return false;
3365
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003366 case EXTERNAL_FLOAT_ELEMENTS:
3367 case EXTERNAL_DOUBLE_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003368 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003369 case FAST_ELEMENTS:
3370 case FAST_DOUBLE_ELEMENTS:
3371 case DICTIONARY_ELEMENTS:
3372 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003373 UNREACHABLE();
3374 return false;
3375 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003376 return false;
lrn@chromium.org7516f052011-03-30 08:52:27 +00003377}
3378
3379
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003380static void GenerateSmiKeyCheck(MacroAssembler* masm,
3381 Register key,
3382 Register scratch0,
3383 Register scratch1,
3384 FPURegister double_scratch0,
3385 Label* fail) {
3386 if (CpuFeatures::IsSupported(FPU)) {
3387 CpuFeatures::Scope scope(FPU);
3388 Label key_ok;
3389 // Check for smi or a smi inside a heap number. We convert the heap
3390 // number and check if the conversion is exact and fits into the smi
3391 // range.
3392 __ JumpIfSmi(key, &key_ok);
3393 __ CheckMap(key,
3394 scratch0,
3395 Heap::kHeapNumberMapRootIndex,
3396 fail,
3397 DONT_DO_SMI_CHECK);
3398 __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
3399 __ EmitFPUTruncate(kRoundToZero,
3400 double_scratch0,
3401 double_scratch0,
3402 scratch0,
3403 scratch1,
3404 kCheckForInexactConversion);
3405
3406 __ Branch(fail, ne, scratch1, Operand(zero_reg));
3407
3408 __ mfc1(scratch0, double_scratch0);
3409 __ SmiTagCheckOverflow(key, scratch0, scratch1);
3410 __ BranchOnOverflow(fail, scratch1);
3411 __ bind(&key_ok);
3412 } else {
3413 // Check that the key is a smi.
3414 __ JumpIfNotSmi(key, fail);
3415 }
3416}
3417
3418
danno@chromium.org40cb8782011-05-25 07:58:50 +00003419void KeyedLoadStubCompiler::GenerateLoadExternalArray(
3420 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003421 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003422 // ---------- S t a t e --------------
3423 // -- ra : return address
3424 // -- a0 : key
3425 // -- a1 : receiver
3426 // -----------------------------------
danno@chromium.org40cb8782011-05-25 07:58:50 +00003427 Label miss_force_generic, slow, failed_allocation;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003428
3429 Register key = a0;
3430 Register receiver = a1;
3431
danno@chromium.org40cb8782011-05-25 07:58:50 +00003432 // This stub is meant to be tail-jumped to, the receiver must already
3433 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003434
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003435 // Check that the key is a smi or a heap number convertible to a smi.
3436 GenerateSmiKeyCheck(masm, key, t0, t1, f2, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003437
3438 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3439 // a3: elements array
3440
3441 // Check that the index is in range.
3442 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3443 __ sra(t2, key, kSmiTagSize);
3444 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003445 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003446
3447 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3448 // a3: base pointer of external storage
3449
3450 // We are not untagging smi key and instead work with it
3451 // as if it was premultiplied by 2.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00003452 STATIC_ASSERT((kSmiTag == 0) && (kSmiTagSize == 1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003453
3454 Register value = a2;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003455 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003456 case EXTERNAL_BYTE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003457 __ srl(t2, key, 1);
3458 __ addu(t3, a3, t2);
3459 __ lb(value, MemOperand(t3, 0));
3460 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003461 case EXTERNAL_PIXEL_ELEMENTS:
3462 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003463 __ srl(t2, key, 1);
3464 __ addu(t3, a3, t2);
3465 __ lbu(value, MemOperand(t3, 0));
3466 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003467 case EXTERNAL_SHORT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003468 __ addu(t3, a3, key);
3469 __ lh(value, MemOperand(t3, 0));
3470 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003471 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003472 __ addu(t3, a3, key);
3473 __ lhu(value, MemOperand(t3, 0));
3474 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003475 case EXTERNAL_INT_ELEMENTS:
3476 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003477 __ sll(t2, key, 1);
3478 __ addu(t3, a3, t2);
3479 __ lw(value, MemOperand(t3, 0));
3480 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003481 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003482 __ sll(t3, t2, 2);
3483 __ addu(t3, a3, t3);
3484 if (CpuFeatures::IsSupported(FPU)) {
3485 CpuFeatures::Scope scope(FPU);
3486 __ lwc1(f0, MemOperand(t3, 0));
3487 } else {
3488 __ lw(value, MemOperand(t3, 0));
3489 }
3490 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003491 case EXTERNAL_DOUBLE_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003492 __ sll(t2, key, 2);
3493 __ addu(t3, a3, t2);
3494 if (CpuFeatures::IsSupported(FPU)) {
3495 CpuFeatures::Scope scope(FPU);
3496 __ ldc1(f0, MemOperand(t3, 0));
3497 } else {
3498 // t3: pointer to the beginning of the double we want to load.
3499 __ lw(a2, MemOperand(t3, 0));
3500 __ lw(a3, MemOperand(t3, Register::kSizeInBytes));
3501 }
3502 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003503 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003504 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003505 case FAST_DOUBLE_ELEMENTS:
3506 case DICTIONARY_ELEMENTS:
3507 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003508 UNREACHABLE();
3509 break;
3510 }
3511
3512 // For integer array types:
3513 // a2: value
3514 // For float array type:
3515 // f0: value (if FPU is supported)
3516 // a2: value (if FPU is not supported)
3517 // For double array type:
3518 // f0: value (if FPU is supported)
3519 // a2/a3: value (if FPU is not supported)
3520
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003521 if (elements_kind == EXTERNAL_INT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003522 // For the Int and UnsignedInt array types, we need to see whether
3523 // the value can be represented in a Smi. If not, we need to convert
3524 // it to a HeapNumber.
3525 Label box_int;
3526 __ Subu(t3, value, Operand(0xC0000000)); // Non-smi value gives neg result.
3527 __ Branch(&box_int, lt, t3, Operand(zero_reg));
3528 // Tag integer as smi and return it.
3529 __ sll(v0, value, kSmiTagSize);
3530 __ Ret();
3531
3532 __ bind(&box_int);
3533 // Allocate a HeapNumber for the result and perform int-to-double
3534 // conversion.
3535 // The arm version uses a temporary here to save r0, but we don't need to
3536 // (a0 is not modified).
3537 __ LoadRoot(t1, Heap::kHeapNumberMapRootIndex);
3538 __ AllocateHeapNumber(v0, a3, t0, t1, &slow);
3539
3540 if (CpuFeatures::IsSupported(FPU)) {
3541 CpuFeatures::Scope scope(FPU);
3542 __ mtc1(value, f0);
3543 __ cvt_d_w(f0, f0);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00003544 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003545 __ Ret();
3546 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003547 Register dst1 = t2;
3548 Register dst2 = t3;
3549 FloatingPointHelper::Destination dest =
3550 FloatingPointHelper::kCoreRegisters;
3551 FloatingPointHelper::ConvertIntToDouble(masm,
3552 value,
3553 dest,
3554 f0,
3555 dst1,
3556 dst2,
3557 t1,
3558 f2);
3559 __ sw(dst1, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3560 __ sw(dst2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3561 __ Ret();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003562 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003563 } else if (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003564 // The test is different for unsigned int values. Since we need
3565 // the value to be in the range of a positive smi, we can't
3566 // handle either of the top two bits being set in the value.
3567 if (CpuFeatures::IsSupported(FPU)) {
3568 CpuFeatures::Scope scope(FPU);
3569 Label pl_box_int;
3570 __ And(t2, value, Operand(0xC0000000));
3571 __ Branch(&pl_box_int, ne, t2, Operand(zero_reg));
3572
3573 // It can fit in an Smi.
3574 // Tag integer as smi and return it.
3575 __ sll(v0, value, kSmiTagSize);
3576 __ Ret();
3577
3578 __ bind(&pl_box_int);
3579 // Allocate a HeapNumber for the result and perform int-to-double
3580 // conversion. Don't use a0 and a1 as AllocateHeapNumber clobbers all
3581 // registers - also when jumping due to exhausted young space.
3582 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3583 __ AllocateHeapNumber(v0, t2, t3, t6, &slow);
3584
3585 // This is replaced by a macro:
3586 // __ mtc1(value, f0); // LS 32-bits.
3587 // __ mtc1(zero_reg, f1); // MS 32-bits are all zero.
3588 // __ cvt_d_l(f0, f0); // Use 64 bit conv to get correct unsigned 32-bit.
3589
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003590 __ Cvt_d_uw(f0, value, f22);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003591
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00003592 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003593
3594 __ Ret();
3595 } else {
3596 // Check whether unsigned integer fits into smi.
3597 Label box_int_0, box_int_1, done;
3598 __ And(t2, value, Operand(0x80000000));
3599 __ Branch(&box_int_0, ne, t2, Operand(zero_reg));
3600 __ And(t2, value, Operand(0x40000000));
3601 __ Branch(&box_int_1, ne, t2, Operand(zero_reg));
3602
3603 // Tag integer as smi and return it.
3604 __ sll(v0, value, kSmiTagSize);
3605 __ Ret();
3606
3607 Register hiword = value; // a2.
3608 Register loword = a3;
3609
3610 __ bind(&box_int_0);
3611 // Integer does not have leading zeros.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003612 GenerateUInt2Double(masm, hiword, loword, t0, 0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003613 __ Branch(&done);
3614
3615 __ bind(&box_int_1);
3616 // Integer has one leading zero.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003617 GenerateUInt2Double(masm, hiword, loword, t0, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003618
3619
3620 __ bind(&done);
3621 // Integer was converted to double in registers hiword:loword.
3622 // Wrap it into a HeapNumber. Don't use a0 and a1 as AllocateHeapNumber
3623 // clobbers all registers - also when jumping due to exhausted young
3624 // space.
3625 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3626 __ AllocateHeapNumber(t2, t3, t5, t6, &slow);
3627
3628 __ sw(hiword, FieldMemOperand(t2, HeapNumber::kExponentOffset));
3629 __ sw(loword, FieldMemOperand(t2, HeapNumber::kMantissaOffset));
3630
3631 __ mov(v0, t2);
3632 __ Ret();
3633 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003634 } else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003635 // For the floating-point array type, we need to always allocate a
3636 // HeapNumber.
3637 if (CpuFeatures::IsSupported(FPU)) {
3638 CpuFeatures::Scope scope(FPU);
3639 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3640 // AllocateHeapNumber clobbers all registers - also when jumping due to
3641 // exhausted young space.
3642 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3643 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3644 // The float (single) value is already in fpu reg f0 (if we use float).
3645 __ cvt_d_s(f0, f0);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00003646 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003647 __ Ret();
3648 } else {
3649 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3650 // AllocateHeapNumber clobbers all registers - also when jumping due to
3651 // exhausted young space.
3652 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3653 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3654 // FPU is not available, do manual single to double conversion.
3655
3656 // a2: floating point value (binary32).
3657 // v0: heap number for result
3658
3659 // Extract mantissa to t4.
3660 __ And(t4, value, Operand(kBinary32MantissaMask));
3661
3662 // Extract exponent to t5.
3663 __ srl(t5, value, kBinary32MantissaBits);
3664 __ And(t5, t5, Operand(kBinary32ExponentMask >> kBinary32MantissaBits));
3665
3666 Label exponent_rebiased;
3667 __ Branch(&exponent_rebiased, eq, t5, Operand(zero_reg));
3668
3669 __ li(t0, 0x7ff);
3670 __ Xor(t1, t5, Operand(0xFF));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003671 __ Movz(t5, t0, t1); // Set t5 to 0x7ff only if t5 is equal to 0xff.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003672 __ Branch(&exponent_rebiased, eq, t0, Operand(0xff));
3673
3674 // Rebias exponent.
3675 __ Addu(t5,
3676 t5,
3677 Operand(-kBinary32ExponentBias + HeapNumber::kExponentBias));
3678
3679 __ bind(&exponent_rebiased);
3680 __ And(a2, value, Operand(kBinary32SignMask));
3681 value = no_reg;
3682 __ sll(t0, t5, HeapNumber::kMantissaBitsInTopWord);
3683 __ or_(a2, a2, t0);
3684
3685 // Shift mantissa.
3686 static const int kMantissaShiftForHiWord =
3687 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3688
3689 static const int kMantissaShiftForLoWord =
3690 kBitsPerInt - kMantissaShiftForHiWord;
3691
3692 __ srl(t0, t4, kMantissaShiftForHiWord);
3693 __ or_(a2, a2, t0);
3694 __ sll(a0, t4, kMantissaShiftForLoWord);
3695
3696 __ sw(a2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3697 __ sw(a0, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3698 __ Ret();
3699 }
3700
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003701 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003702 if (CpuFeatures::IsSupported(FPU)) {
3703 CpuFeatures::Scope scope(FPU);
3704 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3705 // AllocateHeapNumber clobbers all registers - also when jumping due to
3706 // exhausted young space.
3707 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3708 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3709 // The double value is already in f0
3710 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
3711 __ Ret();
3712 } else {
3713 // Allocate a HeapNumber for the result. Don't use a0 and a1 as
3714 // AllocateHeapNumber clobbers all registers - also when jumping due to
3715 // exhausted young space.
3716 __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
3717 __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
3718
3719 __ sw(a2, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
3720 __ sw(a3, FieldMemOperand(v0, HeapNumber::kExponentOffset));
3721 __ Ret();
3722 }
3723
3724 } else {
3725 // Tag integer as smi and return it.
3726 __ sll(v0, value, kSmiTagSize);
3727 __ Ret();
3728 }
3729
3730 // Slow case, key and receiver still in a0 and a1.
3731 __ bind(&slow);
3732 __ IncrementCounter(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003733 masm->isolate()->counters()->keyed_load_external_array_slow(),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003734 1, a2, a3);
3735
3736 // ---------- S t a t e --------------
3737 // -- ra : return address
3738 // -- a0 : key
3739 // -- a1 : receiver
3740 // -----------------------------------
3741
3742 __ Push(a1, a0);
3743
3744 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
3745
danno@chromium.org40cb8782011-05-25 07:58:50 +00003746 __ bind(&miss_force_generic);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003747 Handle<Code> stub =
3748 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3749 __ Jump(stub, RelocInfo::CODE_TARGET);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003750}
3751
3752
danno@chromium.org40cb8782011-05-25 07:58:50 +00003753void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3754 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003755 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003756 // ---------- S t a t e --------------
3757 // -- a0 : value
3758 // -- a1 : key
3759 // -- a2 : receiver
3760 // -- ra : return address
3761 // -----------------------------------
3762
danno@chromium.org40cb8782011-05-25 07:58:50 +00003763 Label slow, check_heap_number, miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003764
3765 // Register usage.
3766 Register value = a0;
3767 Register key = a1;
3768 Register receiver = a2;
3769 // a3 mostly holds the elements array or the destination external array.
3770
danno@chromium.org40cb8782011-05-25 07:58:50 +00003771 // This stub is meant to be tail-jumped to, the receiver must already
3772 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003773
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003774 // Check that the key is a smi or a heap number convertible to a smi.
3775 GenerateSmiKeyCheck(masm, key, t0, t1, f2, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003776
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003777 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3778
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003779 // Check that the index is in range.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003780 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3781 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003782 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003783
3784 // Handle both smis and HeapNumbers in the fast path. Go to the
3785 // runtime for all other kinds of values.
3786 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003787
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003788 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003789 // Double to pixel conversion is only implemented in the runtime for now.
3790 __ JumpIfNotSmi(value, &slow);
3791 } else {
3792 __ JumpIfNotSmi(value, &check_heap_number);
3793 }
3794 __ SmiUntag(t1, value);
3795 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3796
3797 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003798 // t1: value (integer).
3799
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003800 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003801 case EXTERNAL_PIXEL_ELEMENTS: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003802 // Clamp the value to [0..255].
3803 // v0 is used as a scratch register here.
3804 Label done;
3805 __ li(v0, Operand(255));
3806 // Normal branch: nop in delay slot.
3807 __ Branch(&done, gt, t1, Operand(v0));
3808 // Use delay slot in this branch.
3809 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg));
3810 __ mov(v0, zero_reg); // In delay slot.
3811 __ mov(v0, t1); // Value is in range 0..255.
3812 __ bind(&done);
3813 __ mov(t1, v0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003814
3815 __ srl(t8, key, 1);
3816 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003817 __ sb(t1, MemOperand(t8, 0));
3818 }
3819 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003820 case EXTERNAL_BYTE_ELEMENTS:
3821 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003822 __ srl(t8, key, 1);
3823 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003824 __ sb(t1, MemOperand(t8, 0));
3825 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003826 case EXTERNAL_SHORT_ELEMENTS:
3827 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003828 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003829 __ sh(t1, MemOperand(t8, 0));
3830 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003831 case EXTERNAL_INT_ELEMENTS:
3832 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003833 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003834 __ addu(t8, a3, t8);
3835 __ sw(t1, MemOperand(t8, 0));
3836 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003837 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003838 // Perform int-to-float conversion and store to memory.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003839 __ SmiUntag(t0, key);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003840 StoreIntAsFloat(masm, a3, t0, t1, t2, t3, t4);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003841 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003842 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003843 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003844 __ addu(a3, a3, t8);
3845 // a3: effective address of the double element
3846 FloatingPointHelper::Destination destination;
3847 if (CpuFeatures::IsSupported(FPU)) {
3848 destination = FloatingPointHelper::kFPURegisters;
3849 } else {
3850 destination = FloatingPointHelper::kCoreRegisters;
3851 }
3852 FloatingPointHelper::ConvertIntToDouble(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003853 masm, t1, destination,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003854 f0, t2, t3, // These are: double_dst, dst1, dst2.
3855 t0, f2); // These are: scratch2, single_scratch.
3856 if (destination == FloatingPointHelper::kFPURegisters) {
3857 CpuFeatures::Scope scope(FPU);
3858 __ sdc1(f0, MemOperand(a3, 0));
3859 } else {
3860 __ sw(t2, MemOperand(a3, 0));
3861 __ sw(t3, MemOperand(a3, Register::kSizeInBytes));
3862 }
3863 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003864 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003865 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003866 case FAST_DOUBLE_ELEMENTS:
3867 case DICTIONARY_ELEMENTS:
3868 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003869 UNREACHABLE();
3870 break;
3871 }
3872
3873 // Entry registers are intact, a0 holds the value which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003874 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003875 __ Ret();
3876
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003877 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003878 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003879 __ bind(&check_heap_number);
3880 __ GetObjectType(value, t1, t2);
3881 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE));
3882
3883 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3884
3885 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003886
3887 // The WebGL specification leaves the behavior of storing NaN and
3888 // +/-Infinity into integer arrays basically undefined. For more
3889 // reproducible behavior, convert these to zero.
3890
3891 if (CpuFeatures::IsSupported(FPU)) {
3892 CpuFeatures::Scope scope(FPU);
3893
3894 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
3895
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003896 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003897 __ cvt_s_d(f0, f0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003898 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003899 __ addu(t8, a3, t8);
3900 __ swc1(f0, MemOperand(t8, 0));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003901 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003902 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003903 __ addu(t8, a3, t8);
3904 __ sdc1(f0, MemOperand(t8, 0));
3905 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003906 __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003907
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003908 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003909 case EXTERNAL_BYTE_ELEMENTS:
3910 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003911 __ srl(t8, key, 1);
3912 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003913 __ sb(t3, MemOperand(t8, 0));
3914 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003915 case EXTERNAL_SHORT_ELEMENTS:
3916 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003917 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003918 __ sh(t3, MemOperand(t8, 0));
3919 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003920 case EXTERNAL_INT_ELEMENTS:
3921 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003922 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003923 __ addu(t8, a3, t8);
3924 __ sw(t3, MemOperand(t8, 0));
3925 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003926 case EXTERNAL_PIXEL_ELEMENTS:
3927 case EXTERNAL_FLOAT_ELEMENTS:
3928 case EXTERNAL_DOUBLE_ELEMENTS:
3929 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003930 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003931 case FAST_DOUBLE_ELEMENTS:
3932 case DICTIONARY_ELEMENTS:
3933 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003934 UNREACHABLE();
3935 break;
3936 }
3937 }
3938
3939 // Entry registers are intact, a0 holds the value
3940 // which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003941 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003942 __ Ret();
3943 } else {
3944 // FPU is not available, do manual conversions.
3945
3946 __ lw(t3, FieldMemOperand(value, HeapNumber::kExponentOffset));
3947 __ lw(t4, FieldMemOperand(value, HeapNumber::kMantissaOffset));
3948
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003949 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003950 Label done, nan_or_infinity_or_zero;
3951 static const int kMantissaInHiWordShift =
3952 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3953
3954 static const int kMantissaInLoWordShift =
3955 kBitsPerInt - kMantissaInHiWordShift;
3956
3957 // Test for all special exponent values: zeros, subnormal numbers, NaNs
3958 // and infinities. All these should be converted to 0.
3959 __ li(t5, HeapNumber::kExponentMask);
3960 __ and_(t6, t3, t5);
3961 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(zero_reg));
3962
3963 __ xor_(t1, t6, t5);
3964 __ li(t2, kBinary32ExponentMask);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003965 __ Movz(t6, t2, t1); // Only if t6 is equal to t5.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003966 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(t5));
3967
3968 // Rebias exponent.
3969 __ srl(t6, t6, HeapNumber::kExponentShift);
3970 __ Addu(t6,
3971 t6,
3972 Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
3973
3974 __ li(t1, Operand(kBinary32MaxExponent));
3975 __ Slt(t1, t1, t6);
3976 __ And(t2, t3, Operand(HeapNumber::kSignMask));
3977 __ Or(t2, t2, Operand(kBinary32ExponentMask));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003978 __ Movn(t3, t2, t1); // Only if t6 is gt kBinary32MaxExponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003979 __ Branch(&done, gt, t6, Operand(kBinary32MaxExponent));
3980
3981 __ Slt(t1, t6, Operand(kBinary32MinExponent));
3982 __ And(t2, t3, Operand(HeapNumber::kSignMask));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003983 __ Movn(t3, t2, t1); // Only if t6 is lt kBinary32MinExponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003984 __ Branch(&done, lt, t6, Operand(kBinary32MinExponent));
3985
3986 __ And(t7, t3, Operand(HeapNumber::kSignMask));
3987 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3988 __ sll(t3, t3, kMantissaInHiWordShift);
3989 __ or_(t7, t7, t3);
3990 __ srl(t4, t4, kMantissaInLoWordShift);
3991 __ or_(t7, t7, t4);
3992 __ sll(t6, t6, kBinary32ExponentShift);
3993 __ or_(t3, t7, t6);
3994
3995 __ bind(&done);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003996 __ sll(t9, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003997 __ addu(t9, a2, t9);
3998 __ sw(t3, MemOperand(t9, 0));
3999
4000 // Entry registers are intact, a0 holds the value which is the return
4001 // value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004002 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004003 __ Ret();
4004
4005 __ bind(&nan_or_infinity_or_zero);
4006 __ And(t7, t3, Operand(HeapNumber::kSignMask));
4007 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4008 __ or_(t6, t6, t7);
4009 __ sll(t3, t3, kMantissaInHiWordShift);
4010 __ or_(t6, t6, t3);
4011 __ srl(t4, t4, kMantissaInLoWordShift);
4012 __ or_(t3, t6, t4);
4013 __ Branch(&done);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004014 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004015 __ sll(t8, t0, 3);
4016 __ addu(t8, a3, t8);
4017 // t8: effective address of destination element.
4018 __ sw(t4, MemOperand(t8, 0));
4019 __ sw(t3, MemOperand(t8, Register::kSizeInBytes));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004020 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004021 __ Ret();
4022 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004023 bool is_signed_type = IsElementTypeSigned(elements_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004024 int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
4025 int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
4026
4027 Label done, sign;
4028
4029 // Test for all special exponent values: zeros, subnormal numbers, NaNs
4030 // and infinities. All these should be converted to 0.
4031 __ li(t5, HeapNumber::kExponentMask);
4032 __ and_(t6, t3, t5);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004033 __ Movz(t3, zero_reg, t6); // Only if t6 is equal to zero.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004034 __ Branch(&done, eq, t6, Operand(zero_reg));
4035
4036 __ xor_(t2, t6, t5);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004037 __ Movz(t3, zero_reg, t2); // Only if t6 is equal to t5.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004038 __ Branch(&done, eq, t6, Operand(t5));
4039
4040 // Unbias exponent.
4041 __ srl(t6, t6, HeapNumber::kExponentShift);
4042 __ Subu(t6, t6, Operand(HeapNumber::kExponentBias));
4043 // If exponent is negative then result is 0.
4044 __ slt(t2, t6, zero_reg);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004045 __ Movn(t3, zero_reg, t2); // Only if exponent is negative.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004046 __ Branch(&done, lt, t6, Operand(zero_reg));
4047
4048 // If exponent is too big then result is minimal value.
4049 __ slti(t1, t6, meaningfull_bits - 1);
4050 __ li(t2, min_value);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004051 __ Movz(t3, t2, t1); // Only if t6 is ge meaningfull_bits - 1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004052 __ Branch(&done, ge, t6, Operand(meaningfull_bits - 1));
4053
4054 __ And(t5, t3, Operand(HeapNumber::kSignMask));
4055 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4056 __ Or(t3, t3, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
4057
4058 __ li(t9, HeapNumber::kMantissaBitsInTopWord);
4059 __ subu(t6, t9, t6);
4060 __ slt(t1, t6, zero_reg);
4061 __ srlv(t2, t3, t6);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004062 __ Movz(t3, t2, t1); // Only if t6 is positive.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004063 __ Branch(&sign, ge, t6, Operand(zero_reg));
4064
4065 __ subu(t6, zero_reg, t6);
4066 __ sllv(t3, t3, t6);
4067 __ li(t9, meaningfull_bits);
4068 __ subu(t6, t9, t6);
4069 __ srlv(t4, t4, t6);
4070 __ or_(t3, t3, t4);
4071
4072 __ bind(&sign);
4073 __ subu(t2, t3, zero_reg);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004074 __ Movz(t3, t2, t5); // Only if t5 is zero.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004075
4076 __ bind(&done);
4077
4078 // Result is in t3.
4079 // This switch block should be exactly the same as above (FPU mode).
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004080 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004081 case EXTERNAL_BYTE_ELEMENTS:
4082 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004083 __ srl(t8, key, 1);
4084 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004085 __ sb(t3, MemOperand(t8, 0));
4086 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004087 case EXTERNAL_SHORT_ELEMENTS:
4088 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004089 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004090 __ sh(t3, MemOperand(t8, 0));
4091 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004092 case EXTERNAL_INT_ELEMENTS:
4093 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004094 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004095 __ addu(t8, a3, t8);
4096 __ sw(t3, MemOperand(t8, 0));
4097 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004098 case EXTERNAL_PIXEL_ELEMENTS:
4099 case EXTERNAL_FLOAT_ELEMENTS:
4100 case EXTERNAL_DOUBLE_ELEMENTS:
4101 case FAST_ELEMENTS:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004102 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004103 case FAST_DOUBLE_ELEMENTS:
4104 case DICTIONARY_ELEMENTS:
4105 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004106 UNREACHABLE();
4107 break;
4108 }
4109 }
4110 }
4111 }
4112
danno@chromium.org40cb8782011-05-25 07:58:50 +00004113 // Slow case, key and receiver still in a0 and a1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004114 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004115 __ IncrementCounter(
4116 masm->isolate()->counters()->keyed_load_external_array_slow(),
4117 1, a2, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004118 // Entry registers are intact.
4119 // ---------- S t a t e --------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004120 // -- ra : return address
danno@chromium.org40cb8782011-05-25 07:58:50 +00004121 // -- a0 : key
4122 // -- a1 : receiver
4123 // -----------------------------------
4124 Handle<Code> slow_ic =
4125 masm->isolate()->builtins()->KeyedStoreIC_Slow();
4126 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4127
4128 // Miss case, call the runtime.
4129 __ bind(&miss_force_generic);
4130
4131 // ---------- S t a t e --------------
4132 // -- ra : return address
4133 // -- a0 : key
4134 // -- a1 : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004135 // -----------------------------------
4136
danno@chromium.org40cb8782011-05-25 07:58:50 +00004137 Handle<Code> miss_ic =
4138 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4139 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
4140}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004141
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004142
danno@chromium.org40cb8782011-05-25 07:58:50 +00004143void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
4144 // ----------- S t a t e -------------
4145 // -- ra : return address
4146 // -- a0 : key
4147 // -- a1 : receiver
4148 // -----------------------------------
4149 Label miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004150
danno@chromium.org40cb8782011-05-25 07:58:50 +00004151 // This stub is meant to be tail-jumped to, the receiver must already
4152 // have been verified by the caller to not be a smi.
4153
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004154 // Check that the key is a smi or a heap number convertible to a smi.
4155 GenerateSmiKeyCheck(masm, a0, t0, t1, f2, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004156
4157 // Get the elements array.
4158 __ lw(a2, FieldMemOperand(a1, JSObject::kElementsOffset));
4159 __ AssertFastElements(a2);
4160
4161 // Check that the key is within bounds.
4162 __ lw(a3, FieldMemOperand(a2, FixedArray::kLengthOffset));
ulan@chromium.org6ff65142012-03-21 09:52:17 +00004163 __ Branch(USE_DELAY_SLOT, &miss_force_generic, hs, a0, Operand(a3));
danno@chromium.org40cb8782011-05-25 07:58:50 +00004164
4165 // Load the result and make sure it's not the hole.
4166 __ Addu(a3, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
fschneider@chromium.org1805e212011-09-05 10:49:12 +00004167 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004168 __ sll(t0, a0, kPointerSizeLog2 - kSmiTagSize);
4169 __ Addu(t0, t0, a3);
4170 __ lw(t0, MemOperand(t0));
4171 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
4172 __ Branch(&miss_force_generic, eq, t0, Operand(t1));
ulan@chromium.org6ff65142012-03-21 09:52:17 +00004173 __ Ret(USE_DELAY_SLOT);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004174 __ mov(v0, t0);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004175
4176 __ bind(&miss_force_generic);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004177 Handle<Code> stub =
4178 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4179 __ Jump(stub, RelocInfo::CODE_TARGET);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004180}
4181
4182
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004183void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
4184 MacroAssembler* masm) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004185 // ----------- S t a t e -------------
4186 // -- ra : return address
4187 // -- a0 : key
4188 // -- a1 : receiver
4189 // -----------------------------------
4190 Label miss_force_generic, slow_allocate_heapnumber;
4191
4192 Register key_reg = a0;
4193 Register receiver_reg = a1;
4194 Register elements_reg = a2;
4195 Register heap_number_reg = a2;
4196 Register indexed_double_offset = a3;
4197 Register scratch = t0;
4198 Register scratch2 = t1;
4199 Register scratch3 = t2;
4200 Register heap_number_map = t3;
4201
4202 // This stub is meant to be tail-jumped to, the receiver must already
4203 // have been verified by the caller to not be a smi.
4204
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004205 // Check that the key is a smi or a heap number convertible to a smi.
4206 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004207
4208 // Get the elements array.
4209 __ lw(elements_reg,
4210 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4211
4212 // Check that the key is within bounds.
4213 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4214 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4215
4216 // Load the upper word of the double in the fixed array and test for NaN.
4217 __ sll(scratch2, key_reg, kDoubleSizeLog2 - kSmiTagSize);
4218 __ Addu(indexed_double_offset, elements_reg, Operand(scratch2));
4219 uint32_t upper_32_offset = FixedArray::kHeaderSize + sizeof(kHoleNanLower32);
4220 __ lw(scratch, FieldMemOperand(indexed_double_offset, upper_32_offset));
4221 __ Branch(&miss_force_generic, eq, scratch, Operand(kHoleNanUpper32));
4222
4223 // Non-NaN. Allocate a new heap number and copy the double value into it.
4224 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
4225 __ AllocateHeapNumber(heap_number_reg, scratch2, scratch3,
4226 heap_number_map, &slow_allocate_heapnumber);
4227
4228 // Don't need to reload the upper 32 bits of the double, it's already in
4229 // scratch.
4230 __ sw(scratch, FieldMemOperand(heap_number_reg,
4231 HeapNumber::kExponentOffset));
4232 __ lw(scratch, FieldMemOperand(indexed_double_offset,
4233 FixedArray::kHeaderSize));
4234 __ sw(scratch, FieldMemOperand(heap_number_reg,
4235 HeapNumber::kMantissaOffset));
4236
4237 __ mov(v0, heap_number_reg);
4238 __ Ret();
4239
4240 __ bind(&slow_allocate_heapnumber);
4241 Handle<Code> slow_ic =
4242 masm->isolate()->builtins()->KeyedLoadIC_Slow();
4243 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4244
4245 __ bind(&miss_force_generic);
4246 Handle<Code> miss_ic =
4247 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
4248 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004249}
4250
4251
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004252void KeyedStoreStubCompiler::GenerateStoreFastElement(
4253 MacroAssembler* masm,
4254 bool is_js_array,
yangguo@chromium.org56454712012-02-16 15:33:53 +00004255 ElementsKind elements_kind,
4256 KeyedAccessGrowMode grow_mode) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00004257 // ----------- S t a t e -------------
4258 // -- a0 : value
4259 // -- a1 : key
4260 // -- a2 : receiver
4261 // -- ra : return address
4262 // -- a3 : scratch
4263 // -- a4 : scratch (elements)
4264 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00004265 Label miss_force_generic, transition_elements_kind, grow, slow;
4266 Label finish_store, check_capacity;
danno@chromium.org40cb8782011-05-25 07:58:50 +00004267
4268 Register value_reg = a0;
4269 Register key_reg = a1;
4270 Register receiver_reg = a2;
yangguo@chromium.org56454712012-02-16 15:33:53 +00004271 Register scratch = t0;
4272 Register elements_reg = a3;
4273 Register length_reg = t1;
4274 Register scratch2 = t2;
danno@chromium.org40cb8782011-05-25 07:58:50 +00004275
4276 // This stub is meant to be tail-jumped to, the receiver must already
4277 // have been verified by the caller to not be a smi.
4278
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004279 // Check that the key is a smi or a heap number convertible to a smi.
4280 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004281
yangguo@chromium.org56454712012-02-16 15:33:53 +00004282 if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
4283 __ JumpIfNotSmi(value_reg, &transition_elements_kind);
4284 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004285
4286 // Check that the key is within bounds.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004287 __ lw(elements_reg,
4288 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00004289 if (is_js_array) {
4290 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4291 } else {
4292 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4293 }
4294 // Compare smis.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004295 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4296 __ Branch(&grow, hs, key_reg, Operand(scratch));
4297 } else {
4298 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4299 }
4300
4301 // Make sure elements is a fast element array, not 'cow'.
4302 __ CheckMap(elements_reg,
4303 scratch,
4304 Heap::kFixedArrayMapRootIndex,
4305 &miss_force_generic,
4306 DONT_DO_SMI_CHECK);
4307
4308 __ bind(&finish_store);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004309
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004310 if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004311 __ Addu(scratch,
4312 elements_reg,
4313 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4314 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4315 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4316 __ Addu(scratch, scratch, scratch2);
4317 __ sw(value_reg, MemOperand(scratch));
4318 } else {
4319 ASSERT(elements_kind == FAST_ELEMENTS);
4320 __ Addu(scratch,
4321 elements_reg,
4322 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4323 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4324 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4325 __ Addu(scratch, scratch, scratch2);
4326 __ sw(value_reg, MemOperand(scratch));
4327 __ mov(receiver_reg, value_reg);
4328 ASSERT(elements_kind == FAST_ELEMENTS);
4329 __ RecordWrite(elements_reg, // Object.
4330 scratch, // Address.
4331 receiver_reg, // Value.
4332 kRAHasNotBeenSaved,
4333 kDontSaveFPRegs);
4334 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004335 // value_reg (a0) is preserved.
4336 // Done.
4337 __ Ret();
4338
4339 __ bind(&miss_force_generic);
4340 Handle<Code> ic =
4341 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4342 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004343
4344 __ bind(&transition_elements_kind);
4345 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4346 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
yangguo@chromium.org56454712012-02-16 15:33:53 +00004347
4348 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4349 // Grow the array by a single element if possible.
4350 __ bind(&grow);
4351
4352 // Make sure the array is only growing by a single element, anything else
4353 // must be handled by the runtime.
4354 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch));
4355
4356 // Check for the empty array, and preallocate a small backing store if
4357 // possible.
4358 __ lw(length_reg,
4359 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4360 __ lw(elements_reg,
4361 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4362 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
4363 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
4364
4365 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
4366 __ AllocateInNewSpace(size, elements_reg, scratch, scratch2, &slow,
4367 TAG_OBJECT);
4368
4369 __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex);
4370 __ sw(scratch, FieldMemOperand(elements_reg, JSObject::kMapOffset));
4371 __ li(scratch, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4372 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4373 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
4374 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
4375 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::SizeFor(i)));
4376 }
4377
4378 // Store the element at index zero.
4379 __ sw(value_reg, FieldMemOperand(elements_reg, FixedArray::SizeFor(0)));
4380
4381 // Install the new backing store in the JSArray.
4382 __ sw(elements_reg,
4383 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4384 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
4385 scratch, kRAHasNotBeenSaved, kDontSaveFPRegs,
4386 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4387
4388 // Increment the length of the array.
4389 __ li(length_reg, Operand(Smi::FromInt(1)));
4390 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4391 __ Ret();
4392
4393 __ bind(&check_capacity);
4394 // Check for cow elements, in general they are not handled by this stub
4395 __ CheckMap(elements_reg,
4396 scratch,
4397 Heap::kFixedCOWArrayMapRootIndex,
4398 &miss_force_generic,
4399 DONT_DO_SMI_CHECK);
4400
4401 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4402 __ Branch(&slow, hs, length_reg, Operand(scratch));
4403
4404 // Grow the array and finish the store.
4405 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
4406 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4407 __ jmp(&finish_store);
4408
4409 __ bind(&slow);
4410 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4411 __ Jump(ic_slow, RelocInfo::CODE_TARGET);
4412 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004413}
4414
4415
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004416void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
4417 MacroAssembler* masm,
yangguo@chromium.org56454712012-02-16 15:33:53 +00004418 bool is_js_array,
4419 KeyedAccessGrowMode grow_mode) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004420 // ----------- S t a t e -------------
4421 // -- a0 : value
4422 // -- a1 : key
4423 // -- a2 : receiver
4424 // -- ra : return address
4425 // -- a3 : scratch
4426 // -- t0 : scratch (elements_reg)
4427 // -- t1 : scratch (mantissa_reg)
4428 // -- t2 : scratch (exponent_reg)
4429 // -- t3 : scratch4
4430 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00004431 Label miss_force_generic, transition_elements_kind, grow, slow;
4432 Label finish_store, check_capacity;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004433
4434 Register value_reg = a0;
4435 Register key_reg = a1;
4436 Register receiver_reg = a2;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004437 Register elements_reg = a3;
4438 Register scratch1 = t0;
4439 Register scratch2 = t1;
4440 Register scratch3 = t2;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004441 Register scratch4 = t3;
yangguo@chromium.org56454712012-02-16 15:33:53 +00004442 Register length_reg = t3;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004443
4444 // This stub is meant to be tail-jumped to, the receiver must already
4445 // have been verified by the caller to not be a smi.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004446
4447 // Check that the key is a smi or a heap number convertible to a smi.
4448 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004449
4450 __ lw(elements_reg,
4451 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4452
4453 // Check that the key is within bounds.
4454 if (is_js_array) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004455 __ lw(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004456 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004457 __ lw(scratch1,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004458 FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4459 }
4460 // Compare smis, unsigned compare catches both negative and out-of-bound
4461 // indexes.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004462 if (grow_mode == ALLOW_JSARRAY_GROWTH) {
4463 __ Branch(&grow, hs, key_reg, Operand(scratch1));
4464 } else {
4465 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch1));
4466 }
4467
4468 __ bind(&finish_store);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004469
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004470 __ StoreNumberToDoubleElements(value_reg,
4471 key_reg,
4472 receiver_reg,
4473 elements_reg,
4474 scratch1,
4475 scratch2,
4476 scratch3,
4477 scratch4,
4478 &transition_elements_kind);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004479
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004480 __ Ret(USE_DELAY_SLOT);
4481 __ mov(v0, value_reg); // In delay slot.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004482
4483 // Handle store cache miss, replacing the ic with the generic stub.
4484 __ bind(&miss_force_generic);
4485 Handle<Code> ic =
4486 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4487 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004488
4489 __ bind(&transition_elements_kind);
4490 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4491 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
yangguo@chromium.org56454712012-02-16 15:33:53 +00004492
4493 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4494 // Grow the array by a single element if possible.
4495 __ bind(&grow);
4496
4497 // Make sure the array is only growing by a single element, anything else
4498 // must be handled by the runtime.
4499 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch1));
4500
4501 // Transition on values that can't be stored in a FixedDoubleArray.
4502 Label value_is_smi;
4503 __ JumpIfSmi(value_reg, &value_is_smi);
4504 __ lw(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
4505 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
4506 __ Branch(&transition_elements_kind, ne, scratch1, Operand(at));
4507 __ bind(&value_is_smi);
4508
4509 // Check for the empty array, and preallocate a small backing store if
4510 // possible.
4511 __ lw(length_reg,
4512 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4513 __ lw(elements_reg,
4514 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4515 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
4516 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
4517
4518 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
4519 __ AllocateInNewSpace(size, elements_reg, scratch1, scratch2, &slow,
4520 TAG_OBJECT);
4521
4522 // Initialize the new FixedDoubleArray. Leave elements unitialized for
4523 // efficiency, they are guaranteed to be initialized before use.
4524 __ LoadRoot(scratch1, Heap::kFixedDoubleArrayMapRootIndex);
4525 __ sw(scratch1, FieldMemOperand(elements_reg, JSObject::kMapOffset));
4526 __ li(scratch1, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4527 __ sw(scratch1,
4528 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
4529
4530 // Install the new backing store in the JSArray.
4531 __ sw(elements_reg,
4532 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4533 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
4534 scratch1, kRAHasNotBeenSaved, kDontSaveFPRegs,
4535 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4536
4537 // Increment the length of the array.
4538 __ li(length_reg, Operand(Smi::FromInt(1)));
4539 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
danno@chromium.org00379b82012-05-04 09:16:29 +00004540 __ lw(elements_reg,
4541 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
yangguo@chromium.org56454712012-02-16 15:33:53 +00004542 __ jmp(&finish_store);
4543
4544 __ bind(&check_capacity);
4545 // Make sure that the backing store can hold additional elements.
4546 __ lw(scratch1,
4547 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
4548 __ Branch(&slow, hs, length_reg, Operand(scratch1));
4549
4550 // Grow the array and finish the store.
4551 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
4552 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4553 __ jmp(&finish_store);
4554
4555 __ bind(&slow);
4556 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4557 __ Jump(ic_slow, RelocInfo::CODE_TARGET);
4558 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004559}
4560
4561
ager@chromium.org5c838252010-02-19 08:53:10 +00004562#undef __
4563
4564} } // namespace v8::internal
4565
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004566#endif // V8_TARGET_ARCH_MIPS