blob: c3d8ad55b6b84278372a8b987b1f357742584238 [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.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000273 __ lw(prototype,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000274 MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
275 // Load the native context from the global or builtins object.
276 __ lw(prototype,
277 FieldMemOperand(prototype, GlobalObject::kNativeContextOffset));
278 // Load the function from the native context.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000279 __ lw(prototype, MemOperand(prototype, Context::SlotOffset(index)));
280 // Load the initial map. The global functions all have initial maps.
281 __ lw(prototype,
282 FieldMemOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
283 // Load the prototype from the initial map.
284 __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000285}
286
287
lrn@chromium.org7516f052011-03-30 08:52:27 +0000288void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000289 MacroAssembler* masm,
290 int index,
291 Register prototype,
292 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000293 Isolate* isolate = masm->isolate();
294 // Check we're still in the same context.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000295 __ lw(prototype,
296 MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000297 ASSERT(!prototype.is(at));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000298 __ li(at, isolate->global_object());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000299 __ Branch(miss, ne, prototype, Operand(at));
300 // Get the global function with the given index.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000301 Handle<JSFunction> function(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000302 JSFunction::cast(isolate->native_context()->get(index)));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000303 // Load its initial map. The global functions all have initial maps.
304 __ li(prototype, Handle<Map>(function->initial_map()));
305 // Load the prototype from the initial map.
306 __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000307}
308
309
ager@chromium.org5c838252010-02-19 08:53:10 +0000310// Load a fast property out of a holder object (src). In-object properties
311// are loaded directly otherwise the property is loaded from the properties
312// fixed array.
313void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000314 Register dst,
315 Register src,
316 Handle<JSObject> holder,
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +0000317 PropertyIndex index) {
318 if (index.is_header_index()) {
319 int offset = index.header_index() * kPointerSize;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000320 __ lw(dst, FieldMemOperand(src, offset));
321 } else {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +0000322 // Adjust for the number of properties stored in the holder.
323 int slot = index.field_index() - holder->map()->inobject_properties();
324 if (slot < 0) {
325 // Get the property straight out of the holder.
326 int offset = holder->map()->instance_size() + (slot * kPointerSize);
327 __ lw(dst, FieldMemOperand(src, offset));
328 } else {
329 // Calculate the offset into the properties array.
330 int offset = slot * kPointerSize + FixedArray::kHeaderSize;
331 __ lw(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
332 __ lw(dst, FieldMemOperand(dst, offset));
333 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000334 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000335}
336
337
338void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
339 Register receiver,
340 Register scratch,
341 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000342 // Check that the receiver isn't a smi.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000343 __ JumpIfSmi(receiver, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000344
345 // Check that the object is a JS array.
346 __ GetObjectType(receiver, scratch, scratch);
347 __ Branch(miss_label, ne, scratch, Operand(JS_ARRAY_TYPE));
348
349 // Load length directly from the JS array.
350 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
351 __ Ret();
352}
353
354
355// Generate code to check if an object is a string. If the object is a
356// heap object, its map's instance type is left in the scratch1 register.
357// If this is not needed, scratch1 and scratch2 may be the same register.
358static void GenerateStringCheck(MacroAssembler* masm,
359 Register receiver,
360 Register scratch1,
361 Register scratch2,
362 Label* smi,
363 Label* non_string_object) {
364 // Check that the receiver isn't a smi.
365 __ JumpIfSmi(receiver, smi, t0);
366
367 // Check that the object is a string.
368 __ lw(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
369 __ lbu(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
370 __ And(scratch2, scratch1, Operand(kIsNotStringMask));
371 // The cast is to resolve the overload for the argument of 0x0.
372 __ Branch(non_string_object,
373 ne,
374 scratch2,
375 Operand(static_cast<int32_t>(kStringTag)));
ager@chromium.org5c838252010-02-19 08:53:10 +0000376}
377
378
lrn@chromium.org7516f052011-03-30 08:52:27 +0000379// Generate code to load the length from a string object and return the length.
380// If the receiver object is not a string or a wrapped string object the
381// execution continues at the miss label. The register containing the
382// receiver is potentially clobbered.
383void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
384 Register receiver,
385 Register scratch1,
386 Register scratch2,
387 Label* miss,
388 bool support_wrappers) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000389 Label check_wrapper;
390
391 // Check if the object is a string leaving the instance type in the
392 // scratch1 register.
393 GenerateStringCheck(masm, receiver, scratch1, scratch2, miss,
394 support_wrappers ? &check_wrapper : miss);
395
396 // Load length directly from the string.
397 __ lw(v0, FieldMemOperand(receiver, String::kLengthOffset));
398 __ Ret();
399
400 if (support_wrappers) {
401 // Check if the object is a JSValue wrapper.
402 __ bind(&check_wrapper);
403 __ Branch(miss, ne, scratch1, Operand(JS_VALUE_TYPE));
404
405 // Unwrap the value and check if the wrapped value is a string.
406 __ lw(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
407 GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
408 __ lw(v0, FieldMemOperand(scratch1, String::kLengthOffset));
409 __ Ret();
410 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000411}
412
413
ager@chromium.org5c838252010-02-19 08:53:10 +0000414void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
415 Register receiver,
416 Register scratch1,
417 Register scratch2,
418 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000419 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
420 __ mov(v0, scratch1);
421 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000422}
423
424
lrn@chromium.org7516f052011-03-30 08:52:27 +0000425// Generate StoreField code, value is passed in a0 register.
ager@chromium.org5c838252010-02-19 08:53:10 +0000426// After executing generated code, the receiver_reg and name_reg
427// may be clobbered.
428void StubCompiler::GenerateStoreField(MacroAssembler* masm,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000429 Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +0000430 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000431 Handle<Map> transition,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000432 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +0000433 Register receiver_reg,
434 Register name_reg,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000435 Register scratch1,
436 Register scratch2,
ager@chromium.org5c838252010-02-19 08:53:10 +0000437 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000438 // a0 : value.
439 Label exit;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000440
441 LookupResult lookup(masm->isolate());
442 object->Lookup(*name, &lookup);
443 if (lookup.IsFound() && (lookup.IsReadOnly() || !lookup.IsCacheable())) {
444 // In sloppy mode, we could just return the value and be done. However, we
445 // might be in strict mode, where we have to throw. Since we cannot tell,
446 // go into slow case unconditionally.
447 __ jmp(miss_label);
448 return;
449 }
450
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000451 // Check that the map of the object hasn't changed.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000452 CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
453 : REQUIRE_EXACT_MAP;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000454 __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000455 DO_SMI_CHECK, mode);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000456
457 // Perform global security token check if needed.
458 if (object->IsJSGlobalProxy()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000459 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
460 }
461
462 // Check that we are allowed to write this.
463 if (!transition.is_null() && object->GetPrototype()->IsJSObject()) {
464 JSObject* holder;
465 if (lookup.IsFound()) {
466 holder = lookup.holder();
467 } else {
468 // Find the top object.
469 holder = *object;
470 do {
471 holder = JSObject::cast(holder->GetPrototype());
472 } while (holder->GetPrototype()->IsJSObject());
473 }
474 // We need an extra register, push
475 __ push(name_reg);
476 Label miss_pop, done_check;
477 CheckPrototypes(object, receiver_reg, Handle<JSObject>(holder), name_reg,
478 scratch1, scratch2, name, &miss_pop);
479 __ jmp(&done_check);
480 __ bind(&miss_pop);
481 __ pop(name_reg);
482 __ jmp(miss_label);
483 __ bind(&done_check);
484 __ pop(name_reg);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000485 }
486
487 // Stub never generated for non-global objects that require access
488 // checks.
489 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
490
491 // Perform map transition for the receiver if necessary.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000492 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000493 // The properties must be extended before we can store the value.
494 // We jump to a runtime call that extends the properties array.
495 __ push(receiver_reg);
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000496 __ li(a2, Operand(transition));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000497 __ Push(a2, a0);
498 __ TailCallExternalReference(
499 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
500 masm->isolate()),
501 3, 1);
502 return;
503 }
504
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000505 if (!transition.is_null()) {
verwaest@chromium.org37141392012-05-31 13:27:02 +0000506 // Update the map of the object.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000507 __ li(scratch1, Operand(transition));
508 __ sw(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
verwaest@chromium.org37141392012-05-31 13:27:02 +0000509
510 // Update the write barrier for the map field and pass the now unused
511 // name_reg as scratch register.
512 __ RecordWriteField(receiver_reg,
513 HeapObject::kMapOffset,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000514 scratch1,
verwaest@chromium.org37141392012-05-31 13:27:02 +0000515 name_reg,
516 kRAHasNotBeenSaved,
517 kDontSaveFPRegs,
518 OMIT_REMEMBERED_SET,
519 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000520 }
521
522 // Adjust for the number of properties stored in the object. Even in the
523 // face of a transition we can use the old map here because the size of the
524 // object and the number of in-object properties is not going to change.
525 index -= object->map()->inobject_properties();
526
527 if (index < 0) {
528 // Set the property straight into the object.
529 int offset = object->map()->instance_size() + (index * kPointerSize);
530 __ sw(a0, FieldMemOperand(receiver_reg, offset));
531
532 // Skip updating write barrier if storing a smi.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000533 __ JumpIfSmi(a0, &exit, scratch1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000534
535 // Update the write barrier for the array address.
536 // Pass the now unused name_reg as a scratch register.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000537 __ mov(name_reg, a0);
538 __ RecordWriteField(receiver_reg,
539 offset,
540 name_reg,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000541 scratch1,
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000542 kRAHasNotBeenSaved,
543 kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000544 } else {
545 // Write to the properties array.
546 int offset = index * kPointerSize + FixedArray::kHeaderSize;
547 // Get the properties array.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000548 __ lw(scratch1,
549 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
550 __ sw(a0, FieldMemOperand(scratch1, offset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000551
552 // Skip updating write barrier if storing a smi.
553 __ JumpIfSmi(a0, &exit);
554
555 // Update the write barrier for the array address.
556 // Ok to clobber receiver_reg and name_reg, since we return.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000557 __ mov(name_reg, a0);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000558 __ RecordWriteField(scratch1,
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000559 offset,
560 name_reg,
561 receiver_reg,
562 kRAHasNotBeenSaved,
563 kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000564 }
565
566 // Return the value (register v0).
567 __ bind(&exit);
568 __ mov(v0, a0);
569 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000570}
571
572
573void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000574 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000575 Handle<Code> code = (kind == Code::LOAD_IC)
576 ? masm->isolate()->builtins()->LoadIC_Miss()
577 : masm->isolate()->builtins()->KeyedLoadIC_Miss();
578 __ Jump(code, RelocInfo::CODE_TARGET);
ager@chromium.org5c838252010-02-19 08:53:10 +0000579}
580
581
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000582static void GenerateCallFunction(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000583 Handle<Object> object,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000584 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000585 Label* miss,
586 Code::ExtraICState extra_ic_state) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000587 // ----------- S t a t e -------------
588 // -- a0: receiver
589 // -- a1: function to call
590 // -----------------------------------
591 // Check that the function really is a function.
592 __ JumpIfSmi(a1, miss);
593 __ GetObjectType(a1, a3, a3);
594 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
595
596 // Patch the receiver on the stack with the global proxy if
597 // necessary.
598 if (object->IsGlobalObject()) {
599 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
600 __ sw(a3, MemOperand(sp, arguments.immediate() * kPointerSize));
601 }
602
603 // Invoke the function.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000604 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
605 ? CALL_AS_FUNCTION
606 : CALL_AS_METHOD;
607 __ InvokeFunction(a1, arguments, JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000608}
609
610
611static void PushInterceptorArguments(MacroAssembler* masm,
612 Register receiver,
613 Register holder,
614 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000615 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000616 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000617 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
618 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000619 Register scratch = name;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000620 __ li(scratch, Operand(interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000621 __ Push(scratch, receiver, holder);
622 __ lw(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
623 __ push(scratch);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000624 __ li(scratch, Operand(ExternalReference::isolate_address()));
625 __ push(scratch);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000626}
627
628
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000629static void CompileCallLoadPropertyWithInterceptor(
630 MacroAssembler* masm,
631 Register receiver,
632 Register holder,
633 Register name,
634 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000635 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
636
637 ExternalReference ref =
638 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
639 masm->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000640 __ PrepareCEntryArgs(6);
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000641 __ PrepareCEntryFunction(ref);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000642
643 CEntryStub stub(1);
644 __ CallStub(&stub);
645}
646
647
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000648static const int kFastApiCallArguments = 4;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000649
650
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000651// Reserves space for the extra arguments to API function in the
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000652// caller's frame.
653//
654// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
655static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
656 Register scratch) {
657 ASSERT(Smi::FromInt(0) == 0);
658 for (int i = 0; i < kFastApiCallArguments; i++) {
659 __ push(zero_reg);
660 }
661}
662
663
664// Undoes the effects of ReserveSpaceForFastApiCall.
665static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
666 __ Drop(kFastApiCallArguments);
667}
668
669
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000670static void GenerateFastApiDirectCall(MacroAssembler* masm,
671 const CallOptimization& optimization,
672 int argc) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000673 // ----------- S t a t e -------------
674 // -- sp[0] : holder (set by CheckPrototypes)
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000675 // -- sp[4] : callee JS function
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000676 // -- sp[8] : call data
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000677 // -- sp[12] : isolate
678 // -- sp[16] : last JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000679 // -- ...
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000680 // -- sp[(argc + 3) * 4] : first JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000681 // -- sp[(argc + 4) * 4] : receiver
682 // -----------------------------------
683 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000684 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000685 __ LoadHeapObject(t1, function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000686 __ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset));
687
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000688 // Pass the additional arguments.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000689 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
690 Handle<Object> call_data(api_call_info->data());
691 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
692 __ li(a0, api_call_info);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000693 __ lw(t2, FieldMemOperand(a0, CallHandlerInfo::kDataOffset));
694 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000695 __ li(t2, call_data);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000696 }
697
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000698 __ li(t3, Operand(ExternalReference::isolate_address()));
699 // Store JS function, call data and isolate.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000700 __ sw(t1, MemOperand(sp, 1 * kPointerSize));
701 __ sw(t2, MemOperand(sp, 2 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000702 __ sw(t3, MemOperand(sp, 3 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000703
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000704 // Prepare arguments.
705 __ Addu(a2, sp, Operand(3 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000706
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000707 // Allocate the v8::Arguments structure in the arguments' space since
708 // it's not controlled by GC.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000709 const int kApiStackSpace = 4;
710
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000711 FrameScope frame_scope(masm, StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000712 __ EnterExitFrame(false, kApiStackSpace);
713
714 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
715 // struct from the function (which is currently the case). This means we pass
716 // the first argument in a1 instead of a0. TryCallApiFunctionAndReturn
717 // will handle setting up a0.
718
719 // a1 = v8::Arguments&
720 // Arguments is built at sp + 1 (sp is a reserved spot for ra).
721 __ Addu(a1, sp, kPointerSize);
722
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000723 // v8::Arguments::implicit_args_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000724 __ sw(a2, MemOperand(a1, 0 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000725 // v8::Arguments::values_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000726 __ Addu(t0, a2, Operand(argc * kPointerSize));
727 __ sw(t0, MemOperand(a1, 1 * kPointerSize));
728 // v8::Arguments::length_ = argc
729 __ li(t0, Operand(argc));
730 __ sw(t0, MemOperand(a1, 2 * kPointerSize));
731 // v8::Arguments::is_construct_call = 0
732 __ sw(zero_reg, MemOperand(a1, 3 * kPointerSize));
733
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000734 const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000735 Address function_address = v8::ToCData<Address>(api_call_info->callback());
736 ApiFunction fun(function_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000737 ExternalReference ref =
738 ExternalReference(&fun,
739 ExternalReference::DIRECT_API_CALL,
740 masm->isolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000741 AllowExternalCallThatCantCauseGC scope(masm);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000742 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000743}
744
lrn@chromium.org7516f052011-03-30 08:52:27 +0000745class CallInterceptorCompiler BASE_EMBEDDED {
746 public:
747 CallInterceptorCompiler(StubCompiler* stub_compiler,
748 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000749 Register name,
750 Code::ExtraICState extra_ic_state)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000751 : stub_compiler_(stub_compiler),
752 arguments_(arguments),
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000753 name_(name),
754 extra_ic_state_(extra_ic_state) {}
lrn@chromium.org7516f052011-03-30 08:52:27 +0000755
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000756 void Compile(MacroAssembler* masm,
757 Handle<JSObject> object,
758 Handle<JSObject> holder,
759 Handle<String> name,
760 LookupResult* lookup,
761 Register receiver,
762 Register scratch1,
763 Register scratch2,
764 Register scratch3,
765 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000766 ASSERT(holder->HasNamedInterceptor());
767 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
768
769 // Check that the receiver isn't a smi.
770 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000771 CallOptimization optimization(lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000772 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000773 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
774 holder, lookup, name, optimization, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000775 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000776 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
777 name, holder, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000778 }
779 }
780
781 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000782 void CompileCacheable(MacroAssembler* masm,
783 Handle<JSObject> object,
784 Register receiver,
785 Register scratch1,
786 Register scratch2,
787 Register scratch3,
788 Handle<JSObject> interceptor_holder,
789 LookupResult* lookup,
790 Handle<String> name,
791 const CallOptimization& optimization,
792 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000793 ASSERT(optimization.is_constant_call());
794 ASSERT(!lookup->holder()->IsGlobalObject());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000795 Counters* counters = masm->isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000796 int depth1 = kInvalidProtoDepth;
797 int depth2 = kInvalidProtoDepth;
798 bool can_do_fast_api_call = false;
799 if (optimization.is_simple_api_call() &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000800 !lookup->holder()->IsGlobalObject()) {
801 depth1 = optimization.GetPrototypeDepthOfExpectedType(
802 object, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000803 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000804 depth2 = optimization.GetPrototypeDepthOfExpectedType(
805 interceptor_holder, Handle<JSObject>(lookup->holder()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000806 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000807 can_do_fast_api_call =
808 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000809 }
810
811 __ IncrementCounter(counters->call_const_interceptor(), 1,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000812 scratch1, scratch2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000813
814 if (can_do_fast_api_call) {
815 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
816 scratch1, scratch2);
817 ReserveSpaceForFastApiCall(masm, scratch1);
818 }
819
820 // Check that the maps from receiver to interceptor's holder
821 // haven't changed and thus we can invoke interceptor.
822 Label miss_cleanup;
823 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
824 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000825 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
826 scratch1, scratch2, scratch3,
827 name, depth1, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000828
829 // Invoke an interceptor and if it provides a value,
830 // branch to |regular_invoke|.
831 Label regular_invoke;
832 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
833 &regular_invoke);
834
835 // Interceptor returned nothing for this property. Try to use cached
836 // constant function.
837
838 // Check that the maps from interceptor's holder to constant function's
839 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000840 if (*interceptor_holder != lookup->holder()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000841 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000842 Handle<JSObject>(lookup->holder()),
843 scratch1, scratch2, scratch3,
844 name, depth2, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000845 } else {
846 // CheckPrototypes has a side effect of fetching a 'holder'
847 // for API (object which is instanceof for the signature). It's
848 // safe to omit it here, as if present, it should be fetched
849 // by the previous CheckPrototypes.
850 ASSERT(depth2 == kInvalidProtoDepth);
851 }
852
853 // Invoke function.
854 if (can_do_fast_api_call) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000855 GenerateFastApiDirectCall(masm, optimization, arguments_.immediate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000856 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000857 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
858 ? CALL_AS_FUNCTION
859 : CALL_AS_METHOD;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000860 __ InvokeFunction(optimization.constant_function(), arguments_,
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000861 JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000862 }
863
864 // Deferred code for fast API call case---clean preallocated space.
865 if (can_do_fast_api_call) {
866 __ bind(&miss_cleanup);
867 FreeSpaceForFastApiCall(masm);
868 __ Branch(miss_label);
869 }
870
871 // Invoke a regular function.
872 __ bind(&regular_invoke);
873 if (can_do_fast_api_call) {
874 FreeSpaceForFastApiCall(masm);
875 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000876 }
877
878 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000879 Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000880 Register receiver,
881 Register scratch1,
882 Register scratch2,
883 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000884 Handle<String> name,
885 Handle<JSObject> interceptor_holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000886 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000887 Register holder =
888 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000889 scratch1, scratch2, scratch3,
890 name, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000891
892 // Call a runtime function to load the interceptor property.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000893 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000894 // Save the name_ register across the call.
895 __ push(name_);
896
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000897 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000898
899 __ CallExternalReference(
900 ExternalReference(
901 IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
902 masm->isolate()),
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000903 6);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000904 // Restore the name_ register.
905 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000906 // Leave the internal frame.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000907 }
908
909 void LoadWithInterceptor(MacroAssembler* masm,
910 Register receiver,
911 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000912 Handle<JSObject> holder_obj,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000913 Register scratch,
914 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000915 {
916 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000917
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000918 __ Push(holder, name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000919 CompileCallLoadPropertyWithInterceptor(masm,
920 receiver,
921 holder,
922 name_,
923 holder_obj);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000924 __ pop(name_); // Restore the name.
925 __ pop(receiver); // Restore the holder.
926 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000927 // If interceptor returns no-result sentinel, call the constant function.
928 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
929 __ Branch(interceptor_succeeded, ne, v0, Operand(scratch));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000930 }
931
932 StubCompiler* stub_compiler_;
933 const ParameterCount& arguments_;
934 Register name_;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000935 Code::ExtraICState extra_ic_state_;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000936};
937
938
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000939
940// Generate code to check that a global property cell is empty. Create
941// the property cell at compilation time if no cell exists for the
942// property.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000943static void GenerateCheckPropertyCell(MacroAssembler* masm,
944 Handle<GlobalObject> global,
945 Handle<String> name,
946 Register scratch,
947 Label* miss) {
948 Handle<JSGlobalPropertyCell> cell =
949 GlobalObject::EnsurePropertyCell(global, name);
950 ASSERT(cell->value()->IsTheHole());
951 __ li(scratch, Operand(cell));
952 __ lw(scratch,
953 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
954 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
955 __ Branch(miss, ne, scratch, Operand(at));
956}
957
958
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000959// Calls GenerateCheckPropertyCell for each global object in the prototype chain
960// from object to (but not including) holder.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000961static void GenerateCheckPropertyCells(MacroAssembler* masm,
962 Handle<JSObject> object,
963 Handle<JSObject> holder,
964 Handle<String> name,
965 Register scratch,
966 Label* miss) {
967 Handle<JSObject> current = object;
968 while (!current.is_identical_to(holder)) {
969 if (current->IsGlobalObject()) {
970 GenerateCheckPropertyCell(masm,
971 Handle<GlobalObject>::cast(current),
972 name,
973 scratch,
974 miss);
975 }
976 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
977 }
978}
979
980
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000981// Convert and store int passed in register ival to IEEE 754 single precision
982// floating point value at memory location (dst + 4 * wordoffset)
983// If FPU is available use it for conversion.
984static void StoreIntAsFloat(MacroAssembler* masm,
985 Register dst,
986 Register wordoffset,
987 Register ival,
988 Register fval,
989 Register scratch1,
990 Register scratch2) {
991 if (CpuFeatures::IsSupported(FPU)) {
992 CpuFeatures::Scope scope(FPU);
993 __ mtc1(ival, f0);
994 __ cvt_s_w(f0, f0);
995 __ sll(scratch1, wordoffset, 2);
996 __ addu(scratch1, dst, scratch1);
997 __ swc1(f0, MemOperand(scratch1, 0));
998 } else {
999 // FPU is not available, do manual conversions.
1000
1001 Label not_special, done;
1002 // Move sign bit from source to destination. This works because the sign
1003 // bit in the exponent word of the double has the same position and polarity
1004 // as the 2's complement sign bit in a Smi.
1005 ASSERT(kBinary32SignMask == 0x80000000u);
1006
1007 __ And(fval, ival, Operand(kBinary32SignMask));
1008 // Negate value if it is negative.
1009 __ subu(scratch1, zero_reg, ival);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001010 __ Movn(ival, scratch1, fval);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001011
1012 // We have -1, 0 or 1, which we treat specially. Register ival contains
1013 // absolute value: it is either equal to 1 (special case of -1 and 1),
1014 // greater than 1 (not a special case) or less than 1 (special case of 0).
1015 __ Branch(&not_special, gt, ival, Operand(1));
1016
1017 // For 1 or -1 we need to or in the 0 exponent (biased).
1018 static const uint32_t exponent_word_for_1 =
1019 kBinary32ExponentBias << kBinary32ExponentShift;
1020
1021 __ Xor(scratch1, ival, Operand(1));
1022 __ li(scratch2, exponent_word_for_1);
1023 __ or_(scratch2, fval, scratch2);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001024 __ Movz(fval, scratch2, scratch1); // Only if ival is equal to 1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001025 __ Branch(&done);
1026
1027 __ bind(&not_special);
1028 // Count leading zeros.
1029 // Gets the wrong answer for 0, but we already checked for that case above.
1030 Register zeros = scratch2;
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001031 __ Clz(zeros, ival);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001032
1033 // Compute exponent and or it into the exponent register.
1034 __ li(scratch1, (kBitsPerInt - 1) + kBinary32ExponentBias);
1035 __ subu(scratch1, scratch1, zeros);
1036
1037 __ sll(scratch1, scratch1, kBinary32ExponentShift);
1038 __ or_(fval, fval, scratch1);
1039
1040 // Shift up the source chopping the top bit off.
1041 __ Addu(zeros, zeros, Operand(1));
1042 // This wouldn't work for 1 and -1 as the shift would be 32 which means 0.
1043 __ sllv(ival, ival, zeros);
1044 // And the top (top 20 bits).
1045 __ srl(scratch1, ival, kBitsPerInt - kBinary32MantissaBits);
1046 __ or_(fval, fval, scratch1);
1047
1048 __ bind(&done);
1049
1050 __ sll(scratch1, wordoffset, 2);
1051 __ addu(scratch1, dst, scratch1);
1052 __ sw(fval, MemOperand(scratch1, 0));
1053 }
1054}
1055
1056
ager@chromium.org5c838252010-02-19 08:53:10 +00001057#undef __
1058#define __ ACCESS_MASM(masm())
1059
1060
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001061Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
1062 Register object_reg,
1063 Handle<JSObject> holder,
1064 Register holder_reg,
1065 Register scratch1,
1066 Register scratch2,
1067 Handle<String> name,
1068 int save_at_depth,
1069 Label* miss) {
1070 // Make sure there's no overlap between holder and object registers.
1071 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1072 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1073 && !scratch2.is(scratch1));
1074
1075 // Keep track of the current object in register reg.
1076 Register reg = object_reg;
1077 int depth = 0;
1078
1079 if (save_at_depth == depth) {
1080 __ sw(reg, MemOperand(sp));
1081 }
1082
1083 // Check the maps in the prototype chain.
1084 // Traverse the prototype chain from the object and do map checks.
1085 Handle<JSObject> current = object;
1086 while (!current.is_identical_to(holder)) {
1087 ++depth;
1088
1089 // Only global objects and objects that do not require access
1090 // checks are allowed in stubs.
1091 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1092
1093 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
1094 if (!current->HasFastProperties() &&
1095 !current->IsJSGlobalObject() &&
1096 !current->IsJSGlobalProxy()) {
1097 if (!name->IsSymbol()) {
1098 name = factory()->LookupSymbol(name);
1099 }
1100 ASSERT(current->property_dictionary()->FindEntry(*name) ==
1101 StringDictionary::kNotFound);
1102
1103 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1104 scratch1, scratch2);
1105
1106 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1107 reg = holder_reg; // From now on the object will be in holder_reg.
1108 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1109 } else {
1110 Handle<Map> current_map(current->map());
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001111 __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK,
1112 ALLOW_ELEMENT_TRANSITION_MAPS);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001113 // Check access rights to the global object. This has to happen after
1114 // the map check so that we know that the object is actually a global
1115 // object.
1116 if (current->IsJSGlobalProxy()) {
1117 __ CheckAccessGlobalProxy(reg, scratch2, miss);
1118 }
1119 reg = holder_reg; // From now on the object will be in holder_reg.
1120
1121 if (heap()->InNewSpace(*prototype)) {
1122 // The prototype is in new space; we cannot store a reference to it
1123 // in the code. Load it from the map.
1124 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1125 } else {
1126 // The prototype is in old space; load it directly.
1127 __ li(reg, Operand(prototype));
1128 }
1129 }
1130
1131 if (save_at_depth == depth) {
1132 __ sw(reg, MemOperand(sp));
1133 }
1134
1135 // Go to the next object in the prototype chain.
1136 current = prototype;
1137 }
1138
1139 // Log the check depth.
1140 LOG(masm()->isolate(), IntEvent("check-maps-depth", depth + 1));
1141
1142 // Check the holder map.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001143 __ CheckMap(reg, scratch1, Handle<Map>(current->map()), miss,
1144 DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001145
1146 // Perform security check for access to the global object.
1147 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1148 if (holder->IsJSGlobalProxy()) {
1149 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1150 }
1151
1152 // If we've skipped any global objects, it's not enough to verify that
1153 // their maps haven't changed. We also need to check that the property
1154 // cell for the property is still empty.
1155 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1156
1157 // Return the register containing the holder.
1158 return reg;
1159}
1160
1161
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001162void StubCompiler::GenerateLoadField(Handle<JSObject> object,
1163 Handle<JSObject> holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001164 Register receiver,
1165 Register scratch1,
1166 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001167 Register scratch3,
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00001168 PropertyIndex index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001169 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001170 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001171 // Check that the receiver isn't a smi.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001172 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001173
1174 // Check that the maps haven't changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001175 Register reg = CheckPrototypes(
1176 object, receiver, holder, scratch1, scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001177 GenerateFastPropertyLoad(masm(), v0, reg, holder, index);
1178 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001179}
1180
1181
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001182void StubCompiler::GenerateLoadConstant(Handle<JSObject> object,
1183 Handle<JSObject> holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001184 Register receiver,
1185 Register scratch1,
1186 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001187 Register scratch3,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001188 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001189 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001190 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001191 // Check that the receiver isn't a smi.
1192 __ JumpIfSmi(receiver, miss, scratch1);
1193
1194 // Check that the maps haven't changed.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001195 CheckPrototypes(object, receiver, holder,
1196 scratch1, scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001197
1198 // Return the constant value.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001199 __ LoadHeapObject(v0, value);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001200 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001201}
1202
1203
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001204void StubCompiler::GenerateDictionaryLoadCallback(Register receiver,
1205 Register name_reg,
1206 Register scratch1,
1207 Register scratch2,
1208 Register scratch3,
1209 Handle<AccessorInfo> callback,
1210 Handle<String> name,
1211 Label* miss) {
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001212 ASSERT(!receiver.is(scratch1));
1213 ASSERT(!receiver.is(scratch2));
1214 ASSERT(!receiver.is(scratch3));
1215
1216 // Load the properties dictionary.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001217 Register dictionary = scratch1;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001218 __ lw(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
1219
1220 // Probe the dictionary.
1221 Label probe_done;
1222 StringDictionaryLookupStub::GeneratePositiveLookup(masm(),
1223 miss,
1224 &probe_done,
1225 dictionary,
1226 name_reg,
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001227 scratch2,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001228 scratch3);
1229 __ bind(&probe_done);
1230
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001231 // If probing finds an entry in the dictionary, scratch3 contains the
1232 // pointer into the dictionary. Check that the value is the callback.
1233 Register pointer = scratch3;
1234 const int kElementsStartOffset = StringDictionary::kHeaderSize +
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001235 StringDictionary::kElementsStartIndex * kPointerSize;
1236 const int kValueOffset = kElementsStartOffset + kPointerSize;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001237 __ lw(scratch2, FieldMemOperand(pointer, kValueOffset));
1238 __ Branch(miss, ne, scratch2, Operand(callback));
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001239}
1240
1241
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001242void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
1243 Handle<JSObject> holder,
1244 Register receiver,
1245 Register name_reg,
1246 Register scratch1,
1247 Register scratch2,
1248 Register scratch3,
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001249 Register scratch4,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001250 Handle<AccessorInfo> callback,
1251 Handle<String> name,
1252 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001253 // Check that the receiver isn't a smi.
1254 __ JumpIfSmi(receiver, miss, scratch1);
1255
1256 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001257 Register reg = CheckPrototypes(object, receiver, holder, scratch1,
1258 scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001259
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001260 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
1261 GenerateDictionaryLoadCallback(
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001262 reg, name_reg, scratch2, scratch3, scratch4, callback, name, miss);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001263 }
1264
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001265 // Build AccessorInfo::args_ list on the stack and push property name below
1266 // the exit frame to make GC aware of them and store pointers to them.
1267 __ push(receiver);
1268 __ mov(scratch2, sp); // scratch2 = AccessorInfo::args_
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001269 if (heap()->InNewSpace(callback->data())) {
1270 __ li(scratch3, callback);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001271 __ lw(scratch3, FieldMemOperand(scratch3, AccessorInfo::kDataOffset));
1272 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001273 __ li(scratch3, Handle<Object>(callback->data()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001274 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001275 __ Subu(sp, sp, 4 * kPointerSize);
1276 __ sw(reg, MemOperand(sp, 3 * kPointerSize));
1277 __ sw(scratch3, MemOperand(sp, 2 * kPointerSize));
1278 __ li(scratch3, Operand(ExternalReference::isolate_address()));
1279 __ sw(scratch3, MemOperand(sp, 1 * kPointerSize));
1280 __ sw(name_reg, MemOperand(sp, 0 * kPointerSize));
1281
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001282 __ mov(a2, scratch2); // Saved in case scratch2 == a1.
1283 __ mov(a1, sp); // a1 (first argument - see note below) = Handle<String>
1284
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001285 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
1286 // struct from the function (which is currently the case). This means we pass
1287 // the arguments in a1-a2 instead of a0-a1. TryCallApiFunctionAndReturn
1288 // will handle setting up a0.
1289
1290 const int kApiStackSpace = 1;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001291 FrameScope frame_scope(masm(), StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001292 __ EnterExitFrame(false, kApiStackSpace);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001293
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001294 // Create AccessorInfo instance on the stack above the exit frame with
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001295 // scratch2 (internal::Object** args_) as the data.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001296 __ sw(a2, MemOperand(sp, kPointerSize));
1297 // a2 (second argument - see note above) = AccessorInfo&
1298 __ Addu(a2, sp, kPointerSize);
1299
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001300 const int kStackUnwindSpace = 5;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001301 Address getter_address = v8::ToCData<Address>(callback->getter());
1302 ApiFunction fun(getter_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001303 ExternalReference ref =
1304 ExternalReference(&fun,
1305 ExternalReference::DIRECT_GETTER_CALL,
1306 masm()->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001307 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
ager@chromium.org5c838252010-02-19 08:53:10 +00001308}
1309
1310
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001311void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
1312 Handle<JSObject> interceptor_holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001313 LookupResult* lookup,
1314 Register receiver,
1315 Register name_reg,
1316 Register scratch1,
1317 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001318 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001319 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001320 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001321 ASSERT(interceptor_holder->HasNamedInterceptor());
1322 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1323
1324 // Check that the receiver isn't a smi.
1325 __ JumpIfSmi(receiver, miss);
1326
1327 // So far the most popular follow ups for interceptor loads are FIELD
1328 // and CALLBACKS, so inline only them, other cases may be added
1329 // later.
1330 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001331 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001332 if (lookup->IsField()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001333 compile_followup_inline = true;
1334 } else if (lookup->type() == CALLBACKS &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001335 lookup->GetCallbackObject()->IsAccessorInfo()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001336 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
1337 compile_followup_inline = callback->getter() != NULL &&
1338 callback->IsCompatibleReceiver(*object);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001339 }
1340 }
1341
1342 if (compile_followup_inline) {
1343 // Compile the interceptor call, followed by inline code to load the
1344 // property from further up the prototype chain if the call fails.
1345 // Check that the maps haven't changed.
1346 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1347 scratch1, scratch2, scratch3,
1348 name, miss);
1349 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
1350
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001351 // Preserve the receiver register explicitly whenever it is different from
1352 // the holder and it is needed should the interceptor return without any
1353 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1354 // the FIELD case might cause a miss during the prototype check.
1355 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
1356 bool must_preserve_receiver_reg = !receiver.is(holder_reg) &&
1357 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1358
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001359 // Save necessary data before invoking an interceptor.
1360 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001361 {
1362 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001363 if (must_preserve_receiver_reg) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001364 __ Push(receiver, holder_reg, name_reg);
1365 } else {
1366 __ Push(holder_reg, name_reg);
1367 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001368 // Invoke an interceptor. Note: map checks from receiver to
1369 // interceptor's holder has been compiled before (see a caller
1370 // of this method).
1371 CompileCallLoadPropertyWithInterceptor(masm(),
1372 receiver,
1373 holder_reg,
1374 name_reg,
1375 interceptor_holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001376 // Check if interceptor provided a value for property. If it's
1377 // the case, return immediately.
1378 Label interceptor_failed;
1379 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
1380 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1));
1381 frame_scope.GenerateLeaveFrame();
1382 __ Ret();
1383
1384 __ bind(&interceptor_failed);
1385 __ pop(name_reg);
1386 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001387 if (must_preserve_receiver_reg) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001388 __ pop(receiver);
1389 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001390 // Leave the internal frame.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001391 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001392 // Check that the maps from interceptor's holder to lookup's holder
1393 // haven't changed. And load lookup's holder into |holder| register.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001394 if (must_perfrom_prototype_check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001395 holder_reg = CheckPrototypes(interceptor_holder,
1396 holder_reg,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001397 Handle<JSObject>(lookup->holder()),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001398 scratch1,
1399 scratch2,
1400 scratch3,
1401 name,
1402 miss);
1403 }
1404
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001405 if (lookup->IsField()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001406 // We found FIELD property in prototype chain of interceptor's holder.
1407 // Retrieve a field from field's holder.
1408 GenerateFastPropertyLoad(masm(), v0, holder_reg,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001409 Handle<JSObject>(lookup->holder()),
1410 lookup->GetFieldIndex());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001411 __ Ret();
1412 } else {
1413 // We found CALLBACKS property in prototype chain of interceptor's
1414 // holder.
1415 ASSERT(lookup->type() == CALLBACKS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001416 Handle<AccessorInfo> callback(
1417 AccessorInfo::cast(lookup->GetCallbackObject()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001418 ASSERT(callback->getter() != NULL);
1419
1420 // Tail call to runtime.
1421 // Important invariant in CALLBACKS case: the code above must be
1422 // structured to never clobber |receiver| register.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001423 __ li(scratch2, callback);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001424
1425 __ Push(receiver, holder_reg);
1426 __ lw(scratch3,
1427 FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
1428 __ li(scratch1, Operand(ExternalReference::isolate_address()));
1429 __ Push(scratch3, scratch1, scratch2, name_reg);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001430
1431 ExternalReference ref =
1432 ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
1433 masm()->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001434 __ TailCallExternalReference(ref, 6, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001435 }
1436 } else { // !compile_followup_inline
1437 // Call the runtime system to load the interceptor.
1438 // Check that the maps haven't changed.
1439 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1440 scratch1, scratch2, scratch3,
1441 name, miss);
1442 PushInterceptorArguments(masm(), receiver, holder_reg,
1443 name_reg, interceptor_holder);
1444
1445 ExternalReference ref = ExternalReference(
1446 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), masm()->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001447 __ TailCallExternalReference(ref, 6, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001448 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001449}
1450
1451
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001452void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001453 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001454 __ Branch(miss, ne, a2, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001455 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001456}
1457
1458
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001459void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1460 Handle<JSObject> holder,
1461 Handle<String> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001462 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001463 ASSERT(holder->IsGlobalObject());
1464
1465 // Get the number of arguments.
1466 const int argc = arguments().immediate();
1467
1468 // Get the receiver from the stack.
1469 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1470
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001471 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001472 __ JumpIfSmi(a0, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001473 CheckPrototypes(object, a0, holder, a3, a1, t0, name, miss);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001474}
1475
1476
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001477void CallStubCompiler::GenerateLoadFunctionFromCell(
1478 Handle<JSGlobalPropertyCell> cell,
1479 Handle<JSFunction> function,
1480 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001481 // Get the value from the cell.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001482 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001483 __ lw(a1, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
1484
1485 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001486 if (heap()->InNewSpace(*function)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001487 // We can't embed a pointer to a function in new space so we have
1488 // to verify that the shared function info is unchanged. This has
1489 // the nice side effect that multiple closures based on the same
1490 // function can all use this call IC. Before we load through the
1491 // function, we have to verify that it still is a function.
1492 __ JumpIfSmi(a1, miss);
1493 __ GetObjectType(a1, a3, a3);
1494 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
1495
1496 // Check the shared function info. Make sure it hasn't changed.
1497 __ li(a3, Handle<SharedFunctionInfo>(function->shared()));
1498 __ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
1499 __ Branch(miss, ne, t0, Operand(a3));
1500 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001501 __ Branch(miss, ne, a1, Operand(function));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001502 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001503}
1504
1505
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001506void CallStubCompiler::GenerateMissBranch() {
1507 Handle<Code> code =
danno@chromium.org40cb8782011-05-25 07:58:50 +00001508 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1509 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001510 extra_state_);
1511 __ Jump(code, RelocInfo::CODE_TARGET);
1512}
1513
1514
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001515Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1516 Handle<JSObject> holder,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001517 PropertyIndex index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001518 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001519 // ----------- S t a t e -------------
1520 // -- a2 : name
1521 // -- ra : return address
1522 // -----------------------------------
1523 Label miss;
1524
1525 GenerateNameCheck(name, &miss);
1526
1527 const int argc = arguments().immediate();
1528
1529 // Get the receiver of the function from the stack into a0.
1530 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1531 // Check that the receiver isn't a smi.
1532 __ JumpIfSmi(a0, &miss, t0);
1533
1534 // Do the right check and compute the holder register.
1535 Register reg = CheckPrototypes(object, a0, holder, a1, a3, t0, name, &miss);
1536 GenerateFastPropertyLoad(masm(), a1, reg, holder, index);
1537
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001538 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001539
1540 // Handle call cache miss.
1541 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001542 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001543
1544 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001545 return GetCode(Code::FIELD, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001546}
1547
1548
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001549Handle<Code> CallStubCompiler::CompileArrayPushCall(
1550 Handle<Object> object,
1551 Handle<JSObject> holder,
1552 Handle<JSGlobalPropertyCell> cell,
1553 Handle<JSFunction> function,
1554 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001555 // ----------- S t a t e -------------
1556 // -- a2 : name
1557 // -- ra : return address
1558 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1559 // -- ...
1560 // -- sp[argc * 4] : receiver
1561 // -----------------------------------
1562
1563 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001564 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001565
1566 Label miss;
1567
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001568 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001569
1570 Register receiver = a1;
1571
1572 // Get the receiver from the stack.
1573 const int argc = arguments().immediate();
1574 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1575
1576 // Check that the receiver isn't a smi.
1577 __ JumpIfSmi(receiver, &miss);
1578
1579 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001580 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, a3, v0, t0,
1581 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001582
1583 if (argc == 0) {
1584 // Nothing to do, just return the length.
1585 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1586 __ Drop(argc + 1);
1587 __ Ret();
1588 } else {
1589 Label call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001590 if (argc == 1) { // Otherwise fall through to call the builtin.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001591 Label attempt_to_grow_elements, with_write_barrier, check_double;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001592
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001593 Register elements = t2;
1594 Register end_elements = t1;
1595 // Get the elements array of the object.
1596 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1597
1598 // Check that the elements are in fast mode and writable.
1599 __ CheckMap(elements,
1600 v0,
1601 Heap::kFixedArrayMapRootIndex,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001602 &check_double,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001603 DONT_DO_SMI_CHECK);
1604
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001605 // Get the array's length into v0 and calculate new length.
1606 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1607 STATIC_ASSERT(kSmiTagSize == 1);
1608 STATIC_ASSERT(kSmiTag == 0);
1609 __ Addu(v0, v0, Operand(Smi::FromInt(argc)));
1610
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001611 // Get the elements' length.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001612 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1613
1614 // Check if we could survive without allocation.
1615 __ Branch(&attempt_to_grow_elements, gt, v0, Operand(t0));
1616
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001617 // Check if value is a smi.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001618 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1619 __ JumpIfNotSmi(t0, &with_write_barrier);
1620
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001621 // Save new length.
1622 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1623
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001624 // Store the value.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001625 // We may need a register containing the address end_elements below,
1626 // so write back the value in end_elements.
1627 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1628 __ Addu(end_elements, elements, end_elements);
1629 const int kEndElementsOffset =
1630 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001631 __ Addu(end_elements, end_elements, kEndElementsOffset);
1632 __ sw(t0, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001633
1634 // Check for a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001635 __ Drop(argc + 1);
1636 __ Ret();
1637
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001638 __ bind(&check_double);
1639
1640 // Check that the elements are in fast mode and writable.
1641 __ CheckMap(elements,
1642 a0,
1643 Heap::kFixedDoubleArrayMapRootIndex,
1644 &call_builtin,
1645 DONT_DO_SMI_CHECK);
1646
1647 // Get the array's length into r0 and calculate new length.
1648 __ lw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1649 STATIC_ASSERT(kSmiTagSize == 1);
1650 STATIC_ASSERT(kSmiTag == 0);
1651 __ Addu(a0, a0, Operand(Smi::FromInt(argc)));
1652
1653 // Get the elements' length.
1654 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1655
1656 // Check if we could survive without allocation.
1657 __ Branch(&call_builtin, gt, a0, Operand(t0));
1658
1659 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1660 __ StoreNumberToDoubleElements(
1661 t0, a0, elements, a3, t1, a2, t5,
1662 &call_builtin, argc * kDoubleSize);
1663
1664 // Save new length.
1665 __ sw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1666
1667 // Check for a smi.
1668 __ Drop(argc + 1);
1669 __ Ret();
1670
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001671 __ bind(&with_write_barrier);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001672
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001673 __ lw(a3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1674
1675 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
1676 Label fast_object, not_fast_object;
1677 __ CheckFastObjectElements(a3, t3, &not_fast_object);
1678 __ jmp(&fast_object);
1679 // In case of fast smi-only, convert to fast object, otherwise bail out.
1680 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001681 __ CheckFastSmiElements(a3, t3, &call_builtin);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001682
1683 __ lw(t3, FieldMemOperand(t0, HeapObject::kMapOffset));
1684 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
1685 __ Branch(&call_builtin, eq, t3, Operand(at));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001686 // edx: receiver
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001687 // a3: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001688 Label try_holey_map;
1689 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001690 FAST_ELEMENTS,
1691 a3,
1692 t3,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001693 &try_holey_map);
1694 __ mov(a2, receiver);
1695 ElementsTransitionGenerator::
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001696 GenerateMapChangeElementsTransition(masm(),
1697 DONT_TRACK_ALLOCATION_SITE,
1698 NULL);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001699 __ jmp(&fast_object);
1700
1701 __ bind(&try_holey_map);
1702 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1703 FAST_HOLEY_ELEMENTS,
1704 a3,
1705 t3,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001706 &call_builtin);
1707 __ mov(a2, receiver);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001708 ElementsTransitionGenerator::
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001709 GenerateMapChangeElementsTransition(masm(),
1710 DONT_TRACK_ALLOCATION_SITE,
1711 NULL);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001712 __ bind(&fast_object);
1713 } else {
1714 __ CheckFastObjectElements(a3, a3, &call_builtin);
1715 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001716
1717 // Save new length.
1718 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1719
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001720 // Store the value.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001721 // We may need a register containing the address end_elements below,
1722 // so write back the value in end_elements.
1723 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1724 __ Addu(end_elements, elements, end_elements);
1725 __ Addu(end_elements, end_elements, kEndElementsOffset);
1726 __ sw(t0, MemOperand(end_elements));
1727
1728 __ RecordWrite(elements,
1729 end_elements,
1730 t0,
1731 kRAHasNotBeenSaved,
1732 kDontSaveFPRegs,
1733 EMIT_REMEMBERED_SET,
1734 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001735 __ Drop(argc + 1);
1736 __ Ret();
1737
1738 __ bind(&attempt_to_grow_elements);
1739 // v0: array's length + 1.
1740 // t0: elements' length.
1741
1742 if (!FLAG_inline_new) {
1743 __ Branch(&call_builtin);
1744 }
1745
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001746 __ lw(a2, MemOperand(sp, (argc - 1) * kPointerSize));
1747 // Growing elements that are SMI-only requires special handling in case
1748 // the new element is non-Smi. For now, delegate to the builtin.
1749 Label no_fast_elements_check;
1750 __ JumpIfSmi(a2, &no_fast_elements_check);
1751 __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1752 __ CheckFastObjectElements(t3, t3, &call_builtin);
1753 __ bind(&no_fast_elements_check);
1754
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001755 ExternalReference new_space_allocation_top =
1756 ExternalReference::new_space_allocation_top_address(
1757 masm()->isolate());
1758 ExternalReference new_space_allocation_limit =
1759 ExternalReference::new_space_allocation_limit_address(
1760 masm()->isolate());
1761
1762 const int kAllocationDelta = 4;
1763 // Load top and check if it is the end of elements.
1764 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1765 __ Addu(end_elements, elements, end_elements);
1766 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset));
1767 __ li(t3, Operand(new_space_allocation_top));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001768 __ lw(a3, MemOperand(t3));
1769 __ Branch(&call_builtin, ne, end_elements, Operand(a3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001770
1771 __ li(t5, Operand(new_space_allocation_limit));
1772 __ lw(t5, MemOperand(t5));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001773 __ Addu(a3, a3, Operand(kAllocationDelta * kPointerSize));
1774 __ Branch(&call_builtin, hi, a3, Operand(t5));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001775
1776 // We fit and could grow elements.
1777 // Update new_space_allocation_top.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001778 __ sw(a3, MemOperand(t3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001779 // Push the argument.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001780 __ sw(a2, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001781 // Fill the rest with holes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001782 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001783 for (int i = 1; i < kAllocationDelta; i++) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001784 __ sw(a3, MemOperand(end_elements, i * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001785 }
1786
1787 // Update elements' and array's sizes.
1788 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1789 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta)));
1790 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1791
1792 // Elements are in new space, so write barrier is not required.
1793 __ Drop(argc + 1);
1794 __ Ret();
1795 }
1796 __ bind(&call_builtin);
1797 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
1798 masm()->isolate()),
1799 argc + 1,
1800 1);
1801 }
1802
1803 // Handle call cache miss.
1804 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001805 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001806
1807 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001808 return GetCode(function);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001809}
1810
1811
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001812Handle<Code> CallStubCompiler::CompileArrayPopCall(
1813 Handle<Object> object,
1814 Handle<JSObject> holder,
1815 Handle<JSGlobalPropertyCell> cell,
1816 Handle<JSFunction> function,
1817 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001818 // ----------- S t a t e -------------
1819 // -- a2 : name
1820 // -- ra : return address
1821 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1822 // -- ...
1823 // -- sp[argc * 4] : receiver
1824 // -----------------------------------
1825
1826 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001827 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001828
1829 Label miss, return_undefined, call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001830 Register receiver = a1;
1831 Register elements = a3;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001832 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001833
1834 // Get the receiver from the stack.
1835 const int argc = arguments().immediate();
1836 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001837 // Check that the receiver isn't a smi.
1838 __ JumpIfSmi(receiver, &miss);
1839
1840 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001841 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, elements,
1842 t0, v0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001843
1844 // Get the elements array of the object.
1845 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1846
1847 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001848 __ CheckMap(elements,
1849 v0,
1850 Heap::kFixedArrayMapRootIndex,
1851 &call_builtin,
1852 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001853
1854 // Get the array's length into t0 and calculate new length.
1855 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1856 __ Subu(t0, t0, Operand(Smi::FromInt(1)));
1857 __ Branch(&return_undefined, lt, t0, Operand(zero_reg));
1858
1859 // Get the last element.
1860 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1861 STATIC_ASSERT(kSmiTagSize == 1);
1862 STATIC_ASSERT(kSmiTag == 0);
1863 // We can't address the last element in one operation. Compute the more
1864 // expensive shift first, and use an offset later on.
1865 __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize);
1866 __ Addu(elements, elements, t1);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001867 __ lw(v0, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001868 __ Branch(&call_builtin, eq, v0, Operand(t2));
1869
1870 // Set the array's length.
1871 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1872
1873 // Fill with the hole.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001874 __ sw(t2, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001875 __ Drop(argc + 1);
1876 __ Ret();
1877
1878 __ bind(&return_undefined);
1879 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
1880 __ Drop(argc + 1);
1881 __ Ret();
1882
1883 __ bind(&call_builtin);
1884 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop,
1885 masm()->isolate()),
1886 argc + 1,
1887 1);
1888
1889 // Handle call cache miss.
1890 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001891 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001892
1893 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001894 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001895}
1896
1897
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001898Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1899 Handle<Object> object,
1900 Handle<JSObject> holder,
1901 Handle<JSGlobalPropertyCell> cell,
1902 Handle<JSFunction> function,
1903 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001904 // ----------- S t a t e -------------
1905 // -- a2 : function name
1906 // -- ra : return address
1907 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1908 // -- ...
1909 // -- sp[argc * 4] : receiver
1910 // -----------------------------------
1911
1912 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001913 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001914
1915 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001916 Label miss;
1917 Label name_miss;
1918 Label index_out_of_range;
1919
1920 Label* index_out_of_range_label = &index_out_of_range;
1921
danno@chromium.org40cb8782011-05-25 07:58:50 +00001922 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001923 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001924 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001925 index_out_of_range_label = &miss;
1926 }
1927
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001928 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001929
1930 // Check that the maps starting from the prototype haven't changed.
1931 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1932 Context::STRING_FUNCTION_INDEX,
1933 v0,
1934 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001935 ASSERT(!object.is_identical_to(holder));
1936 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1937 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001938
1939 Register receiver = a1;
1940 Register index = t1;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001941 Register result = v0;
1942 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1943 if (argc > 0) {
1944 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1945 } else {
1946 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1947 }
1948
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001949 StringCharCodeAtGenerator generator(receiver,
1950 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001951 result,
1952 &miss, // When not a string.
1953 &miss, // When not a number.
1954 index_out_of_range_label,
1955 STRING_INDEX_IS_NUMBER);
1956 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001957 __ Drop(argc + 1);
1958 __ Ret();
1959
1960 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001961 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001962
1963 if (index_out_of_range.is_linked()) {
1964 __ bind(&index_out_of_range);
1965 __ LoadRoot(v0, Heap::kNanValueRootIndex);
1966 __ Drop(argc + 1);
1967 __ Ret();
1968 }
1969
1970 __ bind(&miss);
1971 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001972 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001973 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001974 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001975
1976 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001977 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001978}
1979
1980
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001981Handle<Code> CallStubCompiler::CompileStringCharAtCall(
1982 Handle<Object> object,
1983 Handle<JSObject> holder,
1984 Handle<JSGlobalPropertyCell> cell,
1985 Handle<JSFunction> function,
1986 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001987 // ----------- S t a t e -------------
1988 // -- a2 : function name
1989 // -- ra : return address
1990 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1991 // -- ...
1992 // -- sp[argc * 4] : receiver
1993 // -----------------------------------
1994
1995 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001996 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001997
1998 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001999 Label miss;
2000 Label name_miss;
2001 Label index_out_of_range;
2002 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00002003 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002004 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002005 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002006 index_out_of_range_label = &miss;
2007 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002008 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002009
2010 // Check that the maps starting from the prototype haven't changed.
2011 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2012 Context::STRING_FUNCTION_INDEX,
2013 v0,
2014 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002015 ASSERT(!object.is_identical_to(holder));
2016 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2017 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002018
2019 Register receiver = v0;
2020 Register index = t1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00002021 Register scratch = a3;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002022 Register result = v0;
2023 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
2024 if (argc > 0) {
2025 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
2026 } else {
2027 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
2028 }
2029
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002030 StringCharAtGenerator generator(receiver,
2031 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00002032 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002033 result,
2034 &miss, // When not a string.
2035 &miss, // When not a number.
2036 index_out_of_range_label,
2037 STRING_INDEX_IS_NUMBER);
2038 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002039 __ Drop(argc + 1);
2040 __ Ret();
2041
2042 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002043 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002044
2045 if (index_out_of_range.is_linked()) {
2046 __ bind(&index_out_of_range);
2047 __ LoadRoot(v0, Heap::kEmptyStringRootIndex);
2048 __ Drop(argc + 1);
2049 __ Ret();
2050 }
2051
2052 __ bind(&miss);
2053 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002054 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002055 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002056 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002057
2058 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002059 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002060}
2061
2062
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002063Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
2064 Handle<Object> object,
2065 Handle<JSObject> holder,
2066 Handle<JSGlobalPropertyCell> cell,
2067 Handle<JSFunction> function,
2068 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002069 // ----------- S t a t e -------------
2070 // -- a2 : function name
2071 // -- ra : return address
2072 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2073 // -- ...
2074 // -- sp[argc * 4] : receiver
2075 // -----------------------------------
2076
2077 const int argc = arguments().immediate();
2078
2079 // If the object is not a JSObject or we got an unexpected number of
2080 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002081 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002082
2083 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002084 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002085
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002086 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002087 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
2088
2089 STATIC_ASSERT(kSmiTag == 0);
2090 __ JumpIfSmi(a1, &miss);
2091
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002092 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2093 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002094 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002095 ASSERT(cell->value() == *function);
2096 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2097 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002098 GenerateLoadFunctionFromCell(cell, function, &miss);
2099 }
2100
2101 // Load the char code argument.
2102 Register code = a1;
2103 __ lw(code, MemOperand(sp, 0 * kPointerSize));
2104
2105 // Check the code is a smi.
2106 Label slow;
2107 STATIC_ASSERT(kSmiTag == 0);
2108 __ JumpIfNotSmi(code, &slow);
2109
2110 // Convert the smi code to uint16.
2111 __ And(code, code, Operand(Smi::FromInt(0xffff)));
2112
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002113 StringCharFromCodeGenerator generator(code, v0);
2114 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002115 __ Drop(argc + 1);
2116 __ Ret();
2117
2118 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002119 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002120
2121 // Tail call the full function. We do not have to patch the receiver
2122 // because the function makes no use of it.
2123 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002124 __ InvokeFunction(
2125 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002126
2127 __ bind(&miss);
2128 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002129 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002130
2131 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002132 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002133}
2134
2135
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002136Handle<Code> CallStubCompiler::CompileMathFloorCall(
2137 Handle<Object> object,
2138 Handle<JSObject> holder,
2139 Handle<JSGlobalPropertyCell> cell,
2140 Handle<JSFunction> function,
2141 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002142 // ----------- S t a t e -------------
2143 // -- a2 : function name
2144 // -- ra : return address
2145 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2146 // -- ...
2147 // -- sp[argc * 4] : receiver
2148 // -----------------------------------
2149
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002150 if (!CpuFeatures::IsSupported(FPU)) {
2151 return Handle<Code>::null();
2152 }
2153
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002154 CpuFeatures::Scope scope_fpu(FPU);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002155 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002156 // If the object is not a JSObject or we got an unexpected number of
2157 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002158 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002159
2160 Label miss, slow;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002161 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002162
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002163 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002164 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002165 STATIC_ASSERT(kSmiTag == 0);
2166 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002167 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2168 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002169 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002170 ASSERT(cell->value() == *function);
2171 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2172 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002173 GenerateLoadFunctionFromCell(cell, function, &miss);
2174 }
2175
2176 // Load the (only) argument into v0.
2177 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2178
2179 // If the argument is a smi, just return.
2180 STATIC_ASSERT(kSmiTag == 0);
2181 __ And(t0, v0, Operand(kSmiTagMask));
2182 __ Drop(argc + 1, eq, t0, Operand(zero_reg));
2183 __ Ret(eq, t0, Operand(zero_reg));
2184
danno@chromium.org40cb8782011-05-25 07:58:50 +00002185 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002186
2187 Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return;
2188
2189 // If fpu is enabled, we use the floor instruction.
2190
2191 // Load the HeapNumber value.
2192 __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2193
2194 // Backup FCSR.
2195 __ cfc1(a3, FCSR);
2196 // Clearing FCSR clears the exception mask with no side-effects.
2197 __ ctc1(zero_reg, FCSR);
2198 // Convert the argument to an integer.
2199 __ floor_w_d(f0, f0);
2200
2201 // Start checking for special cases.
2202 // Get the argument exponent and clear the sign bit.
2203 __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize));
2204 __ And(t2, t1, Operand(~HeapNumber::kSignMask));
2205 __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord);
2206
2207 // Retrieve FCSR and check for fpu errors.
2208 __ cfc1(t5, FCSR);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002209 __ And(t5, t5, Operand(kFCSRExceptionFlagMask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002210 __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));
2211
2212 // Check for NaN, Infinity, and -Infinity.
2213 // They are invariant through a Math.Floor call, so just
2214 // return the original argument.
2215 __ Subu(t3, t2, Operand(HeapNumber::kExponentMask
2216 >> HeapNumber::kMantissaBitsInTopWord));
2217 __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg));
2218 // We had an overflow or underflow in the conversion. Check if we
2219 // have a big exponent.
2220 // If greater or equal, the argument is already round and in v0.
2221 __ Branch(&restore_fcsr_and_return, ge, t3,
2222 Operand(HeapNumber::kMantissaBits));
2223 __ Branch(&wont_fit_smi);
2224
2225 __ bind(&no_fpu_error);
2226 // Move the result back to v0.
2227 __ mfc1(v0, f0);
2228 // Check if the result fits into a smi.
2229 __ Addu(a1, v0, Operand(0x40000000));
2230 __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg));
2231 // Tag the result.
2232 STATIC_ASSERT(kSmiTag == 0);
2233 __ sll(v0, v0, kSmiTagSize);
2234
2235 // Check for -0.
2236 __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg));
2237 // t1 already holds the HeapNumber exponent.
2238 __ And(t0, t1, Operand(HeapNumber::kSignMask));
2239 // If our HeapNumber is negative it was -0, so load its address and return.
2240 // Else v0 is loaded with 0, so we can also just return.
2241 __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg));
2242 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2243
2244 __ bind(&restore_fcsr_and_return);
2245 // Restore FCSR and return.
2246 __ ctc1(a3, FCSR);
2247
2248 __ Drop(argc + 1);
2249 __ Ret();
2250
2251 __ bind(&wont_fit_smi);
2252 // Restore FCSR and fall to slow case.
2253 __ ctc1(a3, FCSR);
2254
2255 __ bind(&slow);
2256 // Tail call the full function. We do not have to patch the receiver
2257 // because the function makes no use of it.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002258 __ InvokeFunction(
2259 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002260
2261 __ bind(&miss);
2262 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002263 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002264
2265 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002266 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002267}
2268
2269
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002270Handle<Code> CallStubCompiler::CompileMathAbsCall(
2271 Handle<Object> object,
2272 Handle<JSObject> holder,
2273 Handle<JSGlobalPropertyCell> cell,
2274 Handle<JSFunction> function,
2275 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002276 // ----------- S t a t e -------------
2277 // -- a2 : function name
2278 // -- ra : return address
2279 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2280 // -- ...
2281 // -- sp[argc * 4] : receiver
2282 // -----------------------------------
2283
2284 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002285 // If the object is not a JSObject or we got an unexpected number of
2286 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002287 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002288
2289 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002290
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002291 GenerateNameCheck(name, &miss);
2292 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002293 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002294 STATIC_ASSERT(kSmiTag == 0);
2295 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002296 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2297 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002298 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002299 ASSERT(cell->value() == *function);
2300 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2301 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002302 GenerateLoadFunctionFromCell(cell, function, &miss);
2303 }
2304
2305 // Load the (only) argument into v0.
2306 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2307
2308 // Check if the argument is a smi.
2309 Label not_smi;
2310 STATIC_ASSERT(kSmiTag == 0);
2311 __ JumpIfNotSmi(v0, &not_smi);
2312
2313 // Do bitwise not or do nothing depending on the sign of the
2314 // argument.
2315 __ sra(t0, v0, kBitsPerInt - 1);
2316 __ Xor(a1, v0, t0);
2317
2318 // Add 1 or do nothing depending on the sign of the argument.
2319 __ Subu(v0, a1, t0);
2320
2321 // If the result is still negative, go to the slow case.
2322 // This only happens for the most negative smi.
2323 Label slow;
2324 __ Branch(&slow, lt, v0, Operand(zero_reg));
2325
2326 // Smi case done.
2327 __ Drop(argc + 1);
2328 __ Ret();
2329
2330 // Check if the argument is a heap number and load its exponent and
2331 // sign.
2332 __ bind(&not_smi);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002333 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002334 __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2335
2336 // Check the sign of the argument. If the argument is positive,
2337 // just return it.
2338 Label negative_sign;
2339 __ And(t0, a1, Operand(HeapNumber::kSignMask));
2340 __ Branch(&negative_sign, ne, t0, Operand(zero_reg));
2341 __ Drop(argc + 1);
2342 __ Ret();
2343
2344 // If the argument is negative, clear the sign, and return a new
2345 // number.
2346 __ bind(&negative_sign);
2347 __ Xor(a1, a1, Operand(HeapNumber::kSignMask));
2348 __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2349 __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
2350 __ AllocateHeapNumber(v0, t0, t1, t2, &slow);
2351 __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2352 __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2353 __ Drop(argc + 1);
2354 __ Ret();
2355
2356 // Tail call the full function. We do not have to patch the receiver
2357 // because the function makes no use of it.
2358 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002359 __ InvokeFunction(
2360 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002361
2362 __ bind(&miss);
2363 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002364 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002365
2366 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002367 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002368}
2369
2370
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002371Handle<Code> CallStubCompiler::CompileFastApiCall(
lrn@chromium.org7516f052011-03-30 08:52:27 +00002372 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002373 Handle<Object> object,
2374 Handle<JSObject> holder,
2375 Handle<JSGlobalPropertyCell> cell,
2376 Handle<JSFunction> function,
2377 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002378
danno@chromium.org40cb8782011-05-25 07:58:50 +00002379 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002380
2381 ASSERT(optimization.is_simple_api_call());
2382 // Bail out if object is a global object as we don't want to
2383 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002384 if (object->IsGlobalObject()) return Handle<Code>::null();
2385 if (!cell.is_null()) return Handle<Code>::null();
2386 if (!object->IsJSObject()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002387 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002388 Handle<JSObject>::cast(object), holder);
2389 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002390
2391 Label miss, miss_before_stack_reserved;
2392
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002393 GenerateNameCheck(name, &miss_before_stack_reserved);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002394
2395 // Get the receiver from the stack.
2396 const int argc = arguments().immediate();
2397 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2398
2399 // Check that the receiver isn't a smi.
2400 __ JumpIfSmi(a1, &miss_before_stack_reserved);
2401
2402 __ IncrementCounter(counters->call_const(), 1, a0, a3);
2403 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2404
2405 ReserveSpaceForFastApiCall(masm(), a0);
2406
2407 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002408 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002409 depth, &miss);
2410
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002411 GenerateFastApiDirectCall(masm(), optimization, argc);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002412
2413 __ bind(&miss);
2414 FreeSpaceForFastApiCall(masm());
2415
2416 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002417 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002418
2419 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002420 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002421}
2422
2423
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002424Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object,
2425 Handle<JSObject> holder,
2426 Handle<JSFunction> function,
2427 Handle<String> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002428 CheckType check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002429 // ----------- S t a t e -------------
2430 // -- a2 : name
2431 // -- ra : return address
2432 // -----------------------------------
2433 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002434 Handle<Code> code = CompileCustomCall(object, holder,
2435 Handle<JSGlobalPropertyCell>::null(),
2436 function, name);
2437 // A null handle means bail out to the regular compiler code below.
2438 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002439 }
2440
2441 Label miss;
2442
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002443 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002444
2445 // Get the receiver from the stack.
2446 const int argc = arguments().immediate();
2447 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2448
2449 // Check that the receiver isn't a smi.
2450 if (check != NUMBER_CHECK) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002451 __ JumpIfSmi(a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002452 }
2453
2454 // Make sure that it's okay not to patch the on stack receiver
2455 // unless we're doing a receiver map check.
2456 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002457 switch (check) {
2458 case RECEIVER_MAP_CHECK:
2459 __ IncrementCounter(masm()->isolate()->counters()->call_const(),
2460 1, a0, a3);
2461
2462 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002463 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2464 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002465
2466 // Patch the receiver on the stack with the global proxy if
2467 // necessary.
2468 if (object->IsGlobalObject()) {
2469 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2470 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2471 }
2472 break;
2473
2474 case STRING_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002475 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002476 // Check that the object is a two-byte string or a symbol.
2477 __ GetObjectType(a1, a3, a3);
2478 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2479 // Check that the maps starting from the prototype haven't changed.
2480 GenerateDirectLoadGlobalFunctionPrototype(
2481 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002482 CheckPrototypes(
2483 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2484 a0, holder, a3, a1, t0, name, &miss);
2485 } else {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002486 // Calling non-strict non-builtins with a value as the receiver
2487 // requires boxing.
2488 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002489 }
2490 break;
2491
2492 case NUMBER_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002493 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002494 Label fast;
2495 // Check that the object is a smi or a heap number.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002496 __ JumpIfSmi(a1, &fast);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002497 __ GetObjectType(a1, a0, a0);
2498 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
2499 __ bind(&fast);
2500 // Check that the maps starting from the prototype haven't changed.
2501 GenerateDirectLoadGlobalFunctionPrototype(
2502 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002503 CheckPrototypes(
2504 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2505 a0, holder, a3, a1, t0, name, &miss);
2506 } else {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002507 // Calling non-strict non-builtins with a value as the receiver
2508 // requires boxing.
2509 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002510 }
2511 break;
2512
2513 case BOOLEAN_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002514 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002515 Label fast;
2516 // Check that the object is a boolean.
2517 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
2518 __ Branch(&fast, eq, a1, Operand(t0));
2519 __ LoadRoot(t0, Heap::kFalseValueRootIndex);
2520 __ Branch(&miss, ne, a1, Operand(t0));
2521 __ bind(&fast);
2522 // Check that the maps starting from the prototype haven't changed.
2523 GenerateDirectLoadGlobalFunctionPrototype(
2524 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002525 CheckPrototypes(
2526 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2527 a0, holder, a3, a1, t0, name, &miss);
2528 } else {
2529 // Calling non-strict non-builtins with a value as the receiver
2530 // requires boxing.
2531 __ jmp(&miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002532 }
2533 break;
2534 }
2535
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002536 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002537 ? CALL_AS_FUNCTION
2538 : CALL_AS_METHOD;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002539 __ InvokeFunction(
2540 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002541
2542 // Handle call cache miss.
2543 __ bind(&miss);
2544
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002545 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002546
2547 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002548 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002549}
2550
2551
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002552Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2553 Handle<JSObject> holder,
2554 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002555 // ----------- S t a t e -------------
2556 // -- a2 : name
2557 // -- ra : return address
2558 // -----------------------------------
2559
2560 Label miss;
2561
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002562 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002563
2564 // Get the number of arguments.
2565 const int argc = arguments().immediate();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002566 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002567 LookupPostInterceptor(holder, name, &lookup);
2568
2569 // Get the receiver from the stack.
2570 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2571
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002572 CallInterceptorCompiler compiler(this, arguments(), a2, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002573 compiler.Compile(masm(), object, holder, name, &lookup, a1, a3, t0, a0,
2574 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002575
2576 // Move returned value, the function to call, to a1.
2577 __ mov(a1, v0);
2578 // Restore receiver.
2579 __ lw(a0, MemOperand(sp, argc * kPointerSize));
2580
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002581 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002582
2583 // Handle call cache miss.
2584 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002585 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002586
2587 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002588 return GetCode(Code::INTERCEPTOR, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002589}
2590
2591
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002592Handle<Code> CallStubCompiler::CompileCallGlobal(
2593 Handle<JSObject> object,
2594 Handle<GlobalObject> holder,
2595 Handle<JSGlobalPropertyCell> cell,
2596 Handle<JSFunction> function,
2597 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002598 // ----------- S t a t e -------------
2599 // -- a2 : name
2600 // -- ra : return address
2601 // -----------------------------------
2602
2603 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002604 Handle<Code> code = CompileCustomCall(object, holder, cell, function, name);
2605 // A null handle means bail out to the regular compiler code below.
2606 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002607 }
2608
2609 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002610 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002611
2612 // Get the number of arguments.
2613 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002614 GenerateGlobalReceiverCheck(object, holder, name, &miss);
2615 GenerateLoadFunctionFromCell(cell, function, &miss);
2616
2617 // Patch the receiver on the stack with the global proxy if
2618 // necessary.
2619 if (object->IsGlobalObject()) {
2620 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
2621 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2622 }
2623
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002624 // Set up the context (function already in r1).
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002625 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
2626
2627 // Jump to the cached code (tail call).
2628 Counters* counters = masm()->isolate()->counters();
2629 __ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002630 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002631 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002632 ? CALL_AS_FUNCTION
2633 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002634 // We call indirectly through the code field in the function to
2635 // allow recompilation to take effect without changing any of the
2636 // call sites.
2637 __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
2638 __ InvokeCode(a3, expected, arguments(), JUMP_FUNCTION,
2639 NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002640
2641 // Handle call cache miss.
2642 __ bind(&miss);
2643 __ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002644 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002645
2646 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002647 return GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002648}
2649
2650
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002651Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +00002652 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002653 Handle<Map> transition,
2654 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002655 // ----------- S t a t e -------------
2656 // -- a0 : value
2657 // -- a1 : receiver
2658 // -- a2 : name
2659 // -- ra : return address
2660 // -----------------------------------
2661 Label miss;
2662
2663 // Name register might be clobbered.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002664 GenerateStoreField(masm(),
2665 object,
2666 index,
2667 transition,
2668 name,
2669 a1, a2, a3, t0,
2670 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002671 __ bind(&miss);
2672 __ li(a2, Operand(Handle<String>(name))); // Restore name.
2673 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2674 __ Jump(ic, RelocInfo::CODE_TARGET);
2675
2676 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002677 return GetCode(transition.is_null()
2678 ? Code::FIELD
2679 : Code::MAP_TRANSITION, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002680}
2681
2682
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002683Handle<Code> StoreStubCompiler::CompileStoreCallback(
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002684 Handle<String> name,
2685 Handle<JSObject> receiver,
2686 Handle<JSObject> holder,
2687 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002688 // ----------- S t a t e -------------
2689 // -- a0 : value
2690 // -- a1 : receiver
2691 // -- a2 : name
2692 // -- ra : return address
2693 // -----------------------------------
2694 Label miss;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002695 // Check that the maps haven't changed.
2696 __ JumpIfSmi(a1, &miss, a3);
2697 CheckPrototypes(receiver, a1, holder, a3, t0, t1, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002698
2699 // Stub never generated for non-global objects that require access
2700 // checks.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002701 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002702
2703 __ push(a1); // Receiver.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002704 __ li(a3, Operand(callback)); // Callback info.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002705 __ Push(a3, a2, a0);
2706
2707 // Do tail-call to the runtime system.
2708 ExternalReference store_callback_property =
2709 ExternalReference(IC_Utility(IC::kStoreCallbackProperty),
2710 masm()->isolate());
2711 __ TailCallExternalReference(store_callback_property, 4, 1);
2712
2713 // Handle store cache miss.
2714 __ bind(&miss);
2715 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2716 __ Jump(ic, RelocInfo::CODE_TARGET);
2717
2718 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002719 return GetCode(Code::CALLBACKS, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002720}
2721
2722
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002723#undef __
2724#define __ ACCESS_MASM(masm)
2725
2726
2727void StoreStubCompiler::GenerateStoreViaSetter(
2728 MacroAssembler* masm,
2729 Handle<JSFunction> setter) {
2730 // ----------- S t a t e -------------
2731 // -- a0 : value
2732 // -- a1 : receiver
2733 // -- a2 : name
2734 // -- ra : return address
2735 // -----------------------------------
2736 {
2737 FrameScope scope(masm, StackFrame::INTERNAL);
2738
2739 // Save value register, so we can restore it later.
2740 __ push(a0);
2741
2742 if (!setter.is_null()) {
2743 // Call the JavaScript setter with receiver and value on the stack.
2744 __ push(a1);
2745 __ push(a0);
2746 ParameterCount actual(1);
2747 __ InvokeFunction(setter, actual, CALL_FUNCTION, NullCallWrapper(),
2748 CALL_AS_METHOD);
2749 } else {
2750 // If we generate a global code snippet for deoptimization only, remember
2751 // the place to continue after deoptimization.
2752 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2753 }
2754
2755 // We have to return the passed value, not the return value of the setter.
2756 __ pop(v0);
2757
2758 // Restore context register.
2759 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2760 }
2761 __ Ret();
2762}
2763
2764
2765#undef __
2766#define __ ACCESS_MASM(masm())
2767
2768
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002769Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002770 Handle<String> name,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002771 Handle<JSObject> receiver,
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002772 Handle<JSObject> holder,
2773 Handle<JSFunction> setter) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002774 // ----------- S t a t e -------------
2775 // -- a0 : value
2776 // -- a1 : receiver
2777 // -- a2 : name
2778 // -- ra : return address
2779 // -----------------------------------
2780 Label miss;
2781
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002782 // Check that the maps haven't changed.
2783 __ JumpIfSmi(a1, &miss);
2784 CheckPrototypes(receiver, a1, holder, a3, t0, t1, name, &miss);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002785
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002786 GenerateStoreViaSetter(masm(), setter);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002787
2788 __ bind(&miss);
2789 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2790 __ Jump(ic, RelocInfo::CODE_TARGET);
2791
2792 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002793 return GetCode(Code::CALLBACKS, name);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002794}
2795
2796
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002797Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
2798 Handle<JSObject> receiver,
2799 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002800 // ----------- S t a t e -------------
2801 // -- a0 : value
2802 // -- a1 : receiver
2803 // -- a2 : name
2804 // -- ra : return address
2805 // -----------------------------------
2806 Label miss;
2807
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002808 // Check that the map of the object hasn't changed.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002809 __ CheckMap(a1, a3, Handle<Map>(receiver->map()), &miss,
2810 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002811
2812 // Perform global security token check if needed.
2813 if (receiver->IsJSGlobalProxy()) {
2814 __ CheckAccessGlobalProxy(a1, a3, &miss);
2815 }
2816
2817 // Stub is never generated for non-global objects that require access
2818 // checks.
2819 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2820
2821 __ Push(a1, a2, a0); // Receiver, name, value.
2822
2823 __ li(a0, Operand(Smi::FromInt(strict_mode_)));
2824 __ push(a0); // Strict mode.
2825
2826 // Do tail-call to the runtime system.
2827 ExternalReference store_ic_property =
2828 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty),
2829 masm()->isolate());
2830 __ TailCallExternalReference(store_ic_property, 4, 1);
2831
2832 // Handle store cache miss.
2833 __ bind(&miss);
2834 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2835 __ Jump(ic, RelocInfo::CODE_TARGET);
2836
2837 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002838 return GetCode(Code::INTERCEPTOR, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002839}
2840
2841
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002842Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2843 Handle<GlobalObject> object,
2844 Handle<JSGlobalPropertyCell> cell,
2845 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002846 // ----------- S t a t e -------------
2847 // -- a0 : value
2848 // -- a1 : receiver
2849 // -- a2 : name
2850 // -- ra : return address
2851 // -----------------------------------
2852 Label miss;
2853
2854 // Check that the map of the global has not changed.
2855 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2856 __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map())));
2857
2858 // Check that the value in the cell is not the hole. If it is, this
2859 // cell could have been deleted and reintroducing the global needs
2860 // to update the property details in the property dictionary of the
2861 // global object. We bail out to the runtime system to do that.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002862 __ li(t0, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002863 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
2864 __ lw(t2, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2865 __ Branch(&miss, eq, t1, Operand(t2));
2866
2867 // Store the value in the cell.
2868 __ sw(a0, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2869 __ mov(v0, a0); // Stored value must be returned in v0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002870 // Cells are always rescanned, so no write barrier here.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002871
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002872 Counters* counters = masm()->isolate()->counters();
2873 __ IncrementCounter(counters->named_store_global_inline(), 1, a1, a3);
2874 __ Ret();
2875
2876 // Handle store cache miss.
2877 __ bind(&miss);
2878 __ IncrementCounter(counters->named_store_global_inline_miss(), 1, a1, a3);
2879 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2880 __ Jump(ic, RelocInfo::CODE_TARGET);
2881
2882 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002883 return GetCode(Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002884}
2885
2886
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002887Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
2888 Handle<JSObject> object,
2889 Handle<JSObject> last) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002890 // ----------- S t a t e -------------
2891 // -- a0 : receiver
2892 // -- ra : return address
2893 // -----------------------------------
2894 Label miss;
2895
2896 // Check that the receiver is not a smi.
2897 __ JumpIfSmi(a0, &miss);
2898
2899 // Check the maps of the full prototype chain.
2900 CheckPrototypes(object, a0, last, a3, a1, t0, name, &miss);
2901
2902 // If the last object in the prototype chain is a global object,
2903 // check that the global property cell is empty.
2904 if (last->IsGlobalObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002905 GenerateCheckPropertyCell(
2906 masm(), Handle<GlobalObject>::cast(last), name, a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002907 }
2908
2909 // Return undefined if maps of the full prototype chain is still the same.
2910 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2911 __ Ret();
2912
2913 __ bind(&miss);
2914 GenerateLoadMiss(masm(), Code::LOAD_IC);
2915
2916 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002917 return GetCode(Code::NONEXISTENT, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00002918}
2919
2920
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002921Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object,
2922 Handle<JSObject> holder,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002923 PropertyIndex index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002924 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002925 // ----------- S t a t e -------------
2926 // -- a0 : receiver
2927 // -- a2 : name
2928 // -- ra : return address
2929 // -----------------------------------
2930 Label miss;
2931
2932 __ mov(v0, a0);
2933
2934 GenerateLoadField(object, holder, v0, a3, a1, t0, index, name, &miss);
2935 __ bind(&miss);
2936 GenerateLoadMiss(masm(), Code::LOAD_IC);
2937
2938 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002939 return GetCode(Code::FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002940}
2941
2942
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002943Handle<Code> LoadStubCompiler::CompileLoadCallback(
2944 Handle<String> name,
2945 Handle<JSObject> object,
2946 Handle<JSObject> holder,
2947 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002948 // ----------- S t a t e -------------
2949 // -- a0 : receiver
2950 // -- a2 : name
2951 // -- ra : return address
2952 // -----------------------------------
2953 Label miss;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00002954 GenerateLoadCallback(object, holder, a0, a2, a3, a1, t0, t1, callback, name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002955 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002956 __ bind(&miss);
2957 GenerateLoadMiss(masm(), Code::LOAD_IC);
2958
2959 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002960 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002961}
2962
2963
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002964#undef __
2965#define __ ACCESS_MASM(masm)
2966
2967
2968void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
2969 Handle<JSFunction> getter) {
2970 // ----------- S t a t e -------------
2971 // -- a0 : receiver
2972 // -- a2 : name
2973 // -- ra : return address
2974 // -----------------------------------
2975 {
2976 FrameScope scope(masm, StackFrame::INTERNAL);
2977
2978 if (!getter.is_null()) {
2979 // Call the JavaScript getter with the receiver on the stack.
2980 __ push(a0);
2981 ParameterCount actual(0);
2982 __ InvokeFunction(getter, actual, CALL_FUNCTION, NullCallWrapper(),
2983 CALL_AS_METHOD);
2984 } else {
2985 // If we generate a global code snippet for deoptimization only, remember
2986 // the place to continue after deoptimization.
2987 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
2988 }
2989
2990 // Restore context register.
2991 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2992 }
2993 __ Ret();
2994}
2995
2996
2997#undef __
2998#define __ ACCESS_MASM(masm())
2999
3000
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003001Handle<Code> LoadStubCompiler::CompileLoadViaGetter(
3002 Handle<String> name,
3003 Handle<JSObject> receiver,
3004 Handle<JSObject> holder,
3005 Handle<JSFunction> getter) {
3006 // ----------- S t a t e -------------
3007 // -- a0 : receiver
3008 // -- a2 : name
3009 // -- ra : return address
3010 // -----------------------------------
3011 Label miss;
3012
3013 // Check that the maps haven't changed.
3014 __ JumpIfSmi(a0, &miss);
3015 CheckPrototypes(receiver, a0, holder, a3, t0, a1, name, &miss);
3016
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003017 GenerateLoadViaGetter(masm(), getter);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003018
3019 __ bind(&miss);
3020 GenerateLoadMiss(masm(), Code::LOAD_IC);
3021
3022 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003023 return GetCode(Code::CALLBACKS, name);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003024}
3025
3026
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003027Handle<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object,
3028 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003029 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003030 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003031 // ----------- S t a t e -------------
3032 // -- a0 : receiver
3033 // -- a2 : name
3034 // -- ra : return address
3035 // -----------------------------------
3036 Label miss;
3037
3038 GenerateLoadConstant(object, holder, a0, a3, a1, t0, value, name, &miss);
3039 __ bind(&miss);
3040 GenerateLoadMiss(masm(), Code::LOAD_IC);
3041
3042 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003043 return GetCode(Code::CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003044}
3045
3046
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003047Handle<Code> LoadStubCompiler::CompileLoadInterceptor(Handle<JSObject> object,
3048 Handle<JSObject> holder,
3049 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003050 // ----------- S t a t e -------------
3051 // -- a0 : receiver
3052 // -- a2 : name
3053 // -- ra : return address
3054 // -- [sp] : receiver
3055 // -----------------------------------
3056 Label miss;
3057
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003058 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003059 LookupPostInterceptor(holder, name, &lookup);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003060 GenerateLoadInterceptor(object, holder, &lookup, a0, a2, a3, a1, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003061 &miss);
3062 __ bind(&miss);
3063 GenerateLoadMiss(masm(), Code::LOAD_IC);
3064
3065 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003066 return GetCode(Code::INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003067}
3068
3069
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003070Handle<Code> LoadStubCompiler::CompileLoadGlobal(
3071 Handle<JSObject> object,
3072 Handle<GlobalObject> holder,
3073 Handle<JSGlobalPropertyCell> cell,
3074 Handle<String> name,
3075 bool is_dont_delete) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003076 // ----------- S t a t e -------------
3077 // -- a0 : receiver
3078 // -- a2 : name
3079 // -- ra : return address
3080 // -----------------------------------
3081 Label miss;
3082
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003083 // Check that the map of the global has not changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003084 __ JumpIfSmi(a0, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003085 CheckPrototypes(object, a0, holder, a3, t0, a1, name, &miss);
3086
3087 // Get the value from the cell.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003088 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003089 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
3090
3091 // Check for deleted property if property can actually be deleted.
3092 if (!is_dont_delete) {
3093 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
3094 __ Branch(&miss, eq, t0, Operand(at));
3095 }
3096
3097 __ mov(v0, t0);
3098 Counters* counters = masm()->isolate()->counters();
3099 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
3100 __ Ret();
3101
3102 __ bind(&miss);
3103 __ IncrementCounter(counters->named_load_global_stub_miss(), 1, a1, a3);
3104 GenerateLoadMiss(masm(), Code::LOAD_IC);
3105
3106 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003107 return GetCode(Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003108}
3109
3110
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003111Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
3112 Handle<JSObject> receiver,
3113 Handle<JSObject> holder,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003114 PropertyIndex index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003115 // ----------- S t a t e -------------
3116 // -- ra : return address
3117 // -- a0 : key
3118 // -- a1 : receiver
3119 // -----------------------------------
3120 Label miss;
3121
3122 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003123 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003124
3125 GenerateLoadField(receiver, holder, a1, a2, a3, t0, index, name, &miss);
3126 __ bind(&miss);
3127 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3128
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003129 return GetCode(Code::FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003130}
3131
3132
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003133Handle<Code> KeyedLoadStubCompiler::CompileLoadCallback(
3134 Handle<String> name,
3135 Handle<JSObject> receiver,
3136 Handle<JSObject> holder,
3137 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003138 // ----------- S t a t e -------------
3139 // -- ra : return address
3140 // -- a0 : key
3141 // -- a1 : receiver
3142 // -----------------------------------
3143 Label miss;
3144
3145 // Check the key is the cached one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003146 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003147
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00003148 GenerateLoadCallback(receiver, holder, a1, a0, a2, a3, t0, t1, callback,
3149 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003150 __ bind(&miss);
3151 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3152
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003153 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003154}
3155
3156
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003157Handle<Code> KeyedLoadStubCompiler::CompileLoadConstant(
3158 Handle<String> name,
3159 Handle<JSObject> receiver,
3160 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003161 Handle<JSFunction> value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003162 // ----------- S t a t e -------------
3163 // -- ra : return address
3164 // -- a0 : key
3165 // -- a1 : receiver
3166 // -----------------------------------
3167 Label miss;
3168
3169 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003170 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003171
3172 GenerateLoadConstant(receiver, holder, a1, a2, a3, t0, value, name, &miss);
3173 __ bind(&miss);
3174 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3175
3176 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003177 return GetCode(Code::CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003178}
3179
3180
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003181Handle<Code> KeyedLoadStubCompiler::CompileLoadInterceptor(
3182 Handle<JSObject> receiver,
3183 Handle<JSObject> holder,
3184 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003185 // ----------- S t a t e -------------
3186 // -- ra : return address
3187 // -- a0 : key
3188 // -- a1 : receiver
3189 // -----------------------------------
3190 Label miss;
3191
3192 // Check the key is the cached one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003193 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003194
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003195 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003196 LookupPostInterceptor(holder, name, &lookup);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003197 GenerateLoadInterceptor(receiver, holder, &lookup, a1, a0, a2, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003198 &miss);
3199 __ bind(&miss);
3200 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3201
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003202 return GetCode(Code::INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003203}
3204
3205
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003206Handle<Code> KeyedLoadStubCompiler::CompileLoadArrayLength(
3207 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003208 // ----------- S t a t e -------------
3209 // -- ra : return address
3210 // -- a0 : key
3211 // -- a1 : receiver
3212 // -----------------------------------
3213 Label miss;
3214
3215 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003216 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003217
3218 GenerateLoadArrayLength(masm(), a1, a2, &miss);
3219 __ bind(&miss);
3220 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3221
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003222 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003223}
3224
3225
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003226Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength(
3227 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003228 // ----------- S t a t e -------------
3229 // -- ra : return address
3230 // -- a0 : key
3231 // -- a1 : receiver
3232 // -----------------------------------
3233 Label miss;
3234
3235 Counters* counters = masm()->isolate()->counters();
3236 __ IncrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
3237
3238 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003239 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003240
3241 GenerateLoadStringLength(masm(), a1, a2, a3, &miss, true);
3242 __ bind(&miss);
3243 __ DecrementCounter(counters->keyed_load_string_length(), 1, a2, a3);
3244
3245 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3246
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003247 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003248}
3249
3250
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003251Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype(
3252 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003253 // ----------- S t a t e -------------
3254 // -- ra : return address
3255 // -- a0 : key
3256 // -- a1 : receiver
3257 // -----------------------------------
3258 Label miss;
3259
3260 Counters* counters = masm()->isolate()->counters();
3261 __ IncrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
3262
3263 // Check the name hasn't changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003264 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003265
3266 GenerateLoadFunctionPrototype(masm(), a1, a2, a3, &miss);
3267 __ bind(&miss);
3268 __ DecrementCounter(counters->keyed_load_function_prototype(), 1, a2, a3);
3269 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3270
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003271 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003272}
3273
3274
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003275Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
3276 Handle<Map> receiver_map) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003277 // ----------- S t a t e -------------
3278 // -- ra : return address
3279 // -- a0 : key
3280 // -- a1 : receiver
3281 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003282 ElementsKind elements_kind = receiver_map->elements_kind();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003283 if (receiver_map->has_fast_elements() ||
3284 receiver_map->has_external_array_elements()) {
3285 Handle<Code> stub = KeyedLoadFastElementStub(
3286 receiver_map->instance_type() == JS_ARRAY_TYPE,
3287 elements_kind).GetCode();
3288 __ DispatchMap(a1, a2, receiver_map, stub, DO_SMI_CHECK);
3289 } else {
3290 Handle<Code> stub =
3291 KeyedLoadDictionaryElementStub().GetCode();
3292 __ DispatchMap(a1, a2, receiver_map, stub, DO_SMI_CHECK);
3293 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003294
3295 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
3296 __ Jump(ic, RelocInfo::CODE_TARGET);
3297
3298 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003299 return GetCode(Code::NORMAL, factory()->empty_string());
danno@chromium.org40cb8782011-05-25 07:58:50 +00003300}
3301
3302
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003303Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
3304 MapHandleList* receiver_maps,
3305 CodeHandleList* handler_ics) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003306 // ----------- S t a t e -------------
3307 // -- ra : return address
3308 // -- a0 : key
3309 // -- a1 : receiver
3310 // -----------------------------------
3311 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003312 __ JumpIfSmi(a1, &miss);
3313
danno@chromium.org40cb8782011-05-25 07:58:50 +00003314 int receiver_count = receiver_maps->length();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003315 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003316 for (int current = 0; current < receiver_count; ++current) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003317 __ Jump(handler_ics->at(current), RelocInfo::CODE_TARGET,
3318 eq, a2, Operand(receiver_maps->at(current)));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003319 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003320
3321 __ bind(&miss);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003322 Handle<Code> miss_ic = isolate()->builtins()->KeyedLoadIC_Miss();
3323 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003324
3325 // Return the generated code.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003326 return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003327}
3328
3329
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003330Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +00003331 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003332 Handle<Map> transition,
3333 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003334 // ----------- S t a t e -------------
3335 // -- a0 : value
3336 // -- a1 : key
3337 // -- a2 : receiver
3338 // -- ra : return address
3339 // -----------------------------------
3340
3341 Label miss;
3342
3343 Counters* counters = masm()->isolate()->counters();
3344 __ IncrementCounter(counters->keyed_store_field(), 1, a3, t0);
3345
3346 // Check that the name has not changed.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003347 __ Branch(&miss, ne, a1, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003348
3349 // a3 is used as scratch register. a1 and a2 keep their values if a jump to
3350 // the miss label is generated.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003351 GenerateStoreField(masm(),
3352 object,
3353 index,
3354 transition,
3355 name,
3356 a2, a1, a3, t0,
3357 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003358 __ bind(&miss);
3359
3360 __ DecrementCounter(counters->keyed_store_field(), 1, a3, t0);
3361 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss();
3362 __ Jump(ic, RelocInfo::CODE_TARGET);
3363
3364 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003365 return GetCode(transition.is_null()
3366 ? Code::FIELD
3367 : Code::MAP_TRANSITION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003368}
3369
3370
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003371Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
3372 Handle<Map> receiver_map) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003373 // ----------- S t a t e -------------
3374 // -- a0 : value
3375 // -- a1 : key
3376 // -- a2 : receiver
3377 // -- ra : return address
3378 // -- a3 : scratch
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003379 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003380 ElementsKind elements_kind = receiver_map->elements_kind();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003381 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003382 Handle<Code> stub =
yangguo@chromium.org56454712012-02-16 15:33:53 +00003383 KeyedStoreElementStub(is_js_array, elements_kind, grow_mode_).GetCode();
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003384
3385 __ DispatchMap(a2, a3, receiver_map, stub, DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003386
danno@chromium.org40cb8782011-05-25 07:58:50 +00003387 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003388 __ Jump(ic, RelocInfo::CODE_TARGET);
3389
3390 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003391 return GetCode(Code::NORMAL, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00003392}
3393
3394
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003395Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
3396 MapHandleList* receiver_maps,
3397 CodeHandleList* handler_stubs,
3398 MapHandleList* transitioned_maps) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003399 // ----------- S t a t e -------------
3400 // -- a0 : value
3401 // -- a1 : key
3402 // -- a2 : receiver
3403 // -- ra : return address
3404 // -- a3 : scratch
3405 // -----------------------------------
3406 Label miss;
3407 __ JumpIfSmi(a2, &miss);
3408
3409 int receiver_count = receiver_maps->length();
3410 __ lw(a3, FieldMemOperand(a2, HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003411 for (int i = 0; i < receiver_count; ++i) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003412 if (transitioned_maps->at(i).is_null()) {
3413 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq,
3414 a3, Operand(receiver_maps->at(i)));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003415 } else {
3416 Label next_map;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003417 __ Branch(&next_map, ne, a3, Operand(receiver_maps->at(i)));
3418 __ li(a3, Operand(transitioned_maps->at(i)));
3419 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003420 __ bind(&next_map);
3421 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003422 }
3423
3424 __ bind(&miss);
3425 Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
3426 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3427
3428 // Return the generated code.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003429 return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003430}
3431
3432
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003433Handle<Code> ConstructStubCompiler::CompileConstructStub(
3434 Handle<JSFunction> function) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003435 // a0 : argc
3436 // a1 : constructor
3437 // ra : return address
3438 // [sp] : last argument
3439 Label generic_stub_call;
3440
3441 // Use t7 for holding undefined which is used in several places below.
3442 __ LoadRoot(t7, Heap::kUndefinedValueRootIndex);
3443
3444#ifdef ENABLE_DEBUGGER_SUPPORT
3445 // Check to see whether there are any break points in the function code. If
3446 // there are jump to the generic constructor stub which calls the actual
3447 // code for the function thereby hitting the break points.
3448 __ lw(t5, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3449 __ lw(a2, FieldMemOperand(t5, SharedFunctionInfo::kDebugInfoOffset));
3450 __ Branch(&generic_stub_call, ne, a2, Operand(t7));
3451#endif
3452
3453 // Load the initial map and verify that it is in fact a map.
3454 // a1: constructor function
3455 // t7: undefined
3456 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003457 __ JumpIfSmi(a2, &generic_stub_call);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003458 __ GetObjectType(a2, a3, t0);
3459 __ Branch(&generic_stub_call, ne, t0, Operand(MAP_TYPE));
3460
3461#ifdef DEBUG
3462 // Cannot construct functions this way.
3463 // a0: argc
3464 // a1: constructor function
3465 // a2: initial map
3466 // t7: undefined
3467 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
3468 __ Check(ne, "Function constructed by construct stub.",
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003469 a3, Operand(JS_FUNCTION_TYPE));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003470#endif
3471
3472 // Now allocate the JSObject in new space.
3473 // a0: argc
3474 // a1: constructor function
3475 // a2: initial map
3476 // t7: undefined
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003477 ASSERT(function->has_initial_map());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003478 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003479#ifdef DEBUG
3480 int instance_size = function->initial_map()->instance_size();
3481 __ Check(eq, "Instance size of initial map changed.",
3482 a3, Operand(instance_size >> kPointerSizeLog2));
3483#endif
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003484 __ AllocateInNewSpace(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003485
3486 // Allocated the JSObject, now initialize the fields. Map is set to initial
3487 // map and properties and elements are set to empty fixed array.
3488 // a0: argc
3489 // a1: constructor function
3490 // a2: initial map
3491 // a3: object size (in words)
3492 // t4: JSObject (not tagged)
3493 // t7: undefined
3494 __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex);
3495 __ mov(t5, t4);
3496 __ sw(a2, MemOperand(t5, JSObject::kMapOffset));
3497 __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset));
3498 __ sw(t6, MemOperand(t5, JSObject::kElementsOffset));
3499 __ Addu(t5, t5, Operand(3 * kPointerSize));
3500 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
3501 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
3502 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
3503
3504
3505 // Calculate the location of the first argument. The stack contains only the
3506 // argc arguments.
3507 __ sll(a1, a0, kPointerSizeLog2);
3508 __ Addu(a1, a1, sp);
3509
3510 // Fill all the in-object properties with undefined.
3511 // a0: argc
3512 // a1: first argument
3513 // a3: object size (in words)
3514 // t4: JSObject (not tagged)
3515 // t5: First in-object property of JSObject (not tagged)
3516 // t7: undefined
3517 // Fill the initialized properties with a constant value or a passed argument
3518 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003519 Handle<SharedFunctionInfo> shared(function->shared());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003520 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3521 if (shared->IsThisPropertyAssignmentArgument(i)) {
3522 Label not_passed, next;
3523 // Check if the argument assigned to the property is actually passed.
3524 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3525 __ Branch(&not_passed, less_equal, a0, Operand(arg_number));
3526 // Argument passed - find it on the stack.
3527 __ lw(a2, MemOperand(a1, (arg_number + 1) * -kPointerSize));
3528 __ sw(a2, MemOperand(t5));
3529 __ Addu(t5, t5, kPointerSize);
3530 __ jmp(&next);
3531 __ bind(&not_passed);
3532 // Set the property to undefined.
3533 __ sw(t7, MemOperand(t5));
3534 __ Addu(t5, t5, Operand(kPointerSize));
3535 __ bind(&next);
3536 } else {
3537 // Set the property to the constant value.
3538 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
3539 __ li(a2, Operand(constant));
3540 __ sw(a2, MemOperand(t5));
3541 __ Addu(t5, t5, kPointerSize);
3542 }
3543 }
3544
3545 // Fill the unused in-object property fields with undefined.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003546 for (int i = shared->this_property_assignments_count();
3547 i < function->initial_map()->inobject_properties();
3548 i++) {
3549 __ sw(t7, MemOperand(t5));
3550 __ Addu(t5, t5, kPointerSize);
3551 }
3552
3553 // a0: argc
3554 // t4: JSObject (not tagged)
3555 // Move argc to a1 and the JSObject to return to v0 and tag it.
3556 __ mov(a1, a0);
3557 __ mov(v0, t4);
3558 __ Or(v0, v0, Operand(kHeapObjectTag));
3559
3560 // v0: JSObject
3561 // a1: argc
3562 // Remove caller arguments and receiver from the stack and return.
3563 __ sll(t0, a1, kPointerSizeLog2);
3564 __ Addu(sp, sp, t0);
3565 __ Addu(sp, sp, Operand(kPointerSize));
3566 Counters* counters = masm()->isolate()->counters();
3567 __ IncrementCounter(counters->constructed_objects(), 1, a1, a2);
3568 __ IncrementCounter(counters->constructed_objects_stub(), 1, a1, a2);
3569 __ Ret();
3570
3571 // Jump to the generic stub in case the specialized code cannot handle the
3572 // construction.
3573 __ bind(&generic_stub_call);
3574 Handle<Code> generic_construct_stub =
3575 masm()->isolate()->builtins()->JSConstructStubGeneric();
3576 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
3577
3578 // Return the generated code.
3579 return GetCode();
3580}
3581
3582
danno@chromium.org40cb8782011-05-25 07:58:50 +00003583#undef __
3584#define __ ACCESS_MASM(masm)
3585
3586
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003587void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3588 MacroAssembler* masm) {
3589 // ---------- S t a t e --------------
3590 // -- ra : return address
3591 // -- a0 : key
3592 // -- a1 : receiver
3593 // -----------------------------------
3594 Label slow, miss_force_generic;
3595
3596 Register key = a0;
3597 Register receiver = a1;
3598
3599 __ JumpIfNotSmi(key, &miss_force_generic);
3600 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
3601 __ sra(a2, a0, kSmiTagSize);
3602 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
3603 __ Ret();
3604
3605 // Slow case, key and receiver still in a0 and a1.
3606 __ bind(&slow);
3607 __ IncrementCounter(
3608 masm->isolate()->counters()->keyed_load_external_array_slow(),
3609 1, a2, a3);
3610 // Entry registers are intact.
3611 // ---------- S t a t e --------------
3612 // -- ra : return address
3613 // -- a0 : key
3614 // -- a1 : receiver
3615 // -----------------------------------
3616 Handle<Code> slow_ic =
3617 masm->isolate()->builtins()->KeyedLoadIC_Slow();
3618 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
3619
3620 // Miss case, call the runtime.
3621 __ bind(&miss_force_generic);
3622
3623 // ---------- S t a t e --------------
3624 // -- ra : return address
3625 // -- a0 : key
3626 // -- a1 : receiver
3627 // -----------------------------------
3628
3629 Handle<Code> miss_ic =
3630 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3631 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3632}
3633
3634
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003635static bool IsElementTypeSigned(ElementsKind elements_kind) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003636 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003637 case EXTERNAL_BYTE_ELEMENTS:
3638 case EXTERNAL_SHORT_ELEMENTS:
3639 case EXTERNAL_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003640 return true;
3641
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003642 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3643 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3644 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3645 case EXTERNAL_PIXEL_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003646 return false;
3647
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003648 case EXTERNAL_FLOAT_ELEMENTS:
3649 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003650 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003651 case FAST_ELEMENTS:
3652 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003653 case FAST_HOLEY_SMI_ELEMENTS:
3654 case FAST_HOLEY_ELEMENTS:
3655 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003656 case DICTIONARY_ELEMENTS:
3657 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003658 UNREACHABLE();
3659 return false;
3660 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003661 return false;
lrn@chromium.org7516f052011-03-30 08:52:27 +00003662}
3663
3664
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003665static void GenerateSmiKeyCheck(MacroAssembler* masm,
3666 Register key,
3667 Register scratch0,
3668 Register scratch1,
3669 FPURegister double_scratch0,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003670 FPURegister double_scratch1,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003671 Label* fail) {
3672 if (CpuFeatures::IsSupported(FPU)) {
3673 CpuFeatures::Scope scope(FPU);
3674 Label key_ok;
3675 // Check for smi or a smi inside a heap number. We convert the heap
3676 // number and check if the conversion is exact and fits into the smi
3677 // range.
3678 __ JumpIfSmi(key, &key_ok);
3679 __ CheckMap(key,
3680 scratch0,
3681 Heap::kHeapNumberMapRootIndex,
3682 fail,
3683 DONT_DO_SMI_CHECK);
3684 __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
3685 __ EmitFPUTruncate(kRoundToZero,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003686 scratch0,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003687 double_scratch0,
3688 at,
3689 double_scratch1,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003690 scratch1,
3691 kCheckForInexactConversion);
3692
3693 __ Branch(fail, ne, scratch1, Operand(zero_reg));
3694
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003695 __ SmiTagCheckOverflow(key, scratch0, scratch1);
3696 __ BranchOnOverflow(fail, scratch1);
3697 __ bind(&key_ok);
3698 } else {
3699 // Check that the key is a smi.
3700 __ JumpIfNotSmi(key, fail);
3701 }
3702}
3703
3704
danno@chromium.org40cb8782011-05-25 07:58:50 +00003705void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3706 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003707 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003708 // ---------- S t a t e --------------
3709 // -- a0 : value
3710 // -- a1 : key
3711 // -- a2 : receiver
3712 // -- ra : return address
3713 // -----------------------------------
3714
danno@chromium.org40cb8782011-05-25 07:58:50 +00003715 Label slow, check_heap_number, miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003716
3717 // Register usage.
3718 Register value = a0;
3719 Register key = a1;
3720 Register receiver = a2;
3721 // a3 mostly holds the elements array or the destination external array.
3722
danno@chromium.org40cb8782011-05-25 07:58:50 +00003723 // This stub is meant to be tail-jumped to, the receiver must already
3724 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003725
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003726 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003727 GenerateSmiKeyCheck(masm, key, t0, t1, f2, f4, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003728
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003729 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3730
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003731 // Check that the index is in range.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003732 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3733 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003734 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003735
3736 // Handle both smis and HeapNumbers in the fast path. Go to the
3737 // runtime for all other kinds of values.
3738 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003739
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003740 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003741 // Double to pixel conversion is only implemented in the runtime for now.
3742 __ JumpIfNotSmi(value, &slow);
3743 } else {
3744 __ JumpIfNotSmi(value, &check_heap_number);
3745 }
3746 __ SmiUntag(t1, value);
3747 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3748
3749 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003750 // t1: value (integer).
3751
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003752 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003753 case EXTERNAL_PIXEL_ELEMENTS: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003754 // Clamp the value to [0..255].
3755 // v0 is used as a scratch register here.
3756 Label done;
3757 __ li(v0, Operand(255));
3758 // Normal branch: nop in delay slot.
3759 __ Branch(&done, gt, t1, Operand(v0));
3760 // Use delay slot in this branch.
3761 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg));
3762 __ mov(v0, zero_reg); // In delay slot.
3763 __ mov(v0, t1); // Value is in range 0..255.
3764 __ bind(&done);
3765 __ mov(t1, v0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003766
3767 __ srl(t8, key, 1);
3768 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003769 __ sb(t1, MemOperand(t8, 0));
3770 }
3771 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003772 case EXTERNAL_BYTE_ELEMENTS:
3773 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003774 __ srl(t8, key, 1);
3775 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003776 __ sb(t1, MemOperand(t8, 0));
3777 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003778 case EXTERNAL_SHORT_ELEMENTS:
3779 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003780 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003781 __ sh(t1, MemOperand(t8, 0));
3782 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003783 case EXTERNAL_INT_ELEMENTS:
3784 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003785 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003786 __ addu(t8, a3, t8);
3787 __ sw(t1, MemOperand(t8, 0));
3788 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003789 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003790 // Perform int-to-float conversion and store to memory.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003791 __ SmiUntag(t0, key);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003792 StoreIntAsFloat(masm, a3, t0, t1, t2, t3, t4);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003793 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003794 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003795 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003796 __ addu(a3, a3, t8);
3797 // a3: effective address of the double element
3798 FloatingPointHelper::Destination destination;
3799 if (CpuFeatures::IsSupported(FPU)) {
3800 destination = FloatingPointHelper::kFPURegisters;
3801 } else {
3802 destination = FloatingPointHelper::kCoreRegisters;
3803 }
3804 FloatingPointHelper::ConvertIntToDouble(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003805 masm, t1, destination,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003806 f0, t2, t3, // These are: double_dst, dst_mantissa, dst_exponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003807 t0, f2); // These are: scratch2, single_scratch.
3808 if (destination == FloatingPointHelper::kFPURegisters) {
3809 CpuFeatures::Scope scope(FPU);
3810 __ sdc1(f0, MemOperand(a3, 0));
3811 } else {
3812 __ sw(t2, MemOperand(a3, 0));
3813 __ sw(t3, MemOperand(a3, Register::kSizeInBytes));
3814 }
3815 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003816 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003817 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003818 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003819 case FAST_HOLEY_ELEMENTS:
3820 case FAST_HOLEY_SMI_ELEMENTS:
3821 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003822 case DICTIONARY_ELEMENTS:
3823 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003824 UNREACHABLE();
3825 break;
3826 }
3827
3828 // Entry registers are intact, a0 holds the value which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003829 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003830 __ Ret();
3831
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003832 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003833 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003834 __ bind(&check_heap_number);
3835 __ GetObjectType(value, t1, t2);
3836 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE));
3837
3838 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3839
3840 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003841
3842 // The WebGL specification leaves the behavior of storing NaN and
3843 // +/-Infinity into integer arrays basically undefined. For more
3844 // reproducible behavior, convert these to zero.
3845
3846 if (CpuFeatures::IsSupported(FPU)) {
3847 CpuFeatures::Scope scope(FPU);
3848
3849 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
3850
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003851 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003852 __ cvt_s_d(f0, f0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003853 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003854 __ addu(t8, a3, t8);
3855 __ swc1(f0, MemOperand(t8, 0));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003856 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003857 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003858 __ addu(t8, a3, t8);
3859 __ sdc1(f0, MemOperand(t8, 0));
3860 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003861 __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003862
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003863 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003864 case EXTERNAL_BYTE_ELEMENTS:
3865 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003866 __ srl(t8, key, 1);
3867 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003868 __ sb(t3, MemOperand(t8, 0));
3869 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003870 case EXTERNAL_SHORT_ELEMENTS:
3871 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003872 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003873 __ sh(t3, MemOperand(t8, 0));
3874 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003875 case EXTERNAL_INT_ELEMENTS:
3876 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003877 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003878 __ addu(t8, a3, t8);
3879 __ sw(t3, MemOperand(t8, 0));
3880 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003881 case EXTERNAL_PIXEL_ELEMENTS:
3882 case EXTERNAL_FLOAT_ELEMENTS:
3883 case EXTERNAL_DOUBLE_ELEMENTS:
3884 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003885 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003886 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003887 case FAST_HOLEY_ELEMENTS:
3888 case FAST_HOLEY_SMI_ELEMENTS:
3889 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003890 case DICTIONARY_ELEMENTS:
3891 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003892 UNREACHABLE();
3893 break;
3894 }
3895 }
3896
3897 // Entry registers are intact, a0 holds the value
3898 // which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003899 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003900 __ Ret();
3901 } else {
3902 // FPU is not available, do manual conversions.
3903
3904 __ lw(t3, FieldMemOperand(value, HeapNumber::kExponentOffset));
3905 __ lw(t4, FieldMemOperand(value, HeapNumber::kMantissaOffset));
3906
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003907 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003908 Label done, nan_or_infinity_or_zero;
3909 static const int kMantissaInHiWordShift =
3910 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3911
3912 static const int kMantissaInLoWordShift =
3913 kBitsPerInt - kMantissaInHiWordShift;
3914
3915 // Test for all special exponent values: zeros, subnormal numbers, NaNs
3916 // and infinities. All these should be converted to 0.
3917 __ li(t5, HeapNumber::kExponentMask);
3918 __ and_(t6, t3, t5);
3919 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(zero_reg));
3920
3921 __ xor_(t1, t6, t5);
3922 __ li(t2, kBinary32ExponentMask);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003923 __ Movz(t6, t2, t1); // Only if t6 is equal to t5.
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003924 __ Branch(&nan_or_infinity_or_zero, eq, t1, Operand(zero_reg));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003925
3926 // Rebias exponent.
3927 __ srl(t6, t6, HeapNumber::kExponentShift);
3928 __ Addu(t6,
3929 t6,
3930 Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
3931
3932 __ li(t1, Operand(kBinary32MaxExponent));
3933 __ Slt(t1, t1, t6);
3934 __ And(t2, t3, Operand(HeapNumber::kSignMask));
3935 __ Or(t2, t2, Operand(kBinary32ExponentMask));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003936 __ Movn(t3, t2, t1); // Only if t6 is gt kBinary32MaxExponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003937 __ Branch(&done, gt, t6, Operand(kBinary32MaxExponent));
3938
3939 __ Slt(t1, t6, Operand(kBinary32MinExponent));
3940 __ And(t2, t3, Operand(HeapNumber::kSignMask));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003941 __ Movn(t3, t2, t1); // Only if t6 is lt kBinary32MinExponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003942 __ Branch(&done, lt, t6, Operand(kBinary32MinExponent));
3943
3944 __ And(t7, t3, Operand(HeapNumber::kSignMask));
3945 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3946 __ sll(t3, t3, kMantissaInHiWordShift);
3947 __ or_(t7, t7, t3);
3948 __ srl(t4, t4, kMantissaInLoWordShift);
3949 __ or_(t7, t7, t4);
3950 __ sll(t6, t6, kBinary32ExponentShift);
3951 __ or_(t3, t7, t6);
3952
3953 __ bind(&done);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003954 __ sll(t9, key, 1);
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003955 __ addu(t9, a3, t9);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003956 __ sw(t3, MemOperand(t9, 0));
3957
3958 // Entry registers are intact, a0 holds the value which is the return
3959 // value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003960 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003961 __ Ret();
3962
3963 __ bind(&nan_or_infinity_or_zero);
3964 __ And(t7, t3, Operand(HeapNumber::kSignMask));
3965 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3966 __ or_(t6, t6, t7);
3967 __ sll(t3, t3, kMantissaInHiWordShift);
3968 __ or_(t6, t6, t3);
3969 __ srl(t4, t4, kMantissaInLoWordShift);
3970 __ or_(t3, t6, t4);
3971 __ Branch(&done);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003972 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003973 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003974 __ addu(t8, a3, t8);
3975 // t8: effective address of destination element.
3976 __ sw(t4, MemOperand(t8, 0));
3977 __ sw(t3, MemOperand(t8, Register::kSizeInBytes));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003978 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003979 __ Ret();
3980 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003981 bool is_signed_type = IsElementTypeSigned(elements_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003982 int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
3983 int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
3984
3985 Label done, sign;
3986
3987 // Test for all special exponent values: zeros, subnormal numbers, NaNs
3988 // and infinities. All these should be converted to 0.
3989 __ li(t5, HeapNumber::kExponentMask);
3990 __ and_(t6, t3, t5);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003991 __ Movz(t3, zero_reg, t6); // Only if t6 is equal to zero.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003992 __ Branch(&done, eq, t6, Operand(zero_reg));
3993
3994 __ xor_(t2, t6, t5);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003995 __ Movz(t3, zero_reg, t2); // Only if t6 is equal to t5.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003996 __ Branch(&done, eq, t6, Operand(t5));
3997
3998 // Unbias exponent.
3999 __ srl(t6, t6, HeapNumber::kExponentShift);
4000 __ Subu(t6, t6, Operand(HeapNumber::kExponentBias));
4001 // If exponent is negative then result is 0.
4002 __ slt(t2, t6, zero_reg);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004003 __ Movn(t3, zero_reg, t2); // Only if exponent is negative.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004004 __ Branch(&done, lt, t6, Operand(zero_reg));
4005
4006 // If exponent is too big then result is minimal value.
4007 __ slti(t1, t6, meaningfull_bits - 1);
4008 __ li(t2, min_value);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004009 __ Movz(t3, t2, t1); // Only if t6 is ge meaningfull_bits - 1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004010 __ Branch(&done, ge, t6, Operand(meaningfull_bits - 1));
4011
4012 __ And(t5, t3, Operand(HeapNumber::kSignMask));
4013 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
4014 __ Or(t3, t3, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
4015
4016 __ li(t9, HeapNumber::kMantissaBitsInTopWord);
4017 __ subu(t6, t9, t6);
4018 __ slt(t1, t6, zero_reg);
4019 __ srlv(t2, t3, t6);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004020 __ Movz(t3, t2, t1); // Only if t6 is positive.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004021 __ Branch(&sign, ge, t6, Operand(zero_reg));
4022
4023 __ subu(t6, zero_reg, t6);
4024 __ sllv(t3, t3, t6);
4025 __ li(t9, meaningfull_bits);
4026 __ subu(t6, t9, t6);
4027 __ srlv(t4, t4, t6);
4028 __ or_(t3, t3, t4);
4029
4030 __ bind(&sign);
4031 __ subu(t2, t3, zero_reg);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00004032 __ Movz(t3, t2, t5); // Only if t5 is zero.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004033
4034 __ bind(&done);
4035
4036 // Result is in t3.
4037 // This switch block should be exactly the same as above (FPU mode).
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004038 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004039 case EXTERNAL_BYTE_ELEMENTS:
4040 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004041 __ srl(t8, key, 1);
4042 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004043 __ sb(t3, MemOperand(t8, 0));
4044 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004045 case EXTERNAL_SHORT_ELEMENTS:
4046 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004047 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004048 __ sh(t3, MemOperand(t8, 0));
4049 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004050 case EXTERNAL_INT_ELEMENTS:
4051 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004052 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004053 __ addu(t8, a3, t8);
4054 __ sw(t3, MemOperand(t8, 0));
4055 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004056 case EXTERNAL_PIXEL_ELEMENTS:
4057 case EXTERNAL_FLOAT_ELEMENTS:
4058 case EXTERNAL_DOUBLE_ELEMENTS:
4059 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004060 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004061 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004062 case FAST_HOLEY_ELEMENTS:
4063 case FAST_HOLEY_SMI_ELEMENTS:
4064 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004065 case DICTIONARY_ELEMENTS:
4066 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004067 UNREACHABLE();
4068 break;
4069 }
4070 }
4071 }
4072 }
4073
danno@chromium.org40cb8782011-05-25 07:58:50 +00004074 // Slow case, key and receiver still in a0 and a1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004075 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004076 __ IncrementCounter(
4077 masm->isolate()->counters()->keyed_load_external_array_slow(),
4078 1, a2, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004079 // Entry registers are intact.
4080 // ---------- S t a t e --------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004081 // -- ra : return address
danno@chromium.org40cb8782011-05-25 07:58:50 +00004082 // -- a0 : key
4083 // -- a1 : receiver
4084 // -----------------------------------
4085 Handle<Code> slow_ic =
4086 masm->isolate()->builtins()->KeyedStoreIC_Slow();
4087 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4088
4089 // Miss case, call the runtime.
4090 __ bind(&miss_force_generic);
4091
4092 // ---------- S t a t e --------------
4093 // -- ra : return address
4094 // -- a0 : key
4095 // -- a1 : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004096 // -----------------------------------
4097
danno@chromium.org40cb8782011-05-25 07:58:50 +00004098 Handle<Code> miss_ic =
4099 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4100 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
4101}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004102
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004103
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004104void KeyedStoreStubCompiler::GenerateStoreFastElement(
4105 MacroAssembler* masm,
4106 bool is_js_array,
yangguo@chromium.org56454712012-02-16 15:33:53 +00004107 ElementsKind elements_kind,
4108 KeyedAccessGrowMode grow_mode) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00004109 // ----------- S t a t e -------------
4110 // -- a0 : value
4111 // -- a1 : key
4112 // -- a2 : receiver
4113 // -- ra : return address
4114 // -- a3 : scratch
4115 // -- a4 : scratch (elements)
4116 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00004117 Label miss_force_generic, transition_elements_kind, grow, slow;
4118 Label finish_store, check_capacity;
danno@chromium.org40cb8782011-05-25 07:58:50 +00004119
4120 Register value_reg = a0;
4121 Register key_reg = a1;
4122 Register receiver_reg = a2;
yangguo@chromium.org56454712012-02-16 15:33:53 +00004123 Register scratch = t0;
4124 Register elements_reg = a3;
4125 Register length_reg = t1;
4126 Register scratch2 = t2;
danno@chromium.org40cb8782011-05-25 07:58:50 +00004127
4128 // This stub is meant to be tail-jumped to, the receiver must already
4129 // have been verified by the caller to not be a smi.
4130
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004131 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004132 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004133
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004134 if (IsFastSmiElementsKind(elements_kind)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00004135 __ JumpIfNotSmi(value_reg, &transition_elements_kind);
4136 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004137
4138 // Check that the key is within bounds.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004139 __ lw(elements_reg,
4140 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00004141 if (is_js_array) {
4142 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4143 } else {
4144 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4145 }
4146 // Compare smis.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004147 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4148 __ Branch(&grow, hs, key_reg, Operand(scratch));
4149 } else {
4150 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4151 }
4152
4153 // Make sure elements is a fast element array, not 'cow'.
4154 __ CheckMap(elements_reg,
4155 scratch,
4156 Heap::kFixedArrayMapRootIndex,
4157 &miss_force_generic,
4158 DONT_DO_SMI_CHECK);
4159
4160 __ bind(&finish_store);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004161
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004162 if (IsFastSmiElementsKind(elements_kind)) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004163 __ Addu(scratch,
4164 elements_reg,
4165 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4166 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4167 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4168 __ Addu(scratch, scratch, scratch2);
4169 __ sw(value_reg, MemOperand(scratch));
4170 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004171 ASSERT(IsFastObjectElementsKind(elements_kind));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004172 __ Addu(scratch,
4173 elements_reg,
4174 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4175 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4176 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4177 __ Addu(scratch, scratch, scratch2);
4178 __ sw(value_reg, MemOperand(scratch));
4179 __ mov(receiver_reg, value_reg);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004180 __ RecordWrite(elements_reg, // Object.
4181 scratch, // Address.
4182 receiver_reg, // Value.
4183 kRAHasNotBeenSaved,
4184 kDontSaveFPRegs);
4185 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004186 // value_reg (a0) is preserved.
4187 // Done.
4188 __ Ret();
4189
4190 __ bind(&miss_force_generic);
4191 Handle<Code> ic =
4192 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4193 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004194
4195 __ bind(&transition_elements_kind);
4196 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4197 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
yangguo@chromium.org56454712012-02-16 15:33:53 +00004198
4199 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4200 // Grow the array by a single element if possible.
4201 __ bind(&grow);
4202
4203 // Make sure the array is only growing by a single element, anything else
4204 // must be handled by the runtime.
4205 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch));
4206
4207 // Check for the empty array, and preallocate a small backing store if
4208 // possible.
4209 __ lw(length_reg,
4210 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4211 __ lw(elements_reg,
4212 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4213 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
4214 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
4215
4216 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
4217 __ AllocateInNewSpace(size, elements_reg, scratch, scratch2, &slow,
4218 TAG_OBJECT);
4219
4220 __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex);
4221 __ sw(scratch, FieldMemOperand(elements_reg, JSObject::kMapOffset));
4222 __ li(scratch, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4223 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4224 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
4225 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
4226 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::SizeFor(i)));
4227 }
4228
4229 // Store the element at index zero.
4230 __ sw(value_reg, FieldMemOperand(elements_reg, FixedArray::SizeFor(0)));
4231
4232 // Install the new backing store in the JSArray.
4233 __ sw(elements_reg,
4234 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4235 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
4236 scratch, kRAHasNotBeenSaved, kDontSaveFPRegs,
4237 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4238
4239 // Increment the length of the array.
4240 __ li(length_reg, Operand(Smi::FromInt(1)));
4241 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4242 __ Ret();
4243
4244 __ bind(&check_capacity);
4245 // Check for cow elements, in general they are not handled by this stub
4246 __ CheckMap(elements_reg,
4247 scratch,
4248 Heap::kFixedCOWArrayMapRootIndex,
4249 &miss_force_generic,
4250 DONT_DO_SMI_CHECK);
4251
4252 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4253 __ Branch(&slow, hs, length_reg, Operand(scratch));
4254
4255 // Grow the array and finish the store.
4256 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
4257 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4258 __ jmp(&finish_store);
4259
4260 __ bind(&slow);
4261 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4262 __ Jump(ic_slow, RelocInfo::CODE_TARGET);
4263 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004264}
4265
4266
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004267void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
4268 MacroAssembler* masm,
yangguo@chromium.org56454712012-02-16 15:33:53 +00004269 bool is_js_array,
4270 KeyedAccessGrowMode grow_mode) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004271 // ----------- S t a t e -------------
4272 // -- a0 : value
4273 // -- a1 : key
4274 // -- a2 : receiver
4275 // -- ra : return address
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004276 // -- a3 : scratch (elements backing store)
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004277 // -- t0 : scratch (elements_reg)
4278 // -- t1 : scratch (mantissa_reg)
4279 // -- t2 : scratch (exponent_reg)
4280 // -- t3 : scratch4
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004281 // -- t4 : scratch
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004282 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00004283 Label miss_force_generic, transition_elements_kind, grow, slow;
4284 Label finish_store, check_capacity;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004285
4286 Register value_reg = a0;
4287 Register key_reg = a1;
4288 Register receiver_reg = a2;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004289 Register elements_reg = a3;
4290 Register scratch1 = t0;
4291 Register scratch2 = t1;
4292 Register scratch3 = t2;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004293 Register scratch4 = t3;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004294 Register scratch5 = t4;
yangguo@chromium.org56454712012-02-16 15:33:53 +00004295 Register length_reg = t3;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004296
4297 // This stub is meant to be tail-jumped to, the receiver must already
4298 // have been verified by the caller to not be a smi.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004299
4300 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004301 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004302
4303 __ lw(elements_reg,
4304 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4305
4306 // Check that the key is within bounds.
4307 if (is_js_array) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004308 __ lw(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004309 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004310 __ lw(scratch1,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004311 FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4312 }
4313 // Compare smis, unsigned compare catches both negative and out-of-bound
4314 // indexes.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004315 if (grow_mode == ALLOW_JSARRAY_GROWTH) {
4316 __ Branch(&grow, hs, key_reg, Operand(scratch1));
4317 } else {
4318 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch1));
4319 }
4320
4321 __ bind(&finish_store);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004322
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004323 __ StoreNumberToDoubleElements(value_reg,
4324 key_reg,
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004325 // All registers after this are overwritten.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004326 elements_reg,
4327 scratch1,
4328 scratch2,
4329 scratch3,
4330 scratch4,
4331 &transition_elements_kind);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004332
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004333 __ Ret(USE_DELAY_SLOT);
4334 __ mov(v0, value_reg); // In delay slot.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004335
4336 // Handle store cache miss, replacing the ic with the generic stub.
4337 __ bind(&miss_force_generic);
4338 Handle<Code> ic =
4339 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4340 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004341
4342 __ bind(&transition_elements_kind);
4343 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4344 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
yangguo@chromium.org56454712012-02-16 15:33:53 +00004345
4346 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4347 // Grow the array by a single element if possible.
4348 __ bind(&grow);
4349
4350 // Make sure the array is only growing by a single element, anything else
4351 // must be handled by the runtime.
4352 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch1));
4353
4354 // Transition on values that can't be stored in a FixedDoubleArray.
4355 Label value_is_smi;
4356 __ JumpIfSmi(value_reg, &value_is_smi);
4357 __ lw(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
4358 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
4359 __ Branch(&transition_elements_kind, ne, scratch1, Operand(at));
4360 __ bind(&value_is_smi);
4361
4362 // Check for the empty array, and preallocate a small backing store if
4363 // possible.
4364 __ lw(length_reg,
4365 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4366 __ lw(elements_reg,
4367 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4368 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
4369 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
4370
4371 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
4372 __ AllocateInNewSpace(size, elements_reg, scratch1, scratch2, &slow,
4373 TAG_OBJECT);
4374
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004375 // Initialize the new FixedDoubleArray.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004376 __ LoadRoot(scratch1, Heap::kFixedDoubleArrayMapRootIndex);
4377 __ sw(scratch1, FieldMemOperand(elements_reg, JSObject::kMapOffset));
4378 __ li(scratch1, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4379 __ sw(scratch1,
4380 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
4381
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004382 __ mov(scratch1, elements_reg);
4383 __ StoreNumberToDoubleElements(value_reg,
4384 key_reg,
4385 // All registers after this are overwritten.
4386 scratch1,
4387 scratch2,
4388 scratch3,
4389 scratch4,
4390 scratch5,
4391 &transition_elements_kind);
4392
4393 __ li(scratch1, Operand(kHoleNanLower32));
4394 __ li(scratch2, Operand(kHoleNanUpper32));
4395 for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) {
4396 int offset = FixedDoubleArray::OffsetOfElementAt(i);
4397 __ sw(scratch1, FieldMemOperand(elements_reg, offset));
4398 __ sw(scratch2, FieldMemOperand(elements_reg, offset + kPointerSize));
4399 }
4400
yangguo@chromium.org56454712012-02-16 15:33:53 +00004401 // Install the new backing store in the JSArray.
4402 __ sw(elements_reg,
4403 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4404 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
4405 scratch1, kRAHasNotBeenSaved, kDontSaveFPRegs,
4406 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4407
4408 // Increment the length of the array.
4409 __ li(length_reg, Operand(Smi::FromInt(1)));
4410 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
danno@chromium.org00379b82012-05-04 09:16:29 +00004411 __ lw(elements_reg,
4412 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004413 __ Ret();
yangguo@chromium.org56454712012-02-16 15:33:53 +00004414
4415 __ bind(&check_capacity);
4416 // Make sure that the backing store can hold additional elements.
4417 __ lw(scratch1,
4418 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
4419 __ Branch(&slow, hs, length_reg, Operand(scratch1));
4420
4421 // Grow the array and finish the store.
4422 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
4423 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4424 __ jmp(&finish_store);
4425
4426 __ bind(&slow);
4427 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4428 __ Jump(ic_slow, RelocInfo::CODE_TARGET);
4429 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004430}
4431
4432
ager@chromium.org5c838252010-02-19 08:53:10 +00004433#undef __
4434
4435} } // namespace v8::internal
4436
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004437#endif // V8_TARGET_ARCH_MIPS