blob: 99a35ea9d7b7a48ded36bda643de46ebc2a80f26 [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();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000699 Handle<Object> call_data(api_call_info->data(), masm->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000700 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
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001213void StubCompiler::GenerateDictionaryLoadCallback(
1214 Register receiver,
1215 Register name_reg,
1216 Register scratch1,
1217 Register scratch2,
1218 Register scratch3,
1219 Handle<ExecutableAccessorInfo> callback,
1220 Handle<String> name,
1221 Label* miss) {
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001222 ASSERT(!receiver.is(scratch1));
1223 ASSERT(!receiver.is(scratch2));
1224 ASSERT(!receiver.is(scratch3));
1225
1226 // Load the properties dictionary.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001227 Register dictionary = scratch1;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001228 __ lw(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
1229
1230 // Probe the dictionary.
1231 Label probe_done;
1232 StringDictionaryLookupStub::GeneratePositiveLookup(masm(),
1233 miss,
1234 &probe_done,
1235 dictionary,
1236 name_reg,
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001237 scratch2,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001238 scratch3);
1239 __ bind(&probe_done);
1240
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001241 // If probing finds an entry in the dictionary, scratch3 contains the
1242 // pointer into the dictionary. Check that the value is the callback.
1243 Register pointer = scratch3;
1244 const int kElementsStartOffset = StringDictionary::kHeaderSize +
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001245 StringDictionary::kElementsStartIndex * kPointerSize;
1246 const int kValueOffset = kElementsStartOffset + kPointerSize;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001247 __ lw(scratch2, FieldMemOperand(pointer, kValueOffset));
1248 __ Branch(miss, ne, scratch2, Operand(callback));
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001249}
1250
1251
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001252void StubCompiler::GenerateLoadCallback(
1253 Handle<JSObject> object,
1254 Handle<JSObject> holder,
1255 Register receiver,
1256 Register name_reg,
1257 Register scratch1,
1258 Register scratch2,
1259 Register scratch3,
1260 Register scratch4,
1261 Handle<ExecutableAccessorInfo> callback,
1262 Handle<String> name,
1263 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001264 // Check that the receiver isn't a smi.
1265 __ JumpIfSmi(receiver, miss, scratch1);
1266
1267 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001268 Register reg = CheckPrototypes(object, receiver, holder, scratch1,
1269 scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001270
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001271 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
1272 GenerateDictionaryLoadCallback(
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001273 reg, name_reg, scratch2, scratch3, scratch4, callback, name, miss);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001274 }
1275
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001276 // Build AccessorInfo::args_ list on the stack and push property name below
1277 // the exit frame to make GC aware of them and store pointers to them.
1278 __ push(receiver);
1279 __ mov(scratch2, sp); // scratch2 = AccessorInfo::args_
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001280 if (heap()->InNewSpace(callback->data())) {
1281 __ li(scratch3, callback);
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001282 __ lw(scratch3,
1283 FieldMemOperand(scratch3, ExecutableAccessorInfo::kDataOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001284 } else {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001285 __ li(scratch3, Handle<Object>(callback->data(), masm()->isolate()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001286 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001287 __ Subu(sp, sp, 4 * kPointerSize);
1288 __ sw(reg, MemOperand(sp, 3 * kPointerSize));
1289 __ sw(scratch3, MemOperand(sp, 2 * kPointerSize));
1290 __ li(scratch3, Operand(ExternalReference::isolate_address()));
1291 __ sw(scratch3, MemOperand(sp, 1 * kPointerSize));
1292 __ sw(name_reg, MemOperand(sp, 0 * kPointerSize));
1293
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001294 __ mov(a2, scratch2); // Saved in case scratch2 == a1.
1295 __ mov(a1, sp); // a1 (first argument - see note below) = Handle<String>
1296
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001297 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
1298 // struct from the function (which is currently the case). This means we pass
1299 // the arguments in a1-a2 instead of a0-a1. TryCallApiFunctionAndReturn
1300 // will handle setting up a0.
1301
1302 const int kApiStackSpace = 1;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001303 FrameScope frame_scope(masm(), StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001304 __ EnterExitFrame(false, kApiStackSpace);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001305
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001306 // Create AccessorInfo instance on the stack above the exit frame with
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001307 // scratch2 (internal::Object** args_) as the data.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001308 __ sw(a2, MemOperand(sp, kPointerSize));
1309 // a2 (second argument - see note above) = AccessorInfo&
1310 __ Addu(a2, sp, kPointerSize);
1311
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001312 const int kStackUnwindSpace = 5;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001313 Address getter_address = v8::ToCData<Address>(callback->getter());
1314 ApiFunction fun(getter_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001315 ExternalReference ref =
1316 ExternalReference(&fun,
1317 ExternalReference::DIRECT_GETTER_CALL,
1318 masm()->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001319 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
ager@chromium.org5c838252010-02-19 08:53:10 +00001320}
1321
1322
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001323void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
1324 Handle<JSObject> interceptor_holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001325 LookupResult* lookup,
1326 Register receiver,
1327 Register name_reg,
1328 Register scratch1,
1329 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001330 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001331 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001332 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001333 ASSERT(interceptor_holder->HasNamedInterceptor());
1334 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1335
1336 // Check that the receiver isn't a smi.
1337 __ JumpIfSmi(receiver, miss);
1338
1339 // So far the most popular follow ups for interceptor loads are FIELD
1340 // and CALLBACKS, so inline only them, other cases may be added
1341 // later.
1342 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001343 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001344 if (lookup->IsField()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001345 compile_followup_inline = true;
1346 } else if (lookup->type() == CALLBACKS &&
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001347 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
1348 ExecutableAccessorInfo* callback =
1349 ExecutableAccessorInfo::cast(lookup->GetCallbackObject());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001350 compile_followup_inline = callback->getter() != NULL &&
1351 callback->IsCompatibleReceiver(*object);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001352 }
1353 }
1354
1355 if (compile_followup_inline) {
1356 // Compile the interceptor call, followed by inline code to load the
1357 // property from further up the prototype chain if the call fails.
1358 // Check that the maps haven't changed.
1359 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1360 scratch1, scratch2, scratch3,
1361 name, miss);
1362 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
1363
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001364 // Preserve the receiver register explicitly whenever it is different from
1365 // the holder and it is needed should the interceptor return without any
1366 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1367 // the FIELD case might cause a miss during the prototype check.
1368 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
1369 bool must_preserve_receiver_reg = !receiver.is(holder_reg) &&
1370 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1371
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001372 // Save necessary data before invoking an interceptor.
1373 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001374 {
1375 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001376 if (must_preserve_receiver_reg) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001377 __ Push(receiver, holder_reg, name_reg);
1378 } else {
1379 __ Push(holder_reg, name_reg);
1380 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001381 // Invoke an interceptor. Note: map checks from receiver to
1382 // interceptor's holder has been compiled before (see a caller
1383 // of this method).
1384 CompileCallLoadPropertyWithInterceptor(masm(),
1385 receiver,
1386 holder_reg,
1387 name_reg,
1388 interceptor_holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001389 // Check if interceptor provided a value for property. If it's
1390 // the case, return immediately.
1391 Label interceptor_failed;
1392 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
1393 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1));
1394 frame_scope.GenerateLeaveFrame();
1395 __ Ret();
1396
1397 __ bind(&interceptor_failed);
1398 __ pop(name_reg);
1399 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001400 if (must_preserve_receiver_reg) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001401 __ pop(receiver);
1402 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001403 // Leave the internal frame.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001404 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001405 // Check that the maps from interceptor's holder to lookup's holder
1406 // haven't changed. And load lookup's holder into |holder| register.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001407 if (must_perfrom_prototype_check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001408 holder_reg = CheckPrototypes(interceptor_holder,
1409 holder_reg,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001410 Handle<JSObject>(lookup->holder()),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001411 scratch1,
1412 scratch2,
1413 scratch3,
1414 name,
1415 miss);
1416 }
1417
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001418 if (lookup->IsField()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001419 // We found FIELD property in prototype chain of interceptor's holder.
1420 // Retrieve a field from field's holder.
1421 GenerateFastPropertyLoad(masm(), v0, holder_reg,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001422 Handle<JSObject>(lookup->holder()),
1423 lookup->GetFieldIndex());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001424 __ Ret();
1425 } else {
1426 // We found CALLBACKS property in prototype chain of interceptor's
1427 // holder.
1428 ASSERT(lookup->type() == CALLBACKS);
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001429 Handle<ExecutableAccessorInfo> callback(
1430 ExecutableAccessorInfo::cast(lookup->GetCallbackObject()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001431 ASSERT(callback->getter() != NULL);
1432
1433 // Tail call to runtime.
1434 // Important invariant in CALLBACKS case: the code above must be
1435 // structured to never clobber |receiver| register.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001436 __ li(scratch2, callback);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001437
1438 __ Push(receiver, holder_reg);
1439 __ lw(scratch3,
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001440 FieldMemOperand(scratch2, ExecutableAccessorInfo::kDataOffset));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001441 __ li(scratch1, Operand(ExternalReference::isolate_address()));
1442 __ Push(scratch3, scratch1, scratch2, name_reg);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001443
1444 ExternalReference ref =
1445 ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
1446 masm()->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001447 __ TailCallExternalReference(ref, 6, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001448 }
1449 } else { // !compile_followup_inline
1450 // Call the runtime system to load the interceptor.
1451 // Check that the maps haven't changed.
1452 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1453 scratch1, scratch2, scratch3,
1454 name, miss);
1455 PushInterceptorArguments(masm(), receiver, holder_reg,
1456 name_reg, interceptor_holder);
1457
1458 ExternalReference ref = ExternalReference(
1459 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), masm()->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001460 __ TailCallExternalReference(ref, 6, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001461 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001462}
1463
1464
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001465void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001466 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001467 __ Branch(miss, ne, a2, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001468 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001469}
1470
1471
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001472void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1473 Handle<JSObject> holder,
1474 Handle<String> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001475 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001476 ASSERT(holder->IsGlobalObject());
1477
1478 // Get the number of arguments.
1479 const int argc = arguments().immediate();
1480
1481 // Get the receiver from the stack.
1482 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1483
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001484 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001485 __ JumpIfSmi(a0, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001486 CheckPrototypes(object, a0, holder, a3, a1, t0, name, miss);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001487}
1488
1489
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001490void CallStubCompiler::GenerateLoadFunctionFromCell(
1491 Handle<JSGlobalPropertyCell> cell,
1492 Handle<JSFunction> function,
1493 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001494 // Get the value from the cell.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001495 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001496 __ lw(a1, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
1497
1498 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001499 if (heap()->InNewSpace(*function)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001500 // We can't embed a pointer to a function in new space so we have
1501 // to verify that the shared function info is unchanged. This has
1502 // the nice side effect that multiple closures based on the same
1503 // function can all use this call IC. Before we load through the
1504 // function, we have to verify that it still is a function.
1505 __ JumpIfSmi(a1, miss);
1506 __ GetObjectType(a1, a3, a3);
1507 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
1508
1509 // Check the shared function info. Make sure it hasn't changed.
1510 __ li(a3, Handle<SharedFunctionInfo>(function->shared()));
1511 __ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
1512 __ Branch(miss, ne, t0, Operand(a3));
1513 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001514 __ Branch(miss, ne, a1, Operand(function));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001515 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001516}
1517
1518
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001519void CallStubCompiler::GenerateMissBranch() {
1520 Handle<Code> code =
danno@chromium.org40cb8782011-05-25 07:58:50 +00001521 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1522 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001523 extra_state_);
1524 __ Jump(code, RelocInfo::CODE_TARGET);
1525}
1526
1527
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001528Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1529 Handle<JSObject> holder,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001530 PropertyIndex index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001531 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001532 // ----------- S t a t e -------------
1533 // -- a2 : name
1534 // -- ra : return address
1535 // -----------------------------------
1536 Label miss;
1537
1538 GenerateNameCheck(name, &miss);
1539
1540 const int argc = arguments().immediate();
1541
1542 // Get the receiver of the function from the stack into a0.
1543 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1544 // Check that the receiver isn't a smi.
1545 __ JumpIfSmi(a0, &miss, t0);
1546
1547 // Do the right check and compute the holder register.
1548 Register reg = CheckPrototypes(object, a0, holder, a1, a3, t0, name, &miss);
1549 GenerateFastPropertyLoad(masm(), a1, reg, holder, index);
1550
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001551 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001552
1553 // Handle call cache miss.
1554 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001555 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001556
1557 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001558 return GetCode(Code::FIELD, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001559}
1560
1561
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001562Handle<Code> CallStubCompiler::CompileArrayPushCall(
1563 Handle<Object> object,
1564 Handle<JSObject> holder,
1565 Handle<JSGlobalPropertyCell> cell,
1566 Handle<JSFunction> function,
1567 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001568 // ----------- S t a t e -------------
1569 // -- a2 : name
1570 // -- ra : return address
1571 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1572 // -- ...
1573 // -- sp[argc * 4] : receiver
1574 // -----------------------------------
1575
1576 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001577 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001578
1579 Label miss;
1580
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001581 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001582
1583 Register receiver = a1;
1584
1585 // Get the receiver from the stack.
1586 const int argc = arguments().immediate();
1587 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1588
1589 // Check that the receiver isn't a smi.
1590 __ JumpIfSmi(receiver, &miss);
1591
1592 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001593 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, a3, v0, t0,
1594 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001595
1596 if (argc == 0) {
1597 // Nothing to do, just return the length.
1598 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1599 __ Drop(argc + 1);
1600 __ Ret();
1601 } else {
1602 Label call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001603 if (argc == 1) { // Otherwise fall through to call the builtin.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001604 Label attempt_to_grow_elements, with_write_barrier, check_double;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001605
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001606 Register elements = t2;
1607 Register end_elements = t1;
1608 // Get the elements array of the object.
1609 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1610
1611 // Check that the elements are in fast mode and writable.
1612 __ CheckMap(elements,
1613 v0,
1614 Heap::kFixedArrayMapRootIndex,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001615 &check_double,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001616 DONT_DO_SMI_CHECK);
1617
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001618 // Get the array's length into v0 and calculate new length.
1619 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1620 STATIC_ASSERT(kSmiTagSize == 1);
1621 STATIC_ASSERT(kSmiTag == 0);
1622 __ Addu(v0, v0, Operand(Smi::FromInt(argc)));
1623
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001624 // Get the elements' length.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001625 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1626
1627 // Check if we could survive without allocation.
1628 __ Branch(&attempt_to_grow_elements, gt, v0, Operand(t0));
1629
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001630 // Check if value is a smi.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001631 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1632 __ JumpIfNotSmi(t0, &with_write_barrier);
1633
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001634 // Save new length.
1635 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1636
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001637 // Store the value.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001638 // We may need a register containing the address end_elements below,
1639 // so write back the value in end_elements.
1640 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1641 __ Addu(end_elements, elements, end_elements);
1642 const int kEndElementsOffset =
1643 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001644 __ Addu(end_elements, end_elements, kEndElementsOffset);
1645 __ sw(t0, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001646
1647 // Check for a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001648 __ Drop(argc + 1);
1649 __ Ret();
1650
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001651 __ bind(&check_double);
1652
1653 // Check that the elements are in fast mode and writable.
1654 __ CheckMap(elements,
1655 a0,
1656 Heap::kFixedDoubleArrayMapRootIndex,
1657 &call_builtin,
1658 DONT_DO_SMI_CHECK);
1659
1660 // Get the array's length into r0 and calculate new length.
1661 __ lw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1662 STATIC_ASSERT(kSmiTagSize == 1);
1663 STATIC_ASSERT(kSmiTag == 0);
1664 __ Addu(a0, a0, Operand(Smi::FromInt(argc)));
1665
1666 // Get the elements' length.
1667 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1668
1669 // Check if we could survive without allocation.
1670 __ Branch(&call_builtin, gt, a0, Operand(t0));
1671
1672 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1673 __ StoreNumberToDoubleElements(
1674 t0, a0, elements, a3, t1, a2, t5,
1675 &call_builtin, argc * kDoubleSize);
1676
1677 // Save new length.
1678 __ sw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1679
1680 // Check for a smi.
1681 __ Drop(argc + 1);
1682 __ Ret();
1683
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001684 __ bind(&with_write_barrier);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001685
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001686 __ lw(a3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1687
1688 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
1689 Label fast_object, not_fast_object;
1690 __ CheckFastObjectElements(a3, t3, &not_fast_object);
1691 __ jmp(&fast_object);
1692 // In case of fast smi-only, convert to fast object, otherwise bail out.
1693 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001694 __ CheckFastSmiElements(a3, t3, &call_builtin);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001695
1696 __ lw(t3, FieldMemOperand(t0, HeapObject::kMapOffset));
1697 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
1698 __ Branch(&call_builtin, eq, t3, Operand(at));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001699 // edx: receiver
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001700 // a3: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001701 Label try_holey_map;
1702 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001703 FAST_ELEMENTS,
1704 a3,
1705 t3,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001706 &try_holey_map);
1707 __ mov(a2, receiver);
1708 ElementsTransitionGenerator::
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001709 GenerateMapChangeElementsTransition(masm(),
1710 DONT_TRACK_ALLOCATION_SITE,
1711 NULL);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001712 __ jmp(&fast_object);
1713
1714 __ bind(&try_holey_map);
1715 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1716 FAST_HOLEY_ELEMENTS,
1717 a3,
1718 t3,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001719 &call_builtin);
1720 __ mov(a2, receiver);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001721 ElementsTransitionGenerator::
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001722 GenerateMapChangeElementsTransition(masm(),
1723 DONT_TRACK_ALLOCATION_SITE,
1724 NULL);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001725 __ bind(&fast_object);
1726 } else {
1727 __ CheckFastObjectElements(a3, a3, &call_builtin);
1728 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001729
1730 // Save new length.
1731 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1732
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001733 // Store the value.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001734 // We may need a register containing the address end_elements below,
1735 // so write back the value in end_elements.
1736 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1737 __ Addu(end_elements, elements, end_elements);
1738 __ Addu(end_elements, end_elements, kEndElementsOffset);
1739 __ sw(t0, MemOperand(end_elements));
1740
1741 __ RecordWrite(elements,
1742 end_elements,
1743 t0,
1744 kRAHasNotBeenSaved,
1745 kDontSaveFPRegs,
1746 EMIT_REMEMBERED_SET,
1747 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001748 __ Drop(argc + 1);
1749 __ Ret();
1750
1751 __ bind(&attempt_to_grow_elements);
1752 // v0: array's length + 1.
1753 // t0: elements' length.
1754
1755 if (!FLAG_inline_new) {
1756 __ Branch(&call_builtin);
1757 }
1758
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001759 __ lw(a2, MemOperand(sp, (argc - 1) * kPointerSize));
1760 // Growing elements that are SMI-only requires special handling in case
1761 // the new element is non-Smi. For now, delegate to the builtin.
1762 Label no_fast_elements_check;
1763 __ JumpIfSmi(a2, &no_fast_elements_check);
1764 __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1765 __ CheckFastObjectElements(t3, t3, &call_builtin);
1766 __ bind(&no_fast_elements_check);
1767
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001768 ExternalReference new_space_allocation_top =
1769 ExternalReference::new_space_allocation_top_address(
1770 masm()->isolate());
1771 ExternalReference new_space_allocation_limit =
1772 ExternalReference::new_space_allocation_limit_address(
1773 masm()->isolate());
1774
1775 const int kAllocationDelta = 4;
1776 // Load top and check if it is the end of elements.
1777 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1778 __ Addu(end_elements, elements, end_elements);
1779 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset));
1780 __ li(t3, Operand(new_space_allocation_top));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001781 __ lw(a3, MemOperand(t3));
1782 __ Branch(&call_builtin, ne, end_elements, Operand(a3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001783
1784 __ li(t5, Operand(new_space_allocation_limit));
1785 __ lw(t5, MemOperand(t5));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001786 __ Addu(a3, a3, Operand(kAllocationDelta * kPointerSize));
1787 __ Branch(&call_builtin, hi, a3, Operand(t5));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001788
1789 // We fit and could grow elements.
1790 // Update new_space_allocation_top.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001791 __ sw(a3, MemOperand(t3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001792 // Push the argument.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001793 __ sw(a2, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001794 // Fill the rest with holes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001795 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001796 for (int i = 1; i < kAllocationDelta; i++) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001797 __ sw(a3, MemOperand(end_elements, i * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001798 }
1799
1800 // Update elements' and array's sizes.
1801 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1802 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta)));
1803 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1804
1805 // Elements are in new space, so write barrier is not required.
1806 __ Drop(argc + 1);
1807 __ Ret();
1808 }
1809 __ bind(&call_builtin);
1810 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
1811 masm()->isolate()),
1812 argc + 1,
1813 1);
1814 }
1815
1816 // Handle call cache miss.
1817 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001818 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001819
1820 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001821 return GetCode(function);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001822}
1823
1824
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001825Handle<Code> CallStubCompiler::CompileArrayPopCall(
1826 Handle<Object> object,
1827 Handle<JSObject> holder,
1828 Handle<JSGlobalPropertyCell> cell,
1829 Handle<JSFunction> function,
1830 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001831 // ----------- S t a t e -------------
1832 // -- a2 : name
1833 // -- ra : return address
1834 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1835 // -- ...
1836 // -- sp[argc * 4] : receiver
1837 // -----------------------------------
1838
1839 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001840 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001841
1842 Label miss, return_undefined, call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001843 Register receiver = a1;
1844 Register elements = a3;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001845 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001846
1847 // Get the receiver from the stack.
1848 const int argc = arguments().immediate();
1849 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001850 // Check that the receiver isn't a smi.
1851 __ JumpIfSmi(receiver, &miss);
1852
1853 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001854 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, elements,
1855 t0, v0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001856
1857 // Get the elements array of the object.
1858 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1859
1860 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001861 __ CheckMap(elements,
1862 v0,
1863 Heap::kFixedArrayMapRootIndex,
1864 &call_builtin,
1865 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001866
1867 // Get the array's length into t0 and calculate new length.
1868 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1869 __ Subu(t0, t0, Operand(Smi::FromInt(1)));
1870 __ Branch(&return_undefined, lt, t0, Operand(zero_reg));
1871
1872 // Get the last element.
1873 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1874 STATIC_ASSERT(kSmiTagSize == 1);
1875 STATIC_ASSERT(kSmiTag == 0);
1876 // We can't address the last element in one operation. Compute the more
1877 // expensive shift first, and use an offset later on.
1878 __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize);
1879 __ Addu(elements, elements, t1);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001880 __ lw(v0, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001881 __ Branch(&call_builtin, eq, v0, Operand(t2));
1882
1883 // Set the array's length.
1884 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1885
1886 // Fill with the hole.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001887 __ sw(t2, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001888 __ Drop(argc + 1);
1889 __ Ret();
1890
1891 __ bind(&return_undefined);
1892 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
1893 __ Drop(argc + 1);
1894 __ Ret();
1895
1896 __ bind(&call_builtin);
1897 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop,
1898 masm()->isolate()),
1899 argc + 1,
1900 1);
1901
1902 // Handle call cache miss.
1903 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001904 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001905
1906 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001907 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001908}
1909
1910
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001911Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1912 Handle<Object> object,
1913 Handle<JSObject> holder,
1914 Handle<JSGlobalPropertyCell> cell,
1915 Handle<JSFunction> function,
1916 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001917 // ----------- S t a t e -------------
1918 // -- a2 : function name
1919 // -- ra : return address
1920 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1921 // -- ...
1922 // -- sp[argc * 4] : receiver
1923 // -----------------------------------
1924
1925 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001926 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001927
1928 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001929 Label miss;
1930 Label name_miss;
1931 Label index_out_of_range;
1932
1933 Label* index_out_of_range_label = &index_out_of_range;
1934
danno@chromium.org40cb8782011-05-25 07:58:50 +00001935 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001936 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001937 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001938 index_out_of_range_label = &miss;
1939 }
1940
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001941 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001942
1943 // Check that the maps starting from the prototype haven't changed.
1944 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1945 Context::STRING_FUNCTION_INDEX,
1946 v0,
1947 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001948 ASSERT(!object.is_identical_to(holder));
1949 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1950 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001951
1952 Register receiver = a1;
1953 Register index = t1;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001954 Register result = v0;
1955 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1956 if (argc > 0) {
1957 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1958 } else {
1959 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1960 }
1961
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001962 StringCharCodeAtGenerator generator(receiver,
1963 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001964 result,
1965 &miss, // When not a string.
1966 &miss, // When not a number.
1967 index_out_of_range_label,
1968 STRING_INDEX_IS_NUMBER);
1969 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001970 __ Drop(argc + 1);
1971 __ Ret();
1972
1973 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001974 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001975
1976 if (index_out_of_range.is_linked()) {
1977 __ bind(&index_out_of_range);
1978 __ LoadRoot(v0, Heap::kNanValueRootIndex);
1979 __ Drop(argc + 1);
1980 __ Ret();
1981 }
1982
1983 __ bind(&miss);
1984 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001985 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001986 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001987 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001988
1989 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001990 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001991}
1992
1993
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001994Handle<Code> CallStubCompiler::CompileStringCharAtCall(
1995 Handle<Object> object,
1996 Handle<JSObject> holder,
1997 Handle<JSGlobalPropertyCell> cell,
1998 Handle<JSFunction> function,
1999 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002000 // ----------- S t a t e -------------
2001 // -- a2 : function name
2002 // -- ra : return address
2003 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2004 // -- ...
2005 // -- sp[argc * 4] : receiver
2006 // -----------------------------------
2007
2008 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002009 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002010
2011 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002012 Label miss;
2013 Label name_miss;
2014 Label index_out_of_range;
2015 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00002016 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002017 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002018 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002019 index_out_of_range_label = &miss;
2020 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002021 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002022
2023 // Check that the maps starting from the prototype haven't changed.
2024 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2025 Context::STRING_FUNCTION_INDEX,
2026 v0,
2027 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002028 ASSERT(!object.is_identical_to(holder));
2029 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2030 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002031
2032 Register receiver = v0;
2033 Register index = t1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00002034 Register scratch = a3;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002035 Register result = v0;
2036 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
2037 if (argc > 0) {
2038 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
2039 } else {
2040 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
2041 }
2042
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002043 StringCharAtGenerator generator(receiver,
2044 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00002045 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002046 result,
2047 &miss, // When not a string.
2048 &miss, // When not a number.
2049 index_out_of_range_label,
2050 STRING_INDEX_IS_NUMBER);
2051 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002052 __ Drop(argc + 1);
2053 __ Ret();
2054
2055 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002056 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002057
2058 if (index_out_of_range.is_linked()) {
2059 __ bind(&index_out_of_range);
2060 __ LoadRoot(v0, Heap::kEmptyStringRootIndex);
2061 __ Drop(argc + 1);
2062 __ Ret();
2063 }
2064
2065 __ bind(&miss);
2066 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002067 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002068 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002069 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002070
2071 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002072 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002073}
2074
2075
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002076Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
2077 Handle<Object> object,
2078 Handle<JSObject> holder,
2079 Handle<JSGlobalPropertyCell> cell,
2080 Handle<JSFunction> function,
2081 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002082 // ----------- S t a t e -------------
2083 // -- a2 : function name
2084 // -- ra : return address
2085 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2086 // -- ...
2087 // -- sp[argc * 4] : receiver
2088 // -----------------------------------
2089
2090 const int argc = arguments().immediate();
2091
2092 // If the object is not a JSObject or we got an unexpected number of
2093 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002094 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002095
2096 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002097 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002098
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002099 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002100 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
2101
2102 STATIC_ASSERT(kSmiTag == 0);
2103 __ JumpIfSmi(a1, &miss);
2104
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002105 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2106 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002107 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002108 ASSERT(cell->value() == *function);
2109 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2110 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002111 GenerateLoadFunctionFromCell(cell, function, &miss);
2112 }
2113
2114 // Load the char code argument.
2115 Register code = a1;
2116 __ lw(code, MemOperand(sp, 0 * kPointerSize));
2117
2118 // Check the code is a smi.
2119 Label slow;
2120 STATIC_ASSERT(kSmiTag == 0);
2121 __ JumpIfNotSmi(code, &slow);
2122
2123 // Convert the smi code to uint16.
2124 __ And(code, code, Operand(Smi::FromInt(0xffff)));
2125
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002126 StringCharFromCodeGenerator generator(code, v0);
2127 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002128 __ Drop(argc + 1);
2129 __ Ret();
2130
2131 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002132 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002133
2134 // Tail call the full function. We do not have to patch the receiver
2135 // because the function makes no use of it.
2136 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002137 __ InvokeFunction(
2138 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002139
2140 __ bind(&miss);
2141 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002142 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002143
2144 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002145 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002146}
2147
2148
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002149Handle<Code> CallStubCompiler::CompileMathFloorCall(
2150 Handle<Object> object,
2151 Handle<JSObject> holder,
2152 Handle<JSGlobalPropertyCell> cell,
2153 Handle<JSFunction> function,
2154 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002155 // ----------- S t a t e -------------
2156 // -- a2 : function name
2157 // -- ra : return address
2158 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2159 // -- ...
2160 // -- sp[argc * 4] : receiver
2161 // -----------------------------------
2162
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002163 if (!CpuFeatures::IsSupported(FPU)) {
2164 return Handle<Code>::null();
2165 }
2166
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002167 CpuFeatures::Scope scope_fpu(FPU);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002168 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002169 // If the object is not a JSObject or we got an unexpected number of
2170 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002171 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002172
2173 Label miss, slow;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002174 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002175
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002176 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002177 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002178 STATIC_ASSERT(kSmiTag == 0);
2179 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002180 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2181 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002182 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002183 ASSERT(cell->value() == *function);
2184 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2185 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002186 GenerateLoadFunctionFromCell(cell, function, &miss);
2187 }
2188
2189 // Load the (only) argument into v0.
2190 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2191
2192 // If the argument is a smi, just return.
2193 STATIC_ASSERT(kSmiTag == 0);
2194 __ And(t0, v0, Operand(kSmiTagMask));
2195 __ Drop(argc + 1, eq, t0, Operand(zero_reg));
2196 __ Ret(eq, t0, Operand(zero_reg));
2197
danno@chromium.org40cb8782011-05-25 07:58:50 +00002198 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002199
2200 Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return;
2201
2202 // If fpu is enabled, we use the floor instruction.
2203
2204 // Load the HeapNumber value.
2205 __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2206
2207 // Backup FCSR.
2208 __ cfc1(a3, FCSR);
2209 // Clearing FCSR clears the exception mask with no side-effects.
2210 __ ctc1(zero_reg, FCSR);
2211 // Convert the argument to an integer.
2212 __ floor_w_d(f0, f0);
2213
2214 // Start checking for special cases.
2215 // Get the argument exponent and clear the sign bit.
2216 __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize));
2217 __ And(t2, t1, Operand(~HeapNumber::kSignMask));
2218 __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord);
2219
2220 // Retrieve FCSR and check for fpu errors.
2221 __ cfc1(t5, FCSR);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002222 __ And(t5, t5, Operand(kFCSRExceptionFlagMask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002223 __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));
2224
2225 // Check for NaN, Infinity, and -Infinity.
2226 // They are invariant through a Math.Floor call, so just
2227 // return the original argument.
2228 __ Subu(t3, t2, Operand(HeapNumber::kExponentMask
2229 >> HeapNumber::kMantissaBitsInTopWord));
2230 __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg));
2231 // We had an overflow or underflow in the conversion. Check if we
2232 // have a big exponent.
2233 // If greater or equal, the argument is already round and in v0.
2234 __ Branch(&restore_fcsr_and_return, ge, t3,
2235 Operand(HeapNumber::kMantissaBits));
2236 __ Branch(&wont_fit_smi);
2237
2238 __ bind(&no_fpu_error);
2239 // Move the result back to v0.
2240 __ mfc1(v0, f0);
2241 // Check if the result fits into a smi.
2242 __ Addu(a1, v0, Operand(0x40000000));
2243 __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg));
2244 // Tag the result.
2245 STATIC_ASSERT(kSmiTag == 0);
2246 __ sll(v0, v0, kSmiTagSize);
2247
2248 // Check for -0.
2249 __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg));
2250 // t1 already holds the HeapNumber exponent.
2251 __ And(t0, t1, Operand(HeapNumber::kSignMask));
2252 // If our HeapNumber is negative it was -0, so load its address and return.
2253 // Else v0 is loaded with 0, so we can also just return.
2254 __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg));
2255 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2256
2257 __ bind(&restore_fcsr_and_return);
2258 // Restore FCSR and return.
2259 __ ctc1(a3, FCSR);
2260
2261 __ Drop(argc + 1);
2262 __ Ret();
2263
2264 __ bind(&wont_fit_smi);
2265 // Restore FCSR and fall to slow case.
2266 __ ctc1(a3, FCSR);
2267
2268 __ bind(&slow);
2269 // Tail call the full function. We do not have to patch the receiver
2270 // because the function makes no use of it.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002271 __ InvokeFunction(
2272 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002273
2274 __ bind(&miss);
2275 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002276 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002277
2278 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002279 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002280}
2281
2282
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002283Handle<Code> CallStubCompiler::CompileMathAbsCall(
2284 Handle<Object> object,
2285 Handle<JSObject> holder,
2286 Handle<JSGlobalPropertyCell> cell,
2287 Handle<JSFunction> function,
2288 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002289 // ----------- S t a t e -------------
2290 // -- a2 : function name
2291 // -- ra : return address
2292 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2293 // -- ...
2294 // -- sp[argc * 4] : receiver
2295 // -----------------------------------
2296
2297 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002298 // If the object is not a JSObject or we got an unexpected number of
2299 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002300 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002301
2302 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002303
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002304 GenerateNameCheck(name, &miss);
2305 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002306 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002307 STATIC_ASSERT(kSmiTag == 0);
2308 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002309 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2310 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002311 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002312 ASSERT(cell->value() == *function);
2313 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2314 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002315 GenerateLoadFunctionFromCell(cell, function, &miss);
2316 }
2317
2318 // Load the (only) argument into v0.
2319 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2320
2321 // Check if the argument is a smi.
2322 Label not_smi;
2323 STATIC_ASSERT(kSmiTag == 0);
2324 __ JumpIfNotSmi(v0, &not_smi);
2325
2326 // Do bitwise not or do nothing depending on the sign of the
2327 // argument.
2328 __ sra(t0, v0, kBitsPerInt - 1);
2329 __ Xor(a1, v0, t0);
2330
2331 // Add 1 or do nothing depending on the sign of the argument.
2332 __ Subu(v0, a1, t0);
2333
2334 // If the result is still negative, go to the slow case.
2335 // This only happens for the most negative smi.
2336 Label slow;
2337 __ Branch(&slow, lt, v0, Operand(zero_reg));
2338
2339 // Smi case done.
2340 __ Drop(argc + 1);
2341 __ Ret();
2342
2343 // Check if the argument is a heap number and load its exponent and
2344 // sign.
2345 __ bind(&not_smi);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002346 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002347 __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2348
2349 // Check the sign of the argument. If the argument is positive,
2350 // just return it.
2351 Label negative_sign;
2352 __ And(t0, a1, Operand(HeapNumber::kSignMask));
2353 __ Branch(&negative_sign, ne, t0, Operand(zero_reg));
2354 __ Drop(argc + 1);
2355 __ Ret();
2356
2357 // If the argument is negative, clear the sign, and return a new
2358 // number.
2359 __ bind(&negative_sign);
2360 __ Xor(a1, a1, Operand(HeapNumber::kSignMask));
2361 __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2362 __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
2363 __ AllocateHeapNumber(v0, t0, t1, t2, &slow);
2364 __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2365 __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2366 __ Drop(argc + 1);
2367 __ Ret();
2368
2369 // Tail call the full function. We do not have to patch the receiver
2370 // because the function makes no use of it.
2371 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002372 __ InvokeFunction(
2373 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002374
2375 __ bind(&miss);
2376 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002377 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002378
2379 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002380 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002381}
2382
2383
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002384Handle<Code> CallStubCompiler::CompileFastApiCall(
lrn@chromium.org7516f052011-03-30 08:52:27 +00002385 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002386 Handle<Object> object,
2387 Handle<JSObject> holder,
2388 Handle<JSGlobalPropertyCell> cell,
2389 Handle<JSFunction> function,
2390 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002391
danno@chromium.org40cb8782011-05-25 07:58:50 +00002392 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002393
2394 ASSERT(optimization.is_simple_api_call());
2395 // Bail out if object is a global object as we don't want to
2396 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002397 if (object->IsGlobalObject()) return Handle<Code>::null();
2398 if (!cell.is_null()) return Handle<Code>::null();
2399 if (!object->IsJSObject()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002400 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002401 Handle<JSObject>::cast(object), holder);
2402 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002403
2404 Label miss, miss_before_stack_reserved;
2405
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002406 GenerateNameCheck(name, &miss_before_stack_reserved);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002407
2408 // Get the receiver from the stack.
2409 const int argc = arguments().immediate();
2410 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2411
2412 // Check that the receiver isn't a smi.
2413 __ JumpIfSmi(a1, &miss_before_stack_reserved);
2414
2415 __ IncrementCounter(counters->call_const(), 1, a0, a3);
2416 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2417
2418 ReserveSpaceForFastApiCall(masm(), a0);
2419
2420 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002421 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002422 depth, &miss);
2423
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002424 GenerateFastApiDirectCall(masm(), optimization, argc);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002425
2426 __ bind(&miss);
2427 FreeSpaceForFastApiCall(masm());
2428
2429 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002430 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002431
2432 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002433 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002434}
2435
2436
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002437void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
2438 Handle<JSObject> holder,
2439 Handle<String> name,
2440 CheckType check,
2441 Label* success) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002442 // ----------- S t a t e -------------
2443 // -- a2 : name
2444 // -- ra : return address
2445 // -----------------------------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002446 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002447 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002448
2449 // Get the receiver from the stack.
2450 const int argc = arguments().immediate();
2451 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2452
2453 // Check that the receiver isn't a smi.
2454 if (check != NUMBER_CHECK) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002455 __ JumpIfSmi(a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002456 }
2457
2458 // Make sure that it's okay not to patch the on stack receiver
2459 // unless we're doing a receiver map check.
2460 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002461 switch (check) {
2462 case RECEIVER_MAP_CHECK:
2463 __ IncrementCounter(masm()->isolate()->counters()->call_const(),
2464 1, a0, a3);
2465
2466 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002467 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2468 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002469
2470 // Patch the receiver on the stack with the global proxy if
2471 // necessary.
2472 if (object->IsGlobalObject()) {
2473 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2474 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2475 }
2476 break;
2477
2478 case STRING_CHECK:
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002479 // Check that the object is a two-byte string or a symbol.
2480 __ GetObjectType(a1, a3, a3);
2481 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2482 // Check that the maps starting from the prototype haven't changed.
2483 GenerateDirectLoadGlobalFunctionPrototype(
2484 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
2485 CheckPrototypes(
2486 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2487 a0, holder, a3, a1, t0, name, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002488 break;
2489
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002490 case NUMBER_CHECK: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002491 Label fast;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002492 // Check that the object is a smi or a heap number.
2493 __ JumpIfSmi(a1, &fast);
2494 __ GetObjectType(a1, a0, a0);
2495 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
2496 __ bind(&fast);
2497 // Check that the maps starting from the prototype haven't changed.
2498 GenerateDirectLoadGlobalFunctionPrototype(
2499 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
2500 CheckPrototypes(
2501 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2502 a0, holder, a3, a1, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002503 break;
2504 }
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002505 case BOOLEAN_CHECK: {
2506 Label fast;
2507 // Check that the object is a boolean.
2508 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
2509 __ Branch(&fast, eq, a1, Operand(t0));
2510 __ LoadRoot(t0, Heap::kFalseValueRootIndex);
2511 __ Branch(&miss, ne, a1, Operand(t0));
2512 __ bind(&fast);
2513 // Check that the maps starting from the prototype haven't changed.
2514 GenerateDirectLoadGlobalFunctionPrototype(
2515 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
2516 CheckPrototypes(
2517 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2518 a0, holder, a3, a1, t0, name, &miss);
2519 break;
2520 }
2521 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002522
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002523 __ jmp(success);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002524
2525 // Handle call cache miss.
2526 __ bind(&miss);
2527
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002528 GenerateMissBranch();
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002529}
2530
2531
2532void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) {
2533 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
2534 ? CALL_AS_FUNCTION
2535 : CALL_AS_METHOD;
2536 __ InvokeFunction(
2537 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), call_kind);
2538}
2539
2540
2541Handle<Code> CallStubCompiler::CompileCallConstant(
2542 Handle<Object> object,
2543 Handle<JSObject> holder,
2544 Handle<String> name,
2545 CheckType check,
2546 Handle<JSFunction> function) {
2547 if (HasCustomCallGenerator(function)) {
2548 Handle<Code> code = CompileCustomCall(object, holder,
2549 Handle<JSGlobalPropertyCell>::null(),
2550 function, name);
2551 // A null handle means bail out to the regular compiler code below.
2552 if (!code.is_null()) return code;
2553 }
2554
2555 Label success;
2556
2557 CompileHandlerFrontend(object, holder, name, check, &success);
2558 __ bind(&success);
2559 CompileHandlerBackend(function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002560
2561 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002562 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002563}
2564
2565
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002566Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2567 Handle<JSObject> holder,
2568 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002569 // ----------- S t a t e -------------
2570 // -- a2 : name
2571 // -- ra : return address
2572 // -----------------------------------
2573
2574 Label miss;
2575
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002576 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002577
2578 // Get the number of arguments.
2579 const int argc = arguments().immediate();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002580 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002581 LookupPostInterceptor(holder, name, &lookup);
2582
2583 // Get the receiver from the stack.
2584 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2585
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002586 CallInterceptorCompiler compiler(this, arguments(), a2, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002587 compiler.Compile(masm(), object, holder, name, &lookup, a1, a3, t0, a0,
2588 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002589
2590 // Move returned value, the function to call, to a1.
2591 __ mov(a1, v0);
2592 // Restore receiver.
2593 __ lw(a0, MemOperand(sp, argc * kPointerSize));
2594
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002595 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002596
2597 // Handle call cache miss.
2598 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002599 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002600
2601 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002602 return GetCode(Code::INTERCEPTOR, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002603}
2604
2605
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002606Handle<Code> CallStubCompiler::CompileCallGlobal(
2607 Handle<JSObject> object,
2608 Handle<GlobalObject> holder,
2609 Handle<JSGlobalPropertyCell> cell,
2610 Handle<JSFunction> function,
2611 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002612 // ----------- S t a t e -------------
2613 // -- a2 : name
2614 // -- ra : return address
2615 // -----------------------------------
2616
2617 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002618 Handle<Code> code = CompileCustomCall(object, holder, cell, function, name);
2619 // A null handle means bail out to the regular compiler code below.
2620 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002621 }
2622
2623 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002624 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002625
2626 // Get the number of arguments.
2627 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002628 GenerateGlobalReceiverCheck(object, holder, name, &miss);
2629 GenerateLoadFunctionFromCell(cell, function, &miss);
2630
2631 // Patch the receiver on the stack with the global proxy if
2632 // necessary.
2633 if (object->IsGlobalObject()) {
2634 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
2635 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2636 }
2637
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002638 // Set up the context (function already in r1).
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002639 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
2640
2641 // Jump to the cached code (tail call).
2642 Counters* counters = masm()->isolate()->counters();
2643 __ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002644 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002645 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002646 ? CALL_AS_FUNCTION
2647 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002648 // We call indirectly through the code field in the function to
2649 // allow recompilation to take effect without changing any of the
2650 // call sites.
2651 __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
2652 __ InvokeCode(a3, expected, arguments(), JUMP_FUNCTION,
2653 NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002654
2655 // Handle call cache miss.
2656 __ bind(&miss);
2657 __ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002658 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002659
2660 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002661 return GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002662}
2663
2664
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002665Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +00002666 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002667 Handle<Map> transition,
2668 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002669 // ----------- S t a t e -------------
2670 // -- a0 : value
2671 // -- a1 : receiver
2672 // -- a2 : name
2673 // -- ra : return address
2674 // -----------------------------------
2675 Label miss;
2676
2677 // Name register might be clobbered.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002678 GenerateStoreField(masm(),
2679 object,
2680 index,
2681 transition,
2682 name,
2683 a1, a2, a3, t0,
2684 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002685 __ bind(&miss);
2686 __ li(a2, Operand(Handle<String>(name))); // Restore name.
2687 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2688 __ Jump(ic, RelocInfo::CODE_TARGET);
2689
2690 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002691 return GetCode(transition.is_null()
2692 ? Code::FIELD
2693 : Code::MAP_TRANSITION, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002694}
2695
2696
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002697Handle<Code> StoreStubCompiler::CompileStoreCallback(
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002698 Handle<String> name,
2699 Handle<JSObject> receiver,
2700 Handle<JSObject> holder,
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002701 Handle<ExecutableAccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002702 // ----------- S t a t e -------------
2703 // -- a0 : value
2704 // -- a1 : receiver
2705 // -- a2 : name
2706 // -- ra : return address
2707 // -----------------------------------
2708 Label miss;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002709 // Check that the maps haven't changed.
2710 __ JumpIfSmi(a1, &miss, a3);
2711 CheckPrototypes(receiver, a1, holder, a3, t0, t1, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002712
2713 // Stub never generated for non-global objects that require access
2714 // checks.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002715 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002716
2717 __ push(a1); // Receiver.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002718 __ li(a3, Operand(callback)); // Callback info.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002719 __ Push(a3, a2, a0);
2720
2721 // Do tail-call to the runtime system.
2722 ExternalReference store_callback_property =
2723 ExternalReference(IC_Utility(IC::kStoreCallbackProperty),
2724 masm()->isolate());
2725 __ TailCallExternalReference(store_callback_property, 4, 1);
2726
2727 // Handle store cache miss.
2728 __ bind(&miss);
2729 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2730 __ Jump(ic, RelocInfo::CODE_TARGET);
2731
2732 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002733 return GetCode(Code::CALLBACKS, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002734}
2735
2736
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002737#undef __
2738#define __ ACCESS_MASM(masm)
2739
2740
2741void StoreStubCompiler::GenerateStoreViaSetter(
2742 MacroAssembler* masm,
2743 Handle<JSFunction> setter) {
2744 // ----------- S t a t e -------------
2745 // -- a0 : value
2746 // -- a1 : receiver
2747 // -- a2 : name
2748 // -- ra : return address
2749 // -----------------------------------
2750 {
2751 FrameScope scope(masm, StackFrame::INTERNAL);
2752
2753 // Save value register, so we can restore it later.
2754 __ push(a0);
2755
2756 if (!setter.is_null()) {
2757 // Call the JavaScript setter with receiver and value on the stack.
2758 __ push(a1);
2759 __ push(a0);
2760 ParameterCount actual(1);
2761 __ InvokeFunction(setter, actual, CALL_FUNCTION, NullCallWrapper(),
2762 CALL_AS_METHOD);
2763 } else {
2764 // If we generate a global code snippet for deoptimization only, remember
2765 // the place to continue after deoptimization.
2766 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2767 }
2768
2769 // We have to return the passed value, not the return value of the setter.
2770 __ pop(v0);
2771
2772 // Restore context register.
2773 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2774 }
2775 __ Ret();
2776}
2777
2778
2779#undef __
2780#define __ ACCESS_MASM(masm())
2781
2782
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002783Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002784 Handle<String> name,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002785 Handle<JSObject> receiver,
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002786 Handle<JSObject> holder,
2787 Handle<JSFunction> setter) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002788 // ----------- S t a t e -------------
2789 // -- a0 : value
2790 // -- a1 : receiver
2791 // -- a2 : name
2792 // -- ra : return address
2793 // -----------------------------------
2794 Label miss;
2795
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002796 // Check that the maps haven't changed.
2797 __ JumpIfSmi(a1, &miss);
2798 CheckPrototypes(receiver, a1, holder, a3, t0, t1, name, &miss);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002799
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002800 GenerateStoreViaSetter(masm(), setter);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002801
2802 __ bind(&miss);
2803 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2804 __ Jump(ic, RelocInfo::CODE_TARGET);
2805
2806 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002807 return GetCode(Code::CALLBACKS, name);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002808}
2809
2810
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002811Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
2812 Handle<JSObject> receiver,
2813 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002814 // ----------- S t a t e -------------
2815 // -- a0 : value
2816 // -- a1 : receiver
2817 // -- a2 : name
2818 // -- ra : return address
2819 // -----------------------------------
2820 Label miss;
2821
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002822 // Check that the map of the object hasn't changed.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002823 __ CheckMap(a1, a3, Handle<Map>(receiver->map()), &miss,
2824 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002825
2826 // Perform global security token check if needed.
2827 if (receiver->IsJSGlobalProxy()) {
2828 __ CheckAccessGlobalProxy(a1, a3, &miss);
2829 }
2830
2831 // Stub is never generated for non-global objects that require access
2832 // checks.
2833 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2834
2835 __ Push(a1, a2, a0); // Receiver, name, value.
2836
2837 __ li(a0, Operand(Smi::FromInt(strict_mode_)));
2838 __ push(a0); // Strict mode.
2839
2840 // Do tail-call to the runtime system.
2841 ExternalReference store_ic_property =
2842 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty),
2843 masm()->isolate());
2844 __ TailCallExternalReference(store_ic_property, 4, 1);
2845
2846 // Handle store cache miss.
2847 __ bind(&miss);
2848 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2849 __ Jump(ic, RelocInfo::CODE_TARGET);
2850
2851 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002852 return GetCode(Code::INTERCEPTOR, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002853}
2854
2855
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002856Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2857 Handle<GlobalObject> object,
2858 Handle<JSGlobalPropertyCell> cell,
2859 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002860 // ----------- S t a t e -------------
2861 // -- a0 : value
2862 // -- a1 : receiver
2863 // -- a2 : name
2864 // -- ra : return address
2865 // -----------------------------------
2866 Label miss;
2867
2868 // Check that the map of the global has not changed.
2869 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2870 __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map())));
2871
2872 // Check that the value in the cell is not the hole. If it is, this
2873 // cell could have been deleted and reintroducing the global needs
2874 // to update the property details in the property dictionary of the
2875 // global object. We bail out to the runtime system to do that.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002876 __ li(t0, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002877 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
2878 __ lw(t2, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2879 __ Branch(&miss, eq, t1, Operand(t2));
2880
2881 // Store the value in the cell.
2882 __ sw(a0, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2883 __ mov(v0, a0); // Stored value must be returned in v0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002884 // Cells are always rescanned, so no write barrier here.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002885
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002886 Counters* counters = masm()->isolate()->counters();
2887 __ IncrementCounter(counters->named_store_global_inline(), 1, a1, a3);
2888 __ Ret();
2889
2890 // Handle store cache miss.
2891 __ bind(&miss);
2892 __ IncrementCounter(counters->named_store_global_inline_miss(), 1, a1, a3);
2893 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2894 __ Jump(ic, RelocInfo::CODE_TARGET);
2895
2896 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002897 return GetCode(Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002898}
2899
2900
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002901Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
2902 Handle<JSObject> object,
2903 Handle<JSObject> last,
2904 Handle<String> name,
2905 Handle<GlobalObject> global) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002906 // ----------- S t a t e -------------
2907 // -- a0 : receiver
2908 // -- ra : return address
2909 // -----------------------------------
2910 Label miss;
2911
2912 // Check that the receiver is not a smi.
2913 __ JumpIfSmi(a0, &miss);
2914
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002915 Register scratch = a1;
2916
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002917 // Check the maps of the full prototype chain.
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002918 Register result =
2919 CheckPrototypes(object, a0, last, a3, scratch, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002920
2921 // If the last object in the prototype chain is a global object,
2922 // check that the global property cell is empty.
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002923 if (!global.is_null()) {
2924 GenerateCheckPropertyCell(masm(), global, name, scratch, &miss);
2925 }
2926
2927 if (!last->HasFastProperties()) {
2928 __ lw(scratch, FieldMemOperand(result, HeapObject::kMapOffset));
2929 __ lw(scratch, FieldMemOperand(scratch, Map::kPrototypeOffset));
2930 __ Branch(&miss, ne, scratch, Operand(isolate()->factory()->null_value()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002931 }
2932
2933 // Return undefined if maps of the full prototype chain is still the same.
2934 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2935 __ Ret();
2936
2937 __ bind(&miss);
2938 GenerateLoadMiss(masm(), Code::LOAD_IC);
2939
2940 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002941 return GetCode(Code::NONEXISTENT, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00002942}
2943
2944
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002945Register* LoadStubCompiler::registers() {
2946 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2947 static Register registers[] = { a0, a2, a3, a1, t0, t1 };
2948 return registers;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002949}
2950
2951
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002952Register* KeyedLoadStubCompiler::registers() {
2953 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2954 static Register registers[] = { a1, a0, a2, a3, t0, t1 };
2955 return registers;
2956}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002957
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002958
2959void KeyedLoadStubCompiler::GenerateNameCheck(Handle<String> name,
2960 Register name_reg,
2961 Label* miss) {
2962 __ Branch(miss, ne, name_reg, Operand(name));
lrn@chromium.org7516f052011-03-30 08:52:27 +00002963}
2964
2965
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002966#undef __
2967#define __ ACCESS_MASM(masm)
2968
2969
2970void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
2971 Handle<JSFunction> getter) {
2972 // ----------- S t a t e -------------
2973 // -- a0 : receiver
2974 // -- a2 : name
2975 // -- ra : return address
2976 // -----------------------------------
2977 {
2978 FrameScope scope(masm, StackFrame::INTERNAL);
2979
2980 if (!getter.is_null()) {
2981 // Call the JavaScript getter with the receiver on the stack.
2982 __ push(a0);
2983 ParameterCount actual(0);
2984 __ InvokeFunction(getter, actual, CALL_FUNCTION, NullCallWrapper(),
2985 CALL_AS_METHOD);
2986 } else {
2987 // If we generate a global code snippet for deoptimization only, remember
2988 // the place to continue after deoptimization.
2989 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
2990 }
2991
2992 // Restore context register.
2993 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2994 }
2995 __ Ret();
2996}
2997
2998
2999#undef __
3000#define __ ACCESS_MASM(masm())
3001
3002
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003003Handle<Code> LoadStubCompiler::CompileLoadViaGetter(
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003004 Handle<JSObject> receiver,
3005 Handle<JSObject> holder,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00003006 Handle<String> name,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003007 Handle<JSFunction> getter) {
3008 // ----------- S t a t e -------------
3009 // -- a0 : receiver
3010 // -- a2 : name
3011 // -- ra : return address
3012 // -----------------------------------
3013 Label miss;
3014
3015 // Check that the maps haven't changed.
3016 __ JumpIfSmi(a0, &miss);
3017 CheckPrototypes(receiver, a0, holder, a3, t0, a1, name, &miss);
3018
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003019 GenerateLoadViaGetter(masm(), getter);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003020
3021 __ bind(&miss);
3022 GenerateLoadMiss(masm(), Code::LOAD_IC);
3023
3024 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003025 return GetCode(Code::CALLBACKS, name);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003026}
3027
3028
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003029Handle<Code> LoadStubCompiler::CompileLoadGlobal(
3030 Handle<JSObject> object,
3031 Handle<GlobalObject> holder,
3032 Handle<JSGlobalPropertyCell> cell,
3033 Handle<String> name,
3034 bool is_dont_delete) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003035 // ----------- S t a t e -------------
3036 // -- a0 : receiver
3037 // -- a2 : name
3038 // -- ra : return address
3039 // -----------------------------------
3040 Label miss;
3041
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003042 // Check that the map of the global has not changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003043 __ JumpIfSmi(a0, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003044 CheckPrototypes(object, a0, holder, a3, t0, a1, name, &miss);
3045
3046 // Get the value from the cell.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003047 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003048 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
3049
3050 // Check for deleted property if property can actually be deleted.
3051 if (!is_dont_delete) {
3052 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
3053 __ Branch(&miss, eq, t0, Operand(at));
3054 }
3055
3056 __ mov(v0, t0);
3057 Counters* counters = masm()->isolate()->counters();
3058 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
3059 __ Ret();
3060
3061 __ bind(&miss);
3062 __ IncrementCounter(counters->named_load_global_stub_miss(), 1, a1, a3);
3063 GenerateLoadMiss(masm(), Code::LOAD_IC);
3064
3065 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003066 return GetCode(Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003067}
3068
3069
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003070Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
3071 Handle<Map> receiver_map) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003072 // ----------- S t a t e -------------
3073 // -- ra : return address
3074 // -- a0 : key
3075 // -- a1 : receiver
3076 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003077 ElementsKind elements_kind = receiver_map->elements_kind();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003078 if (receiver_map->has_fast_elements() ||
3079 receiver_map->has_external_array_elements()) {
3080 Handle<Code> stub = KeyedLoadFastElementStub(
3081 receiver_map->instance_type() == JS_ARRAY_TYPE,
3082 elements_kind).GetCode();
3083 __ DispatchMap(a1, a2, receiver_map, stub, DO_SMI_CHECK);
3084 } else {
3085 Handle<Code> stub =
3086 KeyedLoadDictionaryElementStub().GetCode();
3087 __ DispatchMap(a1, a2, receiver_map, stub, DO_SMI_CHECK);
3088 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003089
3090 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
3091 __ Jump(ic, RelocInfo::CODE_TARGET);
3092
3093 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003094 return GetCode(Code::NORMAL, factory()->empty_string());
danno@chromium.org40cb8782011-05-25 07:58:50 +00003095}
3096
3097
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003098Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
3099 MapHandleList* receiver_maps,
3100 CodeHandleList* handler_ics) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003101 // ----------- S t a t e -------------
3102 // -- ra : return address
3103 // -- a0 : key
3104 // -- a1 : receiver
3105 // -----------------------------------
3106 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003107 __ JumpIfSmi(a1, &miss);
3108
danno@chromium.org40cb8782011-05-25 07:58:50 +00003109 int receiver_count = receiver_maps->length();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003110 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003111 for (int current = 0; current < receiver_count; ++current) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003112 __ Jump(handler_ics->at(current), RelocInfo::CODE_TARGET,
3113 eq, a2, Operand(receiver_maps->at(current)));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003114 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003115
3116 __ bind(&miss);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003117 Handle<Code> miss_ic = isolate()->builtins()->KeyedLoadIC_Miss();
3118 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003119
3120 // Return the generated code.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003121 return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003122}
3123
3124
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003125Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +00003126 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003127 Handle<Map> transition,
3128 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003129 // ----------- S t a t e -------------
3130 // -- a0 : value
3131 // -- a1 : key
3132 // -- a2 : receiver
3133 // -- ra : return address
3134 // -----------------------------------
3135
3136 Label miss;
3137
3138 Counters* counters = masm()->isolate()->counters();
3139 __ IncrementCounter(counters->keyed_store_field(), 1, a3, t0);
3140
3141 // Check that the name has not changed.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003142 __ Branch(&miss, ne, a1, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003143
3144 // a3 is used as scratch register. a1 and a2 keep their values if a jump to
3145 // the miss label is generated.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003146 GenerateStoreField(masm(),
3147 object,
3148 index,
3149 transition,
3150 name,
3151 a2, a1, a3, t0,
3152 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003153 __ bind(&miss);
3154
3155 __ DecrementCounter(counters->keyed_store_field(), 1, a3, t0);
3156 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss();
3157 __ Jump(ic, RelocInfo::CODE_TARGET);
3158
3159 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003160 return GetCode(transition.is_null()
3161 ? Code::FIELD
3162 : Code::MAP_TRANSITION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003163}
3164
3165
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003166Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
3167 Handle<Map> receiver_map) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003168 // ----------- S t a t e -------------
3169 // -- a0 : value
3170 // -- a1 : key
3171 // -- a2 : receiver
3172 // -- ra : return address
3173 // -- a3 : scratch
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003174 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003175 ElementsKind elements_kind = receiver_map->elements_kind();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003176 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003177 Handle<Code> stub =
yangguo@chromium.org56454712012-02-16 15:33:53 +00003178 KeyedStoreElementStub(is_js_array, elements_kind, grow_mode_).GetCode();
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003179
3180 __ DispatchMap(a2, a3, receiver_map, stub, DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003181
danno@chromium.org40cb8782011-05-25 07:58:50 +00003182 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003183 __ Jump(ic, RelocInfo::CODE_TARGET);
3184
3185 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003186 return GetCode(Code::NORMAL, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00003187}
3188
3189
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003190Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
3191 MapHandleList* receiver_maps,
3192 CodeHandleList* handler_stubs,
3193 MapHandleList* transitioned_maps) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003194 // ----------- S t a t e -------------
3195 // -- a0 : value
3196 // -- a1 : key
3197 // -- a2 : receiver
3198 // -- ra : return address
3199 // -- a3 : scratch
3200 // -----------------------------------
3201 Label miss;
3202 __ JumpIfSmi(a2, &miss);
3203
3204 int receiver_count = receiver_maps->length();
3205 __ lw(a3, FieldMemOperand(a2, HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003206 for (int i = 0; i < receiver_count; ++i) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003207 if (transitioned_maps->at(i).is_null()) {
3208 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq,
3209 a3, Operand(receiver_maps->at(i)));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003210 } else {
3211 Label next_map;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003212 __ Branch(&next_map, ne, a3, Operand(receiver_maps->at(i)));
3213 __ li(a3, Operand(transitioned_maps->at(i)));
3214 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003215 __ bind(&next_map);
3216 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003217 }
3218
3219 __ bind(&miss);
3220 Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
3221 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3222
3223 // Return the generated code.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003224 return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003225}
3226
3227
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003228Handle<Code> ConstructStubCompiler::CompileConstructStub(
3229 Handle<JSFunction> function) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003230 // a0 : argc
3231 // a1 : constructor
3232 // ra : return address
3233 // [sp] : last argument
3234 Label generic_stub_call;
3235
3236 // Use t7 for holding undefined which is used in several places below.
3237 __ LoadRoot(t7, Heap::kUndefinedValueRootIndex);
3238
3239#ifdef ENABLE_DEBUGGER_SUPPORT
3240 // Check to see whether there are any break points in the function code. If
3241 // there are jump to the generic constructor stub which calls the actual
3242 // code for the function thereby hitting the break points.
3243 __ lw(t5, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3244 __ lw(a2, FieldMemOperand(t5, SharedFunctionInfo::kDebugInfoOffset));
3245 __ Branch(&generic_stub_call, ne, a2, Operand(t7));
3246#endif
3247
3248 // Load the initial map and verify that it is in fact a map.
3249 // a1: constructor function
3250 // t7: undefined
3251 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003252 __ JumpIfSmi(a2, &generic_stub_call);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003253 __ GetObjectType(a2, a3, t0);
3254 __ Branch(&generic_stub_call, ne, t0, Operand(MAP_TYPE));
3255
3256#ifdef DEBUG
3257 // Cannot construct functions this way.
3258 // a0: argc
3259 // a1: constructor function
3260 // a2: initial map
3261 // t7: undefined
3262 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
3263 __ Check(ne, "Function constructed by construct stub.",
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003264 a3, Operand(JS_FUNCTION_TYPE));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003265#endif
3266
3267 // Now allocate the JSObject in new space.
3268 // a0: argc
3269 // a1: constructor function
3270 // a2: initial map
3271 // t7: undefined
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003272 ASSERT(function->has_initial_map());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003273 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003274#ifdef DEBUG
3275 int instance_size = function->initial_map()->instance_size();
3276 __ Check(eq, "Instance size of initial map changed.",
3277 a3, Operand(instance_size >> kPointerSizeLog2));
3278#endif
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003279 __ AllocateInNewSpace(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003280
3281 // Allocated the JSObject, now initialize the fields. Map is set to initial
3282 // map and properties and elements are set to empty fixed array.
3283 // a0: argc
3284 // a1: constructor function
3285 // a2: initial map
3286 // a3: object size (in words)
3287 // t4: JSObject (not tagged)
3288 // t7: undefined
3289 __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex);
3290 __ mov(t5, t4);
3291 __ sw(a2, MemOperand(t5, JSObject::kMapOffset));
3292 __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset));
3293 __ sw(t6, MemOperand(t5, JSObject::kElementsOffset));
3294 __ Addu(t5, t5, Operand(3 * kPointerSize));
3295 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
3296 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
3297 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
3298
3299
3300 // Calculate the location of the first argument. The stack contains only the
3301 // argc arguments.
3302 __ sll(a1, a0, kPointerSizeLog2);
3303 __ Addu(a1, a1, sp);
3304
3305 // Fill all the in-object properties with undefined.
3306 // a0: argc
3307 // a1: first argument
3308 // a3: object size (in words)
3309 // t4: JSObject (not tagged)
3310 // t5: First in-object property of JSObject (not tagged)
3311 // t7: undefined
3312 // Fill the initialized properties with a constant value or a passed argument
3313 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003314 Handle<SharedFunctionInfo> shared(function->shared());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003315 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3316 if (shared->IsThisPropertyAssignmentArgument(i)) {
3317 Label not_passed, next;
3318 // Check if the argument assigned to the property is actually passed.
3319 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3320 __ Branch(&not_passed, less_equal, a0, Operand(arg_number));
3321 // Argument passed - find it on the stack.
3322 __ lw(a2, MemOperand(a1, (arg_number + 1) * -kPointerSize));
3323 __ sw(a2, MemOperand(t5));
3324 __ Addu(t5, t5, kPointerSize);
3325 __ jmp(&next);
3326 __ bind(&not_passed);
3327 // Set the property to undefined.
3328 __ sw(t7, MemOperand(t5));
3329 __ Addu(t5, t5, Operand(kPointerSize));
3330 __ bind(&next);
3331 } else {
3332 // Set the property to the constant value.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003333 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i),
3334 masm()->isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003335 __ li(a2, Operand(constant));
3336 __ sw(a2, MemOperand(t5));
3337 __ Addu(t5, t5, kPointerSize);
3338 }
3339 }
3340
3341 // Fill the unused in-object property fields with undefined.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003342 for (int i = shared->this_property_assignments_count();
3343 i < function->initial_map()->inobject_properties();
3344 i++) {
3345 __ sw(t7, MemOperand(t5));
3346 __ Addu(t5, t5, kPointerSize);
3347 }
3348
3349 // a0: argc
3350 // t4: JSObject (not tagged)
3351 // Move argc to a1 and the JSObject to return to v0 and tag it.
3352 __ mov(a1, a0);
3353 __ mov(v0, t4);
3354 __ Or(v0, v0, Operand(kHeapObjectTag));
3355
3356 // v0: JSObject
3357 // a1: argc
3358 // Remove caller arguments and receiver from the stack and return.
3359 __ sll(t0, a1, kPointerSizeLog2);
3360 __ Addu(sp, sp, t0);
3361 __ Addu(sp, sp, Operand(kPointerSize));
3362 Counters* counters = masm()->isolate()->counters();
3363 __ IncrementCounter(counters->constructed_objects(), 1, a1, a2);
3364 __ IncrementCounter(counters->constructed_objects_stub(), 1, a1, a2);
3365 __ Ret();
3366
3367 // Jump to the generic stub in case the specialized code cannot handle the
3368 // construction.
3369 __ bind(&generic_stub_call);
3370 Handle<Code> generic_construct_stub =
3371 masm()->isolate()->builtins()->JSConstructStubGeneric();
3372 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
3373
3374 // Return the generated code.
3375 return GetCode();
3376}
3377
3378
danno@chromium.org40cb8782011-05-25 07:58:50 +00003379#undef __
3380#define __ ACCESS_MASM(masm)
3381
3382
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003383void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3384 MacroAssembler* masm) {
3385 // ---------- S t a t e --------------
3386 // -- ra : return address
3387 // -- a0 : key
3388 // -- a1 : receiver
3389 // -----------------------------------
3390 Label slow, miss_force_generic;
3391
3392 Register key = a0;
3393 Register receiver = a1;
3394
3395 __ JumpIfNotSmi(key, &miss_force_generic);
3396 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
3397 __ sra(a2, a0, kSmiTagSize);
3398 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
3399 __ Ret();
3400
3401 // Slow case, key and receiver still in a0 and a1.
3402 __ bind(&slow);
3403 __ IncrementCounter(
3404 masm->isolate()->counters()->keyed_load_external_array_slow(),
3405 1, a2, a3);
3406 // Entry registers are intact.
3407 // ---------- S t a t e --------------
3408 // -- ra : return address
3409 // -- a0 : key
3410 // -- a1 : receiver
3411 // -----------------------------------
3412 Handle<Code> slow_ic =
3413 masm->isolate()->builtins()->KeyedLoadIC_Slow();
3414 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
3415
3416 // Miss case, call the runtime.
3417 __ bind(&miss_force_generic);
3418
3419 // ---------- S t a t e --------------
3420 // -- ra : return address
3421 // -- a0 : key
3422 // -- a1 : receiver
3423 // -----------------------------------
3424
3425 Handle<Code> miss_ic =
3426 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3427 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3428}
3429
3430
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003431static bool IsElementTypeSigned(ElementsKind elements_kind) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003432 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003433 case EXTERNAL_BYTE_ELEMENTS:
3434 case EXTERNAL_SHORT_ELEMENTS:
3435 case EXTERNAL_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003436 return true;
3437
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003438 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3439 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3440 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3441 case EXTERNAL_PIXEL_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003442 return false;
3443
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003444 case EXTERNAL_FLOAT_ELEMENTS:
3445 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003446 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003447 case FAST_ELEMENTS:
3448 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003449 case FAST_HOLEY_SMI_ELEMENTS:
3450 case FAST_HOLEY_ELEMENTS:
3451 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003452 case DICTIONARY_ELEMENTS:
3453 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003454 UNREACHABLE();
3455 return false;
3456 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003457 return false;
lrn@chromium.org7516f052011-03-30 08:52:27 +00003458}
3459
3460
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003461static void GenerateSmiKeyCheck(MacroAssembler* masm,
3462 Register key,
3463 Register scratch0,
3464 Register scratch1,
3465 FPURegister double_scratch0,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003466 FPURegister double_scratch1,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003467 Label* fail) {
3468 if (CpuFeatures::IsSupported(FPU)) {
3469 CpuFeatures::Scope scope(FPU);
3470 Label key_ok;
3471 // Check for smi or a smi inside a heap number. We convert the heap
3472 // number and check if the conversion is exact and fits into the smi
3473 // range.
3474 __ JumpIfSmi(key, &key_ok);
3475 __ CheckMap(key,
3476 scratch0,
3477 Heap::kHeapNumberMapRootIndex,
3478 fail,
3479 DONT_DO_SMI_CHECK);
3480 __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
3481 __ EmitFPUTruncate(kRoundToZero,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003482 scratch0,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003483 double_scratch0,
3484 at,
3485 double_scratch1,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003486 scratch1,
3487 kCheckForInexactConversion);
3488
3489 __ Branch(fail, ne, scratch1, Operand(zero_reg));
3490
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003491 __ SmiTagCheckOverflow(key, scratch0, scratch1);
3492 __ BranchOnOverflow(fail, scratch1);
3493 __ bind(&key_ok);
3494 } else {
3495 // Check that the key is a smi.
3496 __ JumpIfNotSmi(key, fail);
3497 }
3498}
3499
3500
danno@chromium.org40cb8782011-05-25 07:58:50 +00003501void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3502 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003503 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003504 // ---------- S t a t e --------------
3505 // -- a0 : value
3506 // -- a1 : key
3507 // -- a2 : receiver
3508 // -- ra : return address
3509 // -----------------------------------
3510
danno@chromium.org40cb8782011-05-25 07:58:50 +00003511 Label slow, check_heap_number, miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003512
3513 // Register usage.
3514 Register value = a0;
3515 Register key = a1;
3516 Register receiver = a2;
3517 // a3 mostly holds the elements array or the destination external array.
3518
danno@chromium.org40cb8782011-05-25 07:58:50 +00003519 // This stub is meant to be tail-jumped to, the receiver must already
3520 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003521
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003522 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003523 GenerateSmiKeyCheck(masm, key, t0, t1, f2, f4, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003524
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003525 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3526
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003527 // Check that the index is in range.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003528 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3529 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003530 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003531
3532 // Handle both smis and HeapNumbers in the fast path. Go to the
3533 // runtime for all other kinds of values.
3534 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003535
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003536 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003537 // Double to pixel conversion is only implemented in the runtime for now.
3538 __ JumpIfNotSmi(value, &slow);
3539 } else {
3540 __ JumpIfNotSmi(value, &check_heap_number);
3541 }
3542 __ SmiUntag(t1, value);
3543 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3544
3545 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003546 // t1: value (integer).
3547
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003548 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003549 case EXTERNAL_PIXEL_ELEMENTS: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003550 // Clamp the value to [0..255].
3551 // v0 is used as a scratch register here.
3552 Label done;
3553 __ li(v0, Operand(255));
3554 // Normal branch: nop in delay slot.
3555 __ Branch(&done, gt, t1, Operand(v0));
3556 // Use delay slot in this branch.
3557 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg));
3558 __ mov(v0, zero_reg); // In delay slot.
3559 __ mov(v0, t1); // Value is in range 0..255.
3560 __ bind(&done);
3561 __ mov(t1, v0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003562
3563 __ srl(t8, key, 1);
3564 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003565 __ sb(t1, MemOperand(t8, 0));
3566 }
3567 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003568 case EXTERNAL_BYTE_ELEMENTS:
3569 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003570 __ srl(t8, key, 1);
3571 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003572 __ sb(t1, MemOperand(t8, 0));
3573 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003574 case EXTERNAL_SHORT_ELEMENTS:
3575 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003576 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003577 __ sh(t1, MemOperand(t8, 0));
3578 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003579 case EXTERNAL_INT_ELEMENTS:
3580 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003581 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003582 __ addu(t8, a3, t8);
3583 __ sw(t1, MemOperand(t8, 0));
3584 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003585 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003586 // Perform int-to-float conversion and store to memory.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003587 __ SmiUntag(t0, key);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003588 StoreIntAsFloat(masm, a3, t0, t1, t2, t3, t4);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003589 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003590 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003591 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003592 __ addu(a3, a3, t8);
3593 // a3: effective address of the double element
3594 FloatingPointHelper::Destination destination;
3595 if (CpuFeatures::IsSupported(FPU)) {
3596 destination = FloatingPointHelper::kFPURegisters;
3597 } else {
3598 destination = FloatingPointHelper::kCoreRegisters;
3599 }
3600 FloatingPointHelper::ConvertIntToDouble(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003601 masm, t1, destination,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003602 f0, t2, t3, // These are: double_dst, dst_mantissa, dst_exponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003603 t0, f2); // These are: scratch2, single_scratch.
3604 if (destination == FloatingPointHelper::kFPURegisters) {
3605 CpuFeatures::Scope scope(FPU);
3606 __ sdc1(f0, MemOperand(a3, 0));
3607 } else {
3608 __ sw(t2, MemOperand(a3, 0));
3609 __ sw(t3, MemOperand(a3, Register::kSizeInBytes));
3610 }
3611 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003612 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003613 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003614 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003615 case FAST_HOLEY_ELEMENTS:
3616 case FAST_HOLEY_SMI_ELEMENTS:
3617 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003618 case DICTIONARY_ELEMENTS:
3619 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003620 UNREACHABLE();
3621 break;
3622 }
3623
3624 // Entry registers are intact, a0 holds the value which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003625 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003626 __ Ret();
3627
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003628 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003629 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003630 __ bind(&check_heap_number);
3631 __ GetObjectType(value, t1, t2);
3632 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE));
3633
3634 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3635
3636 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003637
3638 // The WebGL specification leaves the behavior of storing NaN and
3639 // +/-Infinity into integer arrays basically undefined. For more
3640 // reproducible behavior, convert these to zero.
3641
3642 if (CpuFeatures::IsSupported(FPU)) {
3643 CpuFeatures::Scope scope(FPU);
3644
3645 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
3646
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003647 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003648 __ cvt_s_d(f0, f0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003649 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003650 __ addu(t8, a3, t8);
3651 __ swc1(f0, MemOperand(t8, 0));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003652 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003653 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003654 __ addu(t8, a3, t8);
3655 __ sdc1(f0, MemOperand(t8, 0));
3656 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003657 __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003658
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003659 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003660 case EXTERNAL_BYTE_ELEMENTS:
3661 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003662 __ srl(t8, key, 1);
3663 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003664 __ sb(t3, MemOperand(t8, 0));
3665 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003666 case EXTERNAL_SHORT_ELEMENTS:
3667 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003668 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003669 __ sh(t3, MemOperand(t8, 0));
3670 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003671 case EXTERNAL_INT_ELEMENTS:
3672 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003673 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003674 __ addu(t8, a3, t8);
3675 __ sw(t3, MemOperand(t8, 0));
3676 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003677 case EXTERNAL_PIXEL_ELEMENTS:
3678 case EXTERNAL_FLOAT_ELEMENTS:
3679 case EXTERNAL_DOUBLE_ELEMENTS:
3680 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003681 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003682 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003683 case FAST_HOLEY_ELEMENTS:
3684 case FAST_HOLEY_SMI_ELEMENTS:
3685 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003686 case DICTIONARY_ELEMENTS:
3687 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003688 UNREACHABLE();
3689 break;
3690 }
3691 }
3692
3693 // Entry registers are intact, a0 holds the value
3694 // which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003695 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003696 __ Ret();
3697 } else {
3698 // FPU is not available, do manual conversions.
3699
3700 __ lw(t3, FieldMemOperand(value, HeapNumber::kExponentOffset));
3701 __ lw(t4, FieldMemOperand(value, HeapNumber::kMantissaOffset));
3702
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003703 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003704 Label done, nan_or_infinity_or_zero;
3705 static const int kMantissaInHiWordShift =
3706 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3707
3708 static const int kMantissaInLoWordShift =
3709 kBitsPerInt - kMantissaInHiWordShift;
3710
3711 // Test for all special exponent values: zeros, subnormal numbers, NaNs
3712 // and infinities. All these should be converted to 0.
3713 __ li(t5, HeapNumber::kExponentMask);
3714 __ and_(t6, t3, t5);
3715 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(zero_reg));
3716
3717 __ xor_(t1, t6, t5);
3718 __ li(t2, kBinary32ExponentMask);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003719 __ Movz(t6, t2, t1); // Only if t6 is equal to t5.
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003720 __ Branch(&nan_or_infinity_or_zero, eq, t1, Operand(zero_reg));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003721
3722 // Rebias exponent.
3723 __ srl(t6, t6, HeapNumber::kExponentShift);
3724 __ Addu(t6,
3725 t6,
3726 Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
3727
3728 __ li(t1, Operand(kBinary32MaxExponent));
3729 __ Slt(t1, t1, t6);
3730 __ And(t2, t3, Operand(HeapNumber::kSignMask));
3731 __ Or(t2, t2, Operand(kBinary32ExponentMask));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003732 __ Movn(t3, t2, t1); // Only if t6 is gt kBinary32MaxExponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003733 __ Branch(&done, gt, t6, Operand(kBinary32MaxExponent));
3734
3735 __ Slt(t1, t6, Operand(kBinary32MinExponent));
3736 __ And(t2, t3, Operand(HeapNumber::kSignMask));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003737 __ Movn(t3, t2, t1); // Only if t6 is lt kBinary32MinExponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003738 __ Branch(&done, lt, t6, Operand(kBinary32MinExponent));
3739
3740 __ And(t7, t3, Operand(HeapNumber::kSignMask));
3741 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3742 __ sll(t3, t3, kMantissaInHiWordShift);
3743 __ or_(t7, t7, t3);
3744 __ srl(t4, t4, kMantissaInLoWordShift);
3745 __ or_(t7, t7, t4);
3746 __ sll(t6, t6, kBinary32ExponentShift);
3747 __ or_(t3, t7, t6);
3748
3749 __ bind(&done);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003750 __ sll(t9, key, 1);
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003751 __ addu(t9, a3, t9);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003752 __ sw(t3, MemOperand(t9, 0));
3753
3754 // Entry registers are intact, a0 holds the value which is the return
3755 // value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003756 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003757 __ Ret();
3758
3759 __ bind(&nan_or_infinity_or_zero);
3760 __ And(t7, t3, Operand(HeapNumber::kSignMask));
3761 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3762 __ or_(t6, t6, t7);
3763 __ sll(t3, t3, kMantissaInHiWordShift);
3764 __ or_(t6, t6, t3);
3765 __ srl(t4, t4, kMantissaInLoWordShift);
3766 __ or_(t3, t6, t4);
3767 __ Branch(&done);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003768 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003769 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003770 __ addu(t8, a3, t8);
3771 // t8: effective address of destination element.
3772 __ sw(t4, MemOperand(t8, 0));
3773 __ sw(t3, MemOperand(t8, Register::kSizeInBytes));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003774 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003775 __ Ret();
3776 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003777 bool is_signed_type = IsElementTypeSigned(elements_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003778 int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
3779 int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
3780
3781 Label done, sign;
3782
3783 // Test for all special exponent values: zeros, subnormal numbers, NaNs
3784 // and infinities. All these should be converted to 0.
3785 __ li(t5, HeapNumber::kExponentMask);
3786 __ and_(t6, t3, t5);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003787 __ Movz(t3, zero_reg, t6); // Only if t6 is equal to zero.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003788 __ Branch(&done, eq, t6, Operand(zero_reg));
3789
3790 __ xor_(t2, t6, t5);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003791 __ Movz(t3, zero_reg, t2); // Only if t6 is equal to t5.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003792 __ Branch(&done, eq, t6, Operand(t5));
3793
3794 // Unbias exponent.
3795 __ srl(t6, t6, HeapNumber::kExponentShift);
3796 __ Subu(t6, t6, Operand(HeapNumber::kExponentBias));
3797 // If exponent is negative then result is 0.
3798 __ slt(t2, t6, zero_reg);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003799 __ Movn(t3, zero_reg, t2); // Only if exponent is negative.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003800 __ Branch(&done, lt, t6, Operand(zero_reg));
3801
3802 // If exponent is too big then result is minimal value.
3803 __ slti(t1, t6, meaningfull_bits - 1);
3804 __ li(t2, min_value);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003805 __ Movz(t3, t2, t1); // Only if t6 is ge meaningfull_bits - 1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003806 __ Branch(&done, ge, t6, Operand(meaningfull_bits - 1));
3807
3808 __ And(t5, t3, Operand(HeapNumber::kSignMask));
3809 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3810 __ Or(t3, t3, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
3811
3812 __ li(t9, HeapNumber::kMantissaBitsInTopWord);
3813 __ subu(t6, t9, t6);
3814 __ slt(t1, t6, zero_reg);
3815 __ srlv(t2, t3, t6);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003816 __ Movz(t3, t2, t1); // Only if t6 is positive.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003817 __ Branch(&sign, ge, t6, Operand(zero_reg));
3818
3819 __ subu(t6, zero_reg, t6);
3820 __ sllv(t3, t3, t6);
3821 __ li(t9, meaningfull_bits);
3822 __ subu(t6, t9, t6);
3823 __ srlv(t4, t4, t6);
3824 __ or_(t3, t3, t4);
3825
3826 __ bind(&sign);
3827 __ subu(t2, t3, zero_reg);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003828 __ Movz(t3, t2, t5); // Only if t5 is zero.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003829
3830 __ bind(&done);
3831
3832 // Result is in t3.
3833 // This switch block should be exactly the same as above (FPU mode).
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003834 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003835 case EXTERNAL_BYTE_ELEMENTS:
3836 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003837 __ srl(t8, key, 1);
3838 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003839 __ sb(t3, MemOperand(t8, 0));
3840 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003841 case EXTERNAL_SHORT_ELEMENTS:
3842 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003843 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003844 __ sh(t3, MemOperand(t8, 0));
3845 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003846 case EXTERNAL_INT_ELEMENTS:
3847 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003848 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003849 __ addu(t8, a3, t8);
3850 __ sw(t3, MemOperand(t8, 0));
3851 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003852 case EXTERNAL_PIXEL_ELEMENTS:
3853 case EXTERNAL_FLOAT_ELEMENTS:
3854 case EXTERNAL_DOUBLE_ELEMENTS:
3855 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003856 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003857 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003858 case FAST_HOLEY_ELEMENTS:
3859 case FAST_HOLEY_SMI_ELEMENTS:
3860 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003861 case DICTIONARY_ELEMENTS:
3862 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003863 UNREACHABLE();
3864 break;
3865 }
3866 }
3867 }
3868 }
3869
danno@chromium.org40cb8782011-05-25 07:58:50 +00003870 // Slow case, key and receiver still in a0 and a1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003871 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003872 __ IncrementCounter(
3873 masm->isolate()->counters()->keyed_load_external_array_slow(),
3874 1, a2, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003875 // Entry registers are intact.
3876 // ---------- S t a t e --------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003877 // -- ra : return address
danno@chromium.org40cb8782011-05-25 07:58:50 +00003878 // -- a0 : key
3879 // -- a1 : receiver
3880 // -----------------------------------
3881 Handle<Code> slow_ic =
3882 masm->isolate()->builtins()->KeyedStoreIC_Slow();
3883 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
3884
3885 // Miss case, call the runtime.
3886 __ bind(&miss_force_generic);
3887
3888 // ---------- S t a t e --------------
3889 // -- ra : return address
3890 // -- a0 : key
3891 // -- a1 : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003892 // -----------------------------------
3893
danno@chromium.org40cb8782011-05-25 07:58:50 +00003894 Handle<Code> miss_ic =
3895 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
3896 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3897}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003898
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003899
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003900void KeyedStoreStubCompiler::GenerateStoreFastElement(
3901 MacroAssembler* masm,
3902 bool is_js_array,
yangguo@chromium.org56454712012-02-16 15:33:53 +00003903 ElementsKind elements_kind,
3904 KeyedAccessGrowMode grow_mode) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003905 // ----------- S t a t e -------------
3906 // -- a0 : value
3907 // -- a1 : key
3908 // -- a2 : receiver
3909 // -- ra : return address
3910 // -- a3 : scratch
3911 // -- a4 : scratch (elements)
3912 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00003913 Label miss_force_generic, transition_elements_kind, grow, slow;
3914 Label finish_store, check_capacity;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003915
3916 Register value_reg = a0;
3917 Register key_reg = a1;
3918 Register receiver_reg = a2;
yangguo@chromium.org56454712012-02-16 15:33:53 +00003919 Register scratch = t0;
3920 Register elements_reg = a3;
3921 Register length_reg = t1;
3922 Register scratch2 = t2;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003923
3924 // This stub is meant to be tail-jumped to, the receiver must already
3925 // have been verified by the caller to not be a smi.
3926
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003927 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003928 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003929
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003930 if (IsFastSmiElementsKind(elements_kind)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003931 __ JumpIfNotSmi(value_reg, &transition_elements_kind);
3932 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003933
3934 // Check that the key is within bounds.
yangguo@chromium.org56454712012-02-16 15:33:53 +00003935 __ lw(elements_reg,
3936 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003937 if (is_js_array) {
3938 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3939 } else {
3940 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3941 }
3942 // Compare smis.
yangguo@chromium.org56454712012-02-16 15:33:53 +00003943 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
3944 __ Branch(&grow, hs, key_reg, Operand(scratch));
3945 } else {
3946 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
3947 }
3948
3949 // Make sure elements is a fast element array, not 'cow'.
3950 __ CheckMap(elements_reg,
3951 scratch,
3952 Heap::kFixedArrayMapRootIndex,
3953 &miss_force_generic,
3954 DONT_DO_SMI_CHECK);
3955
3956 __ bind(&finish_store);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003957
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003958 if (IsFastSmiElementsKind(elements_kind)) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003959 __ Addu(scratch,
3960 elements_reg,
3961 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3962 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
3963 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
3964 __ Addu(scratch, scratch, scratch2);
3965 __ sw(value_reg, MemOperand(scratch));
3966 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003967 ASSERT(IsFastObjectElementsKind(elements_kind));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003968 __ Addu(scratch,
3969 elements_reg,
3970 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3971 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
3972 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
3973 __ Addu(scratch, scratch, scratch2);
3974 __ sw(value_reg, MemOperand(scratch));
3975 __ mov(receiver_reg, value_reg);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003976 __ RecordWrite(elements_reg, // Object.
3977 scratch, // Address.
3978 receiver_reg, // Value.
3979 kRAHasNotBeenSaved,
3980 kDontSaveFPRegs);
3981 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003982 // value_reg (a0) is preserved.
3983 // Done.
3984 __ Ret();
3985
3986 __ bind(&miss_force_generic);
3987 Handle<Code> ic =
3988 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
3989 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003990
3991 __ bind(&transition_elements_kind);
3992 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
3993 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003994
3995 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
3996 // Grow the array by a single element if possible.
3997 __ bind(&grow);
3998
3999 // Make sure the array is only growing by a single element, anything else
4000 // must be handled by the runtime.
4001 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch));
4002
4003 // Check for the empty array, and preallocate a small backing store if
4004 // possible.
4005 __ lw(length_reg,
4006 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4007 __ lw(elements_reg,
4008 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4009 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
4010 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
4011
4012 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
4013 __ AllocateInNewSpace(size, elements_reg, scratch, scratch2, &slow,
4014 TAG_OBJECT);
4015
4016 __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex);
4017 __ sw(scratch, FieldMemOperand(elements_reg, JSObject::kMapOffset));
4018 __ li(scratch, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4019 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4020 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
4021 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
4022 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::SizeFor(i)));
4023 }
4024
4025 // Store the element at index zero.
4026 __ sw(value_reg, FieldMemOperand(elements_reg, FixedArray::SizeFor(0)));
4027
4028 // Install the new backing store in the JSArray.
4029 __ sw(elements_reg,
4030 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4031 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
4032 scratch, kRAHasNotBeenSaved, kDontSaveFPRegs,
4033 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4034
4035 // Increment the length of the array.
4036 __ li(length_reg, Operand(Smi::FromInt(1)));
4037 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4038 __ Ret();
4039
4040 __ bind(&check_capacity);
4041 // Check for cow elements, in general they are not handled by this stub
4042 __ CheckMap(elements_reg,
4043 scratch,
4044 Heap::kFixedCOWArrayMapRootIndex,
4045 &miss_force_generic,
4046 DONT_DO_SMI_CHECK);
4047
4048 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4049 __ Branch(&slow, hs, length_reg, Operand(scratch));
4050
4051 // Grow the array and finish the store.
4052 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
4053 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4054 __ jmp(&finish_store);
4055
4056 __ bind(&slow);
4057 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4058 __ Jump(ic_slow, RelocInfo::CODE_TARGET);
4059 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004060}
4061
4062
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004063void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
4064 MacroAssembler* masm,
yangguo@chromium.org56454712012-02-16 15:33:53 +00004065 bool is_js_array,
4066 KeyedAccessGrowMode grow_mode) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004067 // ----------- S t a t e -------------
4068 // -- a0 : value
4069 // -- a1 : key
4070 // -- a2 : receiver
4071 // -- ra : return address
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004072 // -- a3 : scratch (elements backing store)
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004073 // -- t0 : scratch (elements_reg)
4074 // -- t1 : scratch (mantissa_reg)
4075 // -- t2 : scratch (exponent_reg)
4076 // -- t3 : scratch4
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004077 // -- t4 : scratch
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004078 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00004079 Label miss_force_generic, transition_elements_kind, grow, slow;
4080 Label finish_store, check_capacity;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004081
4082 Register value_reg = a0;
4083 Register key_reg = a1;
4084 Register receiver_reg = a2;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004085 Register elements_reg = a3;
4086 Register scratch1 = t0;
4087 Register scratch2 = t1;
4088 Register scratch3 = t2;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004089 Register scratch4 = t3;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004090 Register scratch5 = t4;
yangguo@chromium.org56454712012-02-16 15:33:53 +00004091 Register length_reg = t3;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004092
4093 // This stub is meant to be tail-jumped to, the receiver must already
4094 // have been verified by the caller to not be a smi.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004095
4096 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004097 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004098
4099 __ lw(elements_reg,
4100 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4101
4102 // Check that the key is within bounds.
4103 if (is_js_array) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004104 __ lw(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004105 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004106 __ lw(scratch1,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004107 FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4108 }
4109 // Compare smis, unsigned compare catches both negative and out-of-bound
4110 // indexes.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004111 if (grow_mode == ALLOW_JSARRAY_GROWTH) {
4112 __ Branch(&grow, hs, key_reg, Operand(scratch1));
4113 } else {
4114 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch1));
4115 }
4116
4117 __ bind(&finish_store);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004118
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004119 __ StoreNumberToDoubleElements(value_reg,
4120 key_reg,
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004121 // All registers after this are overwritten.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004122 elements_reg,
4123 scratch1,
4124 scratch2,
4125 scratch3,
4126 scratch4,
4127 &transition_elements_kind);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004128
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004129 __ Ret(USE_DELAY_SLOT);
4130 __ mov(v0, value_reg); // In delay slot.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004131
4132 // Handle store cache miss, replacing the ic with the generic stub.
4133 __ bind(&miss_force_generic);
4134 Handle<Code> ic =
4135 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4136 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004137
4138 __ bind(&transition_elements_kind);
4139 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4140 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
yangguo@chromium.org56454712012-02-16 15:33:53 +00004141
4142 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4143 // Grow the array by a single element if possible.
4144 __ bind(&grow);
4145
4146 // Make sure the array is only growing by a single element, anything else
4147 // must be handled by the runtime.
4148 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch1));
4149
4150 // Transition on values that can't be stored in a FixedDoubleArray.
4151 Label value_is_smi;
4152 __ JumpIfSmi(value_reg, &value_is_smi);
4153 __ lw(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
4154 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
4155 __ Branch(&transition_elements_kind, ne, scratch1, Operand(at));
4156 __ bind(&value_is_smi);
4157
4158 // Check for the empty array, and preallocate a small backing store if
4159 // possible.
4160 __ lw(length_reg,
4161 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4162 __ lw(elements_reg,
4163 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4164 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
4165 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
4166
4167 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
4168 __ AllocateInNewSpace(size, elements_reg, scratch1, scratch2, &slow,
4169 TAG_OBJECT);
4170
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004171 // Initialize the new FixedDoubleArray.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004172 __ LoadRoot(scratch1, Heap::kFixedDoubleArrayMapRootIndex);
4173 __ sw(scratch1, FieldMemOperand(elements_reg, JSObject::kMapOffset));
4174 __ li(scratch1, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4175 __ sw(scratch1,
4176 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
4177
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004178 __ mov(scratch1, elements_reg);
4179 __ StoreNumberToDoubleElements(value_reg,
4180 key_reg,
4181 // All registers after this are overwritten.
4182 scratch1,
4183 scratch2,
4184 scratch3,
4185 scratch4,
4186 scratch5,
4187 &transition_elements_kind);
4188
4189 __ li(scratch1, Operand(kHoleNanLower32));
4190 __ li(scratch2, Operand(kHoleNanUpper32));
4191 for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) {
4192 int offset = FixedDoubleArray::OffsetOfElementAt(i);
4193 __ sw(scratch1, FieldMemOperand(elements_reg, offset));
4194 __ sw(scratch2, FieldMemOperand(elements_reg, offset + kPointerSize));
4195 }
4196
yangguo@chromium.org56454712012-02-16 15:33:53 +00004197 // Install the new backing store in the JSArray.
4198 __ sw(elements_reg,
4199 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4200 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
4201 scratch1, kRAHasNotBeenSaved, kDontSaveFPRegs,
4202 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4203
4204 // Increment the length of the array.
4205 __ li(length_reg, Operand(Smi::FromInt(1)));
4206 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
danno@chromium.org00379b82012-05-04 09:16:29 +00004207 __ lw(elements_reg,
4208 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004209 __ Ret();
yangguo@chromium.org56454712012-02-16 15:33:53 +00004210
4211 __ bind(&check_capacity);
4212 // Make sure that the backing store can hold additional elements.
4213 __ lw(scratch1,
4214 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
4215 __ Branch(&slow, hs, length_reg, Operand(scratch1));
4216
4217 // Grow the array and finish the store.
4218 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
4219 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4220 __ jmp(&finish_store);
4221
4222 __ bind(&slow);
4223 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4224 __ Jump(ic_slow, RelocInfo::CODE_TARGET);
4225 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004226}
4227
4228
ager@chromium.org5c838252010-02-19 08:53:10 +00004229#undef __
4230
4231} } // namespace v8::internal
4232
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004233#endif // V8_TARGET_ARCH_MIPS