blob: 0f205c144af2b67703d7007a0ab61ca566d0aa9f [file] [log] [blame]
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001// Copyright 2012 the V8 project authors. All rights reserved.
ager@chromium.org5c838252010-02-19 08:53:10 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000030#if defined(V8_TARGET_ARCH_MIPS)
31
ager@chromium.org5c838252010-02-19 08:53:10 +000032#include "ic-inl.h"
karlklose@chromium.org83a47282011-05-11 11:54:09 +000033#include "codegen.h"
ager@chromium.org5c838252010-02-19 08:53:10 +000034#include "stub-cache.h"
35
36namespace v8 {
37namespace internal {
38
39#define __ ACCESS_MASM(masm)
40
41
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000042static void ProbeTable(Isolate* isolate,
43 MacroAssembler* masm,
44 Code::Flags flags,
45 StubCache::Table table,
fschneider@chromium.org35814e52012-03-01 15:43:35 +000046 Register receiver,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000047 Register name,
fschneider@chromium.org35814e52012-03-01 15:43:35 +000048 // Number of the cache entry, not scaled.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000049 Register offset,
50 Register scratch,
fschneider@chromium.org35814e52012-03-01 15:43:35 +000051 Register scratch2,
52 Register offset_scratch) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000053 ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
54 ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
fschneider@chromium.org35814e52012-03-01 15:43:35 +000055 ExternalReference map_offset(isolate->stub_cache()->map_reference(table));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000056
57 uint32_t key_off_addr = reinterpret_cast<uint32_t>(key_offset.address());
58 uint32_t value_off_addr = reinterpret_cast<uint32_t>(value_offset.address());
fschneider@chromium.org35814e52012-03-01 15:43:35 +000059 uint32_t map_off_addr = reinterpret_cast<uint32_t>(map_offset.address());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000060
61 // Check the relative positions of the address fields.
62 ASSERT(value_off_addr > key_off_addr);
63 ASSERT((value_off_addr - key_off_addr) % 4 == 0);
64 ASSERT((value_off_addr - key_off_addr) < (256 * 4));
fschneider@chromium.org35814e52012-03-01 15:43:35 +000065 ASSERT(map_off_addr > key_off_addr);
66 ASSERT((map_off_addr - key_off_addr) % 4 == 0);
67 ASSERT((map_off_addr - key_off_addr) < (256 * 4));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000068
69 Label miss;
fschneider@chromium.org35814e52012-03-01 15:43:35 +000070 Register base_addr = scratch;
71 scratch = no_reg;
72
73 // Multiply by 3 because there are 3 fields per entry (name, code, map).
74 __ sll(offset_scratch, offset, 1);
75 __ Addu(offset_scratch, offset_scratch, offset);
76
77 // Calculate the base address of the entry.
78 __ li(base_addr, Operand(key_offset));
79 __ sll(at, offset_scratch, kPointerSizeLog2);
80 __ Addu(base_addr, base_addr, at);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000081
82 // Check that the key in the entry matches the name.
fschneider@chromium.org35814e52012-03-01 15:43:35 +000083 __ lw(at, MemOperand(base_addr, 0));
84 __ Branch(&miss, ne, name, Operand(at));
85
86 // Check the map matches.
87 __ lw(at, MemOperand(base_addr, map_off_addr - key_off_addr));
88 __ lw(scratch2, FieldMemOperand(receiver, HeapObject::kMapOffset));
89 __ Branch(&miss, ne, at, Operand(scratch2));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000090
91 // Get the code entry from the cache.
fschneider@chromium.org35814e52012-03-01 15:43:35 +000092 Register code = scratch2;
93 scratch2 = no_reg;
94 __ lw(code, MemOperand(base_addr, value_off_addr - key_off_addr));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000095
96 // Check that the flags match what we're looking for.
fschneider@chromium.org35814e52012-03-01 15:43:35 +000097 Register flags_reg = base_addr;
98 base_addr = no_reg;
99 __ lw(flags_reg, FieldMemOperand(code, Code::kFlagsOffset));
100 __ And(flags_reg, flags_reg, Operand(~Code::kFlagsNotUsedInLookup));
101 __ Branch(&miss, ne, flags_reg, Operand(flags));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000102
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000103#ifdef DEBUG
104 if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
105 __ jmp(&miss);
106 } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
107 __ jmp(&miss);
108 }
109#endif
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000110
111 // Jump to the first instruction in the code stub.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000112 __ Addu(at, code, Operand(Code::kHeaderSize - kHeapObjectTag));
113 __ Jump(at);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000114
115 // Miss: fall through.
116 __ bind(&miss);
117}
118
119
120// Helper function used to check that the dictionary doesn't contain
121// the property. This function may return false negatives, so miss_label
122// must always call a backup property check that is complete.
123// This function is safe to call if the receiver has fast properties.
124// Name must be a symbol and receiver must be a heap object.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000125static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
126 Label* miss_label,
127 Register receiver,
128 Handle<String> name,
129 Register scratch0,
130 Register scratch1) {
131 ASSERT(name->IsSymbol());
132 Counters* counters = masm->isolate()->counters();
133 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
134 __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
135
136 Label done;
137
138 const int kInterceptorOrAccessCheckNeededMask =
139 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
140
141 // Bail out if the receiver has a named interceptor or requires access checks.
142 Register map = scratch1;
143 __ lw(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
144 __ lbu(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
145 __ And(scratch0, scratch0, Operand(kInterceptorOrAccessCheckNeededMask));
146 __ Branch(miss_label, ne, scratch0, Operand(zero_reg));
147
148 // Check that receiver is a JSObject.
149 __ lbu(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
150 __ Branch(miss_label, lt, scratch0, Operand(FIRST_SPEC_OBJECT_TYPE));
151
152 // Load properties array.
153 Register properties = scratch0;
154 __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
155 // Check that the properties array is a dictionary.
156 __ lw(map, FieldMemOperand(properties, HeapObject::kMapOffset));
157 Register tmp = properties;
158 __ LoadRoot(tmp, Heap::kHashTableMapRootIndex);
159 __ Branch(miss_label, ne, map, Operand(tmp));
160
161 // Restore the temporarily used register.
162 __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
163
164
165 StringDictionaryLookupStub::GenerateNegativeLookup(masm,
166 miss_label,
167 &done,
168 receiver,
169 properties,
170 name,
171 scratch1);
172 __ bind(&done);
173 __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
174}
175
176
ager@chromium.org5c838252010-02-19 08:53:10 +0000177void StubCache::GenerateProbe(MacroAssembler* masm,
178 Code::Flags flags,
179 Register receiver,
180 Register name,
181 Register scratch,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000182 Register extra,
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000183 Register extra2,
184 Register extra3) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000185 Isolate* isolate = masm->isolate();
186 Label miss;
187
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000188 // Make sure that code is valid. The multiplying code relies on the
189 // entry size being 12.
190 ASSERT(sizeof(Entry) == 12);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000191
192 // Make sure the flags does not name a specific type.
193 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
194
195 // Make sure that there are no register conflicts.
196 ASSERT(!scratch.is(receiver));
197 ASSERT(!scratch.is(name));
198 ASSERT(!extra.is(receiver));
199 ASSERT(!extra.is(name));
200 ASSERT(!extra.is(scratch));
201 ASSERT(!extra2.is(receiver));
202 ASSERT(!extra2.is(name));
203 ASSERT(!extra2.is(scratch));
204 ASSERT(!extra2.is(extra));
205
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000206 // Check register validity.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000207 ASSERT(!scratch.is(no_reg));
208 ASSERT(!extra.is(no_reg));
209 ASSERT(!extra2.is(no_reg));
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000210 ASSERT(!extra3.is(no_reg));
211
212 Counters* counters = masm->isolate()->counters();
213 __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1,
214 extra2, extra3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000215
216 // Check that the receiver isn't a smi.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000217 __ JumpIfSmi(receiver, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000218
219 // Get the map of the receiver and compute the hash.
220 __ lw(scratch, FieldMemOperand(name, String::kHashFieldOffset));
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000221 __ lw(at, FieldMemOperand(receiver, HeapObject::kMapOffset));
222 __ Addu(scratch, scratch, at);
223 uint32_t mask = kPrimaryTableSize - 1;
224 // We shift out the last two bits because they are not part of the hash and
225 // they are always 01 for maps.
226 __ srl(scratch, scratch, kHeapObjectTagSize);
227 __ Xor(scratch, scratch, Operand((flags >> kHeapObjectTagSize) & mask));
228 __ And(scratch, scratch, Operand(mask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000229
230 // Probe the primary table.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000231 ProbeTable(isolate,
232 masm,
233 flags,
234 kPrimary,
235 receiver,
236 name,
237 scratch,
238 extra,
239 extra2,
240 extra3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000241
242 // Primary miss: Compute hash for secondary probe.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000243 __ srl(at, name, kHeapObjectTagSize);
244 __ Subu(scratch, scratch, at);
245 uint32_t mask2 = kSecondaryTableSize - 1;
246 __ Addu(scratch, scratch, Operand((flags >> kHeapObjectTagSize) & mask2));
247 __ And(scratch, scratch, Operand(mask2));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000248
249 // Probe the secondary table.
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000250 ProbeTable(isolate,
251 masm,
252 flags,
253 kSecondary,
254 receiver,
255 name,
256 scratch,
257 extra,
258 extra2,
259 extra3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000260
261 // Cache miss: Fall-through and let caller handle the miss by
262 // entering the runtime system.
263 __ bind(&miss);
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000264 __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1,
265 extra2, extra3);
ager@chromium.org5c838252010-02-19 08:53:10 +0000266}
267
268
269void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
270 int index,
271 Register prototype) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000272 // Load the global or builtins object from the current context.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000273 __ lw(prototype,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000274 MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
275 // Load the native context from the global or builtins object.
276 __ lw(prototype,
277 FieldMemOperand(prototype, GlobalObject::kNativeContextOffset));
278 // Load the function from the native context.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000279 __ lw(prototype, MemOperand(prototype, Context::SlotOffset(index)));
280 // Load the initial map. The global functions all have initial maps.
281 __ lw(prototype,
282 FieldMemOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
283 // Load the prototype from the initial map.
284 __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000285}
286
287
lrn@chromium.org7516f052011-03-30 08:52:27 +0000288void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000289 MacroAssembler* masm,
290 int index,
291 Register prototype,
292 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000293 Isolate* isolate = masm->isolate();
294 // Check we're still in the same context.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000295 __ lw(prototype,
296 MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000297 ASSERT(!prototype.is(at));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000298 __ li(at, isolate->global_object());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000299 __ Branch(miss, ne, prototype, Operand(at));
300 // Get the global function with the given index.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000301 Handle<JSFunction> function(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000302 JSFunction::cast(isolate->native_context()->get(index)));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000303 // Load its initial map. The global functions all have initial maps.
304 __ li(prototype, Handle<Map>(function->initial_map()));
305 // Load the prototype from the initial map.
306 __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000307}
308
309
ager@chromium.org5c838252010-02-19 08:53:10 +0000310// Load a fast property out of a holder object (src). In-object properties
311// are loaded directly otherwise the property is loaded from the properties
312// fixed array.
313void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000314 Register dst,
315 Register src,
316 Handle<JSObject> holder,
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +0000317 PropertyIndex index) {
318 if (index.is_header_index()) {
319 int offset = index.header_index() * kPointerSize;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000320 __ lw(dst, FieldMemOperand(src, offset));
321 } else {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +0000322 // Adjust for the number of properties stored in the holder.
323 int slot = index.field_index() - holder->map()->inobject_properties();
324 if (slot < 0) {
325 // Get the property straight out of the holder.
326 int offset = holder->map()->instance_size() + (slot * kPointerSize);
327 __ lw(dst, FieldMemOperand(src, offset));
328 } else {
329 // Calculate the offset into the properties array.
330 int offset = slot * kPointerSize + FixedArray::kHeaderSize;
331 __ lw(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
332 __ lw(dst, FieldMemOperand(dst, offset));
333 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000334 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000335}
336
337
338void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
339 Register receiver,
340 Register scratch,
341 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000342 // Check that the receiver isn't a smi.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000343 __ JumpIfSmi(receiver, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000344
345 // Check that the object is a JS array.
346 __ GetObjectType(receiver, scratch, scratch);
347 __ Branch(miss_label, ne, scratch, Operand(JS_ARRAY_TYPE));
348
349 // Load length directly from the JS array.
350 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
351 __ Ret();
352}
353
354
355// Generate code to check if an object is a string. If the object is a
356// heap object, its map's instance type is left in the scratch1 register.
357// If this is not needed, scratch1 and scratch2 may be the same register.
358static void GenerateStringCheck(MacroAssembler* masm,
359 Register receiver,
360 Register scratch1,
361 Register scratch2,
362 Label* smi,
363 Label* non_string_object) {
364 // Check that the receiver isn't a smi.
365 __ JumpIfSmi(receiver, smi, t0);
366
367 // Check that the object is a string.
368 __ lw(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
369 __ lbu(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
370 __ And(scratch2, scratch1, Operand(kIsNotStringMask));
371 // The cast is to resolve the overload for the argument of 0x0.
372 __ Branch(non_string_object,
373 ne,
374 scratch2,
375 Operand(static_cast<int32_t>(kStringTag)));
ager@chromium.org5c838252010-02-19 08:53:10 +0000376}
377
378
lrn@chromium.org7516f052011-03-30 08:52:27 +0000379// Generate code to load the length from a string object and return the length.
380// If the receiver object is not a string or a wrapped string object the
381// execution continues at the miss label. The register containing the
382// receiver is potentially clobbered.
383void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
384 Register receiver,
385 Register scratch1,
386 Register scratch2,
387 Label* miss,
388 bool support_wrappers) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000389 Label check_wrapper;
390
391 // Check if the object is a string leaving the instance type in the
392 // scratch1 register.
393 GenerateStringCheck(masm, receiver, scratch1, scratch2, miss,
394 support_wrappers ? &check_wrapper : miss);
395
396 // Load length directly from the string.
397 __ lw(v0, FieldMemOperand(receiver, String::kLengthOffset));
398 __ Ret();
399
400 if (support_wrappers) {
401 // Check if the object is a JSValue wrapper.
402 __ bind(&check_wrapper);
403 __ Branch(miss, ne, scratch1, Operand(JS_VALUE_TYPE));
404
405 // Unwrap the value and check if the wrapped value is a string.
406 __ lw(scratch1, FieldMemOperand(receiver, JSValue::kValueOffset));
407 GenerateStringCheck(masm, scratch1, scratch2, scratch2, miss, miss);
408 __ lw(v0, FieldMemOperand(scratch1, String::kLengthOffset));
409 __ Ret();
410 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000411}
412
413
ager@chromium.org5c838252010-02-19 08:53:10 +0000414void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
415 Register receiver,
416 Register scratch1,
417 Register scratch2,
418 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000419 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
420 __ mov(v0, scratch1);
421 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000422}
423
424
lrn@chromium.org7516f052011-03-30 08:52:27 +0000425// Generate StoreField code, value is passed in a0 register.
ager@chromium.org5c838252010-02-19 08:53:10 +0000426// After executing generated code, the receiver_reg and name_reg
427// may be clobbered.
428void StubCompiler::GenerateStoreField(MacroAssembler* masm,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000429 Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +0000430 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000431 Handle<Map> transition,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000432 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +0000433 Register receiver_reg,
434 Register name_reg,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000435 Register scratch1,
436 Register scratch2,
ager@chromium.org5c838252010-02-19 08:53:10 +0000437 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000438 // a0 : value.
439 Label exit;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000440
441 LookupResult lookup(masm->isolate());
442 object->Lookup(*name, &lookup);
443 if (lookup.IsFound() && (lookup.IsReadOnly() || !lookup.IsCacheable())) {
444 // In sloppy mode, we could just return the value and be done. However, we
445 // might be in strict mode, where we have to throw. Since we cannot tell,
446 // go into slow case unconditionally.
447 __ jmp(miss_label);
448 return;
449 }
450
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000451 // Check that the map of the object hasn't changed.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000452 CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
453 : REQUIRE_EXACT_MAP;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000454 __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000455 DO_SMI_CHECK, mode);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000456
457 // Perform global security token check if needed.
458 if (object->IsJSGlobalProxy()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000459 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
460 }
461
462 // Check that we are allowed to write this.
463 if (!transition.is_null() && object->GetPrototype()->IsJSObject()) {
464 JSObject* holder;
465 if (lookup.IsFound()) {
466 holder = lookup.holder();
467 } else {
468 // Find the top object.
469 holder = *object;
470 do {
471 holder = JSObject::cast(holder->GetPrototype());
472 } while (holder->GetPrototype()->IsJSObject());
473 }
474 // We need an extra register, push
475 __ push(name_reg);
476 Label miss_pop, done_check;
477 CheckPrototypes(object, receiver_reg, Handle<JSObject>(holder), name_reg,
478 scratch1, scratch2, name, &miss_pop);
479 __ jmp(&done_check);
480 __ bind(&miss_pop);
481 __ pop(name_reg);
482 __ jmp(miss_label);
483 __ bind(&done_check);
484 __ pop(name_reg);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000485 }
486
487 // Stub never generated for non-global objects that require access
488 // checks.
489 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
490
491 // Perform map transition for the receiver if necessary.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000492 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000493 // The properties must be extended before we can store the value.
494 // We jump to a runtime call that extends the properties array.
495 __ push(receiver_reg);
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000496 __ li(a2, Operand(transition));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000497 __ Push(a2, a0);
498 __ TailCallExternalReference(
499 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
500 masm->isolate()),
501 3, 1);
502 return;
503 }
504
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +0000505 if (!transition.is_null()) {
verwaest@chromium.org37141392012-05-31 13:27:02 +0000506 // Update the map of the object.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000507 __ li(scratch1, Operand(transition));
508 __ sw(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
verwaest@chromium.org37141392012-05-31 13:27:02 +0000509
510 // Update the write barrier for the map field and pass the now unused
511 // name_reg as scratch register.
512 __ RecordWriteField(receiver_reg,
513 HeapObject::kMapOffset,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000514 scratch1,
verwaest@chromium.org37141392012-05-31 13:27:02 +0000515 name_reg,
516 kRAHasNotBeenSaved,
517 kDontSaveFPRegs,
518 OMIT_REMEMBERED_SET,
519 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000520 }
521
522 // Adjust for the number of properties stored in the object. Even in the
523 // face of a transition we can use the old map here because the size of the
524 // object and the number of in-object properties is not going to change.
525 index -= object->map()->inobject_properties();
526
527 if (index < 0) {
528 // Set the property straight into the object.
529 int offset = object->map()->instance_size() + (index * kPointerSize);
530 __ sw(a0, FieldMemOperand(receiver_reg, offset));
531
532 // Skip updating write barrier if storing a smi.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000533 __ JumpIfSmi(a0, &exit, scratch1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000534
535 // Update the write barrier for the array address.
536 // Pass the now unused name_reg as a scratch register.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000537 __ mov(name_reg, a0);
538 __ RecordWriteField(receiver_reg,
539 offset,
540 name_reg,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000541 scratch1,
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000542 kRAHasNotBeenSaved,
543 kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000544 } else {
545 // Write to the properties array.
546 int offset = index * kPointerSize + FixedArray::kHeaderSize;
547 // Get the properties array.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000548 __ lw(scratch1,
549 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
550 __ sw(a0, FieldMemOperand(scratch1, offset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000551
552 // Skip updating write barrier if storing a smi.
553 __ JumpIfSmi(a0, &exit);
554
555 // Update the write barrier for the array address.
556 // Ok to clobber receiver_reg and name_reg, since we return.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000557 __ mov(name_reg, a0);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000558 __ RecordWriteField(scratch1,
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000559 offset,
560 name_reg,
561 receiver_reg,
562 kRAHasNotBeenSaved,
563 kDontSaveFPRegs);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000564 }
565
566 // Return the value (register v0).
567 __ bind(&exit);
568 __ mov(v0, a0);
569 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +0000570}
571
572
573void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000574 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000575 Handle<Code> code = (kind == Code::LOAD_IC)
576 ? masm->isolate()->builtins()->LoadIC_Miss()
577 : masm->isolate()->builtins()->KeyedLoadIC_Miss();
578 __ Jump(code, RelocInfo::CODE_TARGET);
ager@chromium.org5c838252010-02-19 08:53:10 +0000579}
580
581
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000582void StubCompiler::GenerateStoreMiss(MacroAssembler* masm, Code::Kind kind) {
583 ASSERT(kind == Code::STORE_IC || kind == Code::KEYED_STORE_IC);
584 Handle<Code> code = (kind == Code::STORE_IC)
585 ? masm->isolate()->builtins()->StoreIC_Miss()
586 : masm->isolate()->builtins()->KeyedStoreIC_Miss();
587 __ Jump(code, RelocInfo::CODE_TARGET);
588}
589
590
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000591static void GenerateCallFunction(MacroAssembler* masm,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000592 Handle<Object> object,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000593 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000594 Label* miss,
595 Code::ExtraICState extra_ic_state) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000596 // ----------- S t a t e -------------
597 // -- a0: receiver
598 // -- a1: function to call
599 // -----------------------------------
600 // Check that the function really is a function.
601 __ JumpIfSmi(a1, miss);
602 __ GetObjectType(a1, a3, a3);
603 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
604
605 // Patch the receiver on the stack with the global proxy if
606 // necessary.
607 if (object->IsGlobalObject()) {
608 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
609 __ sw(a3, MemOperand(sp, arguments.immediate() * kPointerSize));
610 }
611
612 // Invoke the function.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000613 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
614 ? CALL_AS_FUNCTION
615 : CALL_AS_METHOD;
616 __ InvokeFunction(a1, arguments, JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000617}
618
619
620static void PushInterceptorArguments(MacroAssembler* masm,
621 Register receiver,
622 Register holder,
623 Register name,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000624 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000625 __ push(name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000626 Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
627 ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000628 Register scratch = name;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000629 __ li(scratch, Operand(interceptor));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000630 __ Push(scratch, receiver, holder);
631 __ lw(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
632 __ push(scratch);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000633 __ li(scratch, Operand(ExternalReference::isolate_address()));
634 __ push(scratch);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000635}
636
637
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000638static void CompileCallLoadPropertyWithInterceptor(
639 MacroAssembler* masm,
640 Register receiver,
641 Register holder,
642 Register name,
643 Handle<JSObject> holder_obj) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000644 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
645
646 ExternalReference ref =
647 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
648 masm->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000649 __ PrepareCEntryArgs(6);
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000650 __ PrepareCEntryFunction(ref);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000651
652 CEntryStub stub(1);
653 __ CallStub(&stub);
654}
655
656
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000657static const int kFastApiCallArguments = 4;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000658
659
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000660// Reserves space for the extra arguments to API function in the
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000661// caller's frame.
662//
663// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
664static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
665 Register scratch) {
666 ASSERT(Smi::FromInt(0) == 0);
667 for (int i = 0; i < kFastApiCallArguments; i++) {
668 __ push(zero_reg);
669 }
670}
671
672
673// Undoes the effects of ReserveSpaceForFastApiCall.
674static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
675 __ Drop(kFastApiCallArguments);
676}
677
678
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000679static void GenerateFastApiDirectCall(MacroAssembler* masm,
680 const CallOptimization& optimization,
681 int argc) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000682 // ----------- S t a t e -------------
683 // -- sp[0] : holder (set by CheckPrototypes)
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000684 // -- sp[4] : callee JS function
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000685 // -- sp[8] : call data
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000686 // -- sp[12] : isolate
687 // -- sp[16] : last JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000688 // -- ...
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000689 // -- sp[(argc + 3) * 4] : first JS argument
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000690 // -- sp[(argc + 4) * 4] : receiver
691 // -----------------------------------
692 // Get the function and setup the context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000693 Handle<JSFunction> function = optimization.constant_function();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000694 __ LoadHeapObject(t1, function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000695 __ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset));
696
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000697 // Pass the additional arguments.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000698 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
699 Handle<Object> call_data(api_call_info->data());
700 if (masm->isolate()->heap()->InNewSpace(*call_data)) {
701 __ li(a0, api_call_info);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000702 __ lw(t2, FieldMemOperand(a0, CallHandlerInfo::kDataOffset));
703 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000704 __ li(t2, call_data);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000705 }
706
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000707 __ li(t3, Operand(ExternalReference::isolate_address()));
708 // Store JS function, call data and isolate.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000709 __ sw(t1, MemOperand(sp, 1 * kPointerSize));
710 __ sw(t2, MemOperand(sp, 2 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000711 __ sw(t3, MemOperand(sp, 3 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000712
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000713 // Prepare arguments.
714 __ Addu(a2, sp, Operand(3 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000715
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000716 // Allocate the v8::Arguments structure in the arguments' space since
717 // it's not controlled by GC.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000718 const int kApiStackSpace = 4;
719
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000720 FrameScope frame_scope(masm, StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000721 __ EnterExitFrame(false, kApiStackSpace);
722
723 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
724 // struct from the function (which is currently the case). This means we pass
725 // the first argument in a1 instead of a0. TryCallApiFunctionAndReturn
726 // will handle setting up a0.
727
728 // a1 = v8::Arguments&
729 // Arguments is built at sp + 1 (sp is a reserved spot for ra).
730 __ Addu(a1, sp, kPointerSize);
731
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000732 // v8::Arguments::implicit_args_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000733 __ sw(a2, MemOperand(a1, 0 * kPointerSize));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000734 // v8::Arguments::values_
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000735 __ Addu(t0, a2, Operand(argc * kPointerSize));
736 __ sw(t0, MemOperand(a1, 1 * kPointerSize));
737 // v8::Arguments::length_ = argc
738 __ li(t0, Operand(argc));
739 __ sw(t0, MemOperand(a1, 2 * kPointerSize));
740 // v8::Arguments::is_construct_call = 0
741 __ sw(zero_reg, MemOperand(a1, 3 * kPointerSize));
742
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000743 const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000744 Address function_address = v8::ToCData<Address>(api_call_info->callback());
745 ApiFunction fun(function_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000746 ExternalReference ref =
747 ExternalReference(&fun,
748 ExternalReference::DIRECT_API_CALL,
749 masm->isolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000750 AllowExternalCallThatCantCauseGC scope(masm);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000751 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000752}
753
lrn@chromium.org7516f052011-03-30 08:52:27 +0000754class CallInterceptorCompiler BASE_EMBEDDED {
755 public:
756 CallInterceptorCompiler(StubCompiler* stub_compiler,
757 const ParameterCount& arguments,
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000758 Register name,
759 Code::ExtraICState extra_ic_state)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000760 : stub_compiler_(stub_compiler),
761 arguments_(arguments),
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000762 name_(name),
763 extra_ic_state_(extra_ic_state) {}
lrn@chromium.org7516f052011-03-30 08:52:27 +0000764
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000765 void Compile(MacroAssembler* masm,
766 Handle<JSObject> object,
767 Handle<JSObject> holder,
768 Handle<String> name,
769 LookupResult* lookup,
770 Register receiver,
771 Register scratch1,
772 Register scratch2,
773 Register scratch3,
774 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000775 ASSERT(holder->HasNamedInterceptor());
776 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
777
778 // Check that the receiver isn't a smi.
779 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000780 CallOptimization optimization(lookup);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000781 if (optimization.is_constant_call()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000782 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
783 holder, lookup, name, optimization, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000784 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000785 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
786 name, holder, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000787 }
788 }
789
790 private:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000791 void CompileCacheable(MacroAssembler* masm,
792 Handle<JSObject> object,
793 Register receiver,
794 Register scratch1,
795 Register scratch2,
796 Register scratch3,
797 Handle<JSObject> interceptor_holder,
798 LookupResult* lookup,
799 Handle<String> name,
800 const CallOptimization& optimization,
801 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000802 ASSERT(optimization.is_constant_call());
803 ASSERT(!lookup->holder()->IsGlobalObject());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000804 Counters* counters = masm->isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000805 int depth1 = kInvalidProtoDepth;
806 int depth2 = kInvalidProtoDepth;
807 bool can_do_fast_api_call = false;
808 if (optimization.is_simple_api_call() &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000809 !lookup->holder()->IsGlobalObject()) {
810 depth1 = optimization.GetPrototypeDepthOfExpectedType(
811 object, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000812 if (depth1 == kInvalidProtoDepth) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000813 depth2 = optimization.GetPrototypeDepthOfExpectedType(
814 interceptor_holder, Handle<JSObject>(lookup->holder()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000815 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000816 can_do_fast_api_call =
817 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000818 }
819
820 __ IncrementCounter(counters->call_const_interceptor(), 1,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000821 scratch1, scratch2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000822
823 if (can_do_fast_api_call) {
824 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1,
825 scratch1, scratch2);
826 ReserveSpaceForFastApiCall(masm, scratch1);
827 }
828
829 // Check that the maps from receiver to interceptor's holder
830 // haven't changed and thus we can invoke interceptor.
831 Label miss_cleanup;
832 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
833 Register holder =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000834 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
835 scratch1, scratch2, scratch3,
836 name, depth1, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000837
838 // Invoke an interceptor and if it provides a value,
839 // branch to |regular_invoke|.
840 Label regular_invoke;
841 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
842 &regular_invoke);
843
844 // Interceptor returned nothing for this property. Try to use cached
845 // constant function.
846
847 // Check that the maps from interceptor's holder to constant function's
848 // holder haven't changed and thus we can use cached constant function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000849 if (*interceptor_holder != lookup->holder()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000850 stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000851 Handle<JSObject>(lookup->holder()),
852 scratch1, scratch2, scratch3,
853 name, depth2, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000854 } else {
855 // CheckPrototypes has a side effect of fetching a 'holder'
856 // for API (object which is instanceof for the signature). It's
857 // safe to omit it here, as if present, it should be fetched
858 // by the previous CheckPrototypes.
859 ASSERT(depth2 == kInvalidProtoDepth);
860 }
861
862 // Invoke function.
863 if (can_do_fast_api_call) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000864 GenerateFastApiDirectCall(masm, optimization, arguments_.immediate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000865 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000866 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
867 ? CALL_AS_FUNCTION
868 : CALL_AS_METHOD;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000869 __ InvokeFunction(optimization.constant_function(), arguments_,
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000870 JUMP_FUNCTION, NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000871 }
872
873 // Deferred code for fast API call case---clean preallocated space.
874 if (can_do_fast_api_call) {
875 __ bind(&miss_cleanup);
876 FreeSpaceForFastApiCall(masm);
877 __ Branch(miss_label);
878 }
879
880 // Invoke a regular function.
881 __ bind(&regular_invoke);
882 if (can_do_fast_api_call) {
883 FreeSpaceForFastApiCall(masm);
884 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000885 }
886
887 void CompileRegular(MacroAssembler* masm,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000888 Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000889 Register receiver,
890 Register scratch1,
891 Register scratch2,
892 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000893 Handle<String> name,
894 Handle<JSObject> interceptor_holder,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000895 Label* miss_label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000896 Register holder =
897 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000898 scratch1, scratch2, scratch3,
899 name, miss_label);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000900
901 // Call a runtime function to load the interceptor property.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000902 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000903 // Save the name_ register across the call.
904 __ push(name_);
905
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000906 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000907
908 __ CallExternalReference(
909 ExternalReference(
910 IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
911 masm->isolate()),
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000912 6);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000913 // Restore the name_ register.
914 __ pop(name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000915 // Leave the internal frame.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000916 }
917
918 void LoadWithInterceptor(MacroAssembler* masm,
919 Register receiver,
920 Register holder,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000921 Handle<JSObject> holder_obj,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000922 Register scratch,
923 Label* interceptor_succeeded) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000924 {
925 FrameScope scope(masm, StackFrame::INTERNAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000926
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000927 __ Push(holder, name_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000928 CompileCallLoadPropertyWithInterceptor(masm,
929 receiver,
930 holder,
931 name_,
932 holder_obj);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000933 __ pop(name_); // Restore the name.
934 __ pop(receiver); // Restore the holder.
935 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000936 // If interceptor returns no-result sentinel, call the constant function.
937 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
938 __ Branch(interceptor_succeeded, ne, v0, Operand(scratch));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000939 }
940
941 StubCompiler* stub_compiler_;
942 const ParameterCount& arguments_;
943 Register name_;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000944 Code::ExtraICState extra_ic_state_;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000945};
946
947
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000948
949// Generate code to check that a global property cell is empty. Create
950// the property cell at compilation time if no cell exists for the
951// property.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000952static void GenerateCheckPropertyCell(MacroAssembler* masm,
953 Handle<GlobalObject> global,
954 Handle<String> name,
955 Register scratch,
956 Label* miss) {
957 Handle<JSGlobalPropertyCell> cell =
958 GlobalObject::EnsurePropertyCell(global, name);
959 ASSERT(cell->value()->IsTheHole());
960 __ li(scratch, Operand(cell));
961 __ lw(scratch,
962 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
963 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
964 __ Branch(miss, ne, scratch, Operand(at));
965}
966
967
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000968// Calls GenerateCheckPropertyCell for each global object in the prototype chain
969// from object to (but not including) holder.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000970static void GenerateCheckPropertyCells(MacroAssembler* masm,
971 Handle<JSObject> object,
972 Handle<JSObject> holder,
973 Handle<String> name,
974 Register scratch,
975 Label* miss) {
976 Handle<JSObject> current = object;
977 while (!current.is_identical_to(holder)) {
978 if (current->IsGlobalObject()) {
979 GenerateCheckPropertyCell(masm,
980 Handle<GlobalObject>::cast(current),
981 name,
982 scratch,
983 miss);
984 }
985 current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
986 }
987}
988
989
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000990// Convert and store int passed in register ival to IEEE 754 single precision
991// floating point value at memory location (dst + 4 * wordoffset)
992// If FPU is available use it for conversion.
993static void StoreIntAsFloat(MacroAssembler* masm,
994 Register dst,
995 Register wordoffset,
996 Register ival,
997 Register fval,
998 Register scratch1,
999 Register scratch2) {
1000 if (CpuFeatures::IsSupported(FPU)) {
1001 CpuFeatures::Scope scope(FPU);
1002 __ mtc1(ival, f0);
1003 __ cvt_s_w(f0, f0);
1004 __ sll(scratch1, wordoffset, 2);
1005 __ addu(scratch1, dst, scratch1);
1006 __ swc1(f0, MemOperand(scratch1, 0));
1007 } else {
1008 // FPU is not available, do manual conversions.
1009
1010 Label not_special, done;
1011 // Move sign bit from source to destination. This works because the sign
1012 // bit in the exponent word of the double has the same position and polarity
1013 // as the 2's complement sign bit in a Smi.
1014 ASSERT(kBinary32SignMask == 0x80000000u);
1015
1016 __ And(fval, ival, Operand(kBinary32SignMask));
1017 // Negate value if it is negative.
1018 __ subu(scratch1, zero_reg, ival);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001019 __ Movn(ival, scratch1, fval);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001020
1021 // We have -1, 0 or 1, which we treat specially. Register ival contains
1022 // absolute value: it is either equal to 1 (special case of -1 and 1),
1023 // greater than 1 (not a special case) or less than 1 (special case of 0).
1024 __ Branch(&not_special, gt, ival, Operand(1));
1025
1026 // For 1 or -1 we need to or in the 0 exponent (biased).
1027 static const uint32_t exponent_word_for_1 =
1028 kBinary32ExponentBias << kBinary32ExponentShift;
1029
1030 __ Xor(scratch1, ival, Operand(1));
1031 __ li(scratch2, exponent_word_for_1);
1032 __ or_(scratch2, fval, scratch2);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001033 __ Movz(fval, scratch2, scratch1); // Only if ival is equal to 1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001034 __ Branch(&done);
1035
1036 __ bind(&not_special);
1037 // Count leading zeros.
1038 // Gets the wrong answer for 0, but we already checked for that case above.
1039 Register zeros = scratch2;
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001040 __ Clz(zeros, ival);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001041
1042 // Compute exponent and or it into the exponent register.
1043 __ li(scratch1, (kBitsPerInt - 1) + kBinary32ExponentBias);
1044 __ subu(scratch1, scratch1, zeros);
1045
1046 __ sll(scratch1, scratch1, kBinary32ExponentShift);
1047 __ or_(fval, fval, scratch1);
1048
1049 // Shift up the source chopping the top bit off.
1050 __ Addu(zeros, zeros, Operand(1));
1051 // This wouldn't work for 1 and -1 as the shift would be 32 which means 0.
1052 __ sllv(ival, ival, zeros);
1053 // And the top (top 20 bits).
1054 __ srl(scratch1, ival, kBitsPerInt - kBinary32MantissaBits);
1055 __ or_(fval, fval, scratch1);
1056
1057 __ bind(&done);
1058
1059 __ sll(scratch1, wordoffset, 2);
1060 __ addu(scratch1, dst, scratch1);
1061 __ sw(fval, MemOperand(scratch1, 0));
1062 }
1063}
1064
1065
ager@chromium.org5c838252010-02-19 08:53:10 +00001066#undef __
1067#define __ ACCESS_MASM(masm())
1068
1069
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001070Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
1071 Register object_reg,
1072 Handle<JSObject> holder,
1073 Register holder_reg,
1074 Register scratch1,
1075 Register scratch2,
1076 Handle<String> name,
1077 int save_at_depth,
1078 Label* miss) {
1079 // Make sure there's no overlap between holder and object registers.
1080 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
1081 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
1082 && !scratch2.is(scratch1));
1083
1084 // Keep track of the current object in register reg.
1085 Register reg = object_reg;
1086 int depth = 0;
1087
1088 if (save_at_depth == depth) {
1089 __ sw(reg, MemOperand(sp));
1090 }
1091
1092 // Check the maps in the prototype chain.
1093 // Traverse the prototype chain from the object and do map checks.
1094 Handle<JSObject> current = object;
1095 while (!current.is_identical_to(holder)) {
1096 ++depth;
1097
1098 // Only global objects and objects that do not require access
1099 // checks are allowed in stubs.
1100 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
1101
1102 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
1103 if (!current->HasFastProperties() &&
1104 !current->IsJSGlobalObject() &&
1105 !current->IsJSGlobalProxy()) {
1106 if (!name->IsSymbol()) {
1107 name = factory()->LookupSymbol(name);
1108 }
1109 ASSERT(current->property_dictionary()->FindEntry(*name) ==
1110 StringDictionary::kNotFound);
1111
1112 GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
1113 scratch1, scratch2);
1114
1115 __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
1116 reg = holder_reg; // From now on the object will be in holder_reg.
1117 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1118 } else {
1119 Handle<Map> current_map(current->map());
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001120 __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK,
1121 ALLOW_ELEMENT_TRANSITION_MAPS);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001122 // Check access rights to the global object. This has to happen after
1123 // the map check so that we know that the object is actually a global
1124 // object.
1125 if (current->IsJSGlobalProxy()) {
1126 __ CheckAccessGlobalProxy(reg, scratch2, miss);
1127 }
1128 reg = holder_reg; // From now on the object will be in holder_reg.
1129
1130 if (heap()->InNewSpace(*prototype)) {
1131 // The prototype is in new space; we cannot store a reference to it
1132 // in the code. Load it from the map.
1133 __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
1134 } else {
1135 // The prototype is in old space; load it directly.
1136 __ li(reg, Operand(prototype));
1137 }
1138 }
1139
1140 if (save_at_depth == depth) {
1141 __ sw(reg, MemOperand(sp));
1142 }
1143
1144 // Go to the next object in the prototype chain.
1145 current = prototype;
1146 }
1147
1148 // Log the check depth.
1149 LOG(masm()->isolate(), IntEvent("check-maps-depth", depth + 1));
1150
1151 // Check the holder map.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001152 __ CheckMap(reg, scratch1, Handle<Map>(current->map()), miss,
1153 DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001154
1155 // Perform security check for access to the global object.
1156 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
1157 if (holder->IsJSGlobalProxy()) {
1158 __ CheckAccessGlobalProxy(reg, scratch1, miss);
1159 }
1160
1161 // If we've skipped any global objects, it's not enough to verify that
1162 // their maps haven't changed. We also need to check that the property
1163 // cell for the property is still empty.
1164 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
1165
1166 // Return the register containing the holder.
1167 return reg;
1168}
1169
1170
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001171void StubCompiler::GenerateLoadField(Handle<JSObject> object,
1172 Handle<JSObject> holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001173 Register receiver,
1174 Register scratch1,
1175 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001176 Register scratch3,
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00001177 PropertyIndex index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001178 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001179 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001180 // Check that the receiver isn't a smi.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001181 __ JumpIfSmi(receiver, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001182
1183 // Check that the maps haven't changed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001184 Register reg = CheckPrototypes(
1185 object, receiver, holder, scratch1, scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001186 GenerateFastPropertyLoad(masm(), v0, reg, holder, index);
1187 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001188}
1189
1190
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001191void StubCompiler::GenerateLoadConstant(Handle<JSObject> object,
1192 Handle<JSObject> holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001193 Register receiver,
1194 Register scratch1,
1195 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001196 Register scratch3,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001197 Handle<JSFunction> value,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001198 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001199 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001200 // Check that the receiver isn't a smi.
1201 __ JumpIfSmi(receiver, miss, scratch1);
1202
1203 // Check that the maps haven't changed.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001204 CheckPrototypes(object, receiver, holder,
1205 scratch1, scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001206
1207 // Return the constant value.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001208 __ LoadHeapObject(v0, value);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001209 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001210}
1211
1212
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001213void StubCompiler::GenerateDictionaryLoadCallback(Register receiver,
1214 Register name_reg,
1215 Register scratch1,
1216 Register scratch2,
1217 Register scratch3,
1218 Handle<AccessorInfo> callback,
1219 Handle<String> name,
1220 Label* miss) {
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001221 ASSERT(!receiver.is(scratch1));
1222 ASSERT(!receiver.is(scratch2));
1223 ASSERT(!receiver.is(scratch3));
1224
1225 // Load the properties dictionary.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001226 Register dictionary = scratch1;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001227 __ lw(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
1228
1229 // Probe the dictionary.
1230 Label probe_done;
1231 StringDictionaryLookupStub::GeneratePositiveLookup(masm(),
1232 miss,
1233 &probe_done,
1234 dictionary,
1235 name_reg,
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001236 scratch2,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001237 scratch3);
1238 __ bind(&probe_done);
1239
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001240 // If probing finds an entry in the dictionary, scratch3 contains the
1241 // pointer into the dictionary. Check that the value is the callback.
1242 Register pointer = scratch3;
1243 const int kElementsStartOffset = StringDictionary::kHeaderSize +
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001244 StringDictionary::kElementsStartIndex * kPointerSize;
1245 const int kValueOffset = kElementsStartOffset + kPointerSize;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001246 __ lw(scratch2, FieldMemOperand(pointer, kValueOffset));
1247 __ Branch(miss, ne, scratch2, Operand(callback));
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001248}
1249
1250
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001251void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
1252 Handle<JSObject> holder,
1253 Register receiver,
1254 Register name_reg,
1255 Register scratch1,
1256 Register scratch2,
1257 Register scratch3,
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001258 Register scratch4,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001259 Handle<AccessorInfo> callback,
1260 Handle<String> name,
1261 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001262 // Check that the receiver isn't a smi.
1263 __ JumpIfSmi(receiver, miss, scratch1);
1264
1265 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001266 Register reg = CheckPrototypes(object, receiver, holder, scratch1,
1267 scratch2, scratch3, name, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001268
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001269 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
1270 GenerateDictionaryLoadCallback(
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001271 reg, name_reg, scratch2, scratch3, scratch4, callback, name, miss);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001272 }
1273
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001274 // Build AccessorInfo::args_ list on the stack and push property name below
1275 // the exit frame to make GC aware of them and store pointers to them.
1276 __ push(receiver);
1277 __ mov(scratch2, sp); // scratch2 = AccessorInfo::args_
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001278 if (heap()->InNewSpace(callback->data())) {
1279 __ li(scratch3, callback);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001280 __ lw(scratch3, FieldMemOperand(scratch3, AccessorInfo::kDataOffset));
1281 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001282 __ li(scratch3, Handle<Object>(callback->data()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001283 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001284 __ Subu(sp, sp, 4 * kPointerSize);
1285 __ sw(reg, MemOperand(sp, 3 * kPointerSize));
1286 __ sw(scratch3, MemOperand(sp, 2 * kPointerSize));
1287 __ li(scratch3, Operand(ExternalReference::isolate_address()));
1288 __ sw(scratch3, MemOperand(sp, 1 * kPointerSize));
1289 __ sw(name_reg, MemOperand(sp, 0 * kPointerSize));
1290
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001291 __ mov(a2, scratch2); // Saved in case scratch2 == a1.
1292 __ mov(a1, sp); // a1 (first argument - see note below) = Handle<String>
1293
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001294 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a
1295 // struct from the function (which is currently the case). This means we pass
1296 // the arguments in a1-a2 instead of a0-a1. TryCallApiFunctionAndReturn
1297 // will handle setting up a0.
1298
1299 const int kApiStackSpace = 1;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001300 FrameScope frame_scope(masm(), StackFrame::MANUAL);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001301 __ EnterExitFrame(false, kApiStackSpace);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001302
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001303 // Create AccessorInfo instance on the stack above the exit frame with
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001304 // scratch2 (internal::Object** args_) as the data.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001305 __ sw(a2, MemOperand(sp, kPointerSize));
1306 // a2 (second argument - see note above) = AccessorInfo&
1307 __ Addu(a2, sp, kPointerSize);
1308
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001309 const int kStackUnwindSpace = 5;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001310 Address getter_address = v8::ToCData<Address>(callback->getter());
1311 ApiFunction fun(getter_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001312 ExternalReference ref =
1313 ExternalReference(&fun,
1314 ExternalReference::DIRECT_GETTER_CALL,
1315 masm()->isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001316 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
ager@chromium.org5c838252010-02-19 08:53:10 +00001317}
1318
1319
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001320void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
1321 Handle<JSObject> interceptor_holder,
ager@chromium.org5c838252010-02-19 08:53:10 +00001322 LookupResult* lookup,
1323 Register receiver,
1324 Register name_reg,
1325 Register scratch1,
1326 Register scratch2,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001327 Register scratch3,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001328 Handle<String> name,
ager@chromium.org5c838252010-02-19 08:53:10 +00001329 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001330 ASSERT(interceptor_holder->HasNamedInterceptor());
1331 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
1332
1333 // Check that the receiver isn't a smi.
1334 __ JumpIfSmi(receiver, miss);
1335
1336 // So far the most popular follow ups for interceptor loads are FIELD
1337 // and CALLBACKS, so inline only them, other cases may be added
1338 // later.
1339 bool compile_followup_inline = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001340 if (lookup->IsFound() && lookup->IsCacheable()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001341 if (lookup->IsField()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001342 compile_followup_inline = true;
1343 } else if (lookup->type() == CALLBACKS &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001344 lookup->GetCallbackObject()->IsAccessorInfo()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001345 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
1346 compile_followup_inline = callback->getter() != NULL &&
1347 callback->IsCompatibleReceiver(*object);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001348 }
1349 }
1350
1351 if (compile_followup_inline) {
1352 // Compile the interceptor call, followed by inline code to load the
1353 // property from further up the prototype chain if the call fails.
1354 // Check that the maps haven't changed.
1355 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1356 scratch1, scratch2, scratch3,
1357 name, miss);
1358 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
1359
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001360 // Preserve the receiver register explicitly whenever it is different from
1361 // the holder and it is needed should the interceptor return without any
1362 // result. The CALLBACKS case needs the receiver to be passed into C++ code,
1363 // the FIELD case might cause a miss during the prototype check.
1364 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
1365 bool must_preserve_receiver_reg = !receiver.is(holder_reg) &&
1366 (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
1367
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001368 // Save necessary data before invoking an interceptor.
1369 // Requires a frame to make GC aware of pushed pointers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001370 {
1371 FrameScope frame_scope(masm(), StackFrame::INTERNAL);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001372 if (must_preserve_receiver_reg) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001373 __ Push(receiver, holder_reg, name_reg);
1374 } else {
1375 __ Push(holder_reg, name_reg);
1376 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001377 // Invoke an interceptor. Note: map checks from receiver to
1378 // interceptor's holder has been compiled before (see a caller
1379 // of this method).
1380 CompileCallLoadPropertyWithInterceptor(masm(),
1381 receiver,
1382 holder_reg,
1383 name_reg,
1384 interceptor_holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001385 // Check if interceptor provided a value for property. If it's
1386 // the case, return immediately.
1387 Label interceptor_failed;
1388 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
1389 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1));
1390 frame_scope.GenerateLeaveFrame();
1391 __ Ret();
1392
1393 __ bind(&interceptor_failed);
1394 __ pop(name_reg);
1395 __ pop(holder_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001396 if (must_preserve_receiver_reg) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001397 __ pop(receiver);
1398 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001399 // Leave the internal frame.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001400 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001401 // Check that the maps from interceptor's holder to lookup's holder
1402 // haven't changed. And load lookup's holder into |holder| register.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001403 if (must_perfrom_prototype_check) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001404 holder_reg = CheckPrototypes(interceptor_holder,
1405 holder_reg,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001406 Handle<JSObject>(lookup->holder()),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001407 scratch1,
1408 scratch2,
1409 scratch3,
1410 name,
1411 miss);
1412 }
1413
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001414 if (lookup->IsField()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001415 // We found FIELD property in prototype chain of interceptor's holder.
1416 // Retrieve a field from field's holder.
1417 GenerateFastPropertyLoad(masm(), v0, holder_reg,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001418 Handle<JSObject>(lookup->holder()),
1419 lookup->GetFieldIndex());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001420 __ Ret();
1421 } else {
1422 // We found CALLBACKS property in prototype chain of interceptor's
1423 // holder.
1424 ASSERT(lookup->type() == CALLBACKS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001425 Handle<AccessorInfo> callback(
1426 AccessorInfo::cast(lookup->GetCallbackObject()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001427 ASSERT(callback->getter() != NULL);
1428
1429 // Tail call to runtime.
1430 // Important invariant in CALLBACKS case: the code above must be
1431 // structured to never clobber |receiver| register.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001432 __ li(scratch2, callback);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001433
1434 __ Push(receiver, holder_reg);
1435 __ lw(scratch3,
1436 FieldMemOperand(scratch2, AccessorInfo::kDataOffset));
1437 __ li(scratch1, Operand(ExternalReference::isolate_address()));
1438 __ Push(scratch3, scratch1, scratch2, name_reg);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001439
1440 ExternalReference ref =
1441 ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
1442 masm()->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001443 __ TailCallExternalReference(ref, 6, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001444 }
1445 } else { // !compile_followup_inline
1446 // Call the runtime system to load the interceptor.
1447 // Check that the maps haven't changed.
1448 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
1449 scratch1, scratch2, scratch3,
1450 name, miss);
1451 PushInterceptorArguments(masm(), receiver, holder_reg,
1452 name_reg, interceptor_holder);
1453
1454 ExternalReference ref = ExternalReference(
1455 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), masm()->isolate());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001456 __ TailCallExternalReference(ref, 6, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001457 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001458}
1459
1460
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001461void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001462 if (kind_ == Code::KEYED_CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001463 __ Branch(miss, ne, a2, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001464 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001465}
1466
1467
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001468void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
1469 Handle<JSObject> holder,
1470 Handle<String> name,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001471 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001472 ASSERT(holder->IsGlobalObject());
1473
1474 // Get the number of arguments.
1475 const int argc = arguments().immediate();
1476
1477 // Get the receiver from the stack.
1478 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1479
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001480 // Check that the maps haven't changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001481 __ JumpIfSmi(a0, miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001482 CheckPrototypes(object, a0, holder, a3, a1, t0, name, miss);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001483}
1484
1485
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001486void CallStubCompiler::GenerateLoadFunctionFromCell(
1487 Handle<JSGlobalPropertyCell> cell,
1488 Handle<JSFunction> function,
1489 Label* miss) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001490 // Get the value from the cell.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001491 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001492 __ lw(a1, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
1493
1494 // Check that the cell contains the same function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001495 if (heap()->InNewSpace(*function)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001496 // We can't embed a pointer to a function in new space so we have
1497 // to verify that the shared function info is unchanged. This has
1498 // the nice side effect that multiple closures based on the same
1499 // function can all use this call IC. Before we load through the
1500 // function, we have to verify that it still is a function.
1501 __ JumpIfSmi(a1, miss);
1502 __ GetObjectType(a1, a3, a3);
1503 __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
1504
1505 // Check the shared function info. Make sure it hasn't changed.
1506 __ li(a3, Handle<SharedFunctionInfo>(function->shared()));
1507 __ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
1508 __ Branch(miss, ne, t0, Operand(a3));
1509 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001510 __ Branch(miss, ne, a1, Operand(function));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001511 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001512}
1513
1514
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001515void CallStubCompiler::GenerateMissBranch() {
1516 Handle<Code> code =
danno@chromium.org40cb8782011-05-25 07:58:50 +00001517 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
1518 kind_,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001519 extra_state_);
1520 __ Jump(code, RelocInfo::CODE_TARGET);
1521}
1522
1523
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001524Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
1525 Handle<JSObject> holder,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001526 PropertyIndex index,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001527 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001528 // ----------- S t a t e -------------
1529 // -- a2 : name
1530 // -- ra : return address
1531 // -----------------------------------
1532 Label miss;
1533
1534 GenerateNameCheck(name, &miss);
1535
1536 const int argc = arguments().immediate();
1537
1538 // Get the receiver of the function from the stack into a0.
1539 __ lw(a0, MemOperand(sp, argc * kPointerSize));
1540 // Check that the receiver isn't a smi.
1541 __ JumpIfSmi(a0, &miss, t0);
1542
1543 // Do the right check and compute the holder register.
1544 Register reg = CheckPrototypes(object, a0, holder, a1, a3, t0, name, &miss);
1545 GenerateFastPropertyLoad(masm(), a1, reg, holder, index);
1546
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001547 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001548
1549 // Handle call cache miss.
1550 __ bind(&miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001551 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001552
1553 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001554 return GetCode(Code::FIELD, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00001555}
1556
1557
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001558Handle<Code> CallStubCompiler::CompileArrayPushCall(
1559 Handle<Object> object,
1560 Handle<JSObject> holder,
1561 Handle<JSGlobalPropertyCell> cell,
1562 Handle<JSFunction> function,
1563 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001564 // ----------- S t a t e -------------
1565 // -- a2 : name
1566 // -- ra : return address
1567 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1568 // -- ...
1569 // -- sp[argc * 4] : receiver
1570 // -----------------------------------
1571
1572 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001573 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001574
1575 Label miss;
1576
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001577 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001578
1579 Register receiver = a1;
1580
1581 // Get the receiver from the stack.
1582 const int argc = arguments().immediate();
1583 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1584
1585 // Check that the receiver isn't a smi.
1586 __ JumpIfSmi(receiver, &miss);
1587
1588 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001589 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, a3, v0, t0,
1590 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001591
1592 if (argc == 0) {
1593 // Nothing to do, just return the length.
1594 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1595 __ Drop(argc + 1);
1596 __ Ret();
1597 } else {
1598 Label call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001599 if (argc == 1) { // Otherwise fall through to call the builtin.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001600 Label attempt_to_grow_elements, with_write_barrier, check_double;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001601
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001602 Register elements = t2;
1603 Register end_elements = t1;
1604 // Get the elements array of the object.
1605 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1606
1607 // Check that the elements are in fast mode and writable.
1608 __ CheckMap(elements,
1609 v0,
1610 Heap::kFixedArrayMapRootIndex,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001611 &check_double,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001612 DONT_DO_SMI_CHECK);
1613
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001614 // Get the array's length into v0 and calculate new length.
1615 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1616 STATIC_ASSERT(kSmiTagSize == 1);
1617 STATIC_ASSERT(kSmiTag == 0);
1618 __ Addu(v0, v0, Operand(Smi::FromInt(argc)));
1619
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001620 // Get the elements' length.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001621 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1622
1623 // Check if we could survive without allocation.
1624 __ Branch(&attempt_to_grow_elements, gt, v0, Operand(t0));
1625
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001626 // Check if value is a smi.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001627 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1628 __ JumpIfNotSmi(t0, &with_write_barrier);
1629
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001630 // Save new length.
1631 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1632
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001633 // Store the value.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001634 // We may need a register containing the address end_elements below,
1635 // so write back the value in end_elements.
1636 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1637 __ Addu(end_elements, elements, end_elements);
1638 const int kEndElementsOffset =
1639 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001640 __ Addu(end_elements, end_elements, kEndElementsOffset);
1641 __ sw(t0, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001642
1643 // Check for a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001644 __ Drop(argc + 1);
1645 __ Ret();
1646
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001647 __ bind(&check_double);
1648
1649 // Check that the elements are in fast mode and writable.
1650 __ CheckMap(elements,
1651 a0,
1652 Heap::kFixedDoubleArrayMapRootIndex,
1653 &call_builtin,
1654 DONT_DO_SMI_CHECK);
1655
1656 // Get the array's length into r0 and calculate new length.
1657 __ lw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1658 STATIC_ASSERT(kSmiTagSize == 1);
1659 STATIC_ASSERT(kSmiTag == 0);
1660 __ Addu(a0, a0, Operand(Smi::FromInt(argc)));
1661
1662 // Get the elements' length.
1663 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1664
1665 // Check if we could survive without allocation.
1666 __ Branch(&call_builtin, gt, a0, Operand(t0));
1667
1668 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize));
1669 __ StoreNumberToDoubleElements(
1670 t0, a0, elements, a3, t1, a2, t5,
1671 &call_builtin, argc * kDoubleSize);
1672
1673 // Save new length.
1674 __ sw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1675
1676 // Check for a smi.
1677 __ Drop(argc + 1);
1678 __ Ret();
1679
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001680 __ bind(&with_write_barrier);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001681
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001682 __ lw(a3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1683
1684 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) {
1685 Label fast_object, not_fast_object;
1686 __ CheckFastObjectElements(a3, t3, &not_fast_object);
1687 __ jmp(&fast_object);
1688 // In case of fast smi-only, convert to fast object, otherwise bail out.
1689 __ bind(&not_fast_object);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001690 __ CheckFastSmiElements(a3, t3, &call_builtin);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001691
1692 __ lw(t3, FieldMemOperand(t0, HeapObject::kMapOffset));
1693 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
1694 __ Branch(&call_builtin, eq, t3, Operand(at));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001695 // edx: receiver
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001696 // a3: map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001697 Label try_holey_map;
1698 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001699 FAST_ELEMENTS,
1700 a3,
1701 t3,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001702 &try_holey_map);
1703 __ mov(a2, receiver);
1704 ElementsTransitionGenerator::
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001705 GenerateMapChangeElementsTransition(masm(),
1706 DONT_TRACK_ALLOCATION_SITE,
1707 NULL);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001708 __ jmp(&fast_object);
1709
1710 __ bind(&try_holey_map);
1711 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS,
1712 FAST_HOLEY_ELEMENTS,
1713 a3,
1714 t3,
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001715 &call_builtin);
1716 __ mov(a2, receiver);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001717 ElementsTransitionGenerator::
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001718 GenerateMapChangeElementsTransition(masm(),
1719 DONT_TRACK_ALLOCATION_SITE,
1720 NULL);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001721 __ bind(&fast_object);
1722 } else {
1723 __ CheckFastObjectElements(a3, a3, &call_builtin);
1724 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001725
1726 // Save new length.
1727 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1728
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001729 // Store the value.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001730 // We may need a register containing the address end_elements below,
1731 // so write back the value in end_elements.
1732 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1733 __ Addu(end_elements, elements, end_elements);
1734 __ Addu(end_elements, end_elements, kEndElementsOffset);
1735 __ sw(t0, MemOperand(end_elements));
1736
1737 __ RecordWrite(elements,
1738 end_elements,
1739 t0,
1740 kRAHasNotBeenSaved,
1741 kDontSaveFPRegs,
1742 EMIT_REMEMBERED_SET,
1743 OMIT_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001744 __ Drop(argc + 1);
1745 __ Ret();
1746
1747 __ bind(&attempt_to_grow_elements);
1748 // v0: array's length + 1.
1749 // t0: elements' length.
1750
1751 if (!FLAG_inline_new) {
1752 __ Branch(&call_builtin);
1753 }
1754
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001755 __ lw(a2, MemOperand(sp, (argc - 1) * kPointerSize));
1756 // Growing elements that are SMI-only requires special handling in case
1757 // the new element is non-Smi. For now, delegate to the builtin.
1758 Label no_fast_elements_check;
1759 __ JumpIfSmi(a2, &no_fast_elements_check);
1760 __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1761 __ CheckFastObjectElements(t3, t3, &call_builtin);
1762 __ bind(&no_fast_elements_check);
1763
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001764 ExternalReference new_space_allocation_top =
1765 ExternalReference::new_space_allocation_top_address(
1766 masm()->isolate());
1767 ExternalReference new_space_allocation_limit =
1768 ExternalReference::new_space_allocation_limit_address(
1769 masm()->isolate());
1770
1771 const int kAllocationDelta = 4;
1772 // Load top and check if it is the end of elements.
1773 __ sll(end_elements, v0, kPointerSizeLog2 - kSmiTagSize);
1774 __ Addu(end_elements, elements, end_elements);
1775 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset));
1776 __ li(t3, Operand(new_space_allocation_top));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001777 __ lw(a3, MemOperand(t3));
1778 __ Branch(&call_builtin, ne, end_elements, Operand(a3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001779
1780 __ li(t5, Operand(new_space_allocation_limit));
1781 __ lw(t5, MemOperand(t5));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001782 __ Addu(a3, a3, Operand(kAllocationDelta * kPointerSize));
1783 __ Branch(&call_builtin, hi, a3, Operand(t5));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001784
1785 // We fit and could grow elements.
1786 // Update new_space_allocation_top.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001787 __ sw(a3, MemOperand(t3));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001788 // Push the argument.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001789 __ sw(a2, MemOperand(end_elements));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001790 // Fill the rest with holes.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001791 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001792 for (int i = 1; i < kAllocationDelta; i++) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001793 __ sw(a3, MemOperand(end_elements, i * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001794 }
1795
1796 // Update elements' and array's sizes.
1797 __ sw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1798 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta)));
1799 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1800
1801 // Elements are in new space, so write barrier is not required.
1802 __ Drop(argc + 1);
1803 __ Ret();
1804 }
1805 __ bind(&call_builtin);
1806 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush,
1807 masm()->isolate()),
1808 argc + 1,
1809 1);
1810 }
1811
1812 // Handle call cache miss.
1813 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001814 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001815
1816 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001817 return GetCode(function);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001818}
1819
1820
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001821Handle<Code> CallStubCompiler::CompileArrayPopCall(
1822 Handle<Object> object,
1823 Handle<JSObject> holder,
1824 Handle<JSGlobalPropertyCell> cell,
1825 Handle<JSFunction> function,
1826 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001827 // ----------- S t a t e -------------
1828 // -- a2 : name
1829 // -- ra : return address
1830 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1831 // -- ...
1832 // -- sp[argc * 4] : receiver
1833 // -----------------------------------
1834
1835 // If object is not an array, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001836 if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001837
1838 Label miss, return_undefined, call_builtin;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001839 Register receiver = a1;
1840 Register elements = a3;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001841 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001842
1843 // Get the receiver from the stack.
1844 const int argc = arguments().immediate();
1845 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001846 // Check that the receiver isn't a smi.
1847 __ JumpIfSmi(receiver, &miss);
1848
1849 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001850 CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, elements,
1851 t0, v0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001852
1853 // Get the elements array of the object.
1854 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
1855
1856 // Check that the elements are in fast mode and writable.
danno@chromium.org40cb8782011-05-25 07:58:50 +00001857 __ CheckMap(elements,
1858 v0,
1859 Heap::kFixedArrayMapRootIndex,
1860 &call_builtin,
1861 DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001862
1863 // Get the array's length into t0 and calculate new length.
1864 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1865 __ Subu(t0, t0, Operand(Smi::FromInt(1)));
1866 __ Branch(&return_undefined, lt, t0, Operand(zero_reg));
1867
1868 // Get the last element.
1869 __ LoadRoot(t2, Heap::kTheHoleValueRootIndex);
1870 STATIC_ASSERT(kSmiTagSize == 1);
1871 STATIC_ASSERT(kSmiTag == 0);
1872 // We can't address the last element in one operation. Compute the more
1873 // expensive shift first, and use an offset later on.
1874 __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize);
1875 __ Addu(elements, elements, t1);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001876 __ lw(v0, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001877 __ Branch(&call_builtin, eq, v0, Operand(t2));
1878
1879 // Set the array's length.
1880 __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1881
1882 // Fill with the hole.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001883 __ sw(t2, FieldMemOperand(elements, FixedArray::kHeaderSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001884 __ Drop(argc + 1);
1885 __ Ret();
1886
1887 __ bind(&return_undefined);
1888 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
1889 __ Drop(argc + 1);
1890 __ Ret();
1891
1892 __ bind(&call_builtin);
1893 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop,
1894 masm()->isolate()),
1895 argc + 1,
1896 1);
1897
1898 // Handle call cache miss.
1899 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001900 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001901
1902 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001903 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001904}
1905
1906
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001907Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
1908 Handle<Object> object,
1909 Handle<JSObject> holder,
1910 Handle<JSGlobalPropertyCell> cell,
1911 Handle<JSFunction> function,
1912 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001913 // ----------- S t a t e -------------
1914 // -- a2 : function name
1915 // -- ra : return address
1916 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
1917 // -- ...
1918 // -- sp[argc * 4] : receiver
1919 // -----------------------------------
1920
1921 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001922 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001923
1924 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001925 Label miss;
1926 Label name_miss;
1927 Label index_out_of_range;
1928
1929 Label* index_out_of_range_label = &index_out_of_range;
1930
danno@chromium.org40cb8782011-05-25 07:58:50 +00001931 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001932 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00001933 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001934 index_out_of_range_label = &miss;
1935 }
1936
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001937 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001938
1939 // Check that the maps starting from the prototype haven't changed.
1940 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1941 Context::STRING_FUNCTION_INDEX,
1942 v0,
1943 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001944 ASSERT(!object.is_identical_to(holder));
1945 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
1946 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001947
1948 Register receiver = a1;
1949 Register index = t1;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001950 Register result = v0;
1951 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
1952 if (argc > 0) {
1953 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
1954 } else {
1955 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1956 }
1957
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001958 StringCharCodeAtGenerator generator(receiver,
1959 index,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001960 result,
1961 &miss, // When not a string.
1962 &miss, // When not a number.
1963 index_out_of_range_label,
1964 STRING_INDEX_IS_NUMBER);
1965 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001966 __ Drop(argc + 1);
1967 __ Ret();
1968
1969 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001970 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001971
1972 if (index_out_of_range.is_linked()) {
1973 __ bind(&index_out_of_range);
1974 __ LoadRoot(v0, Heap::kNanValueRootIndex);
1975 __ Drop(argc + 1);
1976 __ Ret();
1977 }
1978
1979 __ bind(&miss);
1980 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001981 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001982 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001983 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001984
1985 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001986 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00001987}
1988
1989
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001990Handle<Code> CallStubCompiler::CompileStringCharAtCall(
1991 Handle<Object> object,
1992 Handle<JSObject> holder,
1993 Handle<JSGlobalPropertyCell> cell,
1994 Handle<JSFunction> function,
1995 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001996 // ----------- S t a t e -------------
1997 // -- a2 : function name
1998 // -- ra : return address
1999 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2000 // -- ...
2001 // -- sp[argc * 4] : receiver
2002 // -----------------------------------
2003
2004 // If object is not a string, bail out to regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002005 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002006
2007 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002008 Label miss;
2009 Label name_miss;
2010 Label index_out_of_range;
2011 Label* index_out_of_range_label = &index_out_of_range;
danno@chromium.org40cb8782011-05-25 07:58:50 +00002012 if (kind_ == Code::CALL_IC &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002013 (CallICBase::StringStubState::decode(extra_state_) ==
danno@chromium.org40cb8782011-05-25 07:58:50 +00002014 DEFAULT_STRING_STUB)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002015 index_out_of_range_label = &miss;
2016 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002017 GenerateNameCheck(name, &name_miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002018
2019 // Check that the maps starting from the prototype haven't changed.
2020 GenerateDirectLoadGlobalFunctionPrototype(masm(),
2021 Context::STRING_FUNCTION_INDEX,
2022 v0,
2023 &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002024 ASSERT(!object.is_identical_to(holder));
2025 CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2026 v0, holder, a1, a3, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002027
2028 Register receiver = v0;
2029 Register index = t1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00002030 Register scratch = a3;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002031 Register result = v0;
2032 __ lw(receiver, MemOperand(sp, argc * kPointerSize));
2033 if (argc > 0) {
2034 __ lw(index, MemOperand(sp, (argc - 1) * kPointerSize));
2035 } else {
2036 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
2037 }
2038
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002039 StringCharAtGenerator generator(receiver,
2040 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00002041 scratch,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002042 result,
2043 &miss, // When not a string.
2044 &miss, // When not a number.
2045 index_out_of_range_label,
2046 STRING_INDEX_IS_NUMBER);
2047 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002048 __ Drop(argc + 1);
2049 __ Ret();
2050
2051 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002052 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002053
2054 if (index_out_of_range.is_linked()) {
2055 __ bind(&index_out_of_range);
2056 __ LoadRoot(v0, Heap::kEmptyStringRootIndex);
2057 __ Drop(argc + 1);
2058 __ Ret();
2059 }
2060
2061 __ bind(&miss);
2062 // Restore function name in a2.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002063 __ li(a2, name);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002064 __ bind(&name_miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002065 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002066
2067 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002068 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002069}
2070
2071
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002072Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
2073 Handle<Object> object,
2074 Handle<JSObject> holder,
2075 Handle<JSGlobalPropertyCell> cell,
2076 Handle<JSFunction> function,
2077 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002078 // ----------- S t a t e -------------
2079 // -- a2 : function name
2080 // -- ra : return address
2081 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2082 // -- ...
2083 // -- sp[argc * 4] : receiver
2084 // -----------------------------------
2085
2086 const int argc = arguments().immediate();
2087
2088 // If the object is not a JSObject or we got an unexpected number of
2089 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002090 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002091
2092 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002093 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002094
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002095 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002096 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
2097
2098 STATIC_ASSERT(kSmiTag == 0);
2099 __ JumpIfSmi(a1, &miss);
2100
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002101 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2102 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002103 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002104 ASSERT(cell->value() == *function);
2105 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2106 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002107 GenerateLoadFunctionFromCell(cell, function, &miss);
2108 }
2109
2110 // Load the char code argument.
2111 Register code = a1;
2112 __ lw(code, MemOperand(sp, 0 * kPointerSize));
2113
2114 // Check the code is a smi.
2115 Label slow;
2116 STATIC_ASSERT(kSmiTag == 0);
2117 __ JumpIfNotSmi(code, &slow);
2118
2119 // Convert the smi code to uint16.
2120 __ And(code, code, Operand(Smi::FromInt(0xffff)));
2121
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002122 StringCharFromCodeGenerator generator(code, v0);
2123 generator.GenerateFast(masm());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002124 __ Drop(argc + 1);
2125 __ Ret();
2126
2127 StubRuntimeCallHelper call_helper;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002128 generator.GenerateSlow(masm(), call_helper);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002129
2130 // Tail call the full function. We do not have to patch the receiver
2131 // because the function makes no use of it.
2132 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002133 __ InvokeFunction(
2134 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002135
2136 __ bind(&miss);
2137 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002138 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002139
2140 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002141 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002142}
2143
2144
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002145Handle<Code> CallStubCompiler::CompileMathFloorCall(
2146 Handle<Object> object,
2147 Handle<JSObject> holder,
2148 Handle<JSGlobalPropertyCell> cell,
2149 Handle<JSFunction> function,
2150 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002151 // ----------- S t a t e -------------
2152 // -- a2 : function name
2153 // -- ra : return address
2154 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2155 // -- ...
2156 // -- sp[argc * 4] : receiver
2157 // -----------------------------------
2158
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002159 if (!CpuFeatures::IsSupported(FPU)) {
2160 return Handle<Code>::null();
2161 }
2162
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002163 CpuFeatures::Scope scope_fpu(FPU);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002164 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002165 // If the object is not a JSObject or we got an unexpected number of
2166 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002167 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002168
2169 Label miss, slow;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002170 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002171
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002172 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002173 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002174 STATIC_ASSERT(kSmiTag == 0);
2175 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002176 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2177 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002178 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002179 ASSERT(cell->value() == *function);
2180 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2181 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002182 GenerateLoadFunctionFromCell(cell, function, &miss);
2183 }
2184
2185 // Load the (only) argument into v0.
2186 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2187
2188 // If the argument is a smi, just return.
2189 STATIC_ASSERT(kSmiTag == 0);
2190 __ And(t0, v0, Operand(kSmiTagMask));
2191 __ Drop(argc + 1, eq, t0, Operand(zero_reg));
2192 __ Ret(eq, t0, Operand(zero_reg));
2193
danno@chromium.org40cb8782011-05-25 07:58:50 +00002194 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002195
2196 Label wont_fit_smi, no_fpu_error, restore_fcsr_and_return;
2197
2198 // If fpu is enabled, we use the floor instruction.
2199
2200 // Load the HeapNumber value.
2201 __ ldc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
2202
2203 // Backup FCSR.
2204 __ cfc1(a3, FCSR);
2205 // Clearing FCSR clears the exception mask with no side-effects.
2206 __ ctc1(zero_reg, FCSR);
2207 // Convert the argument to an integer.
2208 __ floor_w_d(f0, f0);
2209
2210 // Start checking for special cases.
2211 // Get the argument exponent and clear the sign bit.
2212 __ lw(t1, FieldMemOperand(v0, HeapNumber::kValueOffset + kPointerSize));
2213 __ And(t2, t1, Operand(~HeapNumber::kSignMask));
2214 __ srl(t2, t2, HeapNumber::kMantissaBitsInTopWord);
2215
2216 // Retrieve FCSR and check for fpu errors.
2217 __ cfc1(t5, FCSR);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002218 __ And(t5, t5, Operand(kFCSRExceptionFlagMask));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002219 __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));
2220
2221 // Check for NaN, Infinity, and -Infinity.
2222 // They are invariant through a Math.Floor call, so just
2223 // return the original argument.
2224 __ Subu(t3, t2, Operand(HeapNumber::kExponentMask
2225 >> HeapNumber::kMantissaBitsInTopWord));
2226 __ Branch(&restore_fcsr_and_return, eq, t3, Operand(zero_reg));
2227 // We had an overflow or underflow in the conversion. Check if we
2228 // have a big exponent.
2229 // If greater or equal, the argument is already round and in v0.
2230 __ Branch(&restore_fcsr_and_return, ge, t3,
2231 Operand(HeapNumber::kMantissaBits));
2232 __ Branch(&wont_fit_smi);
2233
2234 __ bind(&no_fpu_error);
2235 // Move the result back to v0.
2236 __ mfc1(v0, f0);
2237 // Check if the result fits into a smi.
2238 __ Addu(a1, v0, Operand(0x40000000));
2239 __ Branch(&wont_fit_smi, lt, a1, Operand(zero_reg));
2240 // Tag the result.
2241 STATIC_ASSERT(kSmiTag == 0);
2242 __ sll(v0, v0, kSmiTagSize);
2243
2244 // Check for -0.
2245 __ Branch(&restore_fcsr_and_return, ne, v0, Operand(zero_reg));
2246 // t1 already holds the HeapNumber exponent.
2247 __ And(t0, t1, Operand(HeapNumber::kSignMask));
2248 // If our HeapNumber is negative it was -0, so load its address and return.
2249 // Else v0 is loaded with 0, so we can also just return.
2250 __ Branch(&restore_fcsr_and_return, eq, t0, Operand(zero_reg));
2251 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2252
2253 __ bind(&restore_fcsr_and_return);
2254 // Restore FCSR and return.
2255 __ ctc1(a3, FCSR);
2256
2257 __ Drop(argc + 1);
2258 __ Ret();
2259
2260 __ bind(&wont_fit_smi);
2261 // Restore FCSR and fall to slow case.
2262 __ ctc1(a3, FCSR);
2263
2264 __ bind(&slow);
2265 // Tail call the full function. We do not have to patch the receiver
2266 // because the function makes no use of it.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002267 __ InvokeFunction(
2268 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002269
2270 __ bind(&miss);
2271 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002272 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002273
2274 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002275 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002276}
2277
2278
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002279Handle<Code> CallStubCompiler::CompileMathAbsCall(
2280 Handle<Object> object,
2281 Handle<JSObject> holder,
2282 Handle<JSGlobalPropertyCell> cell,
2283 Handle<JSFunction> function,
2284 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002285 // ----------- S t a t e -------------
2286 // -- a2 : function name
2287 // -- ra : return address
2288 // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
2289 // -- ...
2290 // -- sp[argc * 4] : receiver
2291 // -----------------------------------
2292
2293 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002294 // If the object is not a JSObject or we got an unexpected number of
2295 // arguments, bail out to the regular call.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002296 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002297
2298 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002299
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002300 GenerateNameCheck(name, &miss);
2301 if (cell.is_null()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002302 __ lw(a1, MemOperand(sp, 1 * kPointerSize));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002303 STATIC_ASSERT(kSmiTag == 0);
2304 __ JumpIfSmi(a1, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002305 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
2306 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002307 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002308 ASSERT(cell->value() == *function);
2309 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
2310 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002311 GenerateLoadFunctionFromCell(cell, function, &miss);
2312 }
2313
2314 // Load the (only) argument into v0.
2315 __ lw(v0, MemOperand(sp, 0 * kPointerSize));
2316
2317 // Check if the argument is a smi.
2318 Label not_smi;
2319 STATIC_ASSERT(kSmiTag == 0);
2320 __ JumpIfNotSmi(v0, &not_smi);
2321
2322 // Do bitwise not or do nothing depending on the sign of the
2323 // argument.
2324 __ sra(t0, v0, kBitsPerInt - 1);
2325 __ Xor(a1, v0, t0);
2326
2327 // Add 1 or do nothing depending on the sign of the argument.
2328 __ Subu(v0, a1, t0);
2329
2330 // If the result is still negative, go to the slow case.
2331 // This only happens for the most negative smi.
2332 Label slow;
2333 __ Branch(&slow, lt, v0, Operand(zero_reg));
2334
2335 // Smi case done.
2336 __ Drop(argc + 1);
2337 __ Ret();
2338
2339 // Check if the argument is a heap number and load its exponent and
2340 // sign.
2341 __ bind(&not_smi);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002342 __ CheckMap(v0, a1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002343 __ lw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2344
2345 // Check the sign of the argument. If the argument is positive,
2346 // just return it.
2347 Label negative_sign;
2348 __ And(t0, a1, Operand(HeapNumber::kSignMask));
2349 __ Branch(&negative_sign, ne, t0, Operand(zero_reg));
2350 __ Drop(argc + 1);
2351 __ Ret();
2352
2353 // If the argument is negative, clear the sign, and return a new
2354 // number.
2355 __ bind(&negative_sign);
2356 __ Xor(a1, a1, Operand(HeapNumber::kSignMask));
2357 __ lw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2358 __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
2359 __ AllocateHeapNumber(v0, t0, t1, t2, &slow);
2360 __ sw(a1, FieldMemOperand(v0, HeapNumber::kExponentOffset));
2361 __ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
2362 __ Drop(argc + 1);
2363 __ Ret();
2364
2365 // Tail call the full function. We do not have to patch the receiver
2366 // because the function makes no use of it.
2367 __ bind(&slow);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002368 __ InvokeFunction(
2369 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002370
2371 __ bind(&miss);
2372 // a2: function name.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002373 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002374
2375 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002376 return cell.is_null() ? GetCode(function) : GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002377}
2378
2379
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002380Handle<Code> CallStubCompiler::CompileFastApiCall(
lrn@chromium.org7516f052011-03-30 08:52:27 +00002381 const CallOptimization& optimization,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002382 Handle<Object> object,
2383 Handle<JSObject> holder,
2384 Handle<JSGlobalPropertyCell> cell,
2385 Handle<JSFunction> function,
2386 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002387
danno@chromium.org40cb8782011-05-25 07:58:50 +00002388 Counters* counters = isolate()->counters();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002389
2390 ASSERT(optimization.is_simple_api_call());
2391 // Bail out if object is a global object as we don't want to
2392 // repatch it to global receiver.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002393 if (object->IsGlobalObject()) return Handle<Code>::null();
2394 if (!cell.is_null()) return Handle<Code>::null();
2395 if (!object->IsJSObject()) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002396 int depth = optimization.GetPrototypeDepthOfExpectedType(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002397 Handle<JSObject>::cast(object), holder);
2398 if (depth == kInvalidProtoDepth) return Handle<Code>::null();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002399
2400 Label miss, miss_before_stack_reserved;
2401
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002402 GenerateNameCheck(name, &miss_before_stack_reserved);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002403
2404 // Get the receiver from the stack.
2405 const int argc = arguments().immediate();
2406 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2407
2408 // Check that the receiver isn't a smi.
2409 __ JumpIfSmi(a1, &miss_before_stack_reserved);
2410
2411 __ IncrementCounter(counters->call_const(), 1, a0, a3);
2412 __ IncrementCounter(counters->call_const_fast_api(), 1, a0, a3);
2413
2414 ReserveSpaceForFastApiCall(masm(), a0);
2415
2416 // Check that the maps haven't changed and find a Holder as a side effect.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002417 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0, name,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002418 depth, &miss);
2419
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002420 GenerateFastApiDirectCall(masm(), optimization, argc);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002421
2422 __ bind(&miss);
2423 FreeSpaceForFastApiCall(masm());
2424
2425 __ bind(&miss_before_stack_reserved);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002426 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002427
2428 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002429 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002430}
2431
2432
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002433void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
2434 Handle<JSObject> holder,
2435 Handle<String> name,
2436 CheckType check,
2437 Label* success) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002438 // ----------- S t a t e -------------
2439 // -- a2 : name
2440 // -- ra : return address
2441 // -----------------------------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002442 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002443 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002444
2445 // Get the receiver from the stack.
2446 const int argc = arguments().immediate();
2447 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2448
2449 // Check that the receiver isn't a smi.
2450 if (check != NUMBER_CHECK) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002451 __ JumpIfSmi(a1, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002452 }
2453
2454 // Make sure that it's okay not to patch the on stack receiver
2455 // unless we're doing a receiver map check.
2456 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002457 switch (check) {
2458 case RECEIVER_MAP_CHECK:
2459 __ IncrementCounter(masm()->isolate()->counters()->call_const(),
2460 1, a0, a3);
2461
2462 // Check that the maps haven't changed.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002463 CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
2464 name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002465
2466 // Patch the receiver on the stack with the global proxy if
2467 // necessary.
2468 if (object->IsGlobalObject()) {
2469 __ lw(a3, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
2470 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2471 }
2472 break;
2473
2474 case STRING_CHECK:
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002475 // Check that the object is a two-byte string or a symbol.
2476 __ GetObjectType(a1, a3, a3);
2477 __ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
2478 // Check that the maps starting from the prototype haven't changed.
2479 GenerateDirectLoadGlobalFunctionPrototype(
2480 masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
2481 CheckPrototypes(
2482 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2483 a0, holder, a3, a1, t0, name, &miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002484 break;
2485
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002486 case NUMBER_CHECK: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002487 Label fast;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002488 // Check that the object is a smi or a heap number.
2489 __ JumpIfSmi(a1, &fast);
2490 __ GetObjectType(a1, a0, a0);
2491 __ Branch(&miss, ne, a0, Operand(HEAP_NUMBER_TYPE));
2492 __ bind(&fast);
2493 // Check that the maps starting from the prototype haven't changed.
2494 GenerateDirectLoadGlobalFunctionPrototype(
2495 masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
2496 CheckPrototypes(
2497 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2498 a0, holder, a3, a1, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002499 break;
2500 }
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002501 case BOOLEAN_CHECK: {
2502 Label fast;
2503 // Check that the object is a boolean.
2504 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
2505 __ Branch(&fast, eq, a1, Operand(t0));
2506 __ LoadRoot(t0, Heap::kFalseValueRootIndex);
2507 __ Branch(&miss, ne, a1, Operand(t0));
2508 __ bind(&fast);
2509 // Check that the maps starting from the prototype haven't changed.
2510 GenerateDirectLoadGlobalFunctionPrototype(
2511 masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
2512 CheckPrototypes(
2513 Handle<JSObject>(JSObject::cast(object->GetPrototype())),
2514 a0, holder, a3, a1, t0, name, &miss);
2515 break;
2516 }
2517 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002518
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002519 __ jmp(success);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002520
2521 // Handle call cache miss.
2522 __ bind(&miss);
2523
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002524 GenerateMissBranch();
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002525}
2526
2527
2528void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) {
2529 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
2530 ? CALL_AS_FUNCTION
2531 : CALL_AS_METHOD;
2532 __ InvokeFunction(
2533 function, arguments(), JUMP_FUNCTION, NullCallWrapper(), call_kind);
2534}
2535
2536
2537Handle<Code> CallStubCompiler::CompileCallConstant(
2538 Handle<Object> object,
2539 Handle<JSObject> holder,
2540 Handle<String> name,
2541 CheckType check,
2542 Handle<JSFunction> function) {
2543 if (HasCustomCallGenerator(function)) {
2544 Handle<Code> code = CompileCustomCall(object, holder,
2545 Handle<JSGlobalPropertyCell>::null(),
2546 function, name);
2547 // A null handle means bail out to the regular compiler code below.
2548 if (!code.is_null()) return code;
2549 }
2550
2551 Label success;
2552
2553 CompileHandlerFrontend(object, holder, name, check, &success);
2554 __ bind(&success);
2555 CompileHandlerBackend(function);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002556
2557 // Return the generated code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002558 return GetCode(function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002559}
2560
2561
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002562Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
2563 Handle<JSObject> holder,
2564 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002565 // ----------- S t a t e -------------
2566 // -- a2 : name
2567 // -- ra : return address
2568 // -----------------------------------
2569
2570 Label miss;
2571
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002572 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002573
2574 // Get the number of arguments.
2575 const int argc = arguments().immediate();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002576 LookupResult lookup(isolate());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002577 LookupPostInterceptor(holder, name, &lookup);
2578
2579 // Get the receiver from the stack.
2580 __ lw(a1, MemOperand(sp, argc * kPointerSize));
2581
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002582 CallInterceptorCompiler compiler(this, arguments(), a2, extra_state_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002583 compiler.Compile(masm(), object, holder, name, &lookup, a1, a3, t0, a0,
2584 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002585
2586 // Move returned value, the function to call, to a1.
2587 __ mov(a1, v0);
2588 // Restore receiver.
2589 __ lw(a0, MemOperand(sp, argc * kPointerSize));
2590
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002591 GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002592
2593 // Handle call cache miss.
2594 __ bind(&miss);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002595 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002596
2597 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002598 return GetCode(Code::INTERCEPTOR, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002599}
2600
2601
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002602Handle<Code> CallStubCompiler::CompileCallGlobal(
2603 Handle<JSObject> object,
2604 Handle<GlobalObject> holder,
2605 Handle<JSGlobalPropertyCell> cell,
2606 Handle<JSFunction> function,
2607 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002608 // ----------- S t a t e -------------
2609 // -- a2 : name
2610 // -- ra : return address
2611 // -----------------------------------
2612
2613 if (HasCustomCallGenerator(function)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002614 Handle<Code> code = CompileCustomCall(object, holder, cell, function, name);
2615 // A null handle means bail out to the regular compiler code below.
2616 if (!code.is_null()) return code;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002617 }
2618
2619 Label miss;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002620 GenerateNameCheck(name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002621
2622 // Get the number of arguments.
2623 const int argc = arguments().immediate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002624 GenerateGlobalReceiverCheck(object, holder, name, &miss);
2625 GenerateLoadFunctionFromCell(cell, function, &miss);
2626
2627 // Patch the receiver on the stack with the global proxy if
2628 // necessary.
2629 if (object->IsGlobalObject()) {
2630 __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
2631 __ sw(a3, MemOperand(sp, argc * kPointerSize));
2632 }
2633
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002634 // Set up the context (function already in r1).
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002635 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
2636
2637 // Jump to the cached code (tail call).
2638 Counters* counters = masm()->isolate()->counters();
2639 __ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002640 ParameterCount expected(function->shared()->formal_parameter_count());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002641 CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
danno@chromium.org40cb8782011-05-25 07:58:50 +00002642 ? CALL_AS_FUNCTION
2643 : CALL_AS_METHOD;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002644 // We call indirectly through the code field in the function to
2645 // allow recompilation to take effect without changing any of the
2646 // call sites.
2647 __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
2648 __ InvokeCode(a3, expected, arguments(), JUMP_FUNCTION,
2649 NullCallWrapper(), call_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002650
2651 // Handle call cache miss.
2652 __ bind(&miss);
2653 __ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002654 GenerateMissBranch();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002655
2656 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002657 return GetCode(Code::NORMAL, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002658}
2659
2660
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002661Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
ager@chromium.org5c838252010-02-19 08:53:10 +00002662 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002663 Handle<Map> transition,
2664 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002665 // ----------- S t a t e -------------
2666 // -- a0 : value
2667 // -- a1 : receiver
2668 // -- a2 : name
2669 // -- ra : return address
2670 // -----------------------------------
2671 Label miss;
2672
2673 // Name register might be clobbered.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002674 GenerateStoreField(masm(),
2675 object,
2676 index,
2677 transition,
2678 name,
2679 a1, a2, a3, t0,
2680 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002681 __ bind(&miss);
2682 __ li(a2, Operand(Handle<String>(name))); // Restore name.
2683 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2684 __ Jump(ic, RelocInfo::CODE_TARGET);
2685
2686 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002687 return GetCode(transition.is_null()
2688 ? Code::FIELD
2689 : Code::MAP_TRANSITION, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002690}
2691
2692
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002693Handle<Code> StoreStubCompiler::CompileStoreCallback(
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002694 Handle<String> name,
2695 Handle<JSObject> receiver,
2696 Handle<JSObject> holder,
2697 Handle<AccessorInfo> callback) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002698 // ----------- S t a t e -------------
2699 // -- a0 : value
2700 // -- a1 : receiver
2701 // -- a2 : name
2702 // -- ra : return address
2703 // -----------------------------------
2704 Label miss;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002705 // Check that the maps haven't changed.
2706 __ JumpIfSmi(a1, &miss, a3);
2707 CheckPrototypes(receiver, a1, holder, a3, t0, t1, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002708
2709 // Stub never generated for non-global objects that require access
2710 // checks.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002711 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002712
2713 __ push(a1); // Receiver.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002714 __ li(a3, Operand(callback)); // Callback info.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002715 __ Push(a3, a2, a0);
2716
2717 // Do tail-call to the runtime system.
2718 ExternalReference store_callback_property =
2719 ExternalReference(IC_Utility(IC::kStoreCallbackProperty),
2720 masm()->isolate());
2721 __ TailCallExternalReference(store_callback_property, 4, 1);
2722
2723 // Handle store cache miss.
2724 __ bind(&miss);
2725 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2726 __ Jump(ic, RelocInfo::CODE_TARGET);
2727
2728 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002729 return GetCode(Code::CALLBACKS, name);
ager@chromium.org5c838252010-02-19 08:53:10 +00002730}
2731
2732
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002733#undef __
2734#define __ ACCESS_MASM(masm)
2735
2736
2737void StoreStubCompiler::GenerateStoreViaSetter(
2738 MacroAssembler* masm,
2739 Handle<JSFunction> setter) {
2740 // ----------- S t a t e -------------
2741 // -- a0 : value
2742 // -- a1 : receiver
2743 // -- a2 : name
2744 // -- ra : return address
2745 // -----------------------------------
2746 {
2747 FrameScope scope(masm, StackFrame::INTERNAL);
2748
2749 // Save value register, so we can restore it later.
2750 __ push(a0);
2751
2752 if (!setter.is_null()) {
2753 // Call the JavaScript setter with receiver and value on the stack.
2754 __ push(a1);
2755 __ push(a0);
2756 ParameterCount actual(1);
2757 __ InvokeFunction(setter, actual, CALL_FUNCTION, NullCallWrapper(),
2758 CALL_AS_METHOD);
2759 } else {
2760 // If we generate a global code snippet for deoptimization only, remember
2761 // the place to continue after deoptimization.
2762 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
2763 }
2764
2765 // We have to return the passed value, not the return value of the setter.
2766 __ pop(v0);
2767
2768 // Restore context register.
2769 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2770 }
2771 __ Ret();
2772}
2773
2774
2775#undef __
2776#define __ ACCESS_MASM(masm())
2777
2778
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002779Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002780 Handle<String> name,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002781 Handle<JSObject> receiver,
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002782 Handle<JSObject> holder,
2783 Handle<JSFunction> setter) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002784 // ----------- S t a t e -------------
2785 // -- a0 : value
2786 // -- a1 : receiver
2787 // -- a2 : name
2788 // -- ra : return address
2789 // -----------------------------------
2790 Label miss;
2791
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00002792 // Check that the maps haven't changed.
2793 __ JumpIfSmi(a1, &miss);
2794 CheckPrototypes(receiver, a1, holder, a3, t0, t1, name, &miss);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002795
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002796 GenerateStoreViaSetter(masm(), setter);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002797
2798 __ bind(&miss);
2799 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2800 __ Jump(ic, RelocInfo::CODE_TARGET);
2801
2802 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002803 return GetCode(Code::CALLBACKS, name);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002804}
2805
2806
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002807Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
2808 Handle<JSObject> receiver,
2809 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002810 // ----------- S t a t e -------------
2811 // -- a0 : value
2812 // -- a1 : receiver
2813 // -- a2 : name
2814 // -- ra : return address
2815 // -----------------------------------
2816 Label miss;
2817
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002818 // Check that the map of the object hasn't changed.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002819 __ CheckMap(a1, a3, Handle<Map>(receiver->map()), &miss,
2820 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002821
2822 // Perform global security token check if needed.
2823 if (receiver->IsJSGlobalProxy()) {
2824 __ CheckAccessGlobalProxy(a1, a3, &miss);
2825 }
2826
2827 // Stub is never generated for non-global objects that require access
2828 // checks.
2829 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
2830
2831 __ Push(a1, a2, a0); // Receiver, name, value.
2832
2833 __ li(a0, Operand(Smi::FromInt(strict_mode_)));
2834 __ push(a0); // Strict mode.
2835
2836 // Do tail-call to the runtime system.
2837 ExternalReference store_ic_property =
2838 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty),
2839 masm()->isolate());
2840 __ TailCallExternalReference(store_ic_property, 4, 1);
2841
2842 // Handle store cache miss.
2843 __ bind(&miss);
2844 Handle<Code> ic = masm()->isolate()->builtins()->Builtins::StoreIC_Miss();
2845 __ Jump(ic, RelocInfo::CODE_TARGET);
2846
2847 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002848 return GetCode(Code::INTERCEPTOR, name);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002849}
2850
2851
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002852Handle<Code> StoreStubCompiler::CompileStoreGlobal(
2853 Handle<GlobalObject> object,
2854 Handle<JSGlobalPropertyCell> cell,
2855 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002856 // ----------- S t a t e -------------
2857 // -- a0 : value
2858 // -- a1 : receiver
2859 // -- a2 : name
2860 // -- ra : return address
2861 // -----------------------------------
2862 Label miss;
2863
2864 // Check that the map of the global has not changed.
2865 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
2866 __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map())));
2867
2868 // Check that the value in the cell is not the hole. If it is, this
2869 // cell could have been deleted and reintroducing the global needs
2870 // to update the property details in the property dictionary of the
2871 // global object. We bail out to the runtime system to do that.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00002872 __ li(t0, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002873 __ LoadRoot(t1, Heap::kTheHoleValueRootIndex);
2874 __ lw(t2, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2875 __ Branch(&miss, eq, t1, Operand(t2));
2876
2877 // Store the value in the cell.
2878 __ sw(a0, FieldMemOperand(t0, JSGlobalPropertyCell::kValueOffset));
2879 __ mov(v0, a0); // Stored value must be returned in v0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002880 // Cells are always rescanned, so no write barrier here.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002881
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002882 Counters* counters = masm()->isolate()->counters();
2883 __ IncrementCounter(counters->named_store_global_inline(), 1, a1, a3);
2884 __ Ret();
2885
2886 // Handle store cache miss.
2887 __ bind(&miss);
2888 __ IncrementCounter(counters->named_store_global_inline_miss(), 1, a1, a3);
2889 Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
2890 __ Jump(ic, RelocInfo::CODE_TARGET);
2891
2892 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002893 return GetCode(Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002894}
2895
2896
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002897Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
2898 Handle<JSObject> object,
2899 Handle<JSObject> last,
2900 Handle<String> name,
2901 Handle<GlobalObject> global) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002902 // ----------- S t a t e -------------
2903 // -- a0 : receiver
2904 // -- ra : return address
2905 // -----------------------------------
2906 Label miss;
2907
2908 // Check that the receiver is not a smi.
2909 __ JumpIfSmi(a0, &miss);
2910
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002911 Register scratch = a1;
2912
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002913 // Check the maps of the full prototype chain.
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002914 Register result =
2915 CheckPrototypes(object, a0, last, a3, scratch, t0, name, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002916
2917 // If the last object in the prototype chain is a global object,
2918 // check that the global property cell is empty.
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002919 if (!global.is_null()) {
2920 GenerateCheckPropertyCell(masm(), global, name, scratch, &miss);
2921 }
2922
2923 if (!last->HasFastProperties()) {
2924 __ lw(scratch, FieldMemOperand(result, HeapObject::kMapOffset));
2925 __ lw(scratch, FieldMemOperand(scratch, Map::kPrototypeOffset));
2926 __ Branch(&miss, ne, scratch, Operand(isolate()->factory()->null_value()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002927 }
2928
2929 // Return undefined if maps of the full prototype chain is still the same.
2930 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2931 __ Ret();
2932
2933 __ bind(&miss);
2934 GenerateLoadMiss(masm(), Code::LOAD_IC);
2935
2936 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002937 return GetCode(Code::NONEXISTENT, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00002938}
2939
2940
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002941Register* LoadStubCompiler::registers() {
2942 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2943 static Register registers[] = { a0, a2, a3, a1, t0, t1 };
2944 return registers;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002945}
2946
2947
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002948Register* KeyedLoadStubCompiler::registers() {
2949 // receiver, name, scratch1, scratch2, scratch3, scratch4.
2950 static Register registers[] = { a1, a0, a2, a3, t0, t1 };
2951 return registers;
2952}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002953
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002954
2955void KeyedLoadStubCompiler::GenerateNameCheck(Handle<String> name,
2956 Register name_reg,
2957 Label* miss) {
2958 __ Branch(miss, ne, name_reg, Operand(name));
lrn@chromium.org7516f052011-03-30 08:52:27 +00002959}
2960
2961
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002962#undef __
2963#define __ ACCESS_MASM(masm)
2964
2965
2966void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
2967 Handle<JSFunction> getter) {
2968 // ----------- S t a t e -------------
2969 // -- a0 : receiver
2970 // -- a2 : name
2971 // -- ra : return address
2972 // -----------------------------------
2973 {
2974 FrameScope scope(masm, StackFrame::INTERNAL);
2975
2976 if (!getter.is_null()) {
2977 // Call the JavaScript getter with the receiver on the stack.
2978 __ push(a0);
2979 ParameterCount actual(0);
2980 __ InvokeFunction(getter, actual, CALL_FUNCTION, NullCallWrapper(),
2981 CALL_AS_METHOD);
2982 } else {
2983 // If we generate a global code snippet for deoptimization only, remember
2984 // the place to continue after deoptimization.
2985 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
2986 }
2987
2988 // Restore context register.
2989 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2990 }
2991 __ Ret();
2992}
2993
2994
2995#undef __
2996#define __ ACCESS_MASM(masm())
2997
2998
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002999Handle<Code> LoadStubCompiler::CompileLoadViaGetter(
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003000 Handle<JSObject> receiver,
3001 Handle<JSObject> holder,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00003002 Handle<String> name,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003003 Handle<JSFunction> getter) {
3004 // ----------- S t a t e -------------
3005 // -- a0 : receiver
3006 // -- a2 : name
3007 // -- ra : return address
3008 // -----------------------------------
3009 Label miss;
3010
3011 // Check that the maps haven't changed.
3012 __ JumpIfSmi(a0, &miss);
3013 CheckPrototypes(receiver, a0, holder, a3, t0, a1, name, &miss);
3014
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003015 GenerateLoadViaGetter(masm(), getter);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003016
3017 __ bind(&miss);
3018 GenerateLoadMiss(masm(), Code::LOAD_IC);
3019
3020 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003021 return GetCode(Code::CALLBACKS, name);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003022}
3023
3024
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003025Handle<Code> LoadStubCompiler::CompileLoadGlobal(
3026 Handle<JSObject> object,
3027 Handle<GlobalObject> holder,
3028 Handle<JSGlobalPropertyCell> cell,
3029 Handle<String> name,
3030 bool is_dont_delete) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003031 // ----------- S t a t e -------------
3032 // -- a0 : receiver
3033 // -- a2 : name
3034 // -- ra : return address
3035 // -----------------------------------
3036 Label miss;
3037
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003038 // Check that the map of the global has not changed.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003039 __ JumpIfSmi(a0, &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003040 CheckPrototypes(object, a0, holder, a3, t0, a1, name, &miss);
3041
3042 // Get the value from the cell.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003043 __ li(a3, Operand(cell));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003044 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
3045
3046 // Check for deleted property if property can actually be deleted.
3047 if (!is_dont_delete) {
3048 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
3049 __ Branch(&miss, eq, t0, Operand(at));
3050 }
3051
3052 __ mov(v0, t0);
3053 Counters* counters = masm()->isolate()->counters();
3054 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
3055 __ Ret();
3056
3057 __ bind(&miss);
3058 __ IncrementCounter(counters->named_load_global_stub_miss(), 1, a1, a3);
3059 GenerateLoadMiss(masm(), Code::LOAD_IC);
3060
3061 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003062 return GetCode(Code::NORMAL, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003063}
3064
3065
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003066Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
3067 Handle<Map> receiver_map) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003068 // ----------- S t a t e -------------
3069 // -- ra : return address
3070 // -- a0 : key
3071 // -- a1 : receiver
3072 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003073 ElementsKind elements_kind = receiver_map->elements_kind();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003074 if (receiver_map->has_fast_elements() ||
3075 receiver_map->has_external_array_elements()) {
3076 Handle<Code> stub = KeyedLoadFastElementStub(
3077 receiver_map->instance_type() == JS_ARRAY_TYPE,
3078 elements_kind).GetCode();
3079 __ DispatchMap(a1, a2, receiver_map, stub, DO_SMI_CHECK);
3080 } else {
3081 Handle<Code> stub =
3082 KeyedLoadDictionaryElementStub().GetCode();
3083 __ DispatchMap(a1, a2, receiver_map, stub, DO_SMI_CHECK);
3084 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003085
3086 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss();
3087 __ Jump(ic, RelocInfo::CODE_TARGET);
3088
3089 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003090 return GetCode(Code::NORMAL, factory()->empty_string());
danno@chromium.org40cb8782011-05-25 07:58:50 +00003091}
3092
3093
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003094Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
3095 MapHandleList* receiver_maps,
3096 CodeHandleList* handler_ics) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003097 // ----------- S t a t e -------------
3098 // -- ra : return address
3099 // -- a0 : key
3100 // -- a1 : receiver
3101 // -----------------------------------
3102 Label miss;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003103 __ JumpIfSmi(a1, &miss);
3104
danno@chromium.org40cb8782011-05-25 07:58:50 +00003105 int receiver_count = receiver_maps->length();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003106 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003107 for (int current = 0; current < receiver_count; ++current) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003108 __ Jump(handler_ics->at(current), RelocInfo::CODE_TARGET,
3109 eq, a2, Operand(receiver_maps->at(current)));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003110 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003111
3112 __ bind(&miss);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003113 Handle<Code> miss_ic = isolate()->builtins()->KeyedLoadIC_Miss();
3114 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003115
3116 // Return the generated code.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003117 return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003118}
3119
3120
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003121Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
lrn@chromium.org7516f052011-03-30 08:52:27 +00003122 int index,
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003123 Handle<Map> transition,
3124 Handle<String> name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003125 // ----------- S t a t e -------------
3126 // -- a0 : value
3127 // -- a1 : key
3128 // -- a2 : receiver
3129 // -- ra : return address
3130 // -----------------------------------
3131
3132 Label miss;
3133
3134 Counters* counters = masm()->isolate()->counters();
3135 __ IncrementCounter(counters->keyed_store_field(), 1, a3, t0);
3136
3137 // Check that the name has not changed.
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003138 __ Branch(&miss, ne, a1, Operand(name));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003139
3140 // a3 is used as scratch register. a1 and a2 keep their values if a jump to
3141 // the miss label is generated.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003142 GenerateStoreField(masm(),
3143 object,
3144 index,
3145 transition,
3146 name,
3147 a2, a1, a3, t0,
3148 &miss);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003149 __ bind(&miss);
3150
3151 __ DecrementCounter(counters->keyed_store_field(), 1, a3, t0);
3152 Handle<Code> ic = masm()->isolate()->builtins()->KeyedStoreIC_Miss();
3153 __ Jump(ic, RelocInfo::CODE_TARGET);
3154
3155 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003156 return GetCode(transition.is_null()
3157 ? Code::FIELD
3158 : Code::MAP_TRANSITION, name);
lrn@chromium.org7516f052011-03-30 08:52:27 +00003159}
3160
3161
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003162Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
3163 Handle<Map> receiver_map) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003164 // ----------- S t a t e -------------
3165 // -- a0 : value
3166 // -- a1 : key
3167 // -- a2 : receiver
3168 // -- ra : return address
3169 // -- a3 : scratch
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003170 // -----------------------------------
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003171 ElementsKind elements_kind = receiver_map->elements_kind();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003172 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003173 Handle<Code> stub =
yangguo@chromium.org56454712012-02-16 15:33:53 +00003174 KeyedStoreElementStub(is_js_array, elements_kind, grow_mode_).GetCode();
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003175
3176 __ DispatchMap(a2, a3, receiver_map, stub, DO_SMI_CHECK);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003177
danno@chromium.org40cb8782011-05-25 07:58:50 +00003178 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003179 __ Jump(ic, RelocInfo::CODE_TARGET);
3180
3181 // Return the generated code.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003182 return GetCode(Code::NORMAL, factory()->empty_string());
lrn@chromium.org7516f052011-03-30 08:52:27 +00003183}
3184
3185
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003186Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
3187 MapHandleList* receiver_maps,
3188 CodeHandleList* handler_stubs,
3189 MapHandleList* transitioned_maps) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003190 // ----------- S t a t e -------------
3191 // -- a0 : value
3192 // -- a1 : key
3193 // -- a2 : receiver
3194 // -- ra : return address
3195 // -- a3 : scratch
3196 // -----------------------------------
3197 Label miss;
3198 __ JumpIfSmi(a2, &miss);
3199
3200 int receiver_count = receiver_maps->length();
3201 __ lw(a3, FieldMemOperand(a2, HeapObject::kMapOffset));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003202 for (int i = 0; i < receiver_count; ++i) {
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003203 if (transitioned_maps->at(i).is_null()) {
3204 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq,
3205 a3, Operand(receiver_maps->at(i)));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003206 } else {
3207 Label next_map;
erik.corry@gmail.com6e28b562011-10-27 14:20:17 +00003208 __ Branch(&next_map, ne, a3, Operand(receiver_maps->at(i)));
3209 __ li(a3, Operand(transitioned_maps->at(i)));
3210 __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003211 __ bind(&next_map);
3212 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003213 }
3214
3215 __ bind(&miss);
3216 Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
3217 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3218
3219 // Return the generated code.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003220 return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003221}
3222
3223
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003224Handle<Code> ConstructStubCompiler::CompileConstructStub(
3225 Handle<JSFunction> function) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003226 // a0 : argc
3227 // a1 : constructor
3228 // ra : return address
3229 // [sp] : last argument
3230 Label generic_stub_call;
3231
3232 // Use t7 for holding undefined which is used in several places below.
3233 __ LoadRoot(t7, Heap::kUndefinedValueRootIndex);
3234
3235#ifdef ENABLE_DEBUGGER_SUPPORT
3236 // Check to see whether there are any break points in the function code. If
3237 // there are jump to the generic constructor stub which calls the actual
3238 // code for the function thereby hitting the break points.
3239 __ lw(t5, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3240 __ lw(a2, FieldMemOperand(t5, SharedFunctionInfo::kDebugInfoOffset));
3241 __ Branch(&generic_stub_call, ne, a2, Operand(t7));
3242#endif
3243
3244 // Load the initial map and verify that it is in fact a map.
3245 // a1: constructor function
3246 // t7: undefined
3247 __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003248 __ JumpIfSmi(a2, &generic_stub_call);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003249 __ GetObjectType(a2, a3, t0);
3250 __ Branch(&generic_stub_call, ne, t0, Operand(MAP_TYPE));
3251
3252#ifdef DEBUG
3253 // Cannot construct functions this way.
3254 // a0: argc
3255 // a1: constructor function
3256 // a2: initial map
3257 // t7: undefined
3258 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
3259 __ Check(ne, "Function constructed by construct stub.",
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003260 a3, Operand(JS_FUNCTION_TYPE));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003261#endif
3262
3263 // Now allocate the JSObject in new space.
3264 // a0: argc
3265 // a1: constructor function
3266 // a2: initial map
3267 // t7: undefined
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003268 ASSERT(function->has_initial_map());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003269 __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003270#ifdef DEBUG
3271 int instance_size = function->initial_map()->instance_size();
3272 __ Check(eq, "Instance size of initial map changed.",
3273 a3, Operand(instance_size >> kPointerSizeLog2));
3274#endif
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003275 __ AllocateInNewSpace(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003276
3277 // Allocated the JSObject, now initialize the fields. Map is set to initial
3278 // map and properties and elements are set to empty fixed array.
3279 // a0: argc
3280 // a1: constructor function
3281 // a2: initial map
3282 // a3: object size (in words)
3283 // t4: JSObject (not tagged)
3284 // t7: undefined
3285 __ LoadRoot(t6, Heap::kEmptyFixedArrayRootIndex);
3286 __ mov(t5, t4);
3287 __ sw(a2, MemOperand(t5, JSObject::kMapOffset));
3288 __ sw(t6, MemOperand(t5, JSObject::kPropertiesOffset));
3289 __ sw(t6, MemOperand(t5, JSObject::kElementsOffset));
3290 __ Addu(t5, t5, Operand(3 * kPointerSize));
3291 ASSERT_EQ(0 * kPointerSize, JSObject::kMapOffset);
3292 ASSERT_EQ(1 * kPointerSize, JSObject::kPropertiesOffset);
3293 ASSERT_EQ(2 * kPointerSize, JSObject::kElementsOffset);
3294
3295
3296 // Calculate the location of the first argument. The stack contains only the
3297 // argc arguments.
3298 __ sll(a1, a0, kPointerSizeLog2);
3299 __ Addu(a1, a1, sp);
3300
3301 // Fill all the in-object properties with undefined.
3302 // a0: argc
3303 // a1: first argument
3304 // a3: object size (in words)
3305 // t4: JSObject (not tagged)
3306 // t5: First in-object property of JSObject (not tagged)
3307 // t7: undefined
3308 // Fill the initialized properties with a constant value or a passed argument
3309 // depending on the this.x = ...; assignment in the function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003310 Handle<SharedFunctionInfo> shared(function->shared());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003311 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
3312 if (shared->IsThisPropertyAssignmentArgument(i)) {
3313 Label not_passed, next;
3314 // Check if the argument assigned to the property is actually passed.
3315 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
3316 __ Branch(&not_passed, less_equal, a0, Operand(arg_number));
3317 // Argument passed - find it on the stack.
3318 __ lw(a2, MemOperand(a1, (arg_number + 1) * -kPointerSize));
3319 __ sw(a2, MemOperand(t5));
3320 __ Addu(t5, t5, kPointerSize);
3321 __ jmp(&next);
3322 __ bind(&not_passed);
3323 // Set the property to undefined.
3324 __ sw(t7, MemOperand(t5));
3325 __ Addu(t5, t5, Operand(kPointerSize));
3326 __ bind(&next);
3327 } else {
3328 // Set the property to the constant value.
3329 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
3330 __ li(a2, Operand(constant));
3331 __ sw(a2, MemOperand(t5));
3332 __ Addu(t5, t5, kPointerSize);
3333 }
3334 }
3335
3336 // Fill the unused in-object property fields with undefined.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003337 for (int i = shared->this_property_assignments_count();
3338 i < function->initial_map()->inobject_properties();
3339 i++) {
3340 __ sw(t7, MemOperand(t5));
3341 __ Addu(t5, t5, kPointerSize);
3342 }
3343
3344 // a0: argc
3345 // t4: JSObject (not tagged)
3346 // Move argc to a1 and the JSObject to return to v0 and tag it.
3347 __ mov(a1, a0);
3348 __ mov(v0, t4);
3349 __ Or(v0, v0, Operand(kHeapObjectTag));
3350
3351 // v0: JSObject
3352 // a1: argc
3353 // Remove caller arguments and receiver from the stack and return.
3354 __ sll(t0, a1, kPointerSizeLog2);
3355 __ Addu(sp, sp, t0);
3356 __ Addu(sp, sp, Operand(kPointerSize));
3357 Counters* counters = masm()->isolate()->counters();
3358 __ IncrementCounter(counters->constructed_objects(), 1, a1, a2);
3359 __ IncrementCounter(counters->constructed_objects_stub(), 1, a1, a2);
3360 __ Ret();
3361
3362 // Jump to the generic stub in case the specialized code cannot handle the
3363 // construction.
3364 __ bind(&generic_stub_call);
3365 Handle<Code> generic_construct_stub =
3366 masm()->isolate()->builtins()->JSConstructStubGeneric();
3367 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
3368
3369 // Return the generated code.
3370 return GetCode();
3371}
3372
3373
danno@chromium.org40cb8782011-05-25 07:58:50 +00003374#undef __
3375#define __ ACCESS_MASM(masm)
3376
3377
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003378void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
3379 MacroAssembler* masm) {
3380 // ---------- S t a t e --------------
3381 // -- ra : return address
3382 // -- a0 : key
3383 // -- a1 : receiver
3384 // -----------------------------------
3385 Label slow, miss_force_generic;
3386
3387 Register key = a0;
3388 Register receiver = a1;
3389
3390 __ JumpIfNotSmi(key, &miss_force_generic);
3391 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
3392 __ sra(a2, a0, kSmiTagSize);
3393 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
3394 __ Ret();
3395
3396 // Slow case, key and receiver still in a0 and a1.
3397 __ bind(&slow);
3398 __ IncrementCounter(
3399 masm->isolate()->counters()->keyed_load_external_array_slow(),
3400 1, a2, a3);
3401 // Entry registers are intact.
3402 // ---------- S t a t e --------------
3403 // -- ra : return address
3404 // -- a0 : key
3405 // -- a1 : receiver
3406 // -----------------------------------
3407 Handle<Code> slow_ic =
3408 masm->isolate()->builtins()->KeyedLoadIC_Slow();
3409 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
3410
3411 // Miss case, call the runtime.
3412 __ bind(&miss_force_generic);
3413
3414 // ---------- S t a t e --------------
3415 // -- ra : return address
3416 // -- a0 : key
3417 // -- a1 : receiver
3418 // -----------------------------------
3419
3420 Handle<Code> miss_ic =
3421 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
3422 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3423}
3424
3425
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003426static bool IsElementTypeSigned(ElementsKind elements_kind) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003427 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003428 case EXTERNAL_BYTE_ELEMENTS:
3429 case EXTERNAL_SHORT_ELEMENTS:
3430 case EXTERNAL_INT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003431 return true;
3432
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003433 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3434 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3435 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3436 case EXTERNAL_PIXEL_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003437 return false;
3438
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003439 case EXTERNAL_FLOAT_ELEMENTS:
3440 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003441 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003442 case FAST_ELEMENTS:
3443 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003444 case FAST_HOLEY_SMI_ELEMENTS:
3445 case FAST_HOLEY_ELEMENTS:
3446 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003447 case DICTIONARY_ELEMENTS:
3448 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003449 UNREACHABLE();
3450 return false;
3451 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003452 return false;
lrn@chromium.org7516f052011-03-30 08:52:27 +00003453}
3454
3455
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003456static void GenerateSmiKeyCheck(MacroAssembler* masm,
3457 Register key,
3458 Register scratch0,
3459 Register scratch1,
3460 FPURegister double_scratch0,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003461 FPURegister double_scratch1,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003462 Label* fail) {
3463 if (CpuFeatures::IsSupported(FPU)) {
3464 CpuFeatures::Scope scope(FPU);
3465 Label key_ok;
3466 // Check for smi or a smi inside a heap number. We convert the heap
3467 // number and check if the conversion is exact and fits into the smi
3468 // range.
3469 __ JumpIfSmi(key, &key_ok);
3470 __ CheckMap(key,
3471 scratch0,
3472 Heap::kHeapNumberMapRootIndex,
3473 fail,
3474 DONT_DO_SMI_CHECK);
3475 __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
3476 __ EmitFPUTruncate(kRoundToZero,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003477 scratch0,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003478 double_scratch0,
3479 at,
3480 double_scratch1,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003481 scratch1,
3482 kCheckForInexactConversion);
3483
3484 __ Branch(fail, ne, scratch1, Operand(zero_reg));
3485
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003486 __ SmiTagCheckOverflow(key, scratch0, scratch1);
3487 __ BranchOnOverflow(fail, scratch1);
3488 __ bind(&key_ok);
3489 } else {
3490 // Check that the key is a smi.
3491 __ JumpIfNotSmi(key, fail);
3492 }
3493}
3494
3495
danno@chromium.org40cb8782011-05-25 07:58:50 +00003496void KeyedStoreStubCompiler::GenerateStoreExternalArray(
3497 MacroAssembler* masm,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003498 ElementsKind elements_kind) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003499 // ---------- S t a t e --------------
3500 // -- a0 : value
3501 // -- a1 : key
3502 // -- a2 : receiver
3503 // -- ra : return address
3504 // -----------------------------------
3505
danno@chromium.org40cb8782011-05-25 07:58:50 +00003506 Label slow, check_heap_number, miss_force_generic;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003507
3508 // Register usage.
3509 Register value = a0;
3510 Register key = a1;
3511 Register receiver = a2;
3512 // a3 mostly holds the elements array or the destination external array.
3513
danno@chromium.org40cb8782011-05-25 07:58:50 +00003514 // This stub is meant to be tail-jumped to, the receiver must already
3515 // have been verified by the caller to not be a smi.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003516
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003517 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003518 GenerateSmiKeyCheck(masm, key, t0, t1, f2, f4, &miss_force_generic);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003519
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003520 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
3521
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003522 // Check that the index is in range.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003523 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
3524 // Unsigned comparison catches both negative and too-large values.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003525 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003526
3527 // Handle both smis and HeapNumbers in the fast path. Go to the
3528 // runtime for all other kinds of values.
3529 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003530
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003531 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003532 // Double to pixel conversion is only implemented in the runtime for now.
3533 __ JumpIfNotSmi(value, &slow);
3534 } else {
3535 __ JumpIfNotSmi(value, &check_heap_number);
3536 }
3537 __ SmiUntag(t1, value);
3538 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3539
3540 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003541 // t1: value (integer).
3542
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003543 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003544 case EXTERNAL_PIXEL_ELEMENTS: {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003545 // Clamp the value to [0..255].
3546 // v0 is used as a scratch register here.
3547 Label done;
3548 __ li(v0, Operand(255));
3549 // Normal branch: nop in delay slot.
3550 __ Branch(&done, gt, t1, Operand(v0));
3551 // Use delay slot in this branch.
3552 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg));
3553 __ mov(v0, zero_reg); // In delay slot.
3554 __ mov(v0, t1); // Value is in range 0..255.
3555 __ bind(&done);
3556 __ mov(t1, v0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003557
3558 __ srl(t8, key, 1);
3559 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003560 __ sb(t1, MemOperand(t8, 0));
3561 }
3562 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003563 case EXTERNAL_BYTE_ELEMENTS:
3564 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003565 __ srl(t8, key, 1);
3566 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003567 __ sb(t1, MemOperand(t8, 0));
3568 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003569 case EXTERNAL_SHORT_ELEMENTS:
3570 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003571 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003572 __ sh(t1, MemOperand(t8, 0));
3573 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003574 case EXTERNAL_INT_ELEMENTS:
3575 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003576 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003577 __ addu(t8, a3, t8);
3578 __ sw(t1, MemOperand(t8, 0));
3579 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003580 case EXTERNAL_FLOAT_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003581 // Perform int-to-float conversion and store to memory.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003582 __ SmiUntag(t0, key);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003583 StoreIntAsFloat(masm, a3, t0, t1, t2, t3, t4);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003584 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003585 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003586 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003587 __ addu(a3, a3, t8);
3588 // a3: effective address of the double element
3589 FloatingPointHelper::Destination destination;
3590 if (CpuFeatures::IsSupported(FPU)) {
3591 destination = FloatingPointHelper::kFPURegisters;
3592 } else {
3593 destination = FloatingPointHelper::kCoreRegisters;
3594 }
3595 FloatingPointHelper::ConvertIntToDouble(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003596 masm, t1, destination,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003597 f0, t2, t3, // These are: double_dst, dst_mantissa, dst_exponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003598 t0, f2); // These are: scratch2, single_scratch.
3599 if (destination == FloatingPointHelper::kFPURegisters) {
3600 CpuFeatures::Scope scope(FPU);
3601 __ sdc1(f0, MemOperand(a3, 0));
3602 } else {
3603 __ sw(t2, MemOperand(a3, 0));
3604 __ sw(t3, MemOperand(a3, Register::kSizeInBytes));
3605 }
3606 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003607 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003608 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003609 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003610 case FAST_HOLEY_ELEMENTS:
3611 case FAST_HOLEY_SMI_ELEMENTS:
3612 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003613 case DICTIONARY_ELEMENTS:
3614 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003615 UNREACHABLE();
3616 break;
3617 }
3618
3619 // Entry registers are intact, a0 holds the value which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003620 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003621 __ Ret();
3622
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003623 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003624 // a3: external array.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003625 __ bind(&check_heap_number);
3626 __ GetObjectType(value, t1, t2);
3627 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE));
3628
3629 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
3630
3631 // a3: base pointer of external storage.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003632
3633 // The WebGL specification leaves the behavior of storing NaN and
3634 // +/-Infinity into integer arrays basically undefined. For more
3635 // reproducible behavior, convert these to zero.
3636
3637 if (CpuFeatures::IsSupported(FPU)) {
3638 CpuFeatures::Scope scope(FPU);
3639
3640 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
3641
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003642 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003643 __ cvt_s_d(f0, f0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003644 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003645 __ addu(t8, a3, t8);
3646 __ swc1(f0, MemOperand(t8, 0));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003647 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003648 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003649 __ addu(t8, a3, t8);
3650 __ sdc1(f0, MemOperand(t8, 0));
3651 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003652 __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003653
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003654 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003655 case EXTERNAL_BYTE_ELEMENTS:
3656 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003657 __ srl(t8, key, 1);
3658 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003659 __ sb(t3, MemOperand(t8, 0));
3660 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003661 case EXTERNAL_SHORT_ELEMENTS:
3662 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003663 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003664 __ sh(t3, MemOperand(t8, 0));
3665 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003666 case EXTERNAL_INT_ELEMENTS:
3667 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003668 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003669 __ addu(t8, a3, t8);
3670 __ sw(t3, MemOperand(t8, 0));
3671 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003672 case EXTERNAL_PIXEL_ELEMENTS:
3673 case EXTERNAL_FLOAT_ELEMENTS:
3674 case EXTERNAL_DOUBLE_ELEMENTS:
3675 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003676 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003677 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003678 case FAST_HOLEY_ELEMENTS:
3679 case FAST_HOLEY_SMI_ELEMENTS:
3680 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003681 case DICTIONARY_ELEMENTS:
3682 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003683 UNREACHABLE();
3684 break;
3685 }
3686 }
3687
3688 // Entry registers are intact, a0 holds the value
3689 // which is the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003690 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003691 __ Ret();
3692 } else {
3693 // FPU is not available, do manual conversions.
3694
3695 __ lw(t3, FieldMemOperand(value, HeapNumber::kExponentOffset));
3696 __ lw(t4, FieldMemOperand(value, HeapNumber::kMantissaOffset));
3697
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003698 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003699 Label done, nan_or_infinity_or_zero;
3700 static const int kMantissaInHiWordShift =
3701 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
3702
3703 static const int kMantissaInLoWordShift =
3704 kBitsPerInt - kMantissaInHiWordShift;
3705
3706 // Test for all special exponent values: zeros, subnormal numbers, NaNs
3707 // and infinities. All these should be converted to 0.
3708 __ li(t5, HeapNumber::kExponentMask);
3709 __ and_(t6, t3, t5);
3710 __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(zero_reg));
3711
3712 __ xor_(t1, t6, t5);
3713 __ li(t2, kBinary32ExponentMask);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003714 __ Movz(t6, t2, t1); // Only if t6 is equal to t5.
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003715 __ Branch(&nan_or_infinity_or_zero, eq, t1, Operand(zero_reg));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003716
3717 // Rebias exponent.
3718 __ srl(t6, t6, HeapNumber::kExponentShift);
3719 __ Addu(t6,
3720 t6,
3721 Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
3722
3723 __ li(t1, Operand(kBinary32MaxExponent));
3724 __ Slt(t1, t1, t6);
3725 __ And(t2, t3, Operand(HeapNumber::kSignMask));
3726 __ Or(t2, t2, Operand(kBinary32ExponentMask));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003727 __ Movn(t3, t2, t1); // Only if t6 is gt kBinary32MaxExponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003728 __ Branch(&done, gt, t6, Operand(kBinary32MaxExponent));
3729
3730 __ Slt(t1, t6, Operand(kBinary32MinExponent));
3731 __ And(t2, t3, Operand(HeapNumber::kSignMask));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003732 __ Movn(t3, t2, t1); // Only if t6 is lt kBinary32MinExponent.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003733 __ Branch(&done, lt, t6, Operand(kBinary32MinExponent));
3734
3735 __ And(t7, t3, Operand(HeapNumber::kSignMask));
3736 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3737 __ sll(t3, t3, kMantissaInHiWordShift);
3738 __ or_(t7, t7, t3);
3739 __ srl(t4, t4, kMantissaInLoWordShift);
3740 __ or_(t7, t7, t4);
3741 __ sll(t6, t6, kBinary32ExponentShift);
3742 __ or_(t3, t7, t6);
3743
3744 __ bind(&done);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003745 __ sll(t9, key, 1);
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003746 __ addu(t9, a3, t9);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003747 __ sw(t3, MemOperand(t9, 0));
3748
3749 // Entry registers are intact, a0 holds the value which is the return
3750 // value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003751 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003752 __ Ret();
3753
3754 __ bind(&nan_or_infinity_or_zero);
3755 __ And(t7, t3, Operand(HeapNumber::kSignMask));
3756 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3757 __ or_(t6, t6, t7);
3758 __ sll(t3, t3, kMantissaInHiWordShift);
3759 __ or_(t6, t6, t3);
3760 __ srl(t4, t4, kMantissaInLoWordShift);
3761 __ or_(t3, t6, t4);
3762 __ Branch(&done);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003763 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003764 __ sll(t8, key, 2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003765 __ addu(t8, a3, t8);
3766 // t8: effective address of destination element.
3767 __ sw(t4, MemOperand(t8, 0));
3768 __ sw(t3, MemOperand(t8, Register::kSizeInBytes));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003769 __ mov(v0, a0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003770 __ Ret();
3771 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003772 bool is_signed_type = IsElementTypeSigned(elements_kind);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003773 int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
3774 int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
3775
3776 Label done, sign;
3777
3778 // Test for all special exponent values: zeros, subnormal numbers, NaNs
3779 // and infinities. All these should be converted to 0.
3780 __ li(t5, HeapNumber::kExponentMask);
3781 __ and_(t6, t3, t5);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003782 __ Movz(t3, zero_reg, t6); // Only if t6 is equal to zero.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003783 __ Branch(&done, eq, t6, Operand(zero_reg));
3784
3785 __ xor_(t2, t6, t5);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003786 __ Movz(t3, zero_reg, t2); // Only if t6 is equal to t5.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003787 __ Branch(&done, eq, t6, Operand(t5));
3788
3789 // Unbias exponent.
3790 __ srl(t6, t6, HeapNumber::kExponentShift);
3791 __ Subu(t6, t6, Operand(HeapNumber::kExponentBias));
3792 // If exponent is negative then result is 0.
3793 __ slt(t2, t6, zero_reg);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003794 __ Movn(t3, zero_reg, t2); // Only if exponent is negative.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003795 __ Branch(&done, lt, t6, Operand(zero_reg));
3796
3797 // If exponent is too big then result is minimal value.
3798 __ slti(t1, t6, meaningfull_bits - 1);
3799 __ li(t2, min_value);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003800 __ Movz(t3, t2, t1); // Only if t6 is ge meaningfull_bits - 1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003801 __ Branch(&done, ge, t6, Operand(meaningfull_bits - 1));
3802
3803 __ And(t5, t3, Operand(HeapNumber::kSignMask));
3804 __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
3805 __ Or(t3, t3, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
3806
3807 __ li(t9, HeapNumber::kMantissaBitsInTopWord);
3808 __ subu(t6, t9, t6);
3809 __ slt(t1, t6, zero_reg);
3810 __ srlv(t2, t3, t6);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003811 __ Movz(t3, t2, t1); // Only if t6 is positive.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003812 __ Branch(&sign, ge, t6, Operand(zero_reg));
3813
3814 __ subu(t6, zero_reg, t6);
3815 __ sllv(t3, t3, t6);
3816 __ li(t9, meaningfull_bits);
3817 __ subu(t6, t9, t6);
3818 __ srlv(t4, t4, t6);
3819 __ or_(t3, t3, t4);
3820
3821 __ bind(&sign);
3822 __ subu(t2, t3, zero_reg);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00003823 __ Movz(t3, t2, t5); // Only if t5 is zero.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003824
3825 __ bind(&done);
3826
3827 // Result is in t3.
3828 // This switch block should be exactly the same as above (FPU mode).
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003829 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003830 case EXTERNAL_BYTE_ELEMENTS:
3831 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003832 __ srl(t8, key, 1);
3833 __ addu(t8, a3, t8);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003834 __ sb(t3, MemOperand(t8, 0));
3835 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003836 case EXTERNAL_SHORT_ELEMENTS:
3837 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003838 __ addu(t8, a3, key);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003839 __ sh(t3, MemOperand(t8, 0));
3840 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003841 case EXTERNAL_INT_ELEMENTS:
3842 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003843 __ sll(t8, key, 1);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003844 __ addu(t8, a3, t8);
3845 __ sw(t3, MemOperand(t8, 0));
3846 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003847 case EXTERNAL_PIXEL_ELEMENTS:
3848 case EXTERNAL_FLOAT_ELEMENTS:
3849 case EXTERNAL_DOUBLE_ELEMENTS:
3850 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003851 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003852 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003853 case FAST_HOLEY_ELEMENTS:
3854 case FAST_HOLEY_SMI_ELEMENTS:
3855 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003856 case DICTIONARY_ELEMENTS:
3857 case NON_STRICT_ARGUMENTS_ELEMENTS:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003858 UNREACHABLE();
3859 break;
3860 }
3861 }
3862 }
3863 }
3864
danno@chromium.org40cb8782011-05-25 07:58:50 +00003865 // Slow case, key and receiver still in a0 and a1.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003866 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003867 __ IncrementCounter(
3868 masm->isolate()->counters()->keyed_load_external_array_slow(),
3869 1, a2, a3);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003870 // Entry registers are intact.
3871 // ---------- S t a t e --------------
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003872 // -- ra : return address
danno@chromium.org40cb8782011-05-25 07:58:50 +00003873 // -- a0 : key
3874 // -- a1 : receiver
3875 // -----------------------------------
3876 Handle<Code> slow_ic =
3877 masm->isolate()->builtins()->KeyedStoreIC_Slow();
3878 __ Jump(slow_ic, RelocInfo::CODE_TARGET);
3879
3880 // Miss case, call the runtime.
3881 __ bind(&miss_force_generic);
3882
3883 // ---------- S t a t e --------------
3884 // -- ra : return address
3885 // -- a0 : key
3886 // -- a1 : receiver
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003887 // -----------------------------------
3888
danno@chromium.org40cb8782011-05-25 07:58:50 +00003889 Handle<Code> miss_ic =
3890 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
3891 __ Jump(miss_ic, RelocInfo::CODE_TARGET);
3892}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003893
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003894
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003895void KeyedStoreStubCompiler::GenerateStoreFastElement(
3896 MacroAssembler* masm,
3897 bool is_js_array,
yangguo@chromium.org56454712012-02-16 15:33:53 +00003898 ElementsKind elements_kind,
3899 KeyedAccessGrowMode grow_mode) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00003900 // ----------- S t a t e -------------
3901 // -- a0 : value
3902 // -- a1 : key
3903 // -- a2 : receiver
3904 // -- ra : return address
3905 // -- a3 : scratch
3906 // -- a4 : scratch (elements)
3907 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00003908 Label miss_force_generic, transition_elements_kind, grow, slow;
3909 Label finish_store, check_capacity;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003910
3911 Register value_reg = a0;
3912 Register key_reg = a1;
3913 Register receiver_reg = a2;
yangguo@chromium.org56454712012-02-16 15:33:53 +00003914 Register scratch = t0;
3915 Register elements_reg = a3;
3916 Register length_reg = t1;
3917 Register scratch2 = t2;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003918
3919 // This stub is meant to be tail-jumped to, the receiver must already
3920 // have been verified by the caller to not be a smi.
3921
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003922 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003923 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003924
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003925 if (IsFastSmiElementsKind(elements_kind)) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00003926 __ JumpIfNotSmi(value_reg, &transition_elements_kind);
3927 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003928
3929 // Check that the key is within bounds.
yangguo@chromium.org56454712012-02-16 15:33:53 +00003930 __ lw(elements_reg,
3931 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003932 if (is_js_array) {
3933 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
3934 } else {
3935 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
3936 }
3937 // Compare smis.
yangguo@chromium.org56454712012-02-16 15:33:53 +00003938 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
3939 __ Branch(&grow, hs, key_reg, Operand(scratch));
3940 } else {
3941 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
3942 }
3943
3944 // Make sure elements is a fast element array, not 'cow'.
3945 __ CheckMap(elements_reg,
3946 scratch,
3947 Heap::kFixedArrayMapRootIndex,
3948 &miss_force_generic,
3949 DONT_DO_SMI_CHECK);
3950
3951 __ bind(&finish_store);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003952
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003953 if (IsFastSmiElementsKind(elements_kind)) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003954 __ Addu(scratch,
3955 elements_reg,
3956 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3957 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
3958 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
3959 __ Addu(scratch, scratch, scratch2);
3960 __ sw(value_reg, MemOperand(scratch));
3961 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003962 ASSERT(IsFastObjectElementsKind(elements_kind));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003963 __ Addu(scratch,
3964 elements_reg,
3965 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3966 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
3967 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
3968 __ Addu(scratch, scratch, scratch2);
3969 __ sw(value_reg, MemOperand(scratch));
3970 __ mov(receiver_reg, value_reg);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003971 __ RecordWrite(elements_reg, // Object.
3972 scratch, // Address.
3973 receiver_reg, // Value.
3974 kRAHasNotBeenSaved,
3975 kDontSaveFPRegs);
3976 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00003977 // value_reg (a0) is preserved.
3978 // Done.
3979 __ Ret();
3980
3981 __ bind(&miss_force_generic);
3982 Handle<Code> ic =
3983 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
3984 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003985
3986 __ bind(&transition_elements_kind);
3987 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
3988 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
yangguo@chromium.org56454712012-02-16 15:33:53 +00003989
3990 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
3991 // Grow the array by a single element if possible.
3992 __ bind(&grow);
3993
3994 // Make sure the array is only growing by a single element, anything else
3995 // must be handled by the runtime.
3996 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch));
3997
3998 // Check for the empty array, and preallocate a small backing store if
3999 // possible.
4000 __ lw(length_reg,
4001 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4002 __ lw(elements_reg,
4003 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4004 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
4005 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
4006
4007 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
4008 __ AllocateInNewSpace(size, elements_reg, scratch, scratch2, &slow,
4009 TAG_OBJECT);
4010
4011 __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex);
4012 __ sw(scratch, FieldMemOperand(elements_reg, JSObject::kMapOffset));
4013 __ li(scratch, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4014 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4015 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
4016 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) {
4017 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::SizeFor(i)));
4018 }
4019
4020 // Store the element at index zero.
4021 __ sw(value_reg, FieldMemOperand(elements_reg, FixedArray::SizeFor(0)));
4022
4023 // Install the new backing store in the JSArray.
4024 __ sw(elements_reg,
4025 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4026 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
4027 scratch, kRAHasNotBeenSaved, kDontSaveFPRegs,
4028 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4029
4030 // Increment the length of the array.
4031 __ li(length_reg, Operand(Smi::FromInt(1)));
4032 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4033 __ Ret();
4034
4035 __ bind(&check_capacity);
4036 // Check for cow elements, in general they are not handled by this stub
4037 __ CheckMap(elements_reg,
4038 scratch,
4039 Heap::kFixedCOWArrayMapRootIndex,
4040 &miss_force_generic,
4041 DONT_DO_SMI_CHECK);
4042
4043 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4044 __ Branch(&slow, hs, length_reg, Operand(scratch));
4045
4046 // Grow the array and finish the store.
4047 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
4048 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4049 __ jmp(&finish_store);
4050
4051 __ bind(&slow);
4052 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4053 __ Jump(ic_slow, RelocInfo::CODE_TARGET);
4054 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004055}
4056
4057
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004058void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
4059 MacroAssembler* masm,
yangguo@chromium.org56454712012-02-16 15:33:53 +00004060 bool is_js_array,
4061 KeyedAccessGrowMode grow_mode) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004062 // ----------- S t a t e -------------
4063 // -- a0 : value
4064 // -- a1 : key
4065 // -- a2 : receiver
4066 // -- ra : return address
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004067 // -- a3 : scratch (elements backing store)
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004068 // -- t0 : scratch (elements_reg)
4069 // -- t1 : scratch (mantissa_reg)
4070 // -- t2 : scratch (exponent_reg)
4071 // -- t3 : scratch4
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004072 // -- t4 : scratch
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004073 // -----------------------------------
yangguo@chromium.org56454712012-02-16 15:33:53 +00004074 Label miss_force_generic, transition_elements_kind, grow, slow;
4075 Label finish_store, check_capacity;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004076
4077 Register value_reg = a0;
4078 Register key_reg = a1;
4079 Register receiver_reg = a2;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004080 Register elements_reg = a3;
4081 Register scratch1 = t0;
4082 Register scratch2 = t1;
4083 Register scratch3 = t2;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004084 Register scratch4 = t3;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004085 Register scratch5 = t4;
yangguo@chromium.org56454712012-02-16 15:33:53 +00004086 Register length_reg = t3;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004087
4088 // This stub is meant to be tail-jumped to, the receiver must already
4089 // have been verified by the caller to not be a smi.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004090
4091 // Check that the key is a smi or a heap number convertible to a smi.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004092 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004093
4094 __ lw(elements_reg,
4095 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4096
4097 // Check that the key is within bounds.
4098 if (is_js_array) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004099 __ lw(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004100 } else {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004101 __ lw(scratch1,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004102 FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
4103 }
4104 // Compare smis, unsigned compare catches both negative and out-of-bound
4105 // indexes.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004106 if (grow_mode == ALLOW_JSARRAY_GROWTH) {
4107 __ Branch(&grow, hs, key_reg, Operand(scratch1));
4108 } else {
4109 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch1));
4110 }
4111
4112 __ bind(&finish_store);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004113
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004114 __ StoreNumberToDoubleElements(value_reg,
4115 key_reg,
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004116 // All registers after this are overwritten.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004117 elements_reg,
4118 scratch1,
4119 scratch2,
4120 scratch3,
4121 scratch4,
4122 &transition_elements_kind);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004123
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004124 __ Ret(USE_DELAY_SLOT);
4125 __ mov(v0, value_reg); // In delay slot.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004126
4127 // Handle store cache miss, replacing the ic with the generic stub.
4128 __ bind(&miss_force_generic);
4129 Handle<Code> ic =
4130 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
4131 __ Jump(ic, RelocInfo::CODE_TARGET);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00004132
4133 __ bind(&transition_elements_kind);
4134 Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
4135 __ Jump(ic_miss, RelocInfo::CODE_TARGET);
yangguo@chromium.org56454712012-02-16 15:33:53 +00004136
4137 if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
4138 // Grow the array by a single element if possible.
4139 __ bind(&grow);
4140
4141 // Make sure the array is only growing by a single element, anything else
4142 // must be handled by the runtime.
4143 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch1));
4144
4145 // Transition on values that can't be stored in a FixedDoubleArray.
4146 Label value_is_smi;
4147 __ JumpIfSmi(value_reg, &value_is_smi);
4148 __ lw(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
4149 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
4150 __ Branch(&transition_elements_kind, ne, scratch1, Operand(at));
4151 __ bind(&value_is_smi);
4152
4153 // Check for the empty array, and preallocate a small backing store if
4154 // possible.
4155 __ lw(length_reg,
4156 FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4157 __ lw(elements_reg,
4158 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4159 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
4160 __ Branch(&check_capacity, ne, elements_reg, Operand(at));
4161
4162 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements);
4163 __ AllocateInNewSpace(size, elements_reg, scratch1, scratch2, &slow,
4164 TAG_OBJECT);
4165
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004166 // Initialize the new FixedDoubleArray.
yangguo@chromium.org56454712012-02-16 15:33:53 +00004167 __ LoadRoot(scratch1, Heap::kFixedDoubleArrayMapRootIndex);
4168 __ sw(scratch1, FieldMemOperand(elements_reg, JSObject::kMapOffset));
4169 __ li(scratch1, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
4170 __ sw(scratch1,
4171 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
4172
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004173 __ mov(scratch1, elements_reg);
4174 __ StoreNumberToDoubleElements(value_reg,
4175 key_reg,
4176 // All registers after this are overwritten.
4177 scratch1,
4178 scratch2,
4179 scratch3,
4180 scratch4,
4181 scratch5,
4182 &transition_elements_kind);
4183
4184 __ li(scratch1, Operand(kHoleNanLower32));
4185 __ li(scratch2, Operand(kHoleNanUpper32));
4186 for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) {
4187 int offset = FixedDoubleArray::OffsetOfElementAt(i);
4188 __ sw(scratch1, FieldMemOperand(elements_reg, offset));
4189 __ sw(scratch2, FieldMemOperand(elements_reg, offset + kPointerSize));
4190 }
4191
yangguo@chromium.org56454712012-02-16 15:33:53 +00004192 // Install the new backing store in the JSArray.
4193 __ sw(elements_reg,
4194 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
4195 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg,
4196 scratch1, kRAHasNotBeenSaved, kDontSaveFPRegs,
4197 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
4198
4199 // Increment the length of the array.
4200 __ li(length_reg, Operand(Smi::FromInt(1)));
4201 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
danno@chromium.org00379b82012-05-04 09:16:29 +00004202 __ lw(elements_reg,
4203 FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004204 __ Ret();
yangguo@chromium.org56454712012-02-16 15:33:53 +00004205
4206 __ bind(&check_capacity);
4207 // Make sure that the backing store can hold additional elements.
4208 __ lw(scratch1,
4209 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
4210 __ Branch(&slow, hs, length_reg, Operand(scratch1));
4211
4212 // Grow the array and finish the store.
4213 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1)));
4214 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
4215 __ jmp(&finish_store);
4216
4217 __ bind(&slow);
4218 Handle<Code> ic_slow = masm->isolate()->builtins()->KeyedStoreIC_Slow();
4219 __ Jump(ic_slow, RelocInfo::CODE_TARGET);
4220 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004221}
4222
4223
ager@chromium.org5c838252010-02-19 08:53:10 +00004224#undef __
4225
4226} } // namespace v8::internal
4227
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004228#endif // V8_TARGET_ARCH_MIPS