blob: 0be9e03c371b4206978031b0245f5153c8af9ae3 [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
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000582void StubCompiler::GenerateStoreMiss(MacroAssembler* masm, Code::Kind kind) {
583 ASSERT(kind == Code::STORE_IC || kind == Code::KEYED_STORE_IC);
584 Handle<Code> code = (kind == Code::STORE_IC)
585 ? masm->isolate()->builtins()->StoreIC_Miss()
586 : masm->isolate()->builtins()->KeyedStoreIC_Miss();
587 __ Jump(code, RelocInfo::CODE_TARGET);
588}
589
590
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000591static void GenerateCallFunction(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000592 Handle<Object> object,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000593 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000594 Label* miss,
595 Code::ExtraICState extra_ic_state) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000596 // ----------- S t a t e -------------
597 // -- a0: receiver
598 // -- a1: function to call
599 // -----------------------------------
600 // Check that the function really is a function.
601 __ JumpIfSmi(a1, miss);
602 __ GetObjectType(a1, a3, a3);
603 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
604
605 // Patch the receiver on the stack with the global proxy if
606 // necessary.
607 if (object->IsGlobalObject()) {
608 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
609 __ sw(a3, MemOperand(sp, arguments.immediate() * kPointerSize));
610 }
611
612 // Invoke the function.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000613 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
614 ? CALL_AS_FUNCTION
615 : CALL_AS_METHOD;
616 __ InvokeFunction(a1, arguments, JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000617}
618
619
620static void PushInterceptorArguments(MacroAssembler* masm,
621 Register receiver,
622 Register holder,
623 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000624 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000625 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000626 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
627 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000628 Register scratch = name;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000629 __ li(scratch, Operand(interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000630 __ Push(scratch, receiver, holder);
631 __ lw(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
632 __ push(scratch);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000633 __ li(scratch, Operand(ExternalReference::isolate_address()));
634 __ push(scratch);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000635}
636
637
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000638static void CompileCallLoadPropertyWithInterceptor(
639 MacroAssembler* masm,
640 Register receiver,
641 Register holder,
642 Register name,
643 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000644 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
645
646 ExternalReference ref =
647 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
648 masm->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000649 __ PrepareCEntryArgs(6);
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000650 __ PrepareCEntryFunction(ref);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000651
652 CEntryStub stub(1);
653 __ CallStub(&stub);
654}
655
656
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000657static const int kFastApiCallArguments = 4;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000658
659
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000660// Reserves space for the extra arguments to API function in the
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000661// caller's frame.
662//
663// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
664static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
665 Register scratch) {
666 ASSERT(Smi::FromInt(0) == 0);
667 for (int i = 0; i < kFastApiCallArguments; i++) {
668 __ push(zero_reg);
669 }
670}
671
672
673// Undoes the effects of ReserveSpaceForFastApiCall.
674static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
675 __ Drop(kFastApiCallArguments);
676}
677
678
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000679static void GenerateFastApiDirectCall(MacroAssembler* masm,
680 const CallOptimization& optimization,
681 int argc) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000682 // ----------- S t a t e -------------
683 // -- sp[0] : holder (set by CheckPrototypes)
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000684 // -- sp[4] : callee JS function
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000685 // -- sp[8] : call data
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000686 // -- sp[12] : isolate
687 // -- sp[16] : last JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000688 // -- ...
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000689 // -- sp[(argc + 3) * 4] : first JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000690 // -- sp[(argc + 4) * 4] : receiver
691 // -----------------------------------
692 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000693 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000694 __ LoadHeapObject(t1, function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000695 __ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset));
696
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000697 // Pass the additional arguments.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000698 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
699 Handle<Object> call_data(api_call_info->data());
700 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
701 __ li(a0, api_call_info);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000702 __ lw(t2, FieldMemOperand(a0, CallHandlerInfo::kDataOffset));
703 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000704 __ li(t2, call_data);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000705 }
706
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000707 __ li(t3, Operand(ExternalReference::isolate_address()));
708 // Store JS function, call data and isolate.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000709 __ sw(t1, MemOperand(sp, 1 * kPointerSize));
710 __ sw(t2, MemOperand(sp, 2 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000711 __ sw(t3, MemOperand(sp, 3 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000712
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000713 // Prepare arguments.
714 __ Addu(a2, sp, Operand(3 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000715
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000716 // Allocate the v8::Arguments structure in the arguments' space since
717 // it's not controlled by GC.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000718 const int kApiStackSpace = 4;
719
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000720 FrameScope frame_scope(masm, StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000721 __ EnterExitFrame(false, kApiStackSpace);
722
723 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
724 // struct from the function (which is currently the case). This means we pass
725 // the first argument in a1 instead of a0. TryCallApiFunctionAndReturn
726 // will handle setting up a0.
727
728 // a1 = v8::Arguments&
729 // Arguments is built at sp + 1 (sp is a reserved spot for ra).
730 __ Addu(a1, sp, kPointerSize);
731
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000732 // v8::Arguments::implicit_args_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000733 __ sw(a2, MemOperand(a1, 0 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000734 // v8::Arguments::values_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000735 __ Addu(t0, a2, Operand(argc * kPointerSize));
736 __ sw(t0, MemOperand(a1, 1 * kPointerSize));
737 // v8::Arguments::length_ = argc
738 __ li(t0, Operand(argc));
739 __ sw(t0, MemOperand(a1, 2 * kPointerSize));
740 // v8::Arguments::is_construct_call = 0
741 __ sw(zero_reg, MemOperand(a1, 3 * kPointerSize));
742
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000743 const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000744 Address function_address = v8::ToCData<Address>(api_call_info->callback());
745 ApiFunction fun(function_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000746 ExternalReference ref =
747 ExternalReference(&fun,
748 ExternalReference::DIRECT_API_CALL,
749 masm->isolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000750 AllowExternalCallThatCantCauseGC scope(masm);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000751 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000752}
753
lrn@chromium.org7516f052011-03-30 08:52:27 +0000754class CallInterceptorCompiler BASE_EMBEDDED {
755 public:
756 CallInterceptorCompiler(StubCompiler* stub_compiler,
757 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000758 Register name,
759 Code::ExtraICState extra_ic_state)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000760 : stub_compiler_(stub_compiler),
761 arguments_(arguments),
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000762 name_(name),
763 extra_ic_state_(extra_ic_state) {}
lrn@chromium.org7516f052011-03-30 08:52:27 +0000764
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000765 void Compile(MacroAssembler* masm,
766 Handle<JSObject> object,
767 Handle<JSObject> holder,
768 Handle<String> name,
769 LookupResult* lookup,
770 Register receiver,
771 Register scratch1,
772 Register scratch2,
773 Register scratch3,
774 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000775 ASSERT(holder->HasNamedInterceptor());
776 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
777
778 // Check that the receiver isn't a smi.
779 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000780 CallOptimization optimization(lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000781 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000782 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
783 holder, lookup, name, optimization, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000784 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000785 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
786 name, holder, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000787 }
788 }
789
790 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000791 void CompileCacheable(MacroAssembler* masm,
792 Handle<JSObject> object,
793 Register receiver,
794 Register scratch1,
795 Register scratch2,
796 Register scratch3,
797 Handle<JSObject> interceptor_holder,
798 LookupResult* lookup,
799 Handle<String> name,
800 const CallOptimization& optimization,
801 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000802 ASSERT(optimization.is_constant_call());
803 ASSERT(!lookup->holder()->IsGlobalObject());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000804 Counters* counters = masm->isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000805 int depth1 = kInvalidProtoDepth;
806 int depth2 = kInvalidProtoDepth;
807 bool can_do_fast_api_call = false;
808 if (optimization.is_simple_api_call() &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000809 !lookup->holder()->IsGlobalObject()) {
810 depth1 = optimization.GetPrototypeDepthOfExpectedType(
811 object, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000812 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000813 depth2 = optimization.GetPrototypeDepthOfExpectedType(
814 interceptor_holder, Handle<JSObject>(lookup->holder()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000815 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000816 can_do_fast_api_call =
817 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000818 }
819
820 __ IncrementCounter(counters->call_const_interceptor(), 1,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000821 scratch1, scratch2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000822
823 if (can_do_fast_api_call) {
824 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
825 scratch1, scratch2);
826 ReserveSpaceForFastApiCall(masm, scratch1);
827 }
828
829 // Check that the maps from receiver to interceptor's holder
830 // haven't changed and thus we can invoke interceptor.
831 Label miss_cleanup;
832 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
833 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000834 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
835 scratch1, scratch2, scratch3,
836 name, depth1, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000837
838 // Invoke an interceptor and if it provides a value,
839 // branch to |regular_invoke|.
840 Label regular_invoke;
841 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
842 &regular_invoke);
843
844 // Interceptor returned nothing for this property. Try to use cached
845 // constant function.
846
847 // Check that the maps from interceptor's holder to constant function's
848 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000849 if (*interceptor_holder != lookup->holder()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000850 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000851 Handle<JSObject>(lookup->holder()),
852 scratch1, scratch2, scratch3,
853 name, depth2, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000854 } else {
855 // CheckPrototypes has a side effect of fetching a 'holder'
856 // for API (object which is instanceof for the signature). It's
857 // safe to omit it here, as if present, it should be fetched
858 // by the previous CheckPrototypes.
859 ASSERT(depth2 == kInvalidProtoDepth);
860 }
861
862 // Invoke function.
863 if (can_do_fast_api_call) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000864 GenerateFastApiDirectCall(masm, optimization, arguments_.immediate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000865 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000866 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
867 ? CALL_AS_FUNCTION
868 : CALL_AS_METHOD;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000869 __ InvokeFunction(optimization.constant_function(), arguments_,
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000870 JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000871 }
872
873 // Deferred code for fast API call case---clean preallocated space.
874 if (can_do_fast_api_call) {
875 __ bind(&miss_cleanup);
876 FreeSpaceForFastApiCall(masm);
877 __ Branch(miss_label);
878 }
879
880 // Invoke a regular function.
881 __ bind(&regular_invoke);
882 if (can_do_fast_api_call) {
883 FreeSpaceForFastApiCall(masm);
884 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000885 }
886
887 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000888 Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000889 Register receiver,
890 Register scratch1,
891 Register scratch2,
892 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000893 Handle<String> name,
894 Handle<JSObject> interceptor_holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000895 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000896 Register holder =
897 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000898 scratch1, scratch2, scratch3,
899 name, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000900
901 // Call a runtime function to load the interceptor property.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000902 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000903 // Save the name_ register across the call.
904 __ push(name_);
905
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000906 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000907
908 __ CallExternalReference(
909 ExternalReference(
910 IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
911 masm->isolate()),
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000912 6);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000913 // Restore the name_ register.
914 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000915 // Leave the internal frame.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000916 }
917
918 void LoadWithInterceptor(MacroAssembler* masm,
919 Register receiver,
920 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000921 Handle<JSObject> holder_obj,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000922 Register scratch,
923 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000924 {
925 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000926
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000927 __ Push(holder, name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000928 CompileCallLoadPropertyWithInterceptor(masm,
929 receiver,
930 holder,
931 name_,
932 holder_obj);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000933 __ pop(name_); // Restore the name.
934 __ pop(receiver); // Restore the holder.
935 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000936 // If interceptor returns no-result sentinel, call the constant function.
937 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
938 __ Branch(interceptor_succeeded, ne, v0, Operand(scratch));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000939 }
940
941 StubCompiler* stub_compiler_;
942 const ParameterCount& arguments_;
943 Register name_;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000944 Code::ExtraICState extra_ic_state_;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000945};
946
947
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000948
949// Generate code to check that a global property cell is empty. Create
950// the property cell at compilation time if no cell exists for the
951// property.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000952static void GenerateCheckPropertyCell(MacroAssembler* masm,
953 Handle<GlobalObject> global,
954 Handle<String> name,
955 Register scratch,
956 Label* miss) {
957 Handle<JSGlobalPropertyCell> cell =
958 GlobalObject::EnsurePropertyCell(global, name);
959 ASSERT(cell->value()->IsTheHole());
960 __ li(scratch, Operand(cell));
961 __ lw(scratch,
962 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
963 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
964 __ Branch(miss, ne, scratch, Operand(at));
965}
966
967
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000968// Calls GenerateCheckPropertyCell for each global object in the prototype chain
969// from object to (but not including) holder.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000970static void GenerateCheckPropertyCells(MacroAssembler* masm,
971 Handle<JSObject> object,
972 Handle<JSObject> holder,
973 Handle<String> name,
974 Register scratch,
975 Label* miss) {
976 Handle<JSObject> current = object;
977 while (!current.is_identical_to(holder)) {
978 if (current->IsGlobalObject()) {
979 GenerateCheckPropertyCell(masm,
980 Handle<GlobalObject>::cast(current),
981 name,
982 scratch,
983 miss);
984 }
985 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
986 }
987}
988
989
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000990// Convert and store int passed in register ival to IEEE 754 single precision
991// floating point value at memory location (dst + 4 * wordoffset)
992// If FPU is available use it for conversion.
993static void StoreIntAsFloat(MacroAssembler* masm,
994 Register dst,
995 Register wordoffset,
996 Register ival,
997 Register fval,
998 Register scratch1,
999 Register scratch2) {
1000 if (CpuFeatures::IsSupported(FPU)) {
1001 CpuFeatures::Scope scope(FPU);
1002 __ mtc1(ival, f0);
1003 __ cvt_s_w(f0, f0);
1004 __ sll(scratch1, wordoffset, 2);
1005 __ addu(scratch1, dst, scratch1);
1006 __ swc1(f0, MemOperand(scratch1, 0));
1007 } else {
1008 // FPU is not available, do manual conversions.
1009
1010 Label not_special, done;
1011 // Move sign bit from source to destination. This works because the sign
1012 // bit in the exponent word of the double has the same position and polarity
1013 // as the 2's complement sign bit in a Smi.
1014 ASSERT(kBinary32SignMask == 0x80000000u);
1015
1016 __ And(fval, ival, Operand(kBinary32SignMask));
1017 // Negate value if it is negative.
1018 __ subu(scratch1, zero_reg, ival);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001019 __ Movn(ival, scratch1, fval);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001020
1021 // We have -1, 0 or 1, which we treat specially. Register ival contains
1022 // absolute value: it is either equal to 1 (special case of -1 and 1),
1023 // greater than 1 (not a special case) or less than 1 (special case of 0).
1024 __ Branch(&not_special, gt, ival, Operand(1));
1025
1026 // For 1 or -1 we need to or in the 0 exponent (biased).
1027 static const uint32_t exponent_word_for_1 =
1028 kBinary32ExponentBias << kBinary32ExponentShift;
1029
1030 __ Xor(scratch1, ival, Operand(1));
1031 __ li(scratch2, exponent_word_for_1);
1032 __ or_(scratch2, fval, scratch2);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001033 __ Movz(fval, scratch2, scratch1); // Only if ival is equal to 1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001034 __ Branch(&done);
1035
1036 __ bind(&not_special);
1037 // Count leading zeros.
1038 // Gets the wrong answer for 0, but we already checked for that case above.
1039 Register zeros = scratch2;
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001040 __ Clz(zeros, ival);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001041
1042 // Compute exponent and or it into the exponent register.
1043 __ li(scratch1, (kBitsPerInt - 1) + kBinary32ExponentBias);
1044 __ subu(scratch1, scratch1, zeros);
1045
1046 __ sll(scratch1, scratch1, kBinary32ExponentShift);
1047 __ or_(fval, fval, scratch1);
1048
1049 // Shift up the source chopping the top bit off.
1050 __ Addu(zeros, zeros, Operand(1));
1051 // This wouldn't work for 1 and -1 as the shift would be 32 which means 0.
1052 __ sllv(ival, ival, zeros);
1053 // And the top (top 20 bits).
1054 __ srl(scratch1, ival, kBitsPerInt - kBinary32MantissaBits);
1055 __ or_(fval, fval, scratch1);
1056
1057 __ bind(&done);
1058
1059 __ sll(scratch1, wordoffset, 2);
1060 __ addu(scratch1, dst, scratch1);
1061 __ sw(fval, MemOperand(scratch1, 0));
1062 }
1063}
1064
1065
ager@chromium.org5c838252010-02-19 08:53:10 +00001066#undef __
1067#define __ ACCESS_MASM(masm())
1068
1069
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001070Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
1071 Register object_reg,
1072 Handle<JSObject> holder,
1073 Register holder_reg,
1074 Register scratch1,
1075 Register scratch2,
1076 Handle<String> name,
1077 int save_at_depth,
1078 Label* miss) {
1079 // Make sure there's no overlap between holder and object registers.
1080 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1081 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1082 && !scratch2.is(scratch1));
1083
1084 // Keep track of the current object in register reg.
1085 Register reg = object_reg;
1086 int depth = 0;
1087
1088 if (save_at_depth == depth) {
1089 __ sw(reg, MemOperand(sp));
1090 }
1091
1092 // Check the maps in the prototype chain.
1093 // Traverse the prototype chain from the object and do map checks.
1094 Handle<JSObject> current = object;
1095 while (!current.is_identical_to(holder)) {
1096 ++depth;
1097
1098 // Only global objects and objects that do not require access
1099 // checks are allowed in stubs.
1100 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1101
1102 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
1103 if (!current->HasFastProperties() &&
1104 !current->IsJSGlobalObject() &&
1105 !current->IsJSGlobalProxy()) {
1106 if (!name->IsSymbol()) {
1107 name = factory()->LookupSymbol(name);
1108 }
1109 ASSERT(current->property_dictionary()->FindEntry(*name) ==
1110 StringDictionary::kNotFound);
1111
1112 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1113 scratch1, scratch2);
1114
1115 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1116 reg = holder_reg; // From now on the object will be in holder_reg.
1117 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1118 } else {
1119 Handle<Map> current_map(current->map());
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001120 __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK,
1121 ALLOW_ELEMENT_TRANSITION_MAPS);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001122 // Check access rights to the global object. This has to happen after
1123 // the map check so that we know that the object is actually a global
1124 // object.
1125 if (current->IsJSGlobalProxy()) {
1126 __ CheckAccessGlobalProxy(reg, scratch2, miss);
1127 }
1128 reg = holder_reg; // From now on the object will be in holder_reg.
1129
1130 if (heap()->InNewSpace(*prototype)) {
1131 // The prototype is in new space; we cannot store a reference to it
1132 // in the code. Load it from the map.
1133 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1134 } else {
1135 // The prototype is in old space; load it directly.
1136 __ li(reg, Operand(prototype));
1137 }
1138 }
1139
1140 if (save_at_depth == depth) {
1141 __ sw(reg, MemOperand(sp));
1142 }
1143
1144 // Go to the next object in the prototype chain.
1145 current = prototype;
1146 }
1147
1148 // Log the check depth.
1149 LOG(masm()->isolate(), IntEvent("check-maps-depth", depth + 1));
1150
1151 // Check the holder map.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001152 __ CheckMap(reg, scratch1, Handle<Map>(current->map()), miss,
1153 DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001154
1155 // Perform security check for access to the global object.
1156 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1157 if (holder->IsJSGlobalProxy()) {
1158 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1159 }
1160
1161 // If we've skipped any global objects, it's not enough to verify that
1162 // their maps haven't changed. We also need to check that the property
1163 // cell for the property is still empty.
1164 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1165
1166 // Return the register containing the holder.
1167 return reg;
1168}
1169
1170
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001171void StubCompiler::GenerateLoadField(Handle<JSObject> object,
1172 Handle<JSObject> holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001173 Register receiver,
1174 Register scratch1,
1175 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001176 Register scratch3,
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00001177 PropertyIndex index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001178 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001179 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001180 // Check that the receiver isn't a smi.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001181 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001182
1183 // Check that the maps haven't changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001184 Register reg = CheckPrototypes(
1185 object, receiver, holder, scratch1, scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001186 GenerateFastPropertyLoad(masm(), v0, reg, holder, index);
1187 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001188}
1189
1190
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001191void StubCompiler::GenerateLoadConstant(Handle<JSObject> object,
1192 Handle<JSObject> holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001193 Register receiver,
1194 Register scratch1,
1195 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001196 Register scratch3,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001197 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001198 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001199 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001200 // Check that the receiver isn't a smi.
1201 __ JumpIfSmi(receiver, miss, scratch1);
1202
1203 // Check that the maps haven't changed.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001204 CheckPrototypes(object, receiver, holder,
1205 scratch1, scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001206
1207 // Return the constant value.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001208 __ LoadHeapObject(v0, value);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001209 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001210}
1211
1212
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001213void StubCompiler::GenerateDictionaryLoadCallback(Register receiver,
1214 Register name_reg,
1215 Register scratch1,
1216 Register scratch2,
1217 Register scratch3,
1218 Handle<AccessorInfo> callback,
1219 Handle<String> name,
1220 Label* miss) {
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001221 ASSERT(!receiver.is(scratch1));
1222 ASSERT(!receiver.is(scratch2));
1223 ASSERT(!receiver.is(scratch3));
1224
1225 // Load the properties dictionary.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001226 Register dictionary = scratch1;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001227 __ lw(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
1228
1229 // Probe the dictionary.
1230 Label probe_done;
1231 StringDictionaryLookupStub::GeneratePositiveLookup(masm(),
1232 miss,
1233 &probe_done,
1234 dictionary,
1235 name_reg,
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001236 scratch2,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001237 scratch3);
1238 __ bind(&probe_done);
1239
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001240 // If probing finds an entry in the dictionary, scratch3 contains the
1241 // pointer into the dictionary. Check that the value is the callback.
1242 Register pointer = scratch3;
1243 const int kElementsStartOffset = StringDictionary::kHeaderSize +
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001244 StringDictionary::kElementsStartIndex * kPointerSize;
1245 const int kValueOffset = kElementsStartOffset + kPointerSize;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001246 __ lw(scratch2, FieldMemOperand(pointer, kValueOffset));
1247 __ Branch(miss, ne, scratch2, Operand(callback));
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001248}
1249
1250
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001251void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
1252 Handle<JSObject> holder,
1253 Register receiver,
1254 Register name_reg,
1255 Register scratch1,
1256 Register scratch2,
1257 Register scratch3,
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001258 Register scratch4,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001259 Handle<AccessorInfo> callback,
1260 Handle<String> name,
1261 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001262 // Check that the receiver isn't a smi.
1263 __ JumpIfSmi(receiver, miss, scratch1);
1264
1265 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001266 Register reg = CheckPrototypes(object, receiver, holder, scratch1,
1267 scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001268
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001269 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
1270 GenerateDictionaryLoadCallback(
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001271 reg, name_reg, scratch2, scratch3, scratch4, callback, name, miss);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001272 }
1273
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001274 // Build AccessorInfo::args_ list on the stack and push property name below
1275 // the exit frame to make GC aware of them and store pointers to them.
1276 __ push(receiver);
1277 __ mov(scratch2, sp); // scratch2 = AccessorInfo::args_
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001278 if (heap()->InNewSpace(callback->data())) {
1279 __ li(scratch3, callback);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001280 __ lw(scratch3, FieldMemOperand(scratch3, AccessorInfo::kDataOffset));
1281 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001282 __ li(scratch3, Handle<Object>(callback->data()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001283 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001284 __ Subu(sp, sp, 4 * kPointerSize);
1285 __ sw(reg, MemOperand(sp, 3 * kPointerSize));
1286 __ sw(scratch3, MemOperand(sp, 2 * kPointerSize));
1287 __ li(scratch3, Operand(ExternalReference::isolate_address()));
1288 __ sw(scratch3, MemOperand(sp, 1 * kPointerSize));
1289 __ sw(name_reg, MemOperand(sp, 0 * kPointerSize));
1290
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001291 __ mov(a2, scratch2); // Saved in case scratch2 == a1.
1292 __ mov(a1, sp); // a1 (first argument - see note below) = Handle<String>
1293
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001294 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
1295 // struct from the function (which is currently the case). This means we pass
1296 // the arguments in a1-a2 instead of a0-a1. TryCallApiFunctionAndReturn
1297 // will handle setting up a0.
1298
1299 const int kApiStackSpace = 1;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001300 FrameScope frame_scope(masm(), StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001301 __ EnterExitFrame(false, kApiStackSpace);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001302
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001303 // Create AccessorInfo instance on the stack above the exit frame with
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001304 // scratch2 (internal::Object** args_) as the data.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001305 __ sw(a2, MemOperand(sp, kPointerSize));
1306 // a2 (second argument - see note above) = AccessorInfo&
1307 __ Addu(a2, sp, kPointerSize);
1308
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001309 const int kStackUnwindSpace = 5;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001310 Address getter_address = v8::ToCData<Address>(callback->getter());
1311 ApiFunction fun(getter_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001312 ExternalReference ref =
1313 ExternalReference(&fun,
1314 ExternalReference::DIRECT_GETTER_CALL,
1315 masm()->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001316 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
ager@chromium.org5c838252010-02-19 08:53:10 +00001317}
1318
1319
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001320void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
1321 Handle<JSObject> interceptor_holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001322 LookupResult* lookup,
1323 Register receiver,
1324 Register name_reg,
1325 Register scratch1,
1326 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001327 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001328 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001329 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001330 ASSERT(interceptor_holder->HasNamedInterceptor());
1331 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1332
1333 // Check that the receiver isn't a smi.
1334 __ JumpIfSmi(receiver, miss);
1335
1336 // So far the most popular follow ups for interceptor loads are FIELD
1337 // and CALLBACKS, so inline only them, other cases may be added
1338 // later.
1339 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001340 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001341 if (lookup->IsField()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001342 compile_followup_inline = true;
1343 } else if (lookup->type() == CALLBACKS &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001344 lookup->GetCallbackObject()->IsAccessorInfo()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001345 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
1346 compile_followup_inline = callback->getter() != NULL &&
1347 callback->IsCompatibleReceiver(*object);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001348 }
1349 }
1350
1351 if (compile_followup_inline) {
1352 // Compile the interceptor call, followed by inline code to load the
1353 // property from further up the prototype chain if the call fails.
1354 // Check that the maps haven't changed.
1355 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1356 scratch1, scratch2, scratch3,
1357 name, miss);
1358 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
1359
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001360 // Preserve the receiver register explicitly whenever it is different from
1361 // the holder and it is needed should the interceptor return without any
1362 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1363 // the FIELD case might cause a miss during the prototype check.
1364 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
1365 bool must_preserve_receiver_reg = !receiver.is(holder_reg) &&
1366 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1367
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001368 // Save necessary data before invoking an interceptor.
1369 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001370 {
1371 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001372 if (must_preserve_receiver_reg) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001373 __ Push(receiver, holder_reg, name_reg);
1374 } else {
1375 __ Push(holder_reg, name_reg);
1376 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001377 // Invoke an interceptor. Note: map checks from receiver to
1378 // interceptor's holder has been compiled before (see a caller
1379 // of this method).
1380 CompileCallLoadPropertyWithInterceptor(masm(),
1381 receiver,
1382 holder_reg,
1383 name_reg,
1384 interceptor_holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001385 // Check if interceptor provided a value for property. If it's
1386 // the case, return immediately.
1387 Label interceptor_failed;
1388 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
1389 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1));
1390 frame_scope.GenerateLeaveFrame();
1391 __ Ret();
1392
1393 __ bind(&interceptor_failed);
1394 __ pop(name_reg);
1395 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001396 if (must_preserve_receiver_reg) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001397 __ pop(receiver);
1398 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001399 // Leave the internal frame.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001400 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001401 // Check that the maps from interceptor's holder to lookup's holder
1402 // haven't changed. And load lookup's holder into |holder| register.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001403 if (must_perfrom_prototype_check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001404 holder_reg = CheckPrototypes(interceptor_holder,
1405 holder_reg,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001406 Handle<JSObject>(lookup->holder()),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001407 scratch1,
1408 scratch2,
1409 scratch3,
1410 name,
1411 miss);
1412 }
1413
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001414 if (lookup->IsField()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001415 // We found FIELD property in prototype chain of interceptor's holder.
1416 // Retrieve a field from field's holder.
1417 GenerateFastPropertyLoad(masm(), v0, holder_reg,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001418 Handle<JSObject>(lookup->holder()),
1419 lookup->GetFieldIndex());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001420 __ Ret();
1421 } else {
1422 // We found CALLBACKS property in prototype chain of interceptor's
1423 // holder.
1424 ASSERT(lookup->type() == CALLBACKS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001425 Handle<AccessorInfo> callback(
1426 AccessorInfo::cast(lookup->GetCallbackObject()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001427 ASSERT(callback->getter() != NULL);
1428
1429 // Tail call to runtime.
1430 // Important invariant in CALLBACKS case: the code above must be
1431 // structured to never clobber |receiver| register.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001432 __ li(scratch2, callback);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001433
1434 __ Push(receiver, holder_reg);
1435 __ lw(scratch3,
1436 FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
1437 __ li(scratch1, Operand(ExternalReference::isolate_address()));
1438 __ Push(scratch3, scratch1, scratch2, name_reg);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001439
1440 ExternalReference ref =
1441 ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
1442 masm()->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001443 __ TailCallExternalReference(ref, 6, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001444 }
1445 } else { // !compile_followup_inline
1446 // Call the runtime system to load the interceptor.
1447 // Check that the maps haven't changed.
1448 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1449 scratch1, scratch2, scratch3,
1450 name, miss);
1451 PushInterceptorArguments(masm(), receiver, holder_reg,
1452 name_reg, interceptor_holder);
1453
1454 ExternalReference ref = ExternalReference(
1455 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), masm()->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001456 __ TailCallExternalReference(ref, 6, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001457 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001458}
1459
1460
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001461void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001462 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001463 __ Branch(miss, ne, a2, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001464 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001465}
1466
1467
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001468void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1469 Handle<JSObject> holder,
1470 Handle<String> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001471 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001472 ASSERT(holder->IsGlobalObject());
1473
1474 // Get the number of arguments.
1475 const int argc = arguments().immediate();
1476
1477 // Get the receiver from the stack.
1478 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1479
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001480 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001481 __ JumpIfSmi(a0, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001482 CheckPrototypes(object, a0, holder, a3, a1, t0, name, miss);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001483}
1484
1485
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001486void CallStubCompiler::GenerateLoadFunctionFromCell(
1487 Handle<JSGlobalPropertyCell> cell,
1488 Handle<JSFunction> function,
1489 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001490 // Get the value from the cell.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001491 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001492 __ lw(a1, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
1493
1494 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001495 if (heap()->InNewSpace(*function)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001496 // We can't embed a pointer to a function in new space so we have
1497 // to verify that the shared function info is unchanged. This has
1498 // the nice side effect that multiple closures based on the same
1499 // function can all use this call IC. Before we load through the
1500 // function, we have to verify that it still is a function.
1501 __ JumpIfSmi(a1, miss);
1502 __ GetObjectType(a1, a3, a3);
1503 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
1504
1505 // Check the shared function info. Make sure it hasn't changed.
1506 __ li(a3, Handle<SharedFunctionInfo>(function->shared()));
1507 __ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
1508 __ Branch(miss, ne, t0, Operand(a3));
1509 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001510 __ Branch(miss, ne, a1, Operand(function));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001511 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001512}
1513
1514
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001515void CallStubCompiler::GenerateMissBranch() {
1516 Handle<Code> code =
danno@chromium.org40cb8782011-05-25 07:58:50 +00001517 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1518 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001519 extra_state_);
1520 __ Jump(code, RelocInfo::CODE_TARGET);
1521}
1522
1523
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001524Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1525 Handle<JSObject> holder,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001526 PropertyIndex index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001527 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001528 // ----------- S t a t e -------------
1529 // -- a2 : name
1530 // -- ra : return address
1531 // -----------------------------------
1532 Label miss;
1533
1534 GenerateNameCheck(name, &miss);
1535
1536 const int argc = arguments().immediate();
1537
1538 // Get the receiver of the function from the stack into a0.
1539 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1540 // Check that the receiver isn't a smi.
1541 __ JumpIfSmi(a0, &miss, t0);
1542
1543 // Do the right check and compute the holder register.
1544 Register reg = CheckPrototypes(object, a0, holder, a1, a3, t0, name, &miss);
1545 GenerateFastPropertyLoad(masm(), a1, reg, holder, index);
1546
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001547 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001548
1549 // Handle call cache miss.
1550 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001551 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001552
1553 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001554 return GetCode(Code::FIELD, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001555}
1556
1557
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001558Handle<Code> CallStubCompiler::CompileArrayPushCall(
1559 Handle<Object> object,
1560 Handle<JSObject> holder,
1561 Handle<JSGlobalPropertyCell> cell,
1562 Handle<JSFunction> function,
1563 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001564 // ----------- S t a t e -------------
1565 // -- a2 : name
1566 // -- ra : return address
1567 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1568 // -- ...
1569 // -- sp[argc * 4] : receiver
1570 // -----------------------------------
1571
1572 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001573 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001574
1575 Label miss;
1576
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001577 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001578
1579 Register receiver = a1;
1580
1581 // Get the receiver from the stack.
1582 const int argc = arguments().immediate();
1583 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1584
1585 // Check that the receiver isn't a smi.
1586 __ JumpIfSmi(receiver, &miss);
1587
1588 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001589 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, a3, v0, t0,
1590 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001591
1592 if (argc == 0) {
1593 // Nothing to do, just return the length.
1594 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1595 __ Drop(argc + 1);
1596 __ Ret();
1597 } else {
1598 Label call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001599 if (argc == 1) { // Otherwise fall through to call the builtin.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001600 Label attempt_to_grow_elements, with_write_barrier, check_double;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001601
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001602 Register elements = t2;
1603 Register end_elements = t1;
1604 // Get the elements array of the object.
1605 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1606
1607 // Check that the elements are in fast mode and writable.
1608 __ CheckMap(elements,
1609 v0,
1610 Heap::kFixedArrayMapRootIndex,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001611 &check_double,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001612 DONT_DO_SMI_CHECK);
1613
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001614 // Get the array's length into v0 and calculate new length.
1615 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1616 STATIC_ASSERT(kSmiTagSize == 1);
1617 STATIC_ASSERT(kSmiTag == 0);
1618 __ Addu(v0, v0, Operand(Smi::FromInt(argc)));
1619
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001620 // Get the elements' length.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001621 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1622
1623 // Check if we could survive without allocation.
1624 __ Branch(&attempt_to_grow_elements, gt, v0, Operand(t0));
1625
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001626 // Check if value is a smi.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001627 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1628 __ JumpIfNotSmi(t0, &with_write_barrier);
1629
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001630 // Save new length.
1631 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1632
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001633 // Store the value.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001634 // We may need a register containing the address end_elements below,
1635 // so write back the value in end_elements.
1636 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1637 __ Addu(end_elements, elements, end_elements);
1638 const int kEndElementsOffset =
1639 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001640 __ Addu(end_elements, end_elements, kEndElementsOffset);
1641 __ sw(t0, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001642
1643 // Check for a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001644 __ Drop(argc + 1);
1645 __ Ret();
1646
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001647 __ bind(&check_double);
1648
1649 // Check that the elements are in fast mode and writable.
1650 __ CheckMap(elements,
1651 a0,
1652 Heap::kFixedDoubleArrayMapRootIndex,
1653 &call_builtin,
1654 DONT_DO_SMI_CHECK);
1655
1656 // Get the array's length into r0 and calculate new length.
1657 __ lw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1658 STATIC_ASSERT(kSmiTagSize == 1);
1659 STATIC_ASSERT(kSmiTag == 0);
1660 __ Addu(a0, a0, Operand(Smi::FromInt(argc)));
1661
1662 // Get the elements' length.
1663 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1664
1665 // Check if we could survive without allocation.
1666 __ Branch(&call_builtin, gt, a0, Operand(t0));
1667
1668 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1669 __ StoreNumberToDoubleElements(
1670 t0, a0, elements, a3, t1, a2, t5,
1671 &call_builtin, argc * kDoubleSize);
1672
1673 // Save new length.
1674 __ sw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1675
1676 // Check for a smi.
1677 __ Drop(argc + 1);
1678 __ Ret();
1679
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001680 __ bind(&with_write_barrier);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001681
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001682 __ lw(a3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1683
1684 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
1685 Label fast_object, not_fast_object;
1686 __ CheckFastObjectElements(a3, t3, &not_fast_object);
1687 __ jmp(&fast_object);
1688 // In case of fast smi-only, convert to fast object, otherwise bail out.
1689 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001690 __ CheckFastSmiElements(a3, t3, &call_builtin);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001691
1692 __ lw(t3, FieldMemOperand(t0, HeapObject::kMapOffset));
1693 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
1694 __ Branch(&call_builtin, eq, t3, Operand(at));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001695 // edx: receiver
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001696 // a3: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001697 Label try_holey_map;
1698 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001699 FAST_ELEMENTS,
1700 a3,
1701 t3,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001702 &try_holey_map);
1703 __ mov(a2, receiver);
1704 ElementsTransitionGenerator::
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001705 GenerateMapChangeElementsTransition(masm(),
1706 DONT_TRACK_ALLOCATION_SITE,
1707 NULL);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001708 __ jmp(&fast_object);
1709
1710 __ bind(&try_holey_map);
1711 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1712 FAST_HOLEY_ELEMENTS,
1713 a3,
1714 t3,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001715 &call_builtin);
1716 __ mov(a2, receiver);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001717 ElementsTransitionGenerator::
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001718 GenerateMapChangeElementsTransition(masm(),
1719 DONT_TRACK_ALLOCATION_SITE,
1720 NULL);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001721 __ bind(&fast_object);
1722 } else {
1723 __ CheckFastObjectElements(a3, a3, &call_builtin);
1724 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001725
1726 // Save new length.
1727 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1728
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001729 // Store the value.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001730 // We may need a register containing the address end_elements below,
1731 // so write back the value in end_elements.
1732 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1733 __ Addu(end_elements, elements, end_elements);
1734 __ Addu(end_elements, end_elements, kEndElementsOffset);
1735 __ sw(t0, MemOperand(end_elements));
1736
1737 __ RecordWrite(elements,
1738 end_elements,
1739 t0,
1740 kRAHasNotBeenSaved,
1741 kDontSaveFPRegs,
1742 EMIT_REMEMBERED_SET,
1743 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001744 __ Drop(argc + 1);
1745 __ Ret();
1746
1747 __ bind(&attempt_to_grow_elements);
1748 // v0: array's length + 1.
1749 // t0: elements' length.
1750
1751 if (!FLAG_inline_new) {
1752 __ Branch(&call_builtin);
1753 }
1754
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001755 __ lw(a2, MemOperand(sp, (argc - 1) * kPointerSize));
1756 // Growing elements that are SMI-only requires special handling in case
1757 // the new element is non-Smi. For now, delegate to the builtin.
1758 Label no_fast_elements_check;
1759 __ JumpIfSmi(a2, &no_fast_elements_check);
1760 __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1761 __ CheckFastObjectElements(t3, t3, &call_builtin);
1762 __ bind(&no_fast_elements_check);
1763
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001764 ExternalReference new_space_allocation_top =
1765 ExternalReference::new_space_allocation_top_address(
1766 masm()->isolate());
1767 ExternalReference new_space_allocation_limit =
1768 ExternalReference::new_space_allocation_limit_address(
1769 masm()->isolate());
1770
1771 const int kAllocationDelta = 4;
1772 // Load top and check if it is the end of elements.
1773 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1774 __ Addu(end_elements, elements, end_elements);
1775 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset));
1776 __ li(t3, Operand(new_space_allocation_top));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001777 __ lw(a3, MemOperand(t3));
1778 __ Branch(&call_builtin, ne, end_elements, Operand(a3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001779
1780 __ li(t5, Operand(new_space_allocation_limit));
1781 __ lw(t5, MemOperand(t5));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001782 __ Addu(a3, a3, Operand(kAllocationDelta * kPointerSize));
1783 __ Branch(&call_builtin, hi, a3, Operand(t5));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001784
1785 // We fit and could grow elements.
1786 // Update new_space_allocation_top.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001787 __ sw(a3, MemOperand(t3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001788 // Push the argument.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001789 __ sw(a2, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001790 // Fill the rest with holes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001791 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001792 for (int i = 1; i < kAllocationDelta; i++) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001793 __ sw(a3, MemOperand(end_elements, i * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001794 }
1795
1796 // Update elements' and array's sizes.
1797 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1798 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta)));
1799 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1800
1801 // Elements are in new space, so write barrier is not required.
1802 __ Drop(argc + 1);
1803 __ Ret();
1804 }
1805 __ bind(&call_builtin);
1806 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
1807 masm()->isolate()),
1808 argc + 1,
1809 1);
1810 }
1811
1812 // Handle call cache miss.
1813 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001814 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001815
1816 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001817 return GetCode(function);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001818}
1819
1820
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001821Handle<Code> CallStubCompiler::CompileArrayPopCall(
1822 Handle<Object> object,
1823 Handle<JSObject> holder,
1824 Handle<JSGlobalPropertyCell> cell,
1825 Handle<JSFunction> function,
1826 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001827 // ----------- S t a t e -------------
1828 // -- a2 : name
1829 // -- ra : return address
1830 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1831 // -- ...
1832 // -- sp[argc * 4] : receiver
1833 // -----------------------------------
1834
1835 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001836 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001837
1838 Label miss, return_undefined, call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001839 Register receiver = a1;
1840 Register elements = a3;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001841 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001842
1843 // Get the receiver from the stack.
1844 const int argc = arguments().immediate();
1845 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001846 // Check that the receiver isn't a smi.
1847 __ JumpIfSmi(receiver, &miss);
1848
1849 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001850 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, elements,
1851 t0, v0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001852
1853 // Get the elements array of the object.
1854 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1855
1856 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001857 __ CheckMap(elements,
1858 v0,
1859 Heap::kFixedArrayMapRootIndex,
1860 &call_builtin,
1861 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001862
1863 // Get the array's length into t0 and calculate new length.
1864 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1865 __ Subu(t0, t0, Operand(Smi::FromInt(1)));
1866 __ Branch(&return_undefined, lt, t0, Operand(zero_reg));
1867
1868 // Get the last element.
1869 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1870 STATIC_ASSERT(kSmiTagSize == 1);
1871 STATIC_ASSERT(kSmiTag == 0);
1872 // We can't address the last element in one operation. Compute the more
1873 // expensive shift first, and use an offset later on.
1874 __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize);
1875 __ Addu(elements, elements, t1);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001876 __ lw(v0, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001877 __ Branch(&call_builtin, eq, v0, Operand(t2));
1878
1879 // Set the array's length.
1880 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1881
1882 // Fill with the hole.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001883 __ sw(t2, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001884 __ Drop(argc + 1);
1885 __ Ret();
1886
1887 __ bind(&return_undefined);
1888 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
1889 __ Drop(argc + 1);
1890 __ Ret();
1891
1892 __ bind(&call_builtin);
1893 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop,
1894 masm()->isolate()),
1895 argc + 1,
1896 1);
1897
1898 // Handle call cache miss.
1899 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001900 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001901
1902 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001903 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001904}
1905
1906
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001907Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1908 Handle<Object> object,
1909 Handle<JSObject> holder,
1910 Handle<JSGlobalPropertyCell> cell,
1911 Handle<JSFunction> function,
1912 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001913 // ----------- S t a t e -------------
1914 // -- a2 : function name
1915 // -- ra : return address
1916 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1917 // -- ...
1918 // -- sp[argc * 4] : receiver
1919 // -----------------------------------
1920
1921 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001922 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001923
1924 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001925 Label miss;
1926 Label name_miss;
1927 Label index_out_of_range;
1928
1929 Label* index_out_of_range_label = &index_out_of_range;
1930
danno@chromium.org40cb8782011-05-25 07:58:50 +00001931 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001932 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001933 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001934 index_out_of_range_label = &miss;
1935 }
1936
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001937 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001938
1939 // Check that the maps starting from the prototype haven't changed.
1940 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1941 Context::STRING_FUNCTION_INDEX,
1942 v0,
1943 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001944 ASSERT(!object.is_identical_to(holder));
1945 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1946 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001947
1948 Register receiver = a1;
1949 Register index = t1;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001950 Register result = v0;
1951 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1952 if (argc > 0) {
1953 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1954 } else {
1955 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1956 }
1957
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001958 StringCharCodeAtGenerator generator(receiver,
1959 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001960 result,
1961 &miss, // When not a string.
1962 &miss, // When not a number.
1963 index_out_of_range_label,
1964 STRING_INDEX_IS_NUMBER);
1965 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001966 __ Drop(argc + 1);
1967 __ Ret();
1968
1969 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001970 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001971
1972 if (index_out_of_range.is_linked()) {
1973 __ bind(&index_out_of_range);
1974 __ LoadRoot(v0, Heap::kNanValueRootIndex);
1975 __ Drop(argc + 1);
1976 __ Ret();
1977 }
1978
1979 __ bind(&miss);
1980 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001981 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001982 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001983 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001984
1985 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001986 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001987}
1988
1989
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001990Handle<Code> CallStubCompiler::CompileStringCharAtCall(
1991 Handle<Object> object,
1992 Handle<JSObject> holder,
1993 Handle<JSGlobalPropertyCell> cell,
1994 Handle<JSFunction> function,
1995 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001996 // ----------- S t a t e -------------
1997 // -- a2 : function name
1998 // -- ra : return address
1999 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2000 // -- ...
2001 // -- sp[argc * 4] : receiver
2002 // -----------------------------------
2003
2004 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002005 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002006
2007 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002008 Label miss;
2009 Label name_miss;
2010 Label index_out_of_range;
2011 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00002012 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002013 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002014 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002015 index_out_of_range_label = &miss;
2016 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002017 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002018
2019 // Check that the maps starting from the prototype haven't changed.
2020 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2021 Context::STRING_FUNCTION_INDEX,
2022 v0,
2023 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002024 ASSERT(!object.is_identical_to(holder));
2025 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2026 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002027
2028 Register receiver = v0;
2029 Register index = t1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00002030 Register scratch = a3;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002031 Register result = v0;
2032 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
2033 if (argc > 0) {
2034 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
2035 } else {
2036 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
2037 }
2038
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002039 StringCharAtGenerator generator(receiver,
2040 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00002041 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002042 result,
2043 &miss, // When not a string.
2044 &miss, // When not a number.
2045 index_out_of_range_label,
2046 STRING_INDEX_IS_NUMBER);
2047 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002048 __ Drop(argc + 1);
2049 __ Ret();
2050
2051 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002052 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002053
2054 if (index_out_of_range.is_linked()) {
2055 __ bind(&index_out_of_range);
2056 __ LoadRoot(v0, Heap::kEmptyStringRootIndex);
2057 __ Drop(argc + 1);
2058 __ Ret();
2059 }
2060
2061 __ bind(&miss);
2062 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002063 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002064 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002065 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002066
2067 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002068 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002069}
2070
2071
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002072Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
2073 Handle<Object> object,
2074 Handle<JSObject> holder,
2075 Handle<JSGlobalPropertyCell> cell,
2076 Handle<JSFunction> function,
2077 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002078 // ----------- S t a t e -------------
2079 // -- a2 : function name
2080 // -- ra : return address
2081 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2082 // -- ...
2083 // -- sp[argc * 4] : receiver
2084 // -----------------------------------
2085
2086 const int argc = arguments().immediate();
2087
2088 // If the object is not a JSObject or we got an unexpected number of
2089 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002090 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002091
2092 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002093 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002094
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002095 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002096 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
2097
2098 STATIC_ASSERT(kSmiTag == 0);
2099 __ JumpIfSmi(a1, &miss);
2100
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002101 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2102 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002103 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002104 ASSERT(cell->value() == *function);
2105 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2106 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002107 GenerateLoadFunctionFromCell(cell, function, &miss);
2108 }
2109
2110 // Load the char code argument.
2111 Register code = a1;
2112 __ lw(code, MemOperand(sp, 0 * kPointerSize));
2113
2114 // Check the code is a smi.
2115 Label slow;
2116 STATIC_ASSERT(kSmiTag == 0);
2117 __ JumpIfNotSmi(code, &slow);
2118
2119 // Convert the smi code to uint16.
2120 __ And(code, code, Operand(Smi::FromInt(0xffff)));
2121
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002122 StringCharFromCodeGenerator generator(code, v0);
2123 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002124 __ Drop(argc + 1);
2125 __ Ret();
2126
2127 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002128 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002129
2130 // Tail call the full function. We do not have to patch the receiver
2131 // because the function makes no use of it.
2132 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002133 __ InvokeFunction(
2134 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002135
2136 __ bind(&miss);
2137 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002138 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002139
2140 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002141 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002142}
2143
2144
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002145Handle<Code> CallStubCompiler::CompileMathFloorCall(
2146 Handle<Object> object,
2147 Handle<JSObject> holder,
2148 Handle<JSGlobalPropertyCell> cell,
2149 Handle<JSFunction> function,
2150 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002151 // ----------- S t a t e -------------
2152 // -- a2 : function name
2153 // -- ra : return address
2154 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2155 // -- ...
2156 // -- sp[argc * 4] : receiver
2157 // -----------------------------------
2158
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002159 if (!CpuFeatures::IsSupported(FPU)) {
2160 return Handle<Code>::null();
2161 }
2162
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002163 CpuFeatures::Scope scope_fpu(FPU);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002164 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002165 // If the object is not a JSObject or we got an unexpected number of
2166 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002167 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002168
2169 Label miss, slow;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002170 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002171
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002172 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002173 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002174 STATIC_ASSERT(kSmiTag == 0);
2175 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002176 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2177 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002178 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002179 ASSERT(cell->value() == *function);
2180 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2181 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002182 GenerateLoadFunctionFromCell(cell, function, &miss);
2183 }
2184
2185 // Load the (only) argument into v0.
2186 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2187
2188 // If the argument is a smi, just return.
2189 STATIC_ASSERT(kSmiTag == 0);
2190 __ And(t0, v0, Operand(kSmiTagMask));
2191 __ Drop(argc + 1, eq, t0, Operand(zero_reg));
2192 __ Ret(eq, t0, Operand(zero_reg));
2193
danno@chromium.org40cb8782011-05-25 07:58:50 +00002194 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002195
2196 Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return;
2197
2198 // If fpu is enabled, we use the floor instruction.
2199
2200 // Load the HeapNumber value.
2201 __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2202
2203 // Backup FCSR.
2204 __ cfc1(a3, FCSR);
2205 // Clearing FCSR clears the exception mask with no side-effects.
2206 __ ctc1(zero_reg, FCSR);
2207 // Convert the argument to an integer.
2208 __ floor_w_d(f0, f0);
2209
2210 // Start checking for special cases.
2211 // Get the argument exponent and clear the sign bit.
2212 __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize));
2213 __ And(t2, t1, Operand(~HeapNumber::kSignMask));
2214 __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord);
2215
2216 // Retrieve FCSR and check for fpu errors.
2217 __ cfc1(t5, FCSR);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002218 __ And(t5, t5, Operand(kFCSRExceptionFlagMask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002219 __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));
2220
2221 // Check for NaN, Infinity, and -Infinity.
2222 // They are invariant through a Math.Floor call, so just
2223 // return the original argument.
2224 __ Subu(t3, t2, Operand(HeapNumber::kExponentMask
2225 >> HeapNumber::kMantissaBitsInTopWord));
2226 __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg));
2227 // We had an overflow or underflow in the conversion. Check if we
2228 // have a big exponent.
2229 // If greater or equal, the argument is already round and in v0.
2230 __ Branch(&restore_fcsr_and_return, ge, t3,
2231 Operand(HeapNumber::kMantissaBits));
2232 __ Branch(&wont_fit_smi);
2233
2234 __ bind(&no_fpu_error);
2235 // Move the result back to v0.
2236 __ mfc1(v0, f0);
2237 // Check if the result fits into a smi.
2238 __ Addu(a1, v0, Operand(0x40000000));
2239 __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg));
2240 // Tag the result.
2241 STATIC_ASSERT(kSmiTag == 0);
2242 __ sll(v0, v0, kSmiTagSize);
2243
2244 // Check for -0.
2245 __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg));
2246 // t1 already holds the HeapNumber exponent.
2247 __ And(t0, t1, Operand(HeapNumber::kSignMask));
2248 // If our HeapNumber is negative it was -0, so load its address and return.
2249 // Else v0 is loaded with 0, so we can also just return.
2250 __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg));
2251 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2252
2253 __ bind(&restore_fcsr_and_return);
2254 // Restore FCSR and return.
2255 __ ctc1(a3, FCSR);
2256
2257 __ Drop(argc + 1);
2258 __ Ret();
2259
2260 __ bind(&wont_fit_smi);
2261 // Restore FCSR and fall to slow case.
2262 __ ctc1(a3, FCSR);
2263
2264 __ bind(&slow);
2265 // Tail call the full function. We do not have to patch the receiver
2266 // because the function makes no use of it.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002267 __ InvokeFunction(
2268 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002269
2270 __ bind(&miss);
2271 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002272 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002273
2274 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002275 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002276}
2277
2278
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002279Handle<Code> CallStubCompiler::CompileMathAbsCall(
2280 Handle<Object> object,
2281 Handle<JSObject> holder,
2282 Handle<JSGlobalPropertyCell> cell,
2283 Handle<JSFunction> function,
2284 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002285 // ----------- S t a t e -------------
2286 // -- a2 : function name
2287 // -- ra : return address
2288 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2289 // -- ...
2290 // -- sp[argc * 4] : receiver
2291 // -----------------------------------
2292
2293 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002294 // If the object is not a JSObject or we got an unexpected number of
2295 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002296 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002297
2298 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002299
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002300 GenerateNameCheck(name, &miss);
2301 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002302 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002303 STATIC_ASSERT(kSmiTag == 0);
2304 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002305 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2306 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002307 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002308 ASSERT(cell->value() == *function);
2309 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2310 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002311 GenerateLoadFunctionFromCell(cell, function, &miss);
2312 }
2313
2314 // Load the (only) argument into v0.
2315 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2316
2317 // Check if the argument is a smi.
2318 Label not_smi;
2319 STATIC_ASSERT(kSmiTag == 0);
2320 __ JumpIfNotSmi(v0, &not_smi);
2321
2322 // Do bitwise not or do nothing depending on the sign of the
2323 // argument.
2324 __ sra(t0, v0, kBitsPerInt - 1);
2325 __ Xor(a1, v0, t0);
2326
2327 // Add 1 or do nothing depending on the sign of the argument.
2328 __ Subu(v0, a1, t0);
2329
2330 // If the result is still negative, go to the slow case.
2331 // This only happens for the most negative smi.
2332 Label slow;
2333 __ Branch(&slow, lt, v0, Operand(zero_reg));
2334
2335 // Smi case done.
2336 __ Drop(argc + 1);
2337 __ Ret();
2338
2339 // Check if the argument is a heap number and load its exponent and
2340 // sign.
2341 __ bind(&not_smi);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002342 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002343 __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2344
2345 // Check the sign of the argument. If the argument is positive,
2346 // just return it.
2347 Label negative_sign;
2348 __ And(t0, a1, Operand(HeapNumber::kSignMask));
2349 __ Branch(&negative_sign, ne, t0, Operand(zero_reg));
2350 __ Drop(argc + 1);
2351 __ Ret();
2352
2353 // If the argument is negative, clear the sign, and return a new
2354 // number.
2355 __ bind(&negative_sign);
2356 __ Xor(a1, a1, Operand(HeapNumber::kSignMask));
2357 __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2358 __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
2359 __ AllocateHeapNumber(v0, t0, t1, t2, &slow);
2360 __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2361 __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2362 __ Drop(argc + 1);
2363 __ Ret();
2364
2365 // Tail call the full function. We do not have to patch the receiver
2366 // because the function makes no use of it.
2367 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002368 __ InvokeFunction(
2369 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002370
2371 __ bind(&miss);
2372 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002373 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002374
2375 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002376 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002377}
2378
2379
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002380Handle<Code> CallStubCompiler::CompileFastApiCall(
lrn@chromium.org7516f052011-03-30 08:52:27 +00002381 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002382 Handle<Object> object,
2383 Handle<JSObject> holder,
2384 Handle<JSGlobalPropertyCell> cell,
2385 Handle<JSFunction> function,
2386 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002387
danno@chromium.org40cb8782011-05-25 07:58:50 +00002388 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002389
2390 ASSERT(optimization.is_simple_api_call());
2391 // Bail out if object is a global object as we don't want to
2392 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002393 if (object->IsGlobalObject()) return Handle<Code>::null();
2394 if (!cell.is_null()) return Handle<Code>::null();
2395 if (!object->IsJSObject()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002396 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002397 Handle<JSObject>::cast(object), holder);
2398 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002399
2400 Label miss, miss_before_stack_reserved;
2401
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002402 GenerateNameCheck(name, &miss_before_stack_reserved);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002403
2404 // Get the receiver from the stack.
2405 const int argc = arguments().immediate();
2406 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2407
2408 // Check that the receiver isn't a smi.
2409 __ JumpIfSmi(a1, &miss_before_stack_reserved);
2410
2411 __ IncrementCounter(counters->call_const(), 1, a0, a3);
2412 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2413
2414 ReserveSpaceForFastApiCall(masm(), a0);
2415
2416 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002417 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002418 depth, &miss);
2419
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002420 GenerateFastApiDirectCall(masm(), optimization, argc);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002421
2422 __ bind(&miss);
2423 FreeSpaceForFastApiCall(masm());
2424
2425 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002426 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002427
2428 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002429 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002430}
2431
2432
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002433Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object,
2434 Handle<JSObject> holder,
2435 Handle<JSFunction> function,
2436 Handle<String> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00002437 CheckType check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002438 // ----------- S t a t e -------------
2439 // -- a2 : name
2440 // -- ra : return address
2441 // -----------------------------------
2442 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002443 Handle<Code> code = CompileCustomCall(object, holder,
2444 Handle<JSGlobalPropertyCell>::null(),
2445 function, name);
2446 // A null handle means bail out to the regular compiler code below.
2447 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002448 }
2449
2450 Label miss;
2451
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002452 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002453
2454 // Get the receiver from the stack.
2455 const int argc = arguments().immediate();
2456 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2457
2458 // Check that the receiver isn't a smi.
2459 if (check != NUMBER_CHECK) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002460 __ JumpIfSmi(a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002461 }
2462
2463 // Make sure that it's okay not to patch the on stack receiver
2464 // unless we're doing a receiver map check.
2465 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002466 switch (check) {
2467 case RECEIVER_MAP_CHECK:
2468 __ IncrementCounter(masm()->isolate()->counters()->call_const(),
2469 1, a0, a3);
2470
2471 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002472 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2473 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002474
2475 // Patch the receiver on the stack with the global proxy if
2476 // necessary.
2477 if (object->IsGlobalObject()) {
2478 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2479 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2480 }
2481 break;
2482
2483 case STRING_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002484 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002485 // Check that the object is a two-byte string or a symbol.
2486 __ GetObjectType(a1, a3, a3);
2487 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2488 // Check that the maps starting from the prototype haven't changed.
2489 GenerateDirectLoadGlobalFunctionPrototype(
2490 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002491 CheckPrototypes(
2492 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2493 a0, holder, a3, a1, t0, name, &miss);
2494 } else {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002495 // Calling non-strict non-builtins with a value as the receiver
2496 // requires boxing.
2497 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002498 }
2499 break;
2500
2501 case NUMBER_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002502 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002503 Label fast;
2504 // Check that the object is a smi or a heap number.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002505 __ JumpIfSmi(a1, &fast);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002506 __ GetObjectType(a1, a0, a0);
2507 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
2508 __ bind(&fast);
2509 // Check that the maps starting from the prototype haven't changed.
2510 GenerateDirectLoadGlobalFunctionPrototype(
2511 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002512 CheckPrototypes(
2513 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2514 a0, holder, a3, a1, t0, name, &miss);
2515 } else {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002516 // Calling non-strict non-builtins with a value as the receiver
2517 // requires boxing.
2518 __ jmp(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002519 }
2520 break;
2521
2522 case BOOLEAN_CHECK:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002523 if (function->IsBuiltin() || !function->shared()->is_classic_mode()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002524 Label fast;
2525 // Check that the object is a boolean.
2526 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
2527 __ Branch(&fast, eq, a1, Operand(t0));
2528 __ LoadRoot(t0, Heap::kFalseValueRootIndex);
2529 __ Branch(&miss, ne, a1, Operand(t0));
2530 __ bind(&fast);
2531 // Check that the maps starting from the prototype haven't changed.
2532 GenerateDirectLoadGlobalFunctionPrototype(
2533 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002534 CheckPrototypes(
2535 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2536 a0, holder, a3, a1, t0, name, &miss);
2537 } else {
2538 // Calling non-strict non-builtins with a value as the receiver
2539 // requires boxing.
2540 __ jmp(&miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002541 }
2542 break;
2543 }
2544
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002545 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002546 ? CALL_AS_FUNCTION
2547 : CALL_AS_METHOD;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002548 __ InvokeFunction(
2549 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002550
2551 // Handle call cache miss.
2552 __ bind(&miss);
2553
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002554 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002555
2556 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002557 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002558}
2559
2560
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002561Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2562 Handle<JSObject> holder,
2563 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002564 // ----------- S t a t e -------------
2565 // -- a2 : name
2566 // -- ra : return address
2567 // -----------------------------------
2568
2569 Label miss;
2570
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002571 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002572
2573 // Get the number of arguments.
2574 const int argc = arguments().immediate();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002575 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002576 LookupPostInterceptor(holder, name, &lookup);
2577
2578 // Get the receiver from the stack.
2579 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2580
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002581 CallInterceptorCompiler compiler(this, arguments(), a2, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002582 compiler.Compile(masm(), object, holder, name, &lookup, a1, a3, t0, a0,
2583 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002584
2585 // Move returned value, the function to call, to a1.
2586 __ mov(a1, v0);
2587 // Restore receiver.
2588 __ lw(a0, MemOperand(sp, argc * kPointerSize));
2589
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002590 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002591
2592 // Handle call cache miss.
2593 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002594 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002595
2596 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002597 return GetCode(Code::INTERCEPTOR, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002598}
2599
2600
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002601Handle<Code> CallStubCompiler::CompileCallGlobal(
2602 Handle<JSObject> object,
2603 Handle<GlobalObject> holder,
2604 Handle<JSGlobalPropertyCell> cell,
2605 Handle<JSFunction> function,
2606 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002607 // ----------- S t a t e -------------
2608 // -- a2 : name
2609 // -- ra : return address
2610 // -----------------------------------
2611
2612 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002613 Handle<Code> code = CompileCustomCall(object, holder, cell, function, name);
2614 // A null handle means bail out to the regular compiler code below.
2615 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002616 }
2617
2618 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002619 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002620
2621 // Get the number of arguments.
2622 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002623 GenerateGlobalReceiverCheck(object, holder, name, &miss);
2624 GenerateLoadFunctionFromCell(cell, function, &miss);
2625
2626 // Patch the receiver on the stack with the global proxy if
2627 // necessary.
2628 if (object->IsGlobalObject()) {
2629 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
2630 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2631 }
2632
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002633 // Set up the context (function already in r1).
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002634 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
2635
2636 // Jump to the cached code (tail call).
2637 Counters* counters = masm()->isolate()->counters();
2638 __ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002639 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002640 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002641 ? CALL_AS_FUNCTION
2642 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002643 // We call indirectly through the code field in the function to
2644 // allow recompilation to take effect without changing any of the
2645 // call sites.
2646 __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
2647 __ InvokeCode(a3, expected, arguments(), JUMP_FUNCTION,
2648 NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002649
2650 // Handle call cache miss.
2651 __ bind(&miss);
2652 __ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002653 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002654
2655 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002656 return GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002657}
2658
2659
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002660Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +00002661 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002662 Handle<Map> transition,
2663 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002664 // ----------- S t a t e -------------
2665 // -- a0 : value
2666 // -- a1 : receiver
2667 // -- a2 : name
2668 // -- ra : return address
2669 // -----------------------------------
2670 Label miss;
2671
2672 // Name register might be clobbered.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002673 GenerateStoreField(masm(),
2674 object,
2675 index,
2676 transition,
2677 name,
2678 a1, a2, a3, t0,
2679 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002680 __ bind(&miss);
2681 __ li(a2, Operand(Handle<String>(name))); // Restore name.
2682 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2683 __ Jump(ic, RelocInfo::CODE_TARGET);
2684
2685 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002686 return GetCode(transition.is_null()
2687 ? Code::FIELD
2688 : Code::MAP_TRANSITION, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002689}
2690
2691
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002692Handle<Code> StoreStubCompiler::CompileStoreCallback(
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002693 Handle<String> name,
2694 Handle<JSObject> receiver,
2695 Handle<JSObject> holder,
2696 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002697 // ----------- S t a t e -------------
2698 // -- a0 : value
2699 // -- a1 : receiver
2700 // -- a2 : name
2701 // -- ra : return address
2702 // -----------------------------------
2703 Label miss;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002704 // Check that the maps haven't changed.
2705 __ JumpIfSmi(a1, &miss, a3);
2706 CheckPrototypes(receiver, a1, holder, a3, t0, t1, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002707
2708 // Stub never generated for non-global objects that require access
2709 // checks.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002710 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002711
2712 __ push(a1); // Receiver.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002713 __ li(a3, Operand(callback)); // Callback info.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002714 __ Push(a3, a2, a0);
2715
2716 // Do tail-call to the runtime system.
2717 ExternalReference store_callback_property =
2718 ExternalReference(IC_Utility(IC::kStoreCallbackProperty),
2719 masm()->isolate());
2720 __ TailCallExternalReference(store_callback_property, 4, 1);
2721
2722 // Handle store cache miss.
2723 __ bind(&miss);
2724 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2725 __ Jump(ic, RelocInfo::CODE_TARGET);
2726
2727 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002728 return GetCode(Code::CALLBACKS, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002729}
2730
2731
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002732#undef __
2733#define __ ACCESS_MASM(masm)
2734
2735
2736void StoreStubCompiler::GenerateStoreViaSetter(
2737 MacroAssembler* masm,
2738 Handle<JSFunction> setter) {
2739 // ----------- S t a t e -------------
2740 // -- a0 : value
2741 // -- a1 : receiver
2742 // -- a2 : name
2743 // -- ra : return address
2744 // -----------------------------------
2745 {
2746 FrameScope scope(masm, StackFrame::INTERNAL);
2747
2748 // Save value register, so we can restore it later.
2749 __ push(a0);
2750
2751 if (!setter.is_null()) {
2752 // Call the JavaScript setter with receiver and value on the stack.
2753 __ push(a1);
2754 __ push(a0);
2755 ParameterCount actual(1);
2756 __ InvokeFunction(setter, actual, CALL_FUNCTION, NullCallWrapper(),
2757 CALL_AS_METHOD);
2758 } else {
2759 // If we generate a global code snippet for deoptimization only, remember
2760 // the place to continue after deoptimization.
2761 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2762 }
2763
2764 // We have to return the passed value, not the return value of the setter.
2765 __ pop(v0);
2766
2767 // Restore context register.
2768 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2769 }
2770 __ Ret();
2771}
2772
2773
2774#undef __
2775#define __ ACCESS_MASM(masm())
2776
2777
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002778Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002779 Handle<String> name,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002780 Handle<JSObject> receiver,
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002781 Handle<JSObject> holder,
2782 Handle<JSFunction> setter) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002783 // ----------- S t a t e -------------
2784 // -- a0 : value
2785 // -- a1 : receiver
2786 // -- a2 : name
2787 // -- ra : return address
2788 // -----------------------------------
2789 Label miss;
2790
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002791 // Check that the maps haven't changed.
2792 __ JumpIfSmi(a1, &miss);
2793 CheckPrototypes(receiver, a1, holder, a3, t0, t1, name, &miss);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002794
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002795 GenerateStoreViaSetter(masm(), setter);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002796
2797 __ bind(&miss);
2798 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2799 __ Jump(ic, RelocInfo::CODE_TARGET);
2800
2801 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002802 return GetCode(Code::CALLBACKS, name);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002803}
2804
2805
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002806Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
2807 Handle<JSObject> receiver,
2808 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002809 // ----------- S t a t e -------------
2810 // -- a0 : value
2811 // -- a1 : receiver
2812 // -- a2 : name
2813 // -- ra : return address
2814 // -----------------------------------
2815 Label miss;
2816
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002817 // Check that the map of the object hasn't changed.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002818 __ CheckMap(a1, a3, Handle<Map>(receiver->map()), &miss,
2819 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002820
2821 // Perform global security token check if needed.
2822 if (receiver->IsJSGlobalProxy()) {
2823 __ CheckAccessGlobalProxy(a1, a3, &miss);
2824 }
2825
2826 // Stub is never generated for non-global objects that require access
2827 // checks.
2828 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2829
2830 __ Push(a1, a2, a0); // Receiver, name, value.
2831
2832 __ li(a0, Operand(Smi::FromInt(strict_mode_)));
2833 __ push(a0); // Strict mode.
2834
2835 // Do tail-call to the runtime system.
2836 ExternalReference store_ic_property =
2837 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty),
2838 masm()->isolate());
2839 __ TailCallExternalReference(store_ic_property, 4, 1);
2840
2841 // Handle store cache miss.
2842 __ bind(&miss);
2843 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2844 __ Jump(ic, RelocInfo::CODE_TARGET);
2845
2846 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002847 return GetCode(Code::INTERCEPTOR, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002848}
2849
2850
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002851Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2852 Handle<GlobalObject> object,
2853 Handle<JSGlobalPropertyCell> cell,
2854 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002855 // ----------- S t a t e -------------
2856 // -- a0 : value
2857 // -- a1 : receiver
2858 // -- a2 : name
2859 // -- ra : return address
2860 // -----------------------------------
2861 Label miss;
2862
2863 // Check that the map of the global has not changed.
2864 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2865 __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map())));
2866
2867 // Check that the value in the cell is not the hole. If it is, this
2868 // cell could have been deleted and reintroducing the global needs
2869 // to update the property details in the property dictionary of the
2870 // global object. We bail out to the runtime system to do that.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002871 __ li(t0, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002872 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
2873 __ lw(t2, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2874 __ Branch(&miss, eq, t1, Operand(t2));
2875
2876 // Store the value in the cell.
2877 __ sw(a0, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2878 __ mov(v0, a0); // Stored value must be returned in v0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002879 // Cells are always rescanned, so no write barrier here.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002880
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002881 Counters* counters = masm()->isolate()->counters();
2882 __ IncrementCounter(counters->named_store_global_inline(), 1, a1, a3);
2883 __ Ret();
2884
2885 // Handle store cache miss.
2886 __ bind(&miss);
2887 __ IncrementCounter(counters->named_store_global_inline_miss(), 1, a1, a3);
2888 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2889 __ Jump(ic, RelocInfo::CODE_TARGET);
2890
2891 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002892 return GetCode(Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002893}
2894
2895
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002896Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
2897 Handle<JSObject> object,
2898 Handle<JSObject> last) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002899 // ----------- S t a t e -------------
2900 // -- a0 : receiver
2901 // -- ra : return address
2902 // -----------------------------------
2903 Label miss;
2904
2905 // Check that the receiver is not a smi.
2906 __ JumpIfSmi(a0, &miss);
2907
2908 // Check the maps of the full prototype chain.
2909 CheckPrototypes(object, a0, last, a3, a1, t0, name, &miss);
2910
2911 // If the last object in the prototype chain is a global object,
2912 // check that the global property cell is empty.
2913 if (last->IsGlobalObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002914 GenerateCheckPropertyCell(
2915 masm(), Handle<GlobalObject>::cast(last), name, a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002916 }
2917
2918 // Return undefined if maps of the full prototype chain is still the same.
2919 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2920 __ Ret();
2921
2922 __ bind(&miss);
2923 GenerateLoadMiss(masm(), Code::LOAD_IC);
2924
2925 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002926 return GetCode(Code::NONEXISTENT, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00002927}
2928
2929
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002930Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object,
2931 Handle<JSObject> holder,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002932 PropertyIndex index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002933 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002934 // ----------- S t a t e -------------
2935 // -- a0 : receiver
2936 // -- a2 : name
2937 // -- ra : return address
2938 // -----------------------------------
2939 Label miss;
2940
2941 __ mov(v0, a0);
2942
2943 GenerateLoadField(object, holder, v0, a3, a1, t0, index, name, &miss);
2944 __ bind(&miss);
2945 GenerateLoadMiss(masm(), Code::LOAD_IC);
2946
2947 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002948 return GetCode(Code::FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002949}
2950
2951
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002952Handle<Code> LoadStubCompiler::CompileLoadCallback(
2953 Handle<String> name,
2954 Handle<JSObject> object,
2955 Handle<JSObject> holder,
2956 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002957 // ----------- S t a t e -------------
2958 // -- a0 : receiver
2959 // -- a2 : name
2960 // -- ra : return address
2961 // -----------------------------------
2962 Label miss;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00002963 GenerateLoadCallback(object, holder, a0, a2, a3, a1, t0, t1, callback, name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002964 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002965 __ bind(&miss);
2966 GenerateLoadMiss(masm(), Code::LOAD_IC);
2967
2968 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002969 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002970}
2971
2972
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002973#undef __
2974#define __ ACCESS_MASM(masm)
2975
2976
2977void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
2978 Handle<JSFunction> getter) {
2979 // ----------- S t a t e -------------
2980 // -- a0 : receiver
2981 // -- a2 : name
2982 // -- ra : return address
2983 // -----------------------------------
2984 {
2985 FrameScope scope(masm, StackFrame::INTERNAL);
2986
2987 if (!getter.is_null()) {
2988 // Call the JavaScript getter with the receiver on the stack.
2989 __ push(a0);
2990 ParameterCount actual(0);
2991 __ InvokeFunction(getter, actual, CALL_FUNCTION, NullCallWrapper(),
2992 CALL_AS_METHOD);
2993 } else {
2994 // If we generate a global code snippet for deoptimization only, remember
2995 // the place to continue after deoptimization.
2996 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
2997 }
2998
2999 // Restore context register.
3000 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
3001 }
3002 __ Ret();
3003}
3004
3005
3006#undef __
3007#define __ ACCESS_MASM(masm())
3008
3009
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003010Handle<Code> LoadStubCompiler::CompileLoadViaGetter(
3011 Handle<String> name,
3012 Handle<JSObject> receiver,
3013 Handle<JSObject> holder,
3014 Handle<JSFunction> getter) {
3015 // ----------- S t a t e -------------
3016 // -- a0 : receiver
3017 // -- a2 : name
3018 // -- ra : return address
3019 // -----------------------------------
3020 Label miss;
3021
3022 // Check that the maps haven't changed.
3023 __ JumpIfSmi(a0, &miss);
3024 CheckPrototypes(receiver, a0, holder, a3, t0, a1, name, &miss);
3025
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003026 GenerateLoadViaGetter(masm(), getter);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003027
3028 __ bind(&miss);
3029 GenerateLoadMiss(masm(), Code::LOAD_IC);
3030
3031 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003032 return GetCode(Code::CALLBACKS, name);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003033}
3034
3035
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003036Handle<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object,
3037 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003038 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003039 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003040 // ----------- S t a t e -------------
3041 // -- a0 : receiver
3042 // -- a2 : name
3043 // -- ra : return address
3044 // -----------------------------------
3045 Label miss;
3046
3047 GenerateLoadConstant(object, holder, a0, a3, a1, t0, value, name, &miss);
3048 __ bind(&miss);
3049 GenerateLoadMiss(masm(), Code::LOAD_IC);
3050
3051 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003052 return GetCode(Code::CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003053}
3054
3055
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003056Handle<Code> LoadStubCompiler::CompileLoadInterceptor(Handle<JSObject> object,
3057 Handle<JSObject> holder,
3058 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003059 // ----------- S t a t e -------------
3060 // -- a0 : receiver
3061 // -- a2 : name
3062 // -- ra : return address
3063 // -- [sp] : receiver
3064 // -----------------------------------
3065 Label miss;
3066
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003067 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003068 LookupPostInterceptor(holder, name, &lookup);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003069 GenerateLoadInterceptor(object, holder, &lookup, a0, a2, a3, a1, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003070 &miss);
3071 __ bind(&miss);
3072 GenerateLoadMiss(masm(), Code::LOAD_IC);
3073
3074 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003075 return GetCode(Code::INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003076}
3077
3078
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003079Handle<Code> LoadStubCompiler::CompileLoadGlobal(
3080 Handle<JSObject> object,
3081 Handle<GlobalObject> holder,
3082 Handle<JSGlobalPropertyCell> cell,
3083 Handle<String> name,
3084 bool is_dont_delete) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003085 // ----------- S t a t e -------------
3086 // -- a0 : receiver
3087 // -- a2 : name
3088 // -- ra : return address
3089 // -----------------------------------
3090 Label miss;
3091
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003092 // Check that the map of the global has not changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003093 __ JumpIfSmi(a0, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003094 CheckPrototypes(object, a0, holder, a3, t0, a1, name, &miss);
3095
3096 // Get the value from the cell.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003097 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003098 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
3099
3100 // Check for deleted property if property can actually be deleted.
3101 if (!is_dont_delete) {
3102 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
3103 __ Branch(&miss, eq, t0, Operand(at));
3104 }
3105
3106 __ mov(v0, t0);
3107 Counters* counters = masm()->isolate()->counters();
3108 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
3109 __ Ret();
3110
3111 __ bind(&miss);
3112 __ IncrementCounter(counters->named_load_global_stub_miss(), 1, a1, a3);
3113 GenerateLoadMiss(masm(), Code::LOAD_IC);
3114
3115 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003116 return GetCode(Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003117}
3118
3119
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003120Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
3121 Handle<JSObject> receiver,
3122 Handle<JSObject> holder,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003123 PropertyIndex index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003124 // ----------- S t a t e -------------
3125 // -- ra : return address
3126 // -- a0 : key
3127 // -- a1 : receiver
3128 // -----------------------------------
3129 Label miss;
3130
3131 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003132 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003133
3134 GenerateLoadField(receiver, holder, a1, a2, a3, t0, index, name, &miss);
3135 __ bind(&miss);
3136 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3137
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003138 return GetCode(Code::FIELD, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003139}
3140
3141
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003142Handle<Code> KeyedLoadStubCompiler::CompileLoadCallback(
3143 Handle<String> name,
3144 Handle<JSObject> receiver,
3145 Handle<JSObject> holder,
3146 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003147 // ----------- S t a t e -------------
3148 // -- ra : return address
3149 // -- a0 : key
3150 // -- a1 : receiver
3151 // -----------------------------------
3152 Label miss;
3153
3154 // Check the key is the cached one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003155 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003156
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00003157 GenerateLoadCallback(receiver, holder, a1, a0, a2, a3, t0, t1, callback,
3158 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003159 __ bind(&miss);
3160 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3161
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003162 return GetCode(Code::CALLBACKS, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003163}
3164
3165
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003166Handle<Code> KeyedLoadStubCompiler::CompileLoadConstant(
3167 Handle<String> name,
3168 Handle<JSObject> receiver,
3169 Handle<JSObject> holder,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003170 Handle<JSFunction> value) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003171 // ----------- S t a t e -------------
3172 // -- ra : return address
3173 // -- a0 : key
3174 // -- a1 : receiver
3175 // -----------------------------------
3176 Label miss;
3177
3178 // Check the key is the cached one.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003179 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003180
3181 GenerateLoadConstant(receiver, holder, a1, a2, a3, t0, value, name, &miss);
3182 __ bind(&miss);
3183 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3184
3185 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003186 return GetCode(Code::CONSTANT_FUNCTION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003187}
3188
3189
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003190Handle<Code> KeyedLoadStubCompiler::CompileLoadInterceptor(
3191 Handle<JSObject> receiver,
3192 Handle<JSObject> holder,
3193 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003194 // ----------- S t a t e -------------
3195 // -- ra : return address
3196 // -- a0 : key
3197 // -- a1 : receiver
3198 // -----------------------------------
3199 Label miss;
3200
3201 // Check the key is the cached one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003202 __ Branch(&miss, ne, a0, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003203
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003204 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003205 LookupPostInterceptor(holder, name, &lookup);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003206 GenerateLoadInterceptor(receiver, holder, &lookup, a1, a0, a2, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003207 &miss);
3208 __ bind(&miss);
3209 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3210
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003211 return GetCode(Code::INTERCEPTOR, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003212}
3213
3214
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003215Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
3216 Handle<Map> receiver_map) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003217 // ----------- S t a t e -------------
3218 // -- ra : return address
3219 // -- a0 : key
3220 // -- a1 : receiver
3221 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003222 ElementsKind elements_kind = receiver_map->elements_kind();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003223 if (receiver_map->has_fast_elements() ||
3224 receiver_map->has_external_array_elements()) {
3225 Handle<Code> stub = KeyedLoadFastElementStub(
3226 receiver_map->instance_type() == JS_ARRAY_TYPE,
3227 elements_kind).GetCode();
3228 __ DispatchMap(a1, a2, receiver_map, stub, DO_SMI_CHECK);
3229 } else {
3230 Handle<Code> stub =
3231 KeyedLoadDictionaryElementStub().GetCode();
3232 __ DispatchMap(a1, a2, receiver_map, stub, DO_SMI_CHECK);
3233 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003234
3235 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
3236 __ Jump(ic, RelocInfo::CODE_TARGET);
3237
3238 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003239 return GetCode(Code::NORMAL, factory()->empty_string());
danno@chromium.org40cb8782011-05-25 07:58:50 +00003240}
3241
3242
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003243Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
3244 MapHandleList* receiver_maps,
3245 CodeHandleList* handler_ics) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003246 // ----------- S t a t e -------------
3247 // -- ra : return address
3248 // -- a0 : key
3249 // -- a1 : receiver
3250 // -----------------------------------
3251 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003252 __ JumpIfSmi(a1, &miss);
3253
danno@chromium.org40cb8782011-05-25 07:58:50 +00003254 int receiver_count = receiver_maps->length();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003255 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003256 for (int current = 0; current < receiver_count; ++current) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003257 __ Jump(handler_ics->at(current), RelocInfo::CODE_TARGET,
3258 eq, a2, Operand(receiver_maps->at(current)));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003259 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003260
3261 __ bind(&miss);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003262 Handle<Code> miss_ic = isolate()->builtins()->KeyedLoadIC_Miss();
3263 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003264
3265 // Return the generated code.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003266 return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003267}
3268
3269
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003270Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +00003271 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003272 Handle<Map> transition,
3273 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003274 // ----------- S t a t e -------------
3275 // -- a0 : value
3276 // -- a1 : key
3277 // -- a2 : receiver
3278 // -- ra : return address
3279 // -----------------------------------
3280
3281 Label miss;
3282
3283 Counters* counters = masm()->isolate()->counters();
3284 __ IncrementCounter(counters->keyed_store_field(), 1, a3, t0);
3285
3286 // Check that the name has not changed.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003287 __ Branch(&miss, ne, a1, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003288
3289 // a3 is used as scratch register. a1 and a2 keep their values if a jump to
3290 // the miss label is generated.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003291 GenerateStoreField(masm(),
3292 object,
3293 index,
3294 transition,
3295 name,
3296 a2, a1, a3, t0,
3297 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003298 __ bind(&miss);
3299
3300 __ DecrementCounter(counters->keyed_store_field(), 1, a3, t0);
3301 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss();
3302 __ Jump(ic, RelocInfo::CODE_TARGET);
3303
3304 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003305 return GetCode(transition.is_null()
3306 ? Code::FIELD
3307 : Code::MAP_TRANSITION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003308}
3309
3310
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003311Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
3312 Handle<Map> receiver_map) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003313 // ----------- S t a t e -------------
3314 // -- a0 : value
3315 // -- a1 : key
3316 // -- a2 : receiver
3317 // -- ra : return address
3318 // -- a3 : scratch
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003319 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003320 ElementsKind elements_kind = receiver_map->elements_kind();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003321 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003322 Handle<Code> stub =
yangguo@chromium.org56454712012-02-16 15:33:53 +00003323 KeyedStoreElementStub(is_js_array, elements_kind, grow_mode_).GetCode();
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003324
3325 __ DispatchMap(a2, a3, receiver_map, stub, DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003326
danno@chromium.org40cb8782011-05-25 07:58:50 +00003327 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003328 __ Jump(ic, RelocInfo::CODE_TARGET);
3329
3330 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003331 return GetCode(Code::NORMAL, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00003332}
3333
3334
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003335Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
3336 MapHandleList* receiver_maps,
3337 CodeHandleList* handler_stubs,
3338 MapHandleList* transitioned_maps) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003339 // ----------- S t a t e -------------
3340 // -- a0 : value
3341 // -- a1 : key
3342 // -- a2 : receiver
3343 // -- ra : return address
3344 // -- a3 : scratch
3345 // -----------------------------------
3346 Label miss;
3347 __ JumpIfSmi(a2, &miss);
3348
3349 int receiver_count = receiver_maps->length();
3350 __ lw(a3, FieldMemOperand(a2, HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003351 for (int i = 0; i < receiver_count; ++i) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003352 if (transitioned_maps->at(i).is_null()) {
3353 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq,
3354 a3, Operand(receiver_maps->at(i)));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003355 } else {
3356 Label next_map;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003357 __ Branch(&next_map, ne, a3, Operand(receiver_maps->at(i)));
3358 __ li(a3, Operand(transitioned_maps->at(i)));
3359 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003360 __ bind(&next_map);
3361 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003362 }
3363
3364 __ bind(&miss);
3365 Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
3366 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3367
3368 // Return the generated code.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003369 return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003370}
3371
3372
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003373Handle<Code> ConstructStubCompiler::CompileConstructStub(
3374 Handle<JSFunction> function) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003375 // a0 : argc
3376 // a1 : constructor
3377 // ra : return address
3378 // [sp] : last argument
3379 Label generic_stub_call;
3380
3381 // Use t7 for holding undefined which is used in several places below.
3382 __ LoadRoot(t7, Heap::kUndefinedValueRootIndex);
3383
3384#ifdef ENABLE_DEBUGGER_SUPPORT
3385 // Check to see whether there are any break points in the function code. If
3386 // there are jump to the generic constructor stub which calls the actual
3387 // code for the function thereby hitting the break points.
3388 __ lw(t5, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3389 __ lw(a2, FieldMemOperand(t5, SharedFunctionInfo::kDebugInfoOffset));
3390 __ Branch(&generic_stub_call, ne, a2, Operand(t7));
3391#endif
3392
3393 // Load the initial map and verify that it is in fact a map.
3394 // a1: constructor function
3395 // t7: undefined
3396 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003397 __ JumpIfSmi(a2, &generic_stub_call);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003398 __ GetObjectType(a2, a3, t0);
3399 __ Branch(&generic_stub_call, ne, t0, Operand(MAP_TYPE));
3400
3401#ifdef DEBUG
3402 // Cannot construct functions this way.
3403 // a0: argc
3404 // a1: constructor function
3405 // a2: initial map
3406 // t7: undefined
3407 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
3408 __ Check(ne, "Function constructed by construct stub.",
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003409 a3, Operand(JS_FUNCTION_TYPE));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003410#endif
3411
3412 // Now allocate the JSObject in new space.
3413 // a0: argc
3414 // a1: constructor function
3415 // a2: initial map
3416 // t7: undefined
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003417 ASSERT(function->has_initial_map());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003418 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003419#ifdef DEBUG
3420 int instance_size = function->initial_map()->instance_size();
3421 __ Check(eq, "Instance size of initial map changed.",
3422 a3, Operand(instance_size >> kPointerSizeLog2));
3423#endif
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003424 __ AllocateInNewSpace(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003425
3426 // Allocated the JSObject, now initialize the fields. Map is set to initial
3427 // map and properties and elements are set to empty fixed array.
3428 // a0: argc
3429 // a1: constructor function
3430 // a2: initial map
3431 // a3: object size (in words)
3432 // t4: JSObject (not tagged)
3433 // t7: undefined
3434 __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex);
3435 __ mov(t5, t4);
3436 __ sw(a2, MemOperand(t5, JSObject::kMapOffset));
3437 __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset));
3438 __ sw(t6, MemOperand(t5, JSObject::kElementsOffset));
3439 __ Addu(t5, t5, Operand(3 * kPointerSize));
3440 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
3441 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
3442 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
3443
3444
3445 // Calculate the location of the first argument. The stack contains only the
3446 // argc arguments.
3447 __ sll(a1, a0, kPointerSizeLog2);
3448 __ Addu(a1, a1, sp);
3449
3450 // Fill all the in-object properties with undefined.
3451 // a0: argc
3452 // a1: first argument
3453 // a3: object size (in words)
3454 // t4: JSObject (not tagged)
3455 // t5: First in-object property of JSObject (not tagged)
3456 // t7: undefined
3457 // Fill the initialized properties with a constant value or a passed argument
3458 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003459 Handle<SharedFunctionInfo> shared(function->shared());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003460 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3461 if (shared->IsThisPropertyAssignmentArgument(i)) {
3462 Label not_passed, next;
3463 // Check if the argument assigned to the property is actually passed.
3464 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3465 __ Branch(&not_passed, less_equal, a0, Operand(arg_number));
3466 // Argument passed - find it on the stack.
3467 __ lw(a2, MemOperand(a1, (arg_number + 1) * -kPointerSize));
3468 __ sw(a2, MemOperand(t5));
3469 __ Addu(t5, t5, kPointerSize);
3470 __ jmp(&next);
3471 __ bind(&not_passed);
3472 // Set the property to undefined.
3473 __ sw(t7, MemOperand(t5));
3474 __ Addu(t5, t5, Operand(kPointerSize));
3475 __ bind(&next);
3476 } else {
3477 // Set the property to the constant value.
3478 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
3479 __ li(a2, Operand(constant));
3480 __ sw(a2, MemOperand(t5));
3481 __ Addu(t5, t5, kPointerSize);
3482 }
3483 }
3484
3485 // Fill the unused in-object property fields with undefined.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003486 for (int i = shared->this_property_assignments_count();
3487 i < function->initial_map()->inobject_properties();
3488 i++) {
3489 __ sw(t7, MemOperand(t5));
3490 __ Addu(t5, t5, kPointerSize);
3491 }
3492
3493 // a0: argc
3494 // t4: JSObject (not tagged)
3495 // Move argc to a1 and the JSObject to return to v0 and tag it.
3496 __ mov(a1, a0);
3497 __ mov(v0, t4);
3498 __ Or(v0, v0, Operand(kHeapObjectTag));
3499
3500 // v0: JSObject
3501 // a1: argc
3502 // Remove caller arguments and receiver from the stack and return.
3503 __ sll(t0, a1, kPointerSizeLog2);
3504 __ Addu(sp, sp, t0);
3505 __ Addu(sp, sp, Operand(kPointerSize));
3506 Counters* counters = masm()->isolate()->counters();
3507 __ IncrementCounter(counters->constructed_objects(), 1, a1, a2);
3508 __ IncrementCounter(counters->constructed_objects_stub(), 1, a1, a2);
3509 __ Ret();
3510
3511 // Jump to the generic stub in case the specialized code cannot handle the
3512 // construction.
3513 __ bind(&generic_stub_call);
3514 Handle<Code> generic_construct_stub =
3515 masm()->isolate()->builtins()->JSConstructStubGeneric();
3516 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
3517
3518 // Return the generated code.
3519 return GetCode();
3520}
3521
3522
danno@chromium.org40cb8782011-05-25 07:58:50 +00003523#undef __
3524#define __ ACCESS_MASM(masm)
3525
3526
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003527void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3528 MacroAssembler* masm) {
3529 // ---------- S t a t e --------------
3530 // -- ra : return address
3531 // -- a0 : key
3532 // -- a1 : receiver
3533 // -----------------------------------
3534 Label slow, miss_force_generic;
3535
3536 Register key = a0;
3537 Register receiver = a1;
3538
3539 __ JumpIfNotSmi(key, &miss_force_generic);
3540 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
3541 __ sra(a2, a0, kSmiTagSize);
3542 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
3543 __ Ret();
3544
3545 // Slow case, key and receiver still in a0 and a1.
3546 __ bind(&slow);
3547 __ IncrementCounter(
3548 masm->isolate()->counters()->keyed_load_external_array_slow(),
3549 1, a2, a3);
3550 // Entry registers are intact.
3551 // ---------- S t a t e --------------
3552 // -- ra : return address
3553 // -- a0 : key
3554 // -- a1 : receiver
3555 // -----------------------------------
3556 Handle<Code> slow_ic =
3557 masm->isolate()->builtins()->KeyedLoadIC_Slow();
3558 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
3559
3560 // Miss case, call the runtime.
3561 __ bind(&miss_force_generic);
3562
3563 // ---------- S t a t e --------------
3564 // -- ra : return address
3565 // -- a0 : key
3566 // -- a1 : receiver
3567 // -----------------------------------
3568
3569 Handle<Code> miss_ic =
3570 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3571 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3572}
3573
3574
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003575static bool IsElementTypeSigned(ElementsKind elements_kind) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003576 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003577 case EXTERNAL_BYTE_ELEMENTS:
3578 case EXTERNAL_SHORT_ELEMENTS:
3579 case EXTERNAL_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003580 return true;
3581
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003582 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3583 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3584 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3585 case EXTERNAL_PIXEL_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003586 return false;
3587
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003588 case EXTERNAL_FLOAT_ELEMENTS:
3589 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003590 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003591 case FAST_ELEMENTS:
3592 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003593 case FAST_HOLEY_SMI_ELEMENTS:
3594 case FAST_HOLEY_ELEMENTS:
3595 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003596 case DICTIONARY_ELEMENTS:
3597 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003598 UNREACHABLE();
3599 return false;
3600 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003601 return false;
lrn@chromium.org7516f052011-03-30 08:52:27 +00003602}
3603
3604
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003605static void GenerateSmiKeyCheck(MacroAssembler* masm,
3606 Register key,
3607 Register scratch0,
3608 Register scratch1,
3609 FPURegister double_scratch0,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003610 FPURegister double_scratch1,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003611 Label* fail) {
3612 if (CpuFeatures::IsSupported(FPU)) {
3613 CpuFeatures::Scope scope(FPU);
3614 Label key_ok;
3615 // Check for smi or a smi inside a heap number. We convert the heap
3616 // number and check if the conversion is exact and fits into the smi
3617 // range.
3618 __ JumpIfSmi(key, &key_ok);
3619 __ CheckMap(key,
3620 scratch0,
3621 Heap::kHeapNumberMapRootIndex,
3622 fail,
3623 DONT_DO_SMI_CHECK);
3624 __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
3625 __ EmitFPUTruncate(kRoundToZero,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003626 scratch0,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003627 double_scratch0,
3628 at,
3629 double_scratch1,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003630 scratch1,
3631 kCheckForInexactConversion);
3632
3633 __ Branch(fail, ne, scratch1, Operand(zero_reg));
3634
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003635 __ SmiTagCheckOverflow(key, scratch0, scratch1);
3636 __ BranchOnOverflow(fail, scratch1);
3637 __ bind(&key_ok);
3638 } else {
3639 // Check that the key is a smi.
3640 __ JumpIfNotSmi(key, fail);
3641 }
3642}
3643
3644
danno@chromium.org40cb8782011-05-25 07:58:50 +00003645void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3646 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003647 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003648 // ---------- S t a t e --------------
3649 // -- a0 : value
3650 // -- a1 : key
3651 // -- a2 : receiver
3652 // -- ra : return address
3653 // -----------------------------------
3654
danno@chromium.org40cb8782011-05-25 07:58:50 +00003655 Label slow, check_heap_number, miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003656
3657 // Register usage.
3658 Register value = a0;
3659 Register key = a1;
3660 Register receiver = a2;
3661 // a3 mostly holds the elements array or the destination external array.
3662
danno@chromium.org40cb8782011-05-25 07:58:50 +00003663 // This stub is meant to be tail-jumped to, the receiver must already
3664 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003665
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003666 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003667 GenerateSmiKeyCheck(masm, key, t0, t1, f2, f4, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003668
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003669 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3670
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003671 // Check that the index is in range.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003672 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3673 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003674 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003675
3676 // Handle both smis and HeapNumbers in the fast path. Go to the
3677 // runtime for all other kinds of values.
3678 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003679
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003680 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003681 // Double to pixel conversion is only implemented in the runtime for now.
3682 __ JumpIfNotSmi(value, &slow);
3683 } else {
3684 __ JumpIfNotSmi(value, &check_heap_number);
3685 }
3686 __ SmiUntag(t1, value);
3687 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3688
3689 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003690 // t1: value (integer).
3691
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003692 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003693 case EXTERNAL_PIXEL_ELEMENTS: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003694 // Clamp the value to [0..255].
3695 // v0 is used as a scratch register here.
3696 Label done;
3697 __ li(v0, Operand(255));
3698 // Normal branch: nop in delay slot.
3699 __ Branch(&done, gt, t1, Operand(v0));
3700 // Use delay slot in this branch.
3701 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg));
3702 __ mov(v0, zero_reg); // In delay slot.
3703 __ mov(v0, t1); // Value is in range 0..255.
3704 __ bind(&done);
3705 __ mov(t1, v0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003706
3707 __ srl(t8, key, 1);
3708 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003709 __ sb(t1, MemOperand(t8, 0));
3710 }
3711 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003712 case EXTERNAL_BYTE_ELEMENTS:
3713 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003714 __ srl(t8, key, 1);
3715 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003716 __ sb(t1, MemOperand(t8, 0));
3717 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003718 case EXTERNAL_SHORT_ELEMENTS:
3719 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003720 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003721 __ sh(t1, MemOperand(t8, 0));
3722 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003723 case EXTERNAL_INT_ELEMENTS:
3724 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003725 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003726 __ addu(t8, a3, t8);
3727 __ sw(t1, MemOperand(t8, 0));
3728 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003729 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003730 // Perform int-to-float conversion and store to memory.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003731 __ SmiUntag(t0, key);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003732 StoreIntAsFloat(masm, a3, t0, t1, t2, t3, t4);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003733 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003734 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003735 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003736 __ addu(a3, a3, t8);
3737 // a3: effective address of the double element
3738 FloatingPointHelper::Destination destination;
3739 if (CpuFeatures::IsSupported(FPU)) {
3740 destination = FloatingPointHelper::kFPURegisters;
3741 } else {
3742 destination = FloatingPointHelper::kCoreRegisters;
3743 }
3744 FloatingPointHelper::ConvertIntToDouble(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003745 masm, t1, destination,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003746 f0, t2, t3, // These are: double_dst, dst_mantissa, dst_exponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003747 t0, f2); // These are: scratch2, single_scratch.
3748 if (destination == FloatingPointHelper::kFPURegisters) {
3749 CpuFeatures::Scope scope(FPU);
3750 __ sdc1(f0, MemOperand(a3, 0));
3751 } else {
3752 __ sw(t2, MemOperand(a3, 0));
3753 __ sw(t3, MemOperand(a3, Register::kSizeInBytes));
3754 }
3755 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003756 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003757 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003758 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003759 case FAST_HOLEY_ELEMENTS:
3760 case FAST_HOLEY_SMI_ELEMENTS:
3761 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003762 case DICTIONARY_ELEMENTS:
3763 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003764 UNREACHABLE();
3765 break;
3766 }
3767
3768 // Entry registers are intact, a0 holds the value which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003769 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003770 __ Ret();
3771
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003772 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003773 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003774 __ bind(&check_heap_number);
3775 __ GetObjectType(value, t1, t2);
3776 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE));
3777
3778 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3779
3780 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003781
3782 // The WebGL specification leaves the behavior of storing NaN and
3783 // +/-Infinity into integer arrays basically undefined. For more
3784 // reproducible behavior, convert these to zero.
3785
3786 if (CpuFeatures::IsSupported(FPU)) {
3787 CpuFeatures::Scope scope(FPU);
3788
3789 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
3790
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003791 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003792 __ cvt_s_d(f0, f0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003793 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003794 __ addu(t8, a3, t8);
3795 __ swc1(f0, MemOperand(t8, 0));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003796 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003797 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003798 __ addu(t8, a3, t8);
3799 __ sdc1(f0, MemOperand(t8, 0));
3800 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003801 __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003802
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003803 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003804 case EXTERNAL_BYTE_ELEMENTS:
3805 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003806 __ srl(t8, key, 1);
3807 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003808 __ sb(t3, MemOperand(t8, 0));
3809 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003810 case EXTERNAL_SHORT_ELEMENTS:
3811 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003812 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003813 __ sh(t3, MemOperand(t8, 0));
3814 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003815 case EXTERNAL_INT_ELEMENTS:
3816 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003817 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003818 __ addu(t8, a3, t8);
3819 __ sw(t3, MemOperand(t8, 0));
3820 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003821 case EXTERNAL_PIXEL_ELEMENTS:
3822 case EXTERNAL_FLOAT_ELEMENTS:
3823 case EXTERNAL_DOUBLE_ELEMENTS:
3824 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003825 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003826 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003827 case FAST_HOLEY_ELEMENTS:
3828 case FAST_HOLEY_SMI_ELEMENTS:
3829 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003830 case DICTIONARY_ELEMENTS:
3831 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003832 UNREACHABLE();
3833 break;
3834 }
3835 }
3836
3837 // Entry registers are intact, a0 holds the value
3838 // which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003839 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003840 __ Ret();
3841 } else {
3842 // FPU is not available, do manual conversions.
3843
3844 __ lw(t3, FieldMemOperand(value, HeapNumber::kExponentOffset));
3845 __ lw(t4, FieldMemOperand(value, HeapNumber::kMantissaOffset));
3846
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003847 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003848 Label done, nan_or_infinity_or_zero;
3849 static const int kMantissaInHiWordShift =
3850 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3851
3852 static const int kMantissaInLoWordShift =
3853 kBitsPerInt - kMantissaInHiWordShift;
3854
3855 // Test for all special exponent values: zeros, subnormal numbers, NaNs
3856 // and infinities. All these should be converted to 0.
3857 __ li(t5, HeapNumber::kExponentMask);
3858 __ and_(t6, t3, t5);
3859 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(zero_reg));
3860
3861 __ xor_(t1, t6, t5);
3862 __ li(t2, kBinary32ExponentMask);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003863 __ Movz(t6, t2, t1); // Only if t6 is equal to t5.
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003864 __ Branch(&nan_or_infinity_or_zero, eq, t1, Operand(zero_reg));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003865
3866 // Rebias exponent.
3867 __ srl(t6, t6, HeapNumber::kExponentShift);
3868 __ Addu(t6,
3869 t6,
3870 Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
3871
3872 __ li(t1, Operand(kBinary32MaxExponent));
3873 __ Slt(t1, t1, t6);
3874 __ And(t2, t3, Operand(HeapNumber::kSignMask));
3875 __ Or(t2, t2, Operand(kBinary32ExponentMask));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003876 __ Movn(t3, t2, t1); // Only if t6 is gt kBinary32MaxExponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003877 __ Branch(&done, gt, t6, Operand(kBinary32MaxExponent));
3878
3879 __ Slt(t1, t6, Operand(kBinary32MinExponent));
3880 __ And(t2, t3, Operand(HeapNumber::kSignMask));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003881 __ Movn(t3, t2, t1); // Only if t6 is lt kBinary32MinExponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003882 __ Branch(&done, lt, t6, Operand(kBinary32MinExponent));
3883
3884 __ And(t7, t3, Operand(HeapNumber::kSignMask));
3885 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3886 __ sll(t3, t3, kMantissaInHiWordShift);
3887 __ or_(t7, t7, t3);
3888 __ srl(t4, t4, kMantissaInLoWordShift);
3889 __ or_(t7, t7, t4);
3890 __ sll(t6, t6, kBinary32ExponentShift);
3891 __ or_(t3, t7, t6);
3892
3893 __ bind(&done);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003894 __ sll(t9, key, 1);
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003895 __ addu(t9, a3, t9);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003896 __ sw(t3, MemOperand(t9, 0));
3897
3898 // Entry registers are intact, a0 holds the value which is the return
3899 // value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003900 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003901 __ Ret();
3902
3903 __ bind(&nan_or_infinity_or_zero);
3904 __ And(t7, t3, Operand(HeapNumber::kSignMask));
3905 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3906 __ or_(t6, t6, t7);
3907 __ sll(t3, t3, kMantissaInHiWordShift);
3908 __ or_(t6, t6, t3);
3909 __ srl(t4, t4, kMantissaInLoWordShift);
3910 __ or_(t3, t6, t4);
3911 __ Branch(&done);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003912 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003913 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003914 __ addu(t8, a3, t8);
3915 // t8: effective address of destination element.
3916 __ sw(t4, MemOperand(t8, 0));
3917 __ sw(t3, MemOperand(t8, Register::kSizeInBytes));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003918 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003919 __ Ret();
3920 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003921 bool is_signed_type = IsElementTypeSigned(elements_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003922 int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
3923 int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
3924
3925 Label done, sign;
3926
3927 // Test for all special exponent values: zeros, subnormal numbers, NaNs
3928 // and infinities. All these should be converted to 0.
3929 __ li(t5, HeapNumber::kExponentMask);
3930 __ and_(t6, t3, t5);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003931 __ Movz(t3, zero_reg, t6); // Only if t6 is equal to zero.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003932 __ Branch(&done, eq, t6, Operand(zero_reg));
3933
3934 __ xor_(t2, t6, t5);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003935 __ Movz(t3, zero_reg, t2); // Only if t6 is equal to t5.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003936 __ Branch(&done, eq, t6, Operand(t5));
3937
3938 // Unbias exponent.
3939 __ srl(t6, t6, HeapNumber::kExponentShift);
3940 __ Subu(t6, t6, Operand(HeapNumber::kExponentBias));
3941 // If exponent is negative then result is 0.
3942 __ slt(t2, t6, zero_reg);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003943 __ Movn(t3, zero_reg, t2); // Only if exponent is negative.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003944 __ Branch(&done, lt, t6, Operand(zero_reg));
3945
3946 // If exponent is too big then result is minimal value.
3947 __ slti(t1, t6, meaningfull_bits - 1);
3948 __ li(t2, min_value);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003949 __ Movz(t3, t2, t1); // Only if t6 is ge meaningfull_bits - 1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003950 __ Branch(&done, ge, t6, Operand(meaningfull_bits - 1));
3951
3952 __ And(t5, t3, Operand(HeapNumber::kSignMask));
3953 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3954 __ Or(t3, t3, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
3955
3956 __ li(t9, HeapNumber::kMantissaBitsInTopWord);
3957 __ subu(t6, t9, t6);
3958 __ slt(t1, t6, zero_reg);
3959 __ srlv(t2, t3, t6);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003960 __ Movz(t3, t2, t1); // Only if t6 is positive.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003961 __ Branch(&sign, ge, t6, Operand(zero_reg));
3962
3963 __ subu(t6, zero_reg, t6);
3964 __ sllv(t3, t3, t6);
3965 __ li(t9, meaningfull_bits);
3966 __ subu(t6, t9, t6);
3967 __ srlv(t4, t4, t6);
3968 __ or_(t3, t3, t4);
3969
3970 __ bind(&sign);
3971 __ subu(t2, t3, zero_reg);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003972 __ Movz(t3, t2, t5); // Only if t5 is zero.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003973
3974 __ bind(&done);
3975
3976 // Result is in t3.
3977 // This switch block should be exactly the same as above (FPU mode).
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003978 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003979 case EXTERNAL_BYTE_ELEMENTS:
3980 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003981 __ srl(t8, key, 1);
3982 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003983 __ sb(t3, MemOperand(t8, 0));
3984 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003985 case EXTERNAL_SHORT_ELEMENTS:
3986 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003987 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003988 __ sh(t3, MemOperand(t8, 0));
3989 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003990 case EXTERNAL_INT_ELEMENTS:
3991 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003992 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003993 __ addu(t8, a3, t8);
3994 __ sw(t3, MemOperand(t8, 0));
3995 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003996 case EXTERNAL_PIXEL_ELEMENTS:
3997 case EXTERNAL_FLOAT_ELEMENTS:
3998 case EXTERNAL_DOUBLE_ELEMENTS:
3999 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004000 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004001 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004002 case FAST_HOLEY_ELEMENTS:
4003 case FAST_HOLEY_SMI_ELEMENTS:
4004 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004005 case DICTIONARY_ELEMENTS:
4006 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004007 UNREACHABLE();
4008 break;
4009 }
4010 }
4011 }
4012 }
4013
danno@chromium.org40cb8782011-05-25 07:58:50 +00004014 // Slow case, key and receiver still in a0 and a1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004015 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004016 __ IncrementCounter(
4017 masm->isolate()->counters()->keyed_load_external_array_slow(),
4018 1, a2, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004019 // Entry registers are intact.
4020 // ---------- S t a t e --------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004021 // -- ra : return address
danno@chromium.org40cb8782011-05-25 07:58:50 +00004022 // -- a0 : key
4023 // -- a1 : receiver
4024 // -----------------------------------
4025 Handle<Code> slow_ic =
4026 masm->isolate()->builtins()->KeyedStoreIC_Slow();
4027 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
4028
4029 // Miss case, call the runtime.
4030 __ bind(&miss_force_generic);
4031
4032 // ---------- S t a t e --------------
4033 // -- ra : return address
4034 // -- a0 : key
4035 // -- a1 : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004036 // -----------------------------------
4037
danno@chromium.org40cb8782011-05-25 07:58:50 +00004038 Handle<Code> miss_ic =
4039 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4040 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
4041}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004042
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004043
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004044void KeyedStoreStubCompiler::GenerateStoreFastElement(
4045 MacroAssembler* masm,
4046 bool is_js_array,
yangguo@chromium.org56454712012-02-16 15:33:53 +00004047 ElementsKind elements_kind,
4048 KeyedAccessGrowMode grow_mode) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00004049 // ----------- S t a t e -------------
4050 // -- a0 : value
4051 // -- a1 : key
4052 // -- a2 : receiver
4053 // -- ra : return address
4054 // -- a3 : scratch
4055 // -- a4 : scratch (elements)
4056 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00004057 Label miss_force_generic, transition_elements_kind, grow, slow;
4058 Label finish_store, check_capacity;
danno@chromium.org40cb8782011-05-25 07:58:50 +00004059
4060 Register value_reg = a0;
4061 Register key_reg = a1;
4062 Register receiver_reg = a2;
yangguo@chromium.org56454712012-02-16 15:33:53 +00004063 Register scratch = t0;
4064 Register elements_reg = a3;
4065 Register length_reg = t1;
4066 Register scratch2 = t2;
danno@chromium.org40cb8782011-05-25 07:58:50 +00004067
4068 // This stub is meant to be tail-jumped to, the receiver must already
4069 // have been verified by the caller to not be a smi.
4070
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004071 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004072 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004073
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004074 if (IsFastSmiElementsKind(elements_kind)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00004075 __ JumpIfNotSmi(value_reg, &transition_elements_kind);
4076 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004077
4078 // Check that the key is within bounds.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004079 __ lw(elements_reg,
4080 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00004081 if (is_js_array) {
4082 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4083 } else {
4084 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4085 }
4086 // Compare smis.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004087 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4088 __ Branch(&grow, hs, key_reg, Operand(scratch));
4089 } else {
4090 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
4091 }
4092
4093 // Make sure elements is a fast element array, not 'cow'.
4094 __ CheckMap(elements_reg,
4095 scratch,
4096 Heap::kFixedArrayMapRootIndex,
4097 &miss_force_generic,
4098 DONT_DO_SMI_CHECK);
4099
4100 __ bind(&finish_store);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004101
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004102 if (IsFastSmiElementsKind(elements_kind)) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004103 __ Addu(scratch,
4104 elements_reg,
4105 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4106 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4107 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4108 __ Addu(scratch, scratch, scratch2);
4109 __ sw(value_reg, MemOperand(scratch));
4110 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004111 ASSERT(IsFastObjectElementsKind(elements_kind));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004112 __ Addu(scratch,
4113 elements_reg,
4114 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4115 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
4116 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
4117 __ Addu(scratch, scratch, scratch2);
4118 __ sw(value_reg, MemOperand(scratch));
4119 __ mov(receiver_reg, value_reg);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004120 __ RecordWrite(elements_reg, // Object.
4121 scratch, // Address.
4122 receiver_reg, // Value.
4123 kRAHasNotBeenSaved,
4124 kDontSaveFPRegs);
4125 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004126 // value_reg (a0) is preserved.
4127 // Done.
4128 __ Ret();
4129
4130 __ bind(&miss_force_generic);
4131 Handle<Code> ic =
4132 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4133 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004134
4135 __ bind(&transition_elements_kind);
4136 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4137 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
yangguo@chromium.org56454712012-02-16 15:33:53 +00004138
4139 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4140 // Grow the array by a single element if possible.
4141 __ bind(&grow);
4142
4143 // Make sure the array is only growing by a single element, anything else
4144 // must be handled by the runtime.
4145 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch));
4146
4147 // Check for the empty array, and preallocate a small backing store if
4148 // possible.
4149 __ lw(length_reg,
4150 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4151 __ lw(elements_reg,
4152 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4153 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
4154 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
4155
4156 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
4157 __ AllocateInNewSpace(size, elements_reg, scratch, scratch2, &slow,
4158 TAG_OBJECT);
4159
4160 __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex);
4161 __ sw(scratch, FieldMemOperand(elements_reg, JSObject::kMapOffset));
4162 __ li(scratch, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4163 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4164 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
4165 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
4166 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::SizeFor(i)));
4167 }
4168
4169 // Store the element at index zero.
4170 __ sw(value_reg, FieldMemOperand(elements_reg, FixedArray::SizeFor(0)));
4171
4172 // Install the new backing store in the JSArray.
4173 __ sw(elements_reg,
4174 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4175 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
4176 scratch, kRAHasNotBeenSaved, kDontSaveFPRegs,
4177 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4178
4179 // Increment the length of the array.
4180 __ li(length_reg, Operand(Smi::FromInt(1)));
4181 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4182 __ Ret();
4183
4184 __ bind(&check_capacity);
4185 // Check for cow elements, in general they are not handled by this stub
4186 __ CheckMap(elements_reg,
4187 scratch,
4188 Heap::kFixedCOWArrayMapRootIndex,
4189 &miss_force_generic,
4190 DONT_DO_SMI_CHECK);
4191
4192 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4193 __ Branch(&slow, hs, length_reg, Operand(scratch));
4194
4195 // Grow the array and finish the store.
4196 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
4197 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4198 __ jmp(&finish_store);
4199
4200 __ bind(&slow);
4201 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4202 __ Jump(ic_slow, RelocInfo::CODE_TARGET);
4203 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004204}
4205
4206
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004207void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
4208 MacroAssembler* masm,
yangguo@chromium.org56454712012-02-16 15:33:53 +00004209 bool is_js_array,
4210 KeyedAccessGrowMode grow_mode) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004211 // ----------- S t a t e -------------
4212 // -- a0 : value
4213 // -- a1 : key
4214 // -- a2 : receiver
4215 // -- ra : return address
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004216 // -- a3 : scratch (elements backing store)
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004217 // -- t0 : scratch (elements_reg)
4218 // -- t1 : scratch (mantissa_reg)
4219 // -- t2 : scratch (exponent_reg)
4220 // -- t3 : scratch4
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004221 // -- t4 : scratch
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004222 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00004223 Label miss_force_generic, transition_elements_kind, grow, slow;
4224 Label finish_store, check_capacity;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004225
4226 Register value_reg = a0;
4227 Register key_reg = a1;
4228 Register receiver_reg = a2;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004229 Register elements_reg = a3;
4230 Register scratch1 = t0;
4231 Register scratch2 = t1;
4232 Register scratch3 = t2;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004233 Register scratch4 = t3;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004234 Register scratch5 = t4;
yangguo@chromium.org56454712012-02-16 15:33:53 +00004235 Register length_reg = t3;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004236
4237 // This stub is meant to be tail-jumped to, the receiver must already
4238 // have been verified by the caller to not be a smi.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004239
4240 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004241 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004242
4243 __ lw(elements_reg,
4244 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4245
4246 // Check that the key is within bounds.
4247 if (is_js_array) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004248 __ lw(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004249 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004250 __ lw(scratch1,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004251 FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4252 }
4253 // Compare smis, unsigned compare catches both negative and out-of-bound
4254 // indexes.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004255 if (grow_mode == ALLOW_JSARRAY_GROWTH) {
4256 __ Branch(&grow, hs, key_reg, Operand(scratch1));
4257 } else {
4258 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch1));
4259 }
4260
4261 __ bind(&finish_store);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004262
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004263 __ StoreNumberToDoubleElements(value_reg,
4264 key_reg,
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004265 // All registers after this are overwritten.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004266 elements_reg,
4267 scratch1,
4268 scratch2,
4269 scratch3,
4270 scratch4,
4271 &transition_elements_kind);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004272
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004273 __ Ret(USE_DELAY_SLOT);
4274 __ mov(v0, value_reg); // In delay slot.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004275
4276 // Handle store cache miss, replacing the ic with the generic stub.
4277 __ bind(&miss_force_generic);
4278 Handle<Code> ic =
4279 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4280 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004281
4282 __ bind(&transition_elements_kind);
4283 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4284 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
yangguo@chromium.org56454712012-02-16 15:33:53 +00004285
4286 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4287 // Grow the array by a single element if possible.
4288 __ bind(&grow);
4289
4290 // Make sure the array is only growing by a single element, anything else
4291 // must be handled by the runtime.
4292 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch1));
4293
4294 // Transition on values that can't be stored in a FixedDoubleArray.
4295 Label value_is_smi;
4296 __ JumpIfSmi(value_reg, &value_is_smi);
4297 __ lw(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
4298 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
4299 __ Branch(&transition_elements_kind, ne, scratch1, Operand(at));
4300 __ bind(&value_is_smi);
4301
4302 // Check for the empty array, and preallocate a small backing store if
4303 // possible.
4304 __ lw(length_reg,
4305 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4306 __ lw(elements_reg,
4307 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4308 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
4309 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
4310
4311 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
4312 __ AllocateInNewSpace(size, elements_reg, scratch1, scratch2, &slow,
4313 TAG_OBJECT);
4314
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004315 // Initialize the new FixedDoubleArray.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004316 __ LoadRoot(scratch1, Heap::kFixedDoubleArrayMapRootIndex);
4317 __ sw(scratch1, FieldMemOperand(elements_reg, JSObject::kMapOffset));
4318 __ li(scratch1, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4319 __ sw(scratch1,
4320 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
4321
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004322 __ mov(scratch1, elements_reg);
4323 __ StoreNumberToDoubleElements(value_reg,
4324 key_reg,
4325 // All registers after this are overwritten.
4326 scratch1,
4327 scratch2,
4328 scratch3,
4329 scratch4,
4330 scratch5,
4331 &transition_elements_kind);
4332
4333 __ li(scratch1, Operand(kHoleNanLower32));
4334 __ li(scratch2, Operand(kHoleNanUpper32));
4335 for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) {
4336 int offset = FixedDoubleArray::OffsetOfElementAt(i);
4337 __ sw(scratch1, FieldMemOperand(elements_reg, offset));
4338 __ sw(scratch2, FieldMemOperand(elements_reg, offset + kPointerSize));
4339 }
4340
yangguo@chromium.org56454712012-02-16 15:33:53 +00004341 // Install the new backing store in the JSArray.
4342 __ sw(elements_reg,
4343 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4344 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
4345 scratch1, kRAHasNotBeenSaved, kDontSaveFPRegs,
4346 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4347
4348 // Increment the length of the array.
4349 __ li(length_reg, Operand(Smi::FromInt(1)));
4350 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
danno@chromium.org00379b82012-05-04 09:16:29 +00004351 __ lw(elements_reg,
4352 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004353 __ Ret();
yangguo@chromium.org56454712012-02-16 15:33:53 +00004354
4355 __ bind(&check_capacity);
4356 // Make sure that the backing store can hold additional elements.
4357 __ lw(scratch1,
4358 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
4359 __ Branch(&slow, hs, length_reg, Operand(scratch1));
4360
4361 // Grow the array and finish the store.
4362 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
4363 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4364 __ jmp(&finish_store);
4365
4366 __ bind(&slow);
4367 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4368 __ Jump(ic_slow, RelocInfo::CODE_TARGET);
4369 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004370}
4371
4372
ager@chromium.org5c838252010-02-19 08:53:10 +00004373#undef __
4374
4375} } // namespace v8::internal
4376
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004377#endif // V8_TARGET_ARCH_MIPS